pacemaker  2.0.2-debe490
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 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 static void
227 pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
228 {
229  svc_action_t *op = user_data;
230  char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value);
231  int ret, total = 0, len = strlen(buffer);
232 
233  do {
234  errno = 0;
235  ret = write(op->opaque->stdin_fd, buffer + total, len - total);
236  if (ret > 0) {
237  total += ret;
238  }
239 
240  } while ((errno == EINTR) && (total < len));
241  free(buffer);
242 }
243 
250 static void
251 pipe_in_action_stdin_parameters(const svc_action_t *op)
252 {
253  crm_debug("sending args");
254  if (op->params) {
255  g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op);
256  }
257 }
258 
259 gboolean
261 {
262  svc_action_t *op = data;
263 
264  crm_debug("Scheduling another invocation of %s", op->id);
265 
266  /* Clean out the old result */
267  free(op->stdout_data);
268  op->stdout_data = NULL;
269  free(op->stderr_data);
270  op->stderr_data = NULL;
271  op->opaque->repeat_timer = 0;
272 
273  services_action_async(op, NULL);
274  return FALSE;
275 }
276 
277 /* Returns FALSE if 'op' should be free'd by the caller */
278 gboolean
280 {
281  int recurring = 0;
282 
283  if (op->interval_ms) {
284  if (op->cancel) {
287  } else {
288  recurring = 1;
289  op->opaque->repeat_timer = g_timeout_add(op->interval_ms,
290  recurring_action_timer, (void *)op);
291  }
292  }
293 
294  if (op->opaque->callback) {
295  op->opaque->callback(op);
296  }
297 
298  op->pid = 0;
299 
301 
302  if (!recurring && op->synchronous == FALSE) {
303  /*
304  * If this is a recurring action, do not free explicitly.
305  * It will get freed whenever the action gets cancelled.
306  */
308  return TRUE;
309  }
310 
312  return FALSE;
313 }
314 
315 static void
316 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
317 {
319  char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid);
320 
322  op->status = PCMK_LRM_OP_DONE;
323  CRM_ASSERT(op->pid == pid);
324 
325  crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
326  if (op->opaque->stderr_gsource) {
327  /* Make sure we have read everything from the buffer.
328  * Depending on the priority mainloop gives the fd, operation_finished
329  * could occur before all the reads are done. Force the read now.*/
330  crm_trace("%s dispatching stderr", prefix);
331  dispatch_stderr(op);
332  crm_trace("%s: %p", op->id, op->stderr_data);
334  op->opaque->stderr_gsource = NULL;
335  }
336 
337  if (op->opaque->stdout_gsource) {
338  /* Make sure we have read everything from the buffer.
339  * Depending on the priority mainloop gives the fd, operation_finished
340  * could occur before all the reads are done. Force the read now.*/
341  crm_trace("%s dispatching stdout", prefix);
342  dispatch_stdout(op);
343  crm_trace("%s: %p", op->id, op->stdout_data);
345  op->opaque->stdout_gsource = NULL;
346  }
347 
348  if (op->opaque->stdin_fd >= 0) {
349  close(op->opaque->stdin_fd);
350  }
351 
352  if (signo) {
353  if (mainloop_child_timeout(p)) {
354  crm_warn("%s - timed out after %dms", prefix, op->timeout);
356  op->rc = PCMK_OCF_TIMEOUT;
357 
358  } else if (op->cancel) {
359  /* If an in-flight recurring operation was killed because it was
360  * cancelled, don't treat that as a failure.
361  */
362  crm_info("%s - terminated with signal %d", prefix, signo);
364  op->rc = PCMK_OCF_OK;
365 
366  } else {
367  crm_warn("%s - terminated with signal %d", prefix, signo);
369  op->rc = PCMK_OCF_SIGNAL;
370  }
371 
372  } else {
373  op->rc = exitcode;
374  crm_debug("%s - exited with rc=%d", prefix, exitcode);
375  }
376 
377  free(prefix);
378  prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
379  crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
380 
381  free(prefix);
382  prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
383  crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
384 
385  free(prefix);
386  operation_finalize(op);
387 }
388 
398 static void
399 services_handle_exec_error(svc_action_t * op, int error)
400 {
401  int rc_not_installed, rc_insufficient_priv, rc_exec_error;
402 
403  /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
405  && safe_str_eq(op->action, "status")) {
406 
407  rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
408  rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
409  rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
410 
411 #if SUPPORT_NAGIOS
413  rc_not_installed = NAGIOS_NOT_INSTALLED;
414  rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
415  rc_exec_error = PCMK_OCF_EXEC_ERROR;
416 #endif
417 
418  } else {
419  rc_not_installed = PCMK_OCF_NOT_INSTALLED;
420  rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
421  rc_exec_error = PCMK_OCF_EXEC_ERROR;
422  }
423 
424  switch (error) { /* see execve(2), stat(2) and fork(2) */
425  case ENOENT: /* No such file or directory */
426  case EISDIR: /* Is a directory */
427  case ENOTDIR: /* Path component is not a directory */
428  case EINVAL: /* Invalid executable format */
429  case ENOEXEC: /* Invalid executable format */
430  op->rc = rc_not_installed;
432  break;
433  case EACCES: /* permission denied (various errors) */
434  case EPERM: /* permission denied (various errors) */
435  op->rc = rc_insufficient_priv;
437  break;
438  default:
439  op->rc = rc_exec_error;
441  }
442 }
443 
444 static void
445 action_launch_child(svc_action_t *op)
446 {
447  int lpc;
448 
449  /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
450  * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
451  * We do not want this to be inherited by the child process. By resetting this the signal
452  * to the default behavior, we avoid some potential odd problems that occur during OCF
453  * scripts when SIGPIPE is ignored by the environment. */
454  signal(SIGPIPE, SIG_DFL);
455 
456 #if defined(HAVE_SCHED_SETSCHEDULER)
457  if (sched_getscheduler(0) != SCHED_OTHER) {
458  struct sched_param sp;
459 
460  memset(&sp, 0, sizeof(sp));
461  sp.sched_priority = 0;
462 
463  if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
464  crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
465  }
466  }
467 #endif
468  if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
469  crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
470  }
471 
472  /* Man: The call setpgrp() is equivalent to setpgid(0,0)
473  * _and_ compiles on BSD variants too
474  * need to investigate if it works the same too.
475  */
476  setpgid(0, 0);
477 
478  // Close all file descriptors except stdin/stdout/stderr
479  for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
480  close(lpc);
481  }
482 
483 #if SUPPORT_CIBSECRETS
484  if (replace_secret_params(op->rsc, op->params) < 0) {
485  /* replacing secrets failed! */
486  if (safe_str_eq(op->action,"stop")) {
487  /* don't fail on stop! */
488  crm_info("proceeding with the stop operation for %s", op->rsc);
489 
490  } else {
491  crm_err("failed to get secrets for %s, "
492  "considering resource not configured", op->rsc);
494  }
495  }
496 #endif
497 
498  add_action_env_vars(op);
499 
500  /* Become the desired user */
501  if (op->opaque->uid && (geteuid() == 0)) {
502 
503  // If requested, set effective group
504  if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
505  crm_perror(LOG_ERR, "Could not set child group to %d", op->opaque->gid);
507  }
508 
509  // Erase supplementary group list
510  // (We could do initgroups() if we kept a copy of the username)
511  if (setgroups(0, NULL) < 0) {
512  crm_perror(LOG_ERR, "Could not set child groups");
514  }
515 
516  // Set effective user
517  if (setuid(op->opaque->uid) < 0) {
518  crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
520  }
521  }
522 
523  /* execute the RA */
524  execvp(op->opaque->exec, op->opaque->args);
525 
526  /* Most cases should have been already handled by stat() */
527  services_handle_exec_error(op, errno);
528 
529  _exit(op->rc);
530 }
531 
532 #ifndef HAVE_SYS_SIGNALFD_H
533 static int sigchld_pipe[2] = { -1, -1 };
534 
535 static void
536 sigchld_handler()
537 {
538  if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
539  crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
540  }
541 }
542 #endif
543 
544 static void
545 action_synced_wait(svc_action_t * op, sigset_t *mask)
546 {
547  int status = 0;
548  int timeout = op->timeout;
549  int sfd = -1;
550  time_t start = -1;
551  struct pollfd fds[3];
552  int wait_rc = 0;
553 
554 #ifdef HAVE_SYS_SIGNALFD_H
555  sfd = signalfd(-1, mask, SFD_NONBLOCK);
556  if (sfd < 0) {
557  crm_perror(LOG_ERR, "signalfd() failed");
558  }
559 #else
560  sfd = sigchld_pipe[0];
561 #endif
562 
563  fds[0].fd = op->opaque->stdout_fd;
564  fds[0].events = POLLIN;
565  fds[0].revents = 0;
566 
567  fds[1].fd = op->opaque->stderr_fd;
568  fds[1].events = POLLIN;
569  fds[1].revents = 0;
570 
571  fds[2].fd = sfd;
572  fds[2].events = POLLIN;
573  fds[2].revents = 0;
574 
575  crm_trace("Waiting for %d", op->pid);
576  start = time(NULL);
577  do {
578  int poll_rc = poll(fds, 3, timeout);
579 
580  if (poll_rc > 0) {
581  if (fds[0].revents & POLLIN) {
582  svc_read_output(op->opaque->stdout_fd, op, FALSE);
583  }
584 
585  if (fds[1].revents & POLLIN) {
586  svc_read_output(op->opaque->stderr_fd, op, TRUE);
587  }
588 
589  if (fds[2].revents & POLLIN) {
590 #ifdef HAVE_SYS_SIGNALFD_H
591  struct signalfd_siginfo fdsi;
592  ssize_t s;
593 
594  s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
595  if (s != sizeof(struct signalfd_siginfo)) {
596  crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
597 
598  } else if (fdsi.ssi_signo == SIGCHLD) {
599 #else
600  if (1) {
601  /* Clear out the sigchld pipe. */
602  char ch;
603  while (read(sfd, &ch, 1) == 1) /*omit*/;
604 #endif
605  wait_rc = waitpid(op->pid, &status, WNOHANG);
606 
607  if (wait_rc > 0) {
608  break;
609 
610  } else if (wait_rc < 0){
611  if (errno == ECHILD) {
612  /* Here, don't dare to kill and bail out... */
613  break;
614 
615  } else {
616  /* ...otherwise pretend process still runs. */
617  wait_rc = 0;
618  }
619  crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
620  }
621  }
622  }
623 
624  } else if (poll_rc == 0) {
625  timeout = 0;
626  break;
627 
628  } else if (poll_rc < 0) {
629  if (errno != EINTR) {
630  crm_perror(LOG_ERR, "poll() failed");
631  break;
632  }
633  }
634 
635  timeout = op->timeout - (time(NULL) - start) * 1000;
636 
637  } while ((op->timeout < 0 || timeout > 0));
638 
639  crm_trace("Child done: %d", op->pid);
640  if (wait_rc <= 0) {
642 
643  if (op->timeout > 0 && timeout <= 0) {
645  crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
646 
647  } else {
649  }
650 
651  /* If only child hasn't been successfully waited for, yet.
652  This is to limit killing wrong target a bit more. */
653  if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
654  if (kill(op->pid, SIGKILL)) {
655  crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
656  }
657  /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
658  while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
659  }
660 
661  } else if (WIFEXITED(status)) {
662  op->status = PCMK_LRM_OP_DONE;
663  op->rc = WEXITSTATUS(status);
664  crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
665 
666  } else if (WIFSIGNALED(status)) {
667  int signo = WTERMSIG(status);
668 
670  crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
671  }
672 #ifdef WCOREDUMP
673  if (WCOREDUMP(status)) {
674  crm_err("Managed %s process %d dumped core", op->id, op->pid);
675  }
676 #endif
677 
678  svc_read_output(op->opaque->stdout_fd, op, FALSE);
679  svc_read_output(op->opaque->stderr_fd, op, TRUE);
680 
681  close(op->opaque->stdout_fd);
682  close(op->opaque->stderr_fd);
683  if (op->opaque->stdin_fd >= 0) {
684  close(op->opaque->stdin_fd);
685  }
686 
687 #ifdef HAVE_SYS_SIGNALFD_H
688  close(sfd);
689 #endif
690 }
691 
692 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
693 /* For a synchronous 'op', returns FALSE if 'op' fails */
694 gboolean
696 {
697  int stdout_fd[2];
698  int stderr_fd[2];
699  int stdin_fd[2] = {-1, -1};
700  int rc;
701  struct stat st;
702  sigset_t *pmask = NULL;
703 
704 #ifdef HAVE_SYS_SIGNALFD_H
705  sigset_t mask;
706  sigset_t old_mask;
707 #define sigchld_cleanup() do { \
708  if (sigismember(&old_mask, SIGCHLD) == 0) { \
709  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \
710  crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \
711  } \
712  } \
713 } while (0)
714 #else
715  struct sigaction sa;
716  struct sigaction old_sa;
717 #define sigchld_cleanup() do { \
718  if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \
719  crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \
720  } \
721  close(sigchld_pipe[0]); \
722  close(sigchld_pipe[1]); \
723  sigchld_pipe[0] = sigchld_pipe[1] = -1; \
724 } while(0)
725 #endif
726 
727  /* Fail fast */
728  if(stat(op->opaque->exec, &st) != 0) {
729  rc = errno;
730  crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
731  services_handle_exec_error(op, rc);
732  if (!op->synchronous) {
733  return operation_finalize(op);
734  }
735  return FALSE;
736  }
737 
738  if (pipe(stdout_fd) < 0) {
739  rc = errno;
740 
741  crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
742 
743  services_handle_exec_error(op, rc);
744  if (!op->synchronous) {
745  return operation_finalize(op);
746  }
747  return FALSE;
748  }
749 
750  if (pipe(stderr_fd) < 0) {
751  rc = errno;
752 
753  close(stdout_fd[0]);
754  close(stdout_fd[1]);
755 
756  crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
757 
758  services_handle_exec_error(op, rc);
759  if (!op->synchronous) {
760  return operation_finalize(op);
761  }
762  return FALSE;
763  }
764 
766  if (pipe(stdin_fd) < 0) {
767  rc = errno;
768 
769  close(stdout_fd[0]);
770  close(stdout_fd[1]);
771  close(stderr_fd[0]);
772  close(stderr_fd[1]);
773 
774  crm_err("pipe(stdin_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
775 
776  services_handle_exec_error(op, rc);
777  if (!op->synchronous) {
778  return operation_finalize(op);
779  }
780  return FALSE;
781  }
782  }
783 
784  if (op->synchronous) {
785 #ifdef HAVE_SYS_SIGNALFD_H
786  sigemptyset(&mask);
787  sigaddset(&mask, SIGCHLD);
788  sigemptyset(&old_mask);
789 
790  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
791  crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
792  }
793 
794  pmask = &mask;
795 #else
796  if(pipe(sigchld_pipe) == -1) {
797  crm_perror(LOG_ERR, "pipe() failed");
798  }
799 
800  rc = crm_set_nonblocking(sigchld_pipe[0]);
801  if (rc < 0) {
802  crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
803  pcmk_strerror(rc), rc);
804  }
805  rc = crm_set_nonblocking(sigchld_pipe[1]);
806  if (rc < 0) {
807  crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
808  pcmk_strerror(rc), rc);
809  }
810 
811  sa.sa_handler = sigchld_handler;
812  sa.sa_flags = 0;
813  sigemptyset(&sa.sa_mask);
814  if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
815  crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
816  }
817 
818  pmask = NULL;
819 #endif
820  }
821 
822  op->pid = fork();
823  switch (op->pid) {
824  case -1:
825  rc = errno;
826 
827  close(stdout_fd[0]);
828  close(stdout_fd[1]);
829  close(stderr_fd[0]);
830  close(stderr_fd[1]);
831  if (stdin_fd[0] >= 0) {
832  close(stdin_fd[0]);
833  close(stdin_fd[1]);
834  }
835 
836  crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
837  services_handle_exec_error(op, rc);
838  if (!op->synchronous) {
839  return operation_finalize(op);
840  }
841 
842  sigchld_cleanup();
843  return FALSE;
844 
845  case 0: /* Child */
846  close(stdout_fd[0]);
847  close(stderr_fd[0]);
848  if (stdin_fd[1] >= 0) {
849  close(stdin_fd[1]);
850  }
851  if (STDOUT_FILENO != stdout_fd[1]) {
852  if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
853  crm_err("dup2() failed (stdout)");
854  }
855  close(stdout_fd[1]);
856  }
857  if (STDERR_FILENO != stderr_fd[1]) {
858  if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
859  crm_err("dup2() failed (stderr)");
860  }
861  close(stderr_fd[1]);
862  }
863  if ((stdin_fd[0] >= 0) &&
864  (STDIN_FILENO != stdin_fd[0])) {
865  if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
866  crm_err("dup2() failed (stdin)");
867  }
868  close(stdin_fd[0]);
869  }
870 
871  if (op->synchronous) {
872  sigchld_cleanup();
873  }
874 
875  action_launch_child(op);
876  CRM_ASSERT(0); /* action_launch_child is effectively noreturn */
877  }
878 
879  /* Only the parent reaches here */
880  close(stdout_fd[1]);
881  close(stderr_fd[1]);
882  if (stdin_fd[0] >= 0) {
883  close(stdin_fd[0]);
884  }
885 
886  op->opaque->stdout_fd = stdout_fd[0];
888  if (rc < 0) {
889  crm_warn("Could not set child output non-blocking: %s "
890  CRM_XS " rc=%d",
891  pcmk_strerror(rc), rc);
892  }
893 
894  op->opaque->stderr_fd = stderr_fd[0];
896  if (rc < 0) {
897  crm_warn("Could not set child error output non-blocking: %s "
898  CRM_XS " rc=%d",
899  pcmk_strerror(rc), rc);
900  }
901 
902  op->opaque->stdin_fd = stdin_fd[1];
903  if (op->opaque->stdin_fd >= 0) {
904  // using buffer behind non-blocking-fd here - that could be improved
905  // as long as no other standard uses stdin_fd assume stonith
907  if (rc < 0) {
908  crm_warn("Could not set child input non-blocking: %s "
909  CRM_XS " fd=%d,rc=%d",
910  pcmk_strerror(rc), op->opaque->stdin_fd, rc);
911  }
912  pipe_in_action_stdin_parameters(op);
913  // as long as we are handling parameters directly in here just close
914  close(op->opaque->stdin_fd);
915  op->opaque->stdin_fd = -1;
916  }
917 
918  // after fds are setup properly and before we plug anything into mainloop
919  if (op->opaque->fork_callback) {
920  op->opaque->fork_callback(op);
921  }
922 
923  if (op->synchronous) {
924  action_synced_wait(op, pmask);
925  sigchld_cleanup();
926  } else {
927 
928  crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
930  op->timeout,
931  op->id,
932  op,
934  operation_finished);
935 
936 
938  G_PRIORITY_LOW,
939  op->opaque->stdout_fd, op, &stdout_callbacks);
940 
942  G_PRIORITY_LOW,
943  op->opaque->stderr_fd, op, &stderr_callbacks);
944 
946  }
947 
948  return TRUE;
949 }
950 
951 GList *
952 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
953 {
954  GList *list = NULL;
955  struct dirent **namelist;
956  int entries = 0, lpc = 0;
957  char buffer[PATH_MAX];
958 
959  entries = scandir(root, &namelist, NULL, alphasort);
960  if (entries <= 0) {
961  return list;
962  }
963 
964  for (lpc = 0; lpc < entries; lpc++) {
965  struct stat sb;
966 
967  if ('.' == namelist[lpc]->d_name[0]) {
968  free(namelist[lpc]);
969  continue;
970  }
971 
972  snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
973 
974  if (stat(buffer, &sb)) {
975  continue;
976  }
977 
978  if (S_ISDIR(sb.st_mode)) {
979  if (files) {
980  free(namelist[lpc]);
981  continue;
982  }
983 
984  } else if (S_ISREG(sb.st_mode)) {
985  if (files == FALSE) {
986  free(namelist[lpc]);
987  continue;
988 
989  } else if (executable
990  && (sb.st_mode & S_IXUSR) == 0
991  && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
992  free(namelist[lpc]);
993  continue;
994  }
995  }
996 
997  list = g_list_append(list, strdup(namelist[lpc]->d_name));
998 
999  free(namelist[lpc]);
1000  }
1001 
1002  free(namelist);
1003  return list;
1004 }
1005 
1006 GList *
1008 {
1009  return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
1010 }
1011 
1012 GList *
1013 resources_os_list_ocf_agents(const char *provider)
1014 {
1015  GList *gIter = NULL;
1016  GList *result = NULL;
1017  GList *providers = NULL;
1018 
1019  if (provider) {
1020  char buffer[500];
1021 
1022  snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
1023  return get_directory_list(buffer, TRUE, TRUE);
1024  }
1025 
1026  providers = resources_os_list_ocf_providers();
1027  for (gIter = providers; gIter != NULL; gIter = gIter->next) {
1028  GList *tmp1 = result;
1029  GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
1030 
1031  if (tmp2) {
1032  result = g_list_concat(tmp1, tmp2);
1033  }
1034  }
1035  g_list_free_full(providers, free);
1036  return result;
1037 }
1038 
1039 gboolean
1040 services__ocf_agent_exists(const char *provider, const char *agent)
1041 {
1042  char *buf = NULL;
1043  gboolean rc = FALSE;
1044  struct stat st;
1045 
1046  if (provider == NULL || agent == NULL) {
1047  return rc;
1048  }
1049 
1050  buf = crm_strdup_printf(OCF_ROOT_DIR "/resource.d/%s/%s", provider, agent);
1051  if (stat(buf, &st) == 0) {
1052  rc = TRUE;
1053  }
1054 
1055  free(buf);
1056  return rc;
1057 }
1058 
1059 #if SUPPORT_NAGIOS
1060 GList *
1062 {
1063  GList *plugin_list = NULL;
1064  GList *result = NULL;
1065  GList *gIter = NULL;
1066 
1067  plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
1068 
1069  /* Make sure both the plugin and its metadata exist */
1070  for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
1071  const char *plugin = gIter->data;
1072  char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
1073  struct stat st;
1074 
1075  if (stat(metadata, &st) == 0) {
1076  result = g_list_append(result, strdup(plugin));
1077  }
1078 
1079  free(metadata);
1080  }
1081  g_list_free_full(plugin_list, free);
1082  return result;
1083 }
1084 
1085 gboolean
1086 services__nagios_agent_exists(const char *name)
1087 {
1088  char *buf = NULL;
1089  gboolean rc = FALSE;
1090  struct stat st;
1091 
1092  if (name == NULL) {
1093  return rc;
1094  }
1095 
1096  buf = crm_strdup_printf(NAGIOS_PLUGIN_DIR "/%s", name);
1097  if (stat(buf, &st) == 0) {
1098  rc = TRUE;
1099  }
1100 
1101  free(buf);
1102  return rc;
1103 }
1104 #endif
Services API.
#define LOG_TRACE
Definition: logging.h:26
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:188
void services_action_free(svc_action_t *op)
Definition: services.c:463
gboolean services__ocf_agent_exists(const char *provider, const char *agent)
guint interval_ms
Definition: services.h:152
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:864
char * standard
Definition: services.h:154
#define sigchld_cleanup()
#define crm_log_output(level, prefix, output)
Definition: logging.h:84
char * id
Definition: services.h:149
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(* fork_callback)(svc_action_t *op)
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:1151
struct mainloop_child_s mainloop_child_t
Definition: mainloop.h:33
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:92
char * rsc
Definition: services.h:150
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:83
Wrappers for and extensions to glib mainloop.
void services_action_cleanup(svc_action_t *op)
Definition: services.c:424
enum svc_action_flags flags
Definition: services.h:171
#define crm_warn(fmt, args...)
Definition: logging.h:241
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:43
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:515
svc_action_private_t * opaque
Definition: services.h:184
#define OCF_ROOT_DIR
Definition: services.h:30
#define crm_debug(fmt, args...)
Definition: logging.h:245
void * mainloop_child_userdata(mainloop_child_t *child)
Definition: mainloop.c:942
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:174
G_GNUC_INTERNAL gboolean services__nagios_agent_exists(const char *agent)
GHashTable * params
Definition: services.h:159
#define crm_trace(fmt, args...)
Definition: logging.h:246
int setenv(const char *name, const char *value, int why)
int crm_set_nonblocking(int fd)
Definition: io.c:486
void(* callback)(svc_action_t *op)
char * agent
Definition: services.h:156
int synchronous
Definition: services.h:170
#define PCMK_OCF_REASON_PREFIX
Definition: services.h:55
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:49
#define CRM_XS
Definition: logging.h:34
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:699
void services_untrack_op(svc_action_t *op)
Definition: services.c:720
int replace_secret_params(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:90
char * action
Definition: services.h:151
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:48
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:45
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:218
#define NAGIOS_PLUGIN_DIR
Definition: config.h:490
#define crm_err(fmt, args...)
Definition: logging.h:240
#define CRM_ASSERT(expr)
Definition: results.h:42
void mainloop_clear_child_userdata(mainloop_child_t *child)
Definition: mainloop.c:948
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:953
mainloop_io_t * stdout_gsource
char data[0]
Definition: internal.h:92
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:908
#define safe_str_eq(a, b)
Definition: util.h:59
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Definition: services.c:762
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
char * provider
Definition: services.h:155
#define crm_info(fmt, args...)
Definition: logging.h:243
#define NAGIOS_METADATA_DIR
Definition: config.h:487
int mainloop_child_timeout(mainloop_child_t *child)
Definition: mainloop.c:936
char * stderr_data
Definition: services.h:173