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