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