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