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