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