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 
163 static void
164 set_alert_env(gpointer key, gpointer value, gpointer user_data)
165 {
166  int rc;
167 
168  if (value != NULL) {
169  rc = setenv(key, value, 1);
170  } else {
171  rc = unsetenv(key);
172  }
173 
174  if (rc < 0) {
175  crm_perror(LOG_ERR, "setenv %s=%s",
176  (char*)key, (value? (char*)value : ""));
177  } else {
178  crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
179  }
180 }
181 
188 static void
189 add_action_env_vars(const svc_action_t *op)
190 {
191  void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
192  if (op->agent == NULL) {
193  env_setter = set_alert_env; /* we deal with alert handler */
194 
195  } else if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF)) {
196  env_setter = set_ocf_env_with_prefix;
197  }
198 
199  if (env_setter != NULL && op->params != NULL) {
200  g_hash_table_foreach(op->params, env_setter, NULL);
201  }
202 
203  if (env_setter == NULL || env_setter == set_alert_env) {
204  return;
205  }
206 
207  set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
208  set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
209  set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
210  set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
211 
212  if (op->rsc) {
213  set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
214  }
215 
216  if (op->agent != NULL) {
217  set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
218  }
219 
220  /* Notes: this is not added to specification yet. Sept 10,2004 */
221  if (op->provider != NULL) {
222  set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
223  }
224 }
225 
226 gboolean
228 {
229  svc_action_t *op = data;
230 
231  crm_debug("Scheduling another invocation of %s", op->id);
232 
233  /* Clean out the old result */
234  free(op->stdout_data);
235  op->stdout_data = NULL;
236  free(op->stderr_data);
237  op->stderr_data = NULL;
238  op->opaque->repeat_timer = 0;
239 
240  services_action_async(op, NULL);
241  return FALSE;
242 }
243 
244 /* Returns FALSE if 'op' should be free'd by the caller */
245 gboolean
247 {
248  int recurring = 0;
249 
250  if (op->interval_ms) {
251  if (op->cancel) {
254  } else {
255  recurring = 1;
256  op->opaque->repeat_timer = g_timeout_add(op->interval_ms,
257  recurring_action_timer, (void *)op);
258  }
259  }
260 
261  if (op->opaque->callback) {
262  op->opaque->callback(op);
263  }
264 
265  op->pid = 0;
266 
268 
269  if (!recurring && op->synchronous == FALSE) {
270  /*
271  * If this is a recurring action, do not free explicitly.
272  * It will get freed whenever the action gets cancelled.
273  */
275  return TRUE;
276  }
277 
279  return FALSE;
280 }
281 
282 static void
283 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
284 {
286  char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid);
287 
289  op->status = PCMK_LRM_OP_DONE;
290  CRM_ASSERT(op->pid == pid);
291 
292  crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
293  if (op->opaque->stderr_gsource) {
294  /* Make sure we have read everything from the buffer.
295  * Depending on the priority mainloop gives the fd, operation_finished
296  * could occur before all the reads are done. Force the read now.*/
297  crm_trace("%s dispatching stderr", prefix);
298  dispatch_stderr(op);
299  crm_trace("%s: %p", op->id, op->stderr_data);
301  op->opaque->stderr_gsource = NULL;
302  }
303 
304  if (op->opaque->stdout_gsource) {
305  /* Make sure we have read everything from the buffer.
306  * Depending on the priority mainloop gives the fd, operation_finished
307  * could occur before all the reads are done. Force the read now.*/
308  crm_trace("%s dispatching stdout", prefix);
309  dispatch_stdout(op);
310  crm_trace("%s: %p", op->id, op->stdout_data);
312  op->opaque->stdout_gsource = NULL;
313  }
314 
315  if (signo) {
316  if (mainloop_child_timeout(p)) {
317  crm_warn("%s - timed out after %dms", prefix, op->timeout);
319  op->rc = PCMK_OCF_TIMEOUT;
320 
321  } else if (op->cancel) {
322  /* If an in-flight recurring operation was killed because it was
323  * cancelled, don't treat that as a failure.
324  */
325  crm_info("%s - terminated with signal %d", prefix, signo);
327  op->rc = PCMK_OCF_OK;
328 
329  } else {
330  crm_warn("%s - terminated with signal %d", prefix, signo);
332  op->rc = PCMK_OCF_SIGNAL;
333  }
334 
335  } else {
336  op->rc = exitcode;
337  crm_debug("%s - exited with rc=%d", prefix, exitcode);
338  }
339 
340  free(prefix);
341  prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
342  crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
343 
344  free(prefix);
345  prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
346  crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
347 
348  free(prefix);
349  operation_finalize(op);
350 }
351 
361 static void
362 services_handle_exec_error(svc_action_t * op, int error)
363 {
364  int rc_not_installed, rc_insufficient_priv, rc_exec_error;
365 
366  /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
368  && safe_str_eq(op->action, "status")) {
369 
370  rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
371  rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
372  rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
373 
374 #if SUPPORT_NAGIOS
376  rc_not_installed = NAGIOS_NOT_INSTALLED;
377  rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
378  rc_exec_error = PCMK_OCF_EXEC_ERROR;
379 #endif
380 
381  } else {
382  rc_not_installed = PCMK_OCF_NOT_INSTALLED;
383  rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
384  rc_exec_error = PCMK_OCF_EXEC_ERROR;
385  }
386 
387  switch (error) { /* see execve(2), stat(2) and fork(2) */
388  case ENOENT: /* No such file or directory */
389  case EISDIR: /* Is a directory */
390  case ENOTDIR: /* Path component is not a directory */
391  case EINVAL: /* Invalid executable format */
392  case ENOEXEC: /* Invalid executable format */
393  op->rc = rc_not_installed;
395  break;
396  case EACCES: /* permission denied (various errors) */
397  case EPERM: /* permission denied (various errors) */
398  op->rc = rc_insufficient_priv;
400  break;
401  default:
402  op->rc = rc_exec_error;
404  }
405 }
406 
407 static void
408 action_launch_child(svc_action_t *op)
409 {
410  int lpc;
411 
412  /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
413  * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
414  * We do not want this to be inherited by the child process. By resetting this the signal
415  * to the default behavior, we avoid some potential odd problems that occur during OCF
416  * scripts when SIGPIPE is ignored by the environment. */
417  signal(SIGPIPE, SIG_DFL);
418 
419 #if defined(HAVE_SCHED_SETSCHEDULER)
420  if (sched_getscheduler(0) != SCHED_OTHER) {
421  struct sched_param sp;
422 
423  memset(&sp, 0, sizeof(sp));
424  sp.sched_priority = 0;
425 
426  if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
427  crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
428  }
429  }
430 #endif
431  if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
432  crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
433  }
434 
435  /* Man: The call setpgrp() is equivalent to setpgid(0,0)
436  * _and_ compiles on BSD variants too
437  * need to investigate if it works the same too.
438  */
439  setpgid(0, 0);
440 
441  // Close all file descriptors except stdin/stdout/stderr
442  for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
443  close(lpc);
444  }
445 
446 #if SUPPORT_CIBSECRETS
447  if (replace_secret_params(op->rsc, op->params) < 0) {
448  /* replacing secrets failed! */
449  if (safe_str_eq(op->action,"stop")) {
450  /* don't fail on stop! */
451  crm_info("proceeding with the stop operation for %s", op->rsc);
452 
453  } else {
454  crm_err("failed to get secrets for %s, "
455  "considering resource not configured", op->rsc);
457  }
458  }
459 #endif
460 
461  add_action_env_vars(op);
462 
463  /* Become the desired user */
464  if (op->opaque->uid && (geteuid() == 0)) {
465 
466  // If requested, set effective group
467  if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
468  crm_perror(LOG_ERR, "Could not set child group to %d", op->opaque->gid);
470  }
471 
472  // Erase supplementary group list
473  // (We could do initgroups() if we kept a copy of the username)
474  if (setgroups(0, NULL) < 0) {
475  crm_perror(LOG_ERR, "Could not set child groups");
477  }
478 
479  // Set effective user
480  if (setuid(op->opaque->uid) < 0) {
481  crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
483  }
484  }
485 
486  /* execute the RA */
487  execvp(op->opaque->exec, op->opaque->args);
488 
489  /* Most cases should have been already handled by stat() */
490  services_handle_exec_error(op, errno);
491 
492  _exit(op->rc);
493 }
494 
495 #ifndef HAVE_SYS_SIGNALFD_H
496 static int sigchld_pipe[2] = { -1, -1 };
497 
498 static void
499 sigchld_handler()
500 {
501  if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
502  crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
503  }
504 }
505 #endif
506 
507 static void
508 action_synced_wait(svc_action_t * op, sigset_t *mask)
509 {
510  int status = 0;
511  int timeout = op->timeout;
512  int sfd = -1;
513  time_t start = -1;
514  struct pollfd fds[3];
515  int wait_rc = 0;
516 
517 #ifdef HAVE_SYS_SIGNALFD_H
518  sfd = signalfd(-1, mask, SFD_NONBLOCK);
519  if (sfd < 0) {
520  crm_perror(LOG_ERR, "signalfd() failed");
521  }
522 #else
523  sfd = sigchld_pipe[0];
524 #endif
525 
526  fds[0].fd = op->opaque->stdout_fd;
527  fds[0].events = POLLIN;
528  fds[0].revents = 0;
529 
530  fds[1].fd = op->opaque->stderr_fd;
531  fds[1].events = POLLIN;
532  fds[1].revents = 0;
533 
534  fds[2].fd = sfd;
535  fds[2].events = POLLIN;
536  fds[2].revents = 0;
537 
538  crm_trace("Waiting for %d", op->pid);
539  start = time(NULL);
540  do {
541  int poll_rc = poll(fds, 3, timeout);
542 
543  if (poll_rc > 0) {
544  if (fds[0].revents & POLLIN) {
545  svc_read_output(op->opaque->stdout_fd, op, FALSE);
546  }
547 
548  if (fds[1].revents & POLLIN) {
549  svc_read_output(op->opaque->stderr_fd, op, TRUE);
550  }
551 
552  if (fds[2].revents & POLLIN) {
553 #ifdef HAVE_SYS_SIGNALFD_H
554  struct signalfd_siginfo fdsi;
555  ssize_t s;
556 
557  s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
558  if (s != sizeof(struct signalfd_siginfo)) {
559  crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
560 
561  } else if (fdsi.ssi_signo == SIGCHLD) {
562 #else
563  if (1) {
564  /* Clear out the sigchld pipe. */
565  char ch;
566  while (read(sfd, &ch, 1) == 1) /*omit*/;
567 #endif
568  wait_rc = waitpid(op->pid, &status, WNOHANG);
569 
570  if (wait_rc > 0) {
571  break;
572 
573  } else if (wait_rc < 0){
574  if (errno == ECHILD) {
575  /* Here, don't dare to kill and bail out... */
576  break;
577 
578  } else {
579  /* ...otherwise pretend process still runs. */
580  wait_rc = 0;
581  }
582  crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
583  }
584  }
585  }
586 
587  } else if (poll_rc == 0) {
588  timeout = 0;
589  break;
590 
591  } else if (poll_rc < 0) {
592  if (errno != EINTR) {
593  crm_perror(LOG_ERR, "poll() failed");
594  break;
595  }
596  }
597 
598  timeout = op->timeout - (time(NULL) - start) * 1000;
599 
600  } while ((op->timeout < 0 || timeout > 0));
601 
602  crm_trace("Child done: %d", op->pid);
603  if (wait_rc <= 0) {
605 
606  if (op->timeout > 0 && timeout <= 0) {
608  crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
609 
610  } else {
612  }
613 
614  /* If only child hasn't been successfully waited for, yet.
615  This is to limit killing wrong target a bit more. */
616  if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
617  if (kill(op->pid, SIGKILL)) {
618  crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
619  }
620  /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
621  while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
622  }
623 
624  } else if (WIFEXITED(status)) {
625  op->status = PCMK_LRM_OP_DONE;
626  op->rc = WEXITSTATUS(status);
627  crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
628 
629  } else if (WIFSIGNALED(status)) {
630  int signo = WTERMSIG(status);
631 
633  crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
634  }
635 #ifdef WCOREDUMP
636  if (WCOREDUMP(status)) {
637  crm_err("Managed %s process %d dumped core", op->id, op->pid);
638  }
639 #endif
640 
641  svc_read_output(op->opaque->stdout_fd, op, FALSE);
642  svc_read_output(op->opaque->stderr_fd, op, TRUE);
643 
644  close(op->opaque->stdout_fd);
645  close(op->opaque->stderr_fd);
646 
647 #ifdef HAVE_SYS_SIGNALFD_H
648  close(sfd);
649 #endif
650 }
651 
652 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
653 /* For a synchronous 'op', returns FALSE if 'op' fails */
654 gboolean
656 {
657  int stdout_fd[2];
658  int stderr_fd[2];
659  int rc;
660  struct stat st;
661  sigset_t *pmask;
662 
663 #ifdef HAVE_SYS_SIGNALFD_H
664  sigset_t mask;
665  sigset_t old_mask;
666 #define sigchld_cleanup() do { \
667  if (sigismember(&old_mask, SIGCHLD) == 0) { \
668  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \
669  crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \
670  } \
671  } \
672 } while (0)
673 #else
674  struct sigaction sa;
675  struct sigaction old_sa;
676 #define sigchld_cleanup() do { \
677  if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \
678  crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \
679  } \
680  close(sigchld_pipe[0]); \
681  close(sigchld_pipe[1]); \
682  sigchld_pipe[0] = sigchld_pipe[1] = -1; \
683 } while(0)
684 #endif
685 
686  /* Fail fast */
687  if(stat(op->opaque->exec, &st) != 0) {
688  rc = errno;
689  crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
690  services_handle_exec_error(op, rc);
691  if (!op->synchronous) {
692  return operation_finalize(op);
693  }
694  return FALSE;
695  }
696 
697  if (pipe(stdout_fd) < 0) {
698  rc = errno;
699 
700  crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
701 
702  services_handle_exec_error(op, rc);
703  if (!op->synchronous) {
704  return operation_finalize(op);
705  }
706  return FALSE;
707  }
708 
709  if (pipe(stderr_fd) < 0) {
710  rc = errno;
711 
712  close(stdout_fd[0]);
713  close(stdout_fd[1]);
714 
715  crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
716 
717  services_handle_exec_error(op, rc);
718  if (!op->synchronous) {
719  return operation_finalize(op);
720  }
721  return FALSE;
722  }
723 
724  if (op->synchronous) {
725 #ifdef HAVE_SYS_SIGNALFD_H
726  sigemptyset(&mask);
727  sigaddset(&mask, SIGCHLD);
728  sigemptyset(&old_mask);
729 
730  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
731  crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
732  }
733 
734  pmask = &mask;
735 #else
736  if(pipe(sigchld_pipe) == -1) {
737  crm_perror(LOG_ERR, "pipe() failed");
738  }
739 
740  rc = crm_set_nonblocking(sigchld_pipe[0]);
741  if (rc < 0) {
742  crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
743  pcmk_strerror(rc), rc);
744  }
745  rc = crm_set_nonblocking(sigchld_pipe[1]);
746  if (rc < 0) {
747  crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
748  pcmk_strerror(rc), rc);
749  }
750 
751  sa.sa_handler = sigchld_handler;
752  sa.sa_flags = 0;
753  sigemptyset(&sa.sa_mask);
754  if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
755  crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
756  }
757 
758  pmask = NULL;
759 #endif
760  }
761 
762  op->pid = fork();
763  switch (op->pid) {
764  case -1:
765  rc = errno;
766 
767  close(stdout_fd[0]);
768  close(stdout_fd[1]);
769  close(stderr_fd[0]);
770  close(stderr_fd[1]);
771 
772  crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
773  services_handle_exec_error(op, rc);
774  if (!op->synchronous) {
775  return operation_finalize(op);
776  }
777 
778  sigchld_cleanup();
779  return FALSE;
780 
781  case 0: /* Child */
782  close(stdout_fd[0]);
783  close(stderr_fd[0]);
784  if (STDOUT_FILENO != stdout_fd[1]) {
785  if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
786  crm_err("dup2() failed (stdout)");
787  }
788  close(stdout_fd[1]);
789  }
790  if (STDERR_FILENO != stderr_fd[1]) {
791  if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
792  crm_err("dup2() failed (stderr)");
793  }
794  close(stderr_fd[1]);
795  }
796 
797  if (op->synchronous) {
798  sigchld_cleanup();
799  }
800 
801  action_launch_child(op);
802  CRM_ASSERT(0); /* action_launch_child is effectively noreturn */
803  }
804 
805  /* Only the parent reaches here */
806  close(stdout_fd[1]);
807  close(stderr_fd[1]);
808 
809  op->opaque->stdout_fd = stdout_fd[0];
811  if (rc < 0) {
812  crm_warn("Could not set child output non-blocking: %s "
813  CRM_XS " rc=%d",
814  pcmk_strerror(rc), rc);
815  }
816 
817  op->opaque->stderr_fd = stderr_fd[0];
819  if (rc < 0) {
820  crm_warn("Could not set child error output non-blocking: %s "
821  CRM_XS " rc=%d",
822  pcmk_strerror(rc), rc);
823  }
824 
825  if (op->synchronous) {
826  action_synced_wait(op, pmask);
827  sigchld_cleanup();
828  } else {
829 
830  crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
832  op->timeout,
833  op->id,
834  op,
836  operation_finished);
837 
838 
840  G_PRIORITY_LOW,
841  op->opaque->stdout_fd, op, &stdout_callbacks);
842 
844  G_PRIORITY_LOW,
845  op->opaque->stderr_fd, op, &stderr_callbacks);
846 
848  }
849 
850  return TRUE;
851 }
852 
853 GList *
854 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
855 {
856  GList *list = NULL;
857  struct dirent **namelist;
858  int entries = 0, lpc = 0;
859  char buffer[PATH_MAX];
860 
861  entries = scandir(root, &namelist, NULL, alphasort);
862  if (entries <= 0) {
863  return list;
864  }
865 
866  for (lpc = 0; lpc < entries; lpc++) {
867  struct stat sb;
868 
869  if ('.' == namelist[lpc]->d_name[0]) {
870  free(namelist[lpc]);
871  continue;
872  }
873 
874  snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
875 
876  if (stat(buffer, &sb)) {
877  continue;
878  }
879 
880  if (S_ISDIR(sb.st_mode)) {
881  if (files) {
882  free(namelist[lpc]);
883  continue;
884  }
885 
886  } else if (S_ISREG(sb.st_mode)) {
887  if (files == FALSE) {
888  free(namelist[lpc]);
889  continue;
890 
891  } else if (executable
892  && (sb.st_mode & S_IXUSR) == 0
893  && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
894  free(namelist[lpc]);
895  continue;
896  }
897  }
898 
899  list = g_list_append(list, strdup(namelist[lpc]->d_name));
900 
901  free(namelist[lpc]);
902  }
903 
904  free(namelist);
905  return list;
906 }
907 
908 GList *
910 {
911  return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
912 }
913 
914 GList *
915 resources_os_list_ocf_agents(const char *provider)
916 {
917  GList *gIter = NULL;
918  GList *result = NULL;
919  GList *providers = NULL;
920 
921  if (provider) {
922  char buffer[500];
923 
924  snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
925  return get_directory_list(buffer, TRUE, TRUE);
926  }
927 
928  providers = resources_os_list_ocf_providers();
929  for (gIter = providers; gIter != NULL; gIter = gIter->next) {
930  GList *tmp1 = result;
931  GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
932 
933  if (tmp2) {
934  result = g_list_concat(tmp1, tmp2);
935  }
936  }
937  g_list_free_full(providers, free);
938  return result;
939 }
940 
941 #if SUPPORT_NAGIOS
942 GList *
944 {
945  GList *plugin_list = NULL;
946  GList *result = NULL;
947  GList *gIter = NULL;
948 
949  plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
950 
951  /* Make sure both the plugin and its metadata exist */
952  for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
953  const char *plugin = gIter->data;
954  char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
955  struct stat st;
956 
957  if (stat(metadata, &st) == 0) {
958  result = g_list_append(result, strdup(plugin));
959  }
960 
961  free(metadata);
962  }
963  g_list_free_full(plugin_list, free);
964  return result;
965 }
966 #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:462
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:423
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:514
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:698
void services_untrack_op(svc_action_t *op)
Definition: services.c:719
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:941
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:730
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