pacemaker  1.1.19-c3c624ea3d
Scalable High-Availability cluster resource manager
services_linux.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010-2016 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13 
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <dirent.h>
20 #include <string.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 
24 #ifdef HAVE_SYS_SIGNALFD_H
25 #include <sys/signalfd.h>
26 #endif
27 
28 #include "crm/crm.h"
29 #include "crm/common/mainloop.h"
30 #include "crm/services.h"
31 
32 #include "services_private.h"
33 
34 #if SUPPORT_CIBSECRETS
35 # include "crm/common/cib_secrets.h"
36 #endif
37 
38 static gboolean
39 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
40 {
41  char *data = NULL;
42  int rc = 0, len = 0;
43  char buf[500];
44  static const size_t buf_read_len = sizeof(buf) - 1;
45 
46 
47  if (fd < 0) {
48  crm_trace("No fd for %s", op->id);
49  return FALSE;
50  }
51 
52  if (is_stderr && op->stderr_data) {
53  len = strlen(op->stderr_data);
54  data = op->stderr_data;
55  crm_trace("Reading %s stderr into offset %d", op->id, len);
56 
57  } else if (is_stderr == FALSE && op->stdout_data) {
58  len = strlen(op->stdout_data);
59  data = op->stdout_data;
60  crm_trace("Reading %s stdout into offset %d", op->id, len);
61 
62  } else {
63  crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
64  }
65 
66  do {
67  rc = read(fd, buf, buf_read_len);
68  if (rc > 0) {
69  crm_trace("Got %d chars: %.80s", rc, buf);
70  buf[rc] = 0;
71  data = realloc_safe(data, len + rc + 1);
72  len += sprintf(data + len, "%s", buf);
73 
74  } else if (errno != EINTR) {
75  /* error or EOF
76  * Cleanup happens in pipe_done()
77  */
78  rc = FALSE;
79  break;
80  }
81 
82  } while (rc == buf_read_len || rc < 0);
83 
84  if (is_stderr) {
85  op->stderr_data = data;
86  } else {
87  op->stdout_data = data;
88  }
89 
90  return rc;
91 }
92 
93 static int
94 dispatch_stdout(gpointer userdata)
95 {
96  svc_action_t *op = (svc_action_t *) userdata;
97 
98  return svc_read_output(op->opaque->stdout_fd, op, FALSE);
99 }
100 
101 static int
102 dispatch_stderr(gpointer userdata)
103 {
104  svc_action_t *op = (svc_action_t *) userdata;
105 
106  return svc_read_output(op->opaque->stderr_fd, op, TRUE);
107 }
108 
109 static void
110 pipe_out_done(gpointer user_data)
111 {
112  svc_action_t *op = (svc_action_t *) user_data;
113 
114  crm_trace("%p", op);
115 
116  op->opaque->stdout_gsource = NULL;
117  if (op->opaque->stdout_fd > STDOUT_FILENO) {
118  close(op->opaque->stdout_fd);
119  }
120  op->opaque->stdout_fd = -1;
121 }
122 
123 static void
124 pipe_err_done(gpointer user_data)
125 {
126  svc_action_t *op = (svc_action_t *) user_data;
127 
128  op->opaque->stderr_gsource = NULL;
129  if (op->opaque->stderr_fd > STDERR_FILENO) {
130  close(op->opaque->stderr_fd);
131  }
132  op->opaque->stderr_fd = -1;
133 }
134 
135 static struct mainloop_fd_callbacks stdout_callbacks = {
136  .dispatch = dispatch_stdout,
137  .destroy = pipe_out_done,
138 };
139 
140 static struct mainloop_fd_callbacks stderr_callbacks = {
141  .dispatch = dispatch_stderr,
142  .destroy = pipe_err_done,
143 };
144 
145 static void
146 set_ocf_env(const char *key, const char *value, gpointer user_data)
147 {
148  if (setenv(key, value, 1) != 0) {
149  crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
150  }
151 }
152 
153 static void
154 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
155 {
156  char buffer[500];
157 
158  snprintf(buffer, sizeof(buffer), "OCF_RESKEY_%s", (char *)key);
159  set_ocf_env(buffer, value, user_data);
160 }
161 
168 static void
169 add_action_env_vars(const svc_action_t *op)
170 {
171  if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF) == FALSE) {
172  return;
173  }
174 
175  if (op->params) {
176  g_hash_table_foreach(op->params, set_ocf_env_with_prefix, NULL);
177  }
178 
179  set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
180  set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
181  set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
182  set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
183 
184  if (op->rsc) {
185  set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
186  }
187 
188  if (op->agent != NULL) {
189  set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
190  }
191 
192  /* Notes: this is not added to specification yet. Sept 10,2004 */
193  if (op->provider != NULL) {
194  set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
195  }
196 }
197 
198 gboolean
200 {
201  svc_action_t *op = data;
202 
203  crm_debug("Scheduling another invocation of %s", op->id);
204 
205  /* Clean out the old result */
206  free(op->stdout_data);
207  op->stdout_data = NULL;
208  free(op->stderr_data);
209  op->stderr_data = NULL;
210  op->opaque->repeat_timer = 0;
211 
212  services_action_async(op, NULL);
213  return FALSE;
214 }
215 
216 /* Returns FALSE if 'op' should be free'd by the caller */
217 gboolean
219 {
220  int recurring = 0;
221 
222  if (op->interval) {
223  if (op->cancel) {
226  } else {
227  recurring = 1;
228  op->opaque->repeat_timer = g_timeout_add(op->interval,
229  recurring_action_timer, (void *)op);
230  }
231  }
232 
233  if (op->opaque->callback) {
234  op->opaque->callback(op);
235  }
236 
237  op->pid = 0;
238 
240 
241  if (!recurring && op->synchronous == FALSE) {
242  /*
243  * If this is a recurring action, do not free explicitly.
244  * It will get freed whenever the action gets cancelled.
245  */
247  return TRUE;
248  }
249 
251  return FALSE;
252 }
253 
254 static void
255 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
256 {
258  char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid);
259 
261  op->status = PCMK_LRM_OP_DONE;
262  CRM_ASSERT(op->pid == pid);
263 
264  crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
265  if (op->opaque->stderr_gsource) {
266  /* Make sure we have read everything from the buffer.
267  * Depending on the priority mainloop gives the fd, operation_finished
268  * could occur before all the reads are done. Force the read now.*/
269  crm_trace("%s dispatching stderr", prefix);
270  dispatch_stderr(op);
271  crm_trace("%s: %p", op->id, op->stderr_data);
273  op->opaque->stderr_gsource = NULL;
274  }
275 
276  if (op->opaque->stdout_gsource) {
277  /* Make sure we have read everything from the buffer.
278  * Depending on the priority mainloop gives the fd, operation_finished
279  * could occur before all the reads are done. Force the read now.*/
280  crm_trace("%s dispatching stdout", prefix);
281  dispatch_stdout(op);
282  crm_trace("%s: %p", op->id, op->stdout_data);
284  op->opaque->stdout_gsource = NULL;
285  }
286 
287  if (signo) {
288  if (mainloop_child_timeout(p)) {
289  crm_warn("%s - timed out after %dms", prefix, op->timeout);
291  op->rc = PCMK_OCF_TIMEOUT;
292 
293  } else if (op->cancel) {
294  /* If an in-flight recurring operation was killed because it was
295  * cancelled, don't treat that as a failure.
296  */
297  crm_info("%s - terminated with signal %d", prefix, signo);
299  op->rc = PCMK_OCF_OK;
300 
301  } else {
302  crm_warn("%s - terminated with signal %d", prefix, signo);
304  op->rc = PCMK_OCF_SIGNAL;
305  }
306 
307  } else {
308  op->rc = exitcode;
309  crm_debug("%s - exited with rc=%d", prefix, exitcode);
310  }
311 
312  free(prefix);
313  prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
314  crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
315 
316  free(prefix);
317  prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
318  crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
319 
320  free(prefix);
321  operation_finalize(op);
322 }
323 
333 static void
334 services_handle_exec_error(svc_action_t * op, int error)
335 {
336  int rc_not_installed, rc_insufficient_priv, rc_exec_error;
337 
338  /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
340  && safe_str_eq(op->action, "status")) {
341 
342  rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
343  rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
344  rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
345 
346 #if SUPPORT_NAGIOS
348  rc_not_installed = NAGIOS_NOT_INSTALLED;
349  rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
350  rc_exec_error = PCMK_OCF_EXEC_ERROR;
351 #endif
352 
353  } else {
354  rc_not_installed = PCMK_OCF_NOT_INSTALLED;
355  rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
356  rc_exec_error = PCMK_OCF_EXEC_ERROR;
357  }
358 
359  switch (error) { /* see execve(2), stat(2) and fork(2) */
360  case ENOENT: /* No such file or directory */
361  case EISDIR: /* Is a directory */
362  case ENOTDIR: /* Path component is not a directory */
363  case EINVAL: /* Invalid executable format */
364  case ENOEXEC: /* Invalid executable format */
365  op->rc = rc_not_installed;
367  break;
368  case EACCES: /* permission denied (various errors) */
369  case EPERM: /* permission denied (various errors) */
370  op->rc = rc_insufficient_priv;
372  break;
373  default:
374  op->rc = rc_exec_error;
376  }
377 }
378 
379 static void
380 action_launch_child(svc_action_t *op)
381 {
382  int lpc;
383 
384  /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
385  * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
386  * We do not want this to be inherited by the child process. By resetting this the signal
387  * to the default behavior, we avoid some potential odd problems that occur during OCF
388  * scripts when SIGPIPE is ignored by the environment. */
389  signal(SIGPIPE, SIG_DFL);
390 
391 #if defined(HAVE_SCHED_SETSCHEDULER)
392  if (sched_getscheduler(0) != SCHED_OTHER) {
393  struct sched_param sp;
394 
395  memset(&sp, 0, sizeof(sp));
396  sp.sched_priority = 0;
397 
398  if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
399  crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
400  }
401  }
402 #endif
403  if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
404  crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
405  }
406 
407  /* Man: The call setpgrp() is equivalent to setpgid(0,0)
408  * _and_ compiles on BSD variants too
409  * need to investigate if it works the same too.
410  */
411  setpgid(0, 0);
412 
413  /* close all descriptors except stdin/out/err and channels to logd */
414  for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
415  close(lpc);
416  }
417 
418 #if SUPPORT_CIBSECRETS
419  if (replace_secret_params(op->rsc, op->params) < 0) {
420  /* replacing secrets failed! */
421  if (safe_str_eq(op->action,"stop")) {
422  /* don't fail on stop! */
423  crm_info("proceeding with the stop operation for %s", op->rsc);
424 
425  } else {
426  crm_err("failed to get secrets for %s, "
427  "considering resource not configured", op->rsc);
429  }
430  }
431 #endif
432 
433  add_action_env_vars(op);
434 
435  /* Become the desired user */
436  if (op->opaque->uid && (geteuid() == 0)) {
437  if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
438  crm_perror(LOG_ERR, "setting group to %d", op->opaque->gid);
440  }
441  if (setuid(op->opaque->uid) < 0) {
442  crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
444  }
445  /* We could do initgroups() here if we kept a copy of the username */
446  }
447 
448  /* execute the RA */
449  execvp(op->opaque->exec, op->opaque->args);
450 
451  /* Most cases should have been already handled by stat() */
452  services_handle_exec_error(op, errno);
453 
454  _exit(op->rc);
455 }
456 
457 #ifndef HAVE_SYS_SIGNALFD_H
458 static int sigchld_pipe[2] = { -1, -1 };
459 
460 static void
461 sigchld_handler()
462 {
463  if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
464  crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
465  }
466 }
467 #endif
468 
469 static void
470 action_synced_wait(svc_action_t * op, sigset_t *mask)
471 {
472  int status = 0;
473  int timeout = op->timeout;
474  int sfd = -1;
475  time_t start = -1;
476  struct pollfd fds[3];
477  int wait_rc = 0;
478 
479 #ifdef HAVE_SYS_SIGNALFD_H
480  sfd = signalfd(-1, mask, SFD_NONBLOCK);
481  if (sfd < 0) {
482  crm_perror(LOG_ERR, "signalfd() failed");
483  }
484 #else
485  sfd = sigchld_pipe[0];
486 #endif
487 
488  fds[0].fd = op->opaque->stdout_fd;
489  fds[0].events = POLLIN;
490  fds[0].revents = 0;
491 
492  fds[1].fd = op->opaque->stderr_fd;
493  fds[1].events = POLLIN;
494  fds[1].revents = 0;
495 
496  fds[2].fd = sfd;
497  fds[2].events = POLLIN;
498  fds[2].revents = 0;
499 
500  crm_trace("Waiting for %d", op->pid);
501  start = time(NULL);
502  do {
503  int poll_rc = poll(fds, 3, timeout);
504 
505  if (poll_rc > 0) {
506  if (fds[0].revents & POLLIN) {
507  svc_read_output(op->opaque->stdout_fd, op, FALSE);
508  }
509 
510  if (fds[1].revents & POLLIN) {
511  svc_read_output(op->opaque->stderr_fd, op, TRUE);
512  }
513 
514  if (fds[2].revents & POLLIN) {
515 #ifdef HAVE_SYS_SIGNALFD_H
516  struct signalfd_siginfo fdsi;
517  ssize_t s;
518 
519  s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
520  if (s != sizeof(struct signalfd_siginfo)) {
521  crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
522 
523  } else if (fdsi.ssi_signo == SIGCHLD) {
524 #else
525  if (1) {
526  /* Clear out the sigchld pipe. */
527  char ch;
528  while (read(sfd, &ch, 1) == 1) /*omit*/;
529 #endif
530  wait_rc = waitpid(op->pid, &status, WNOHANG);
531 
532  if (wait_rc > 0) {
533  break;
534 
535  } else if (wait_rc < 0){
536  if (errno == ECHILD) {
537  /* Here, don't dare to kill and bail out... */
538  break;
539 
540  } else {
541  /* ...otherwise pretend process still runs. */
542  wait_rc = 0;
543  }
544  crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
545  }
546  }
547  }
548 
549  } else if (poll_rc == 0) {
550  timeout = 0;
551  break;
552 
553  } else if (poll_rc < 0) {
554  if (errno != EINTR) {
555  crm_perror(LOG_ERR, "poll() failed");
556  break;
557  }
558  }
559 
560  timeout = op->timeout - (time(NULL) - start) * 1000;
561 
562  } while ((op->timeout < 0 || timeout > 0));
563 
564  crm_trace("Child done: %d", op->pid);
565  if (wait_rc <= 0) {
567 
568  if (op->timeout > 0 && timeout <= 0) {
570  crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
571 
572  } else {
574  }
575 
576  /* If only child hasn't been successfully waited for, yet.
577  This is to limit killing wrong target a bit more. */
578  if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
579  if (kill(op->pid, SIGKILL)) {
580  crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
581  }
582  /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
583  while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
584  }
585 
586  } else if (WIFEXITED(status)) {
587  op->status = PCMK_LRM_OP_DONE;
588  op->rc = WEXITSTATUS(status);
589  crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
590 
591  } else if (WIFSIGNALED(status)) {
592  int signo = WTERMSIG(status);
593 
595  crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
596  }
597 #ifdef WCOREDUMP
598  if (WCOREDUMP(status)) {
599  crm_err("Managed %s process %d dumped core", op->id, op->pid);
600  }
601 #endif
602 
603  svc_read_output(op->opaque->stdout_fd, op, FALSE);
604  svc_read_output(op->opaque->stderr_fd, op, TRUE);
605 
606  close(op->opaque->stdout_fd);
607  close(op->opaque->stderr_fd);
608 
609 #ifdef HAVE_SYS_SIGNALFD_H
610  close(sfd);
611 #endif
612 }
613 
614 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
615 /* For a synchronous 'op', returns FALSE if 'op' fails */
616 gboolean
618 {
619  int stdout_fd[2];
620  int stderr_fd[2];
621  int rc;
622  struct stat st;
623  sigset_t *pmask;
624 
625 #ifdef HAVE_SYS_SIGNALFD_H
626  sigset_t mask;
627  sigset_t old_mask;
628 #define sigchld_cleanup() do { \
629  if (sigismember(&old_mask, SIGCHLD) == 0) { \
630  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \
631  crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \
632  } \
633  } \
634 } while (0)
635 #else
636  struct sigaction sa;
637  struct sigaction old_sa;
638 #define sigchld_cleanup() do { \
639  if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \
640  crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \
641  } \
642  close(sigchld_pipe[0]); \
643  close(sigchld_pipe[1]); \
644  sigchld_pipe[0] = sigchld_pipe[1] = -1; \
645 } while(0)
646 #endif
647 
648  /* Fail fast */
649  if(stat(op->opaque->exec, &st) != 0) {
650  rc = errno;
651  crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
652  services_handle_exec_error(op, rc);
653  if (!op->synchronous) {
654  return operation_finalize(op);
655  }
656  return FALSE;
657  }
658 
659  if (pipe(stdout_fd) < 0) {
660  rc = errno;
661 
662  crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
663 
664  services_handle_exec_error(op, rc);
665  if (!op->synchronous) {
666  return operation_finalize(op);
667  }
668  return FALSE;
669  }
670 
671  if (pipe(stderr_fd) < 0) {
672  rc = errno;
673 
674  close(stdout_fd[0]);
675  close(stdout_fd[1]);
676 
677  crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
678 
679  services_handle_exec_error(op, rc);
680  if (!op->synchronous) {
681  return operation_finalize(op);
682  }
683  return FALSE;
684  }
685 
686  if (op->synchronous) {
687 #ifdef HAVE_SYS_SIGNALFD_H
688  sigemptyset(&mask);
689  sigaddset(&mask, SIGCHLD);
690  sigemptyset(&old_mask);
691 
692  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
693  crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
694  }
695 
696  pmask = &mask;
697 #else
698  if(pipe(sigchld_pipe) == -1) {
699  crm_perror(LOG_ERR, "pipe() failed");
700  }
701 
702  rc = crm_set_nonblocking(sigchld_pipe[0]);
703  if (rc < 0) {
704  crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
705  pcmk_strerror(rc), rc);
706  }
707  rc = crm_set_nonblocking(sigchld_pipe[1]);
708  if (rc < 0) {
709  crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
710  pcmk_strerror(rc), rc);
711  }
712 
713  sa.sa_handler = sigchld_handler;
714  sa.sa_flags = 0;
715  sigemptyset(&sa.sa_mask);
716  if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
717  crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
718  }
719 
720  pmask = NULL;
721 #endif
722  }
723 
724  op->pid = fork();
725  switch (op->pid) {
726  case -1:
727  rc = errno;
728 
729  close(stdout_fd[0]);
730  close(stdout_fd[1]);
731  close(stderr_fd[0]);
732  close(stderr_fd[1]);
733 
734  crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
735  services_handle_exec_error(op, rc);
736  if (!op->synchronous) {
737  return operation_finalize(op);
738  }
739 
740  sigchld_cleanup();
741  return FALSE;
742 
743  case 0: /* Child */
744  close(stdout_fd[0]);
745  close(stderr_fd[0]);
746  if (STDOUT_FILENO != stdout_fd[1]) {
747  if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
748  crm_err("dup2() failed (stdout)");
749  }
750  close(stdout_fd[1]);
751  }
752  if (STDERR_FILENO != stderr_fd[1]) {
753  if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
754  crm_err("dup2() failed (stderr)");
755  }
756  close(stderr_fd[1]);
757  }
758 
759  if (op->synchronous) {
760  sigchld_cleanup();
761  }
762 
763  action_launch_child(op);
764  CRM_ASSERT(0); /* action_launch_child is effectively noreturn */
765  }
766 
767  /* Only the parent reaches here */
768  close(stdout_fd[1]);
769  close(stderr_fd[1]);
770 
771  op->opaque->stdout_fd = stdout_fd[0];
773  if (rc < 0) {
774  crm_warn("Could not set child output non-blocking: %s "
775  CRM_XS " rc=%d",
776  pcmk_strerror(rc), rc);
777  }
778 
779  op->opaque->stderr_fd = stderr_fd[0];
781  if (rc < 0) {
782  crm_warn("Could not set child error output non-blocking: %s "
783  CRM_XS " rc=%d",
784  pcmk_strerror(rc), rc);
785  }
786 
787  if (op->synchronous) {
788  action_synced_wait(op, pmask);
789  sigchld_cleanup();
790  } else {
791 
792  crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
794  op->timeout,
795  op->id,
796  op,
798  operation_finished);
799 
800 
802  G_PRIORITY_LOW,
803  op->opaque->stdout_fd, op, &stdout_callbacks);
804 
806  G_PRIORITY_LOW,
807  op->opaque->stderr_fd, op, &stderr_callbacks);
808 
810  }
811 
812  return TRUE;
813 }
814 
815 GList *
816 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
817 {
818  GList *list = NULL;
819  struct dirent **namelist;
820  int entries = 0, lpc = 0;
821  char buffer[PATH_MAX];
822 
823  entries = scandir(root, &namelist, NULL, alphasort);
824  if (entries <= 0) {
825  return list;
826  }
827 
828  for (lpc = 0; lpc < entries; lpc++) {
829  struct stat sb;
830 
831  if ('.' == namelist[lpc]->d_name[0]) {
832  free(namelist[lpc]);
833  continue;
834  }
835 
836  snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
837 
838  if (stat(buffer, &sb)) {
839  continue;
840  }
841 
842  if (S_ISDIR(sb.st_mode)) {
843  if (files) {
844  free(namelist[lpc]);
845  continue;
846  }
847 
848  } else if (S_ISREG(sb.st_mode)) {
849  if (files == FALSE) {
850  free(namelist[lpc]);
851  continue;
852 
853  } else if (executable
854  && (sb.st_mode & S_IXUSR) == 0
855  && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
856  free(namelist[lpc]);
857  continue;
858  }
859  }
860 
861  list = g_list_append(list, strdup(namelist[lpc]->d_name));
862 
863  free(namelist[lpc]);
864  }
865 
866  free(namelist);
867  return list;
868 }
869 
870 GList *
872 {
873  return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
874 }
875 
876 GList *
878 {
879  return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
880 }
881 
882 GList *
883 resources_os_list_ocf_agents(const char *provider)
884 {
885  GList *gIter = NULL;
886  GList *result = NULL;
887  GList *providers = NULL;
888 
889  if (provider) {
890  char buffer[500];
891 
892  snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
893  return get_directory_list(buffer, TRUE, TRUE);
894  }
895 
896  providers = resources_os_list_ocf_providers();
897  for (gIter = providers; gIter != NULL; gIter = gIter->next) {
898  GList *tmp1 = result;
899  GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
900 
901  if (tmp2) {
902  result = g_list_concat(tmp1, tmp2);
903  }
904  }
905  g_list_free_full(providers, free);
906  return result;
907 }
908 
909 #if SUPPORT_NAGIOS
910 GList *
912 {
913  GList *plugin_list = NULL;
914  GList *result = NULL;
915  GList *gIter = NULL;
916 
917  plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
918 
919  /* Make sure both the plugin and its metadata exist */
920  for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
921  const char *plugin = gIter->data;
922  char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
923  struct stat st;
924 
925  if (stat(metadata, &st) == 0) {
926  result = g_list_append(result, strdup(plugin));
927  }
928 
929  free(metadata);
930  }
931  g_list_free_full(plugin_list, free);
932  return result;
933 }
934 #endif
Services API.
#define LOG_TRACE
Definition: logging.h:29
void(* callback)(svc_action_t *op)
A dumping ground.
void services_action_free(svc_action_t *op)
Definition: services.c:566
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:810
char * standard
Definition: services.h:168
#define sigchld_cleanup()
#define crm_log_output(level, prefix, output)
Definition: logging.h:92
const char * pcmk_strerror(int rc)
Definition: logging.c:1139
char * id
Definition: services.h:163
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
int alphasort(const void *dirent1, const void *dirent2)
gboolean recurring_action_timer(gpointer data)
void mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *userdata, enum mainloop_child_flags, void(*callback)(mainloop_child_t *p, pid_t pid, int core, int signo, int exitcode))
Definition: mainloop.c:1097
struct mainloop_child_s mainloop_child_t
Definition: mainloop.h:36
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
char * rsc
Definition: services.h:164
int interval
Definition: services.h:166
gboolean services_os_action_execute(svc_action_t *op)
G_GNUC_INTERNAL GList * resources_os_list_nagios_agents(void)
uint32_t pid
Definition: internal.h:49
Wrappers for and extensions to glib mainloop.
GList * resources_os_list_lsb_agents(void)
void services_action_cleanup(svc_action_t *op)
Definition: services.c:530
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:90
enum svc_action_flags flags
Definition: services.h:182
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:57
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:618
svc_action_private_t * opaque
Definition: services.h:195
#define OCF_ROOT_DIR
Definition: services.h:39
#define crm_debug(fmt, args...)
Definition: logging.h:253
void * mainloop_child_userdata(mainloop_child_t *child)
Definition: mainloop.c:888
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:185
GHashTable * params
Definition: services.h:173
#define crm_trace(fmt, args...)
Definition: logging.h:254
int setenv(const char *name, const char *value, int why)
int crm_set_nonblocking(int fd)
Definition: io.c:509
char * agent
Definition: services.h:170
int synchronous
Definition: services.h:181
#define LSB_ROOT_DIR
Definition: services.h:43
#define PCMK_OCF_REASON_PREFIX
Definition: services.h:70
#define CRM_XS
Definition: logging.h:42
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:798
void services_untrack_op(svc_action_t *op)
Definition: services.c:819
int replace_secret_params(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:91
char * action
Definition: services.h:165
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:63
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:59
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define NAGIOS_PLUGIN_DIR
Definition: config.h:621
#define crm_err(fmt, args...)
Definition: logging.h:248
void mainloop_clear_child_userdata(mainloop_child_t *child)
Definition: mainloop.c:894
GList * get_directory_list(const char *root, gboolean files, gboolean executable)
Get a list of files or directories in a given path.
Definition: services.c:1354
mainloop_io_t * stdout_gsource
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:854
#define safe_str_eq(a, b)
Definition: util.h:72
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Definition: services.c:830
char * provider
Definition: services.h:169
#define crm_info(fmt, args...)
Definition: logging.h:251
#define NAGIOS_METADATA_DIR
Definition: config.h:618
int mainloop_child_timeout(mainloop_child_t *child)
Definition: mainloop.c:882
char * stderr_data
Definition: services.h:184