pacemaker  1.1.18-7fdfbbe
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 {
294  do_crm_log_unlikely((op->cancel) ? LOG_INFO : LOG_WARNING,
295  "%s - terminated with signal %d", prefix, signo);
297  op->rc = PCMK_OCF_SIGNAL;
298  }
299 
300  } else {
301  op->rc = exitcode;
302  crm_debug("%s - exited with rc=%d", prefix, exitcode);
303  }
304 
305  free(prefix);
306  prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
307  crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
308 
309  free(prefix);
310  prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
311  crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
312 
313  free(prefix);
314  operation_finalize(op);
315 }
316 
326 static void
327 services_handle_exec_error(svc_action_t * op, int error)
328 {
329  int rc_not_installed, rc_insufficient_priv, rc_exec_error;
330 
331  /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
333  && safe_str_eq(op->action, "status")) {
334 
335  rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
336  rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
337  rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
338 
339 #if SUPPORT_NAGIOS
341  rc_not_installed = NAGIOS_NOT_INSTALLED;
342  rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
343  rc_exec_error = PCMK_OCF_EXEC_ERROR;
344 #endif
345 
346  } else {
347  rc_not_installed = PCMK_OCF_NOT_INSTALLED;
348  rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
349  rc_exec_error = PCMK_OCF_EXEC_ERROR;
350  }
351 
352  switch (error) { /* see execve(2), stat(2) and fork(2) */
353  case ENOENT: /* No such file or directory */
354  case EISDIR: /* Is a directory */
355  case ENOTDIR: /* Path component is not a directory */
356  case EINVAL: /* Invalid executable format */
357  case ENOEXEC: /* Invalid executable format */
358  op->rc = rc_not_installed;
360  break;
361  case EACCES: /* permission denied (various errors) */
362  case EPERM: /* permission denied (various errors) */
363  op->rc = rc_insufficient_priv;
365  break;
366  default:
367  op->rc = rc_exec_error;
369  }
370 }
371 
372 static void
373 action_launch_child(svc_action_t *op)
374 {
375  int lpc;
376 
377  /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
378  * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
379  * We do not want this to be inherited by the child process. By resetting this the signal
380  * to the default behavior, we avoid some potential odd problems that occur during OCF
381  * scripts when SIGPIPE is ignored by the environment. */
382  signal(SIGPIPE, SIG_DFL);
383 
384 #if defined(HAVE_SCHED_SETSCHEDULER)
385  if (sched_getscheduler(0) != SCHED_OTHER) {
386  struct sched_param sp;
387 
388  memset(&sp, 0, sizeof(sp));
389  sp.sched_priority = 0;
390 
391  if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
392  crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
393  }
394  }
395 #endif
396  if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
397  crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
398  }
399 
400  /* Man: The call setpgrp() is equivalent to setpgid(0,0)
401  * _and_ compiles on BSD variants too
402  * need to investigate if it works the same too.
403  */
404  setpgid(0, 0);
405 
406  /* close all descriptors except stdin/out/err and channels to logd */
407  for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
408  close(lpc);
409  }
410 
411 #if SUPPORT_CIBSECRETS
412  if (replace_secret_params(op->rsc, op->params) < 0) {
413  /* replacing secrets failed! */
414  if (safe_str_eq(op->action,"stop")) {
415  /* don't fail on stop! */
416  crm_info("proceeding with the stop operation for %s", op->rsc);
417 
418  } else {
419  crm_err("failed to get secrets for %s, "
420  "considering resource not configured", op->rsc);
422  }
423  }
424 #endif
425 
426  add_action_env_vars(op);
427 
428  /* Become the desired user */
429  if (op->opaque->uid && (geteuid() == 0)) {
430  if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
431  crm_perror(LOG_ERR, "setting group to %d", op->opaque->gid);
433  }
434  if (setuid(op->opaque->uid) < 0) {
435  crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
437  }
438  /* We could do initgroups() here if we kept a copy of the username */
439  }
440 
441  /* execute the RA */
442  execvp(op->opaque->exec, op->opaque->args);
443 
444  /* Most cases should have been already handled by stat() */
445  services_handle_exec_error(op, errno);
446 
447  _exit(op->rc);
448 }
449 
450 #ifndef HAVE_SYS_SIGNALFD_H
451 static int sigchld_pipe[2] = { -1, -1 };
452 
453 static void
454 sigchld_handler()
455 {
456  if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
457  crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
458  }
459 }
460 #endif
461 
462 static void
463 action_synced_wait(svc_action_t * op, sigset_t *mask)
464 {
465  int status = 0;
466  int timeout = op->timeout;
467  int sfd = -1;
468  time_t start = -1;
469  struct pollfd fds[3];
470  int wait_rc = 0;
471 
472 #ifdef HAVE_SYS_SIGNALFD_H
473  sfd = signalfd(-1, mask, SFD_NONBLOCK);
474  if (sfd < 0) {
475  crm_perror(LOG_ERR, "signalfd() failed");
476  }
477 #else
478  sfd = sigchld_pipe[0];
479 #endif
480 
481  fds[0].fd = op->opaque->stdout_fd;
482  fds[0].events = POLLIN;
483  fds[0].revents = 0;
484 
485  fds[1].fd = op->opaque->stderr_fd;
486  fds[1].events = POLLIN;
487  fds[1].revents = 0;
488 
489  fds[2].fd = sfd;
490  fds[2].events = POLLIN;
491  fds[2].revents = 0;
492 
493  crm_trace("Waiting for %d", op->pid);
494  start = time(NULL);
495  do {
496  int poll_rc = poll(fds, 3, timeout);
497 
498  if (poll_rc > 0) {
499  if (fds[0].revents & POLLIN) {
500  svc_read_output(op->opaque->stdout_fd, op, FALSE);
501  }
502 
503  if (fds[1].revents & POLLIN) {
504  svc_read_output(op->opaque->stderr_fd, op, TRUE);
505  }
506 
507  if (fds[2].revents & POLLIN) {
508 #ifdef HAVE_SYS_SIGNALFD_H
509  struct signalfd_siginfo fdsi;
510  ssize_t s;
511 
512  s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
513  if (s != sizeof(struct signalfd_siginfo)) {
514  crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
515 
516  } else if (fdsi.ssi_signo == SIGCHLD) {
517 #else
518  if (1) {
519  /* Clear out the sigchld pipe. */
520  char ch;
521  while (read(sfd, &ch, 1) == 1) /*omit*/;
522 #endif
523  wait_rc = waitpid(op->pid, &status, WNOHANG);
524 
525  if (wait_rc > 0) {
526  break;
527 
528  } else if (wait_rc < 0){
529  if (errno == ECHILD) {
530  /* Here, don't dare to kill and bail out... */
531  break;
532 
533  } else {
534  /* ...otherwise pretend process still runs. */
535  wait_rc = 0;
536  }
537  crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
538  }
539  }
540  }
541 
542  } else if (poll_rc == 0) {
543  timeout = 0;
544  break;
545 
546  } else if (poll_rc < 0) {
547  if (errno != EINTR) {
548  crm_perror(LOG_ERR, "poll() failed");
549  break;
550  }
551  }
552 
553  timeout = op->timeout - (time(NULL) - start) * 1000;
554 
555  } while ((op->timeout < 0 || timeout > 0));
556 
557  crm_trace("Child done: %d", op->pid);
558  if (wait_rc <= 0) {
560 
561  if (op->timeout > 0 && timeout <= 0) {
563  crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
564 
565  } else {
567  }
568 
569  /* If only child hasn't been successfully waited for, yet.
570  This is to limit killing wrong target a bit more. */
571  if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
572  if (kill(op->pid, SIGKILL)) {
573  crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
574  }
575  /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
576  while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
577  }
578 
579  } else if (WIFEXITED(status)) {
580  op->status = PCMK_LRM_OP_DONE;
581  op->rc = WEXITSTATUS(status);
582  crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
583 
584  } else if (WIFSIGNALED(status)) {
585  int signo = WTERMSIG(status);
586 
588  crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
589  }
590 #ifdef WCOREDUMP
591  if (WCOREDUMP(status)) {
592  crm_err("Managed %s process %d dumped core", op->id, op->pid);
593  }
594 #endif
595 
596  svc_read_output(op->opaque->stdout_fd, op, FALSE);
597  svc_read_output(op->opaque->stderr_fd, op, TRUE);
598 
599  close(op->opaque->stdout_fd);
600  close(op->opaque->stderr_fd);
601 
602 #ifdef HAVE_SYS_SIGNALFD_H
603  close(sfd);
604 #endif
605 }
606 
607 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
608 /* For a synchronous 'op', returns FALSE if 'op' fails */
609 gboolean
611 {
612  int stdout_fd[2];
613  int stderr_fd[2];
614  int rc;
615  struct stat st;
616  sigset_t *pmask;
617 
618 #ifdef HAVE_SYS_SIGNALFD_H
619  sigset_t mask;
620  sigset_t old_mask;
621 #define sigchld_cleanup() do { \
622  if (sigismember(&old_mask, SIGCHLD) == 0) { \
623  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \
624  crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \
625  } \
626  } \
627 } while (0)
628 #else
629  struct sigaction sa;
630  struct sigaction old_sa;
631 #define sigchld_cleanup() do { \
632  if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \
633  crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \
634  } \
635  close(sigchld_pipe[0]); \
636  close(sigchld_pipe[1]); \
637  sigchld_pipe[0] = sigchld_pipe[1] = -1; \
638 } while(0)
639 #endif
640 
641  /* Fail fast */
642  if(stat(op->opaque->exec, &st) != 0) {
643  rc = errno;
644  crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
645  services_handle_exec_error(op, rc);
646  if (!op->synchronous) {
647  return operation_finalize(op);
648  }
649  return FALSE;
650  }
651 
652  if (pipe(stdout_fd) < 0) {
653  rc = errno;
654 
655  crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
656 
657  services_handle_exec_error(op, rc);
658  if (!op->synchronous) {
659  return operation_finalize(op);
660  }
661  return FALSE;
662  }
663 
664  if (pipe(stderr_fd) < 0) {
665  rc = errno;
666 
667  close(stdout_fd[0]);
668  close(stdout_fd[1]);
669 
670  crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
671 
672  services_handle_exec_error(op, rc);
673  if (!op->synchronous) {
674  return operation_finalize(op);
675  }
676  return FALSE;
677  }
678 
679  if (op->synchronous) {
680 #ifdef HAVE_SYS_SIGNALFD_H
681  sigemptyset(&mask);
682  sigaddset(&mask, SIGCHLD);
683  sigemptyset(&old_mask);
684 
685  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
686  crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
687  }
688 
689  pmask = &mask;
690 #else
691  if(pipe(sigchld_pipe) == -1) {
692  crm_perror(LOG_ERR, "pipe() failed");
693  }
694 
695  rc = crm_set_nonblocking(sigchld_pipe[0]);
696  if (rc < 0) {
697  crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
698  pcmk_strerror(rc), rc);
699  }
700  rc = crm_set_nonblocking(sigchld_pipe[1]);
701  if (rc < 0) {
702  crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
703  pcmk_strerror(rc), rc);
704  }
705 
706  sa.sa_handler = sigchld_handler;
707  sa.sa_flags = 0;
708  sigemptyset(&sa.sa_mask);
709  if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
710  crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
711  }
712 
713  pmask = NULL;
714 #endif
715  }
716 
717  op->pid = fork();
718  switch (op->pid) {
719  case -1:
720  rc = errno;
721 
722  close(stdout_fd[0]);
723  close(stdout_fd[1]);
724  close(stderr_fd[0]);
725  close(stderr_fd[1]);
726 
727  crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
728  services_handle_exec_error(op, rc);
729  if (!op->synchronous) {
730  return operation_finalize(op);
731  }
732 
733  sigchld_cleanup();
734  return FALSE;
735 
736  case 0: /* Child */
737  close(stdout_fd[0]);
738  close(stderr_fd[0]);
739  if (STDOUT_FILENO != stdout_fd[1]) {
740  if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
741  crm_err("dup2() failed (stdout)");
742  }
743  close(stdout_fd[1]);
744  }
745  if (STDERR_FILENO != stderr_fd[1]) {
746  if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
747  crm_err("dup2() failed (stderr)");
748  }
749  close(stderr_fd[1]);
750  }
751 
752  if (op->synchronous) {
753  sigchld_cleanup();
754  }
755 
756  action_launch_child(op);
757  CRM_ASSERT(0); /* action_launch_child is effectively noreturn */
758  }
759 
760  /* Only the parent reaches here */
761  close(stdout_fd[1]);
762  close(stderr_fd[1]);
763 
764  op->opaque->stdout_fd = stdout_fd[0];
766  if (rc < 0) {
767  crm_warn("Could not set child output non-blocking: %s "
768  CRM_XS " rc=%d",
769  pcmk_strerror(rc), rc);
770  }
771 
772  op->opaque->stderr_fd = stderr_fd[0];
774  if (rc < 0) {
775  crm_warn("Could not set child error output non-blocking: %s "
776  CRM_XS " rc=%d",
777  pcmk_strerror(rc), rc);
778  }
779 
780  if (op->synchronous) {
781  action_synced_wait(op, pmask);
782  sigchld_cleanup();
783  } else {
784 
785  crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
787  op->timeout,
788  op->id,
789  op,
791  operation_finished);
792 
793 
795  G_PRIORITY_LOW,
796  op->opaque->stdout_fd, op, &stdout_callbacks);
797 
799  G_PRIORITY_LOW,
800  op->opaque->stderr_fd, op, &stderr_callbacks);
801 
803  }
804 
805  return TRUE;
806 }
807 
808 GList *
809 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
810 {
811  GList *list = NULL;
812  struct dirent **namelist;
813  int entries = 0, lpc = 0;
814  char buffer[PATH_MAX];
815 
816  entries = scandir(root, &namelist, NULL, alphasort);
817  if (entries <= 0) {
818  return list;
819  }
820 
821  for (lpc = 0; lpc < entries; lpc++) {
822  struct stat sb;
823 
824  if ('.' == namelist[lpc]->d_name[0]) {
825  free(namelist[lpc]);
826  continue;
827  }
828 
829  snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
830 
831  if (stat(buffer, &sb)) {
832  continue;
833  }
834 
835  if (S_ISDIR(sb.st_mode)) {
836  if (files) {
837  free(namelist[lpc]);
838  continue;
839  }
840 
841  } else if (S_ISREG(sb.st_mode)) {
842  if (files == FALSE) {
843  free(namelist[lpc]);
844  continue;
845 
846  } else if (executable
847  && (sb.st_mode & S_IXUSR) == 0
848  && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
849  free(namelist[lpc]);
850  continue;
851  }
852  }
853 
854  list = g_list_append(list, strdup(namelist[lpc]->d_name));
855 
856  free(namelist[lpc]);
857  }
858 
859  free(namelist);
860  return list;
861 }
862 
863 GList *
865 {
866  return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
867 }
868 
869 GList *
871 {
872  return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
873 }
874 
875 GList *
876 resources_os_list_ocf_agents(const char *provider)
877 {
878  GList *gIter = NULL;
879  GList *result = NULL;
880  GList *providers = NULL;
881 
882  if (provider) {
883  char buffer[500];
884 
885  snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
886  return get_directory_list(buffer, TRUE, TRUE);
887  }
888 
889  providers = resources_os_list_ocf_providers();
890  for (gIter = providers; gIter != NULL; gIter = gIter->next) {
891  GList *tmp1 = result;
892  GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
893 
894  if (tmp2) {
895  result = g_list_concat(tmp1, tmp2);
896  }
897  }
898  g_list_free_full(providers, free);
899  return result;
900 }
901 
902 #if SUPPORT_NAGIOS
903 GList *
905 {
906  GList *plugin_list = NULL;
907  GList *result = NULL;
908  GList *gIter = NULL;
909 
910  plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
911 
912  /* Make sure both the plugin and its metadata exist */
913  for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
914  const char *plugin = gIter->data;
915  char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
916  struct stat st;
917 
918  if (stat(metadata, &st) == 0) {
919  result = g_list_append(result, strdup(plugin));
920  }
921 
922  free(metadata);
923  }
924  g_list_free_full(plugin_list, free);
925  return result;
926 }
927 #endif
Services API.
#define LOG_TRACE
Definition: logging.h:29
int replace_secret_params(char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:89
A dumping ground.
void services_action_free(svc_action_t *op)
Definition: services.c:563
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:1135
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)
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:90
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:527
#define do_crm_log_unlikely(level, fmt, args...)
Log a message that is likely to be filtered out.
Definition: logging.h:139
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:615
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:471
void(* callback)(svc_action_t *op)
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:795
void services_untrack_op(svc_action_t *op)
Definition: services.c:816
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:619
#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:1351
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:827
char * provider
Definition: services.h:169
#define crm_info(fmt, args...)
Definition: logging.h:251
#define NAGIOS_METADATA_DIR
Definition: config.h:616
int mainloop_child_timeout(mainloop_child_t *child)
Definition: mainloop.c:882
char * stderr_data
Definition: services.h:184