pacemaker  1.1.14-70404b0
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 (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", 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 static void
461 action_synced_wait(svc_action_t * op, sigset_t mask)
462 {
463 
464 #ifndef HAVE_SYS_SIGNALFD_H
465  CRM_ASSERT(FALSE);
466 #else
467  int status = 0;
468  int timeout = op->timeout;
469  int sfd = -1;
470  time_t start = -1;
471  struct pollfd fds[3];
472  int wait_rc = 0;
473 
474  sfd = signalfd(-1, &mask, SFD_NONBLOCK);
475  if (sfd < 0) {
476  crm_perror(LOG_ERR, "signalfd() failed");
477  }
478 
479  fds[0].fd = op->opaque->stdout_fd;
480  fds[0].events = POLLIN;
481  fds[0].revents = 0;
482 
483  fds[1].fd = op->opaque->stderr_fd;
484  fds[1].events = POLLIN;
485  fds[1].revents = 0;
486 
487  fds[2].fd = sfd;
488  fds[2].events = POLLIN;
489  fds[2].revents = 0;
490 
491  crm_trace("Waiting for %d", op->pid);
492  start = time(NULL);
493  do {
494  int poll_rc = poll(fds, 3, timeout);
495 
496  if (poll_rc > 0) {
497  if (fds[0].revents & POLLIN) {
498  svc_read_output(op->opaque->stdout_fd, op, FALSE);
499  }
500 
501  if (fds[1].revents & POLLIN) {
502  svc_read_output(op->opaque->stderr_fd, op, TRUE);
503  }
504 
505  if (fds[2].revents & POLLIN) {
506  struct signalfd_siginfo fdsi;
507  ssize_t s;
508 
509  s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
510  if (s != sizeof(struct signalfd_siginfo)) {
511  crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
512 
513  } else if (fdsi.ssi_signo == SIGCHLD) {
514  wait_rc = waitpid(op->pid, &status, WNOHANG);
515 
516  if (wait_rc < 0){
517  crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
518 
519  } else if (wait_rc > 0) {
520  break;
521  }
522  }
523  }
524 
525  } else if (poll_rc == 0) {
526  timeout = 0;
527  break;
528 
529  } else if (poll_rc < 0) {
530  if (errno != EINTR) {
531  crm_perror(LOG_ERR, "poll() failed");
532  break;
533  }
534  }
535 
536  timeout = op->timeout - (time(NULL) - start) * 1000;
537 
538  } while ((op->timeout < 0 || timeout > 0));
539 
540  crm_trace("Child done: %d", op->pid);
541  if (wait_rc <= 0) {
542  int killrc = kill(op->pid, SIGKILL);
543 
545  if (op->timeout > 0 && timeout <= 0) {
547  crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
548 
549  } else {
551  }
552 
553  if (killrc && errno != ESRCH) {
554  crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
555  }
556  /*
557  * From sigprocmask(2):
558  * It is not possible to block SIGKILL or SIGSTOP. Attempts to do so are silently ignored.
559  *
560  * This makes it safe to skip WNOHANG here
561  */
562  waitpid(op->pid, &status, 0);
563 
564  } else if (WIFEXITED(status)) {
565  op->status = PCMK_LRM_OP_DONE;
566  op->rc = WEXITSTATUS(status);
567  crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
568 
569  } else if (WIFSIGNALED(status)) {
570  int signo = WTERMSIG(status);
571 
573  crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
574  }
575 #ifdef WCOREDUMP
576  if (WCOREDUMP(status)) {
577  crm_err("Managed %s process %d dumped core", op->id, op->pid);
578  }
579 #endif
580 
581  svc_read_output(op->opaque->stdout_fd, op, FALSE);
582  svc_read_output(op->opaque->stderr_fd, op, TRUE);
583 
584  close(op->opaque->stdout_fd);
585  close(op->opaque->stderr_fd);
586  close(sfd);
587 
588 #endif
589 
590 }
591 
592 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
593 /* For a synchronous 'op', returns FALSE if 'op' fails */
594 gboolean
595 services_os_action_execute(svc_action_t * op, gboolean synchronous)
596 {
597  int stdout_fd[2];
598  int stderr_fd[2];
599  sigset_t mask;
600  sigset_t old_mask;
601  struct stat st;
602 
603  if (pipe(stdout_fd) < 0) {
604  crm_err("pipe() failed");
605  }
606 
607  if (pipe(stderr_fd) < 0) {
608  crm_err("pipe() failed");
609  }
610 
611  /* Fail fast */
612  if(stat(op->opaque->exec, &st) != 0) {
613  int rc = errno;
614  crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
615  services_handle_exec_error(op, rc);
616  if (!synchronous) {
617  return operation_finalize(op);
618  }
619  return FALSE;
620  }
621 
622  if (synchronous) {
623  sigemptyset(&mask);
624  sigaddset(&mask, SIGCHLD);
625  sigemptyset(&old_mask);
626 
627  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
628  crm_perror(LOG_ERR, "sigprocmask() failed");
629  }
630  }
631 
632  op->pid = fork();
633  switch (op->pid) {
634  case -1:
635  {
636  int rc = errno;
637 
638  close(stdout_fd[0]);
639  close(stdout_fd[1]);
640  close(stderr_fd[0]);
641  close(stderr_fd[1]);
642 
643  crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
644  services_handle_exec_error(op, rc);
645  if (!synchronous) {
646  return operation_finalize(op);
647  }
648  return FALSE;
649  }
650  case 0: /* Child */
651  close(stdout_fd[0]);
652  close(stderr_fd[0]);
653  if (STDOUT_FILENO != stdout_fd[1]) {
654  if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
655  crm_err("dup2() failed (stdout)");
656  }
657  close(stdout_fd[1]);
658  }
659  if (STDERR_FILENO != stderr_fd[1]) {
660  if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
661  crm_err("dup2() failed (stderr)");
662  }
663  close(stderr_fd[1]);
664  }
665 
666  action_launch_child(op);
667  }
668 
669  /* Only the parent reaches here */
670  close(stdout_fd[1]);
671  close(stderr_fd[1]);
672 
673  op->opaque->stdout_fd = stdout_fd[0];
674  set_fd_opts(op->opaque->stdout_fd, O_NONBLOCK);
675 
676  op->opaque->stderr_fd = stderr_fd[0];
677  set_fd_opts(op->opaque->stderr_fd, O_NONBLOCK);
678 
679  if (synchronous) {
680  action_synced_wait(op, mask);
681 
682  if (sigismember(&old_mask, SIGCHLD) == 0) {
683  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) {
684  crm_perror(LOG_ERR, "sigprocmask() to unblocked failed");
685  }
686  }
687 
688  } else {
689 
690  crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
692  op->timeout,
693  op->id,
694  op,
696  operation_finished);
697 
698 
700  G_PRIORITY_LOW,
701  op->opaque->stdout_fd, op, &stdout_callbacks);
702 
704  G_PRIORITY_LOW,
705  op->opaque->stderr_fd, op, &stderr_callbacks);
706 
708  }
709 
710  return TRUE;
711 }
712 
713 GList *
714 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
715 {
716  GList *list = NULL;
717  struct dirent **namelist;
718  int entries = 0, lpc = 0;
719  char buffer[PATH_MAX];
720 
721  entries = scandir(root, &namelist, NULL, alphasort);
722  if (entries <= 0) {
723  return list;
724  }
725 
726  for (lpc = 0; lpc < entries; lpc++) {
727  struct stat sb;
728 
729  if ('.' == namelist[lpc]->d_name[0]) {
730  free(namelist[lpc]);
731  continue;
732  }
733 
734  snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
735 
736  if (stat(buffer, &sb)) {
737  continue;
738  }
739 
740  if (S_ISDIR(sb.st_mode)) {
741  if (files) {
742  free(namelist[lpc]);
743  continue;
744  }
745 
746  } else if (S_ISREG(sb.st_mode)) {
747  if (files == FALSE) {
748  free(namelist[lpc]);
749  continue;
750 
751  } else if (executable
752  && (sb.st_mode & S_IXUSR) == 0
753  && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
754  free(namelist[lpc]);
755  continue;
756  }
757  }
758 
759  list = g_list_append(list, strdup(namelist[lpc]->d_name));
760 
761  free(namelist[lpc]);
762  }
763 
764  free(namelist);
765  return list;
766 }
767 
768 GList *
770 {
771  return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
772 }
773 
774 GList *
776 {
777  return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
778 }
779 
780 GList *
781 resources_os_list_ocf_agents(const char *provider)
782 {
783  GList *gIter = NULL;
784  GList *result = NULL;
785  GList *providers = NULL;
786 
787  if (provider) {
788  char buffer[500];
789 
790  snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
791  return get_directory_list(buffer, TRUE, TRUE);
792  }
793 
794  providers = resources_os_list_ocf_providers();
795  for (gIter = providers; gIter != NULL; gIter = gIter->next) {
796  GList *tmp1 = result;
797  GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
798 
799  if (tmp2) {
800  result = g_list_concat(tmp1, tmp2);
801  }
802  }
803  g_list_free_full(providers, free);
804  return result;
805 }
806 
807 #if SUPPORT_NAGIOS
808 GList *
810 {
811  GList *plugin_list = NULL;
812  GList *result = NULL;
813  GList *gIter = NULL;
814 
815  plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
816 
817  /* Make sure both the plugin and its metadata exist */
818  for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
819  const char *plugin = gIter->data;
820  char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
821  struct stat st;
822 
823  if (stat(metadata, &st) == 0) {
824  result = g_list_append(result, strdup(plugin));
825  }
826 
827  free(metadata);
828  }
829  g_list_free_full(plugin_list, free);
830  return result;
831 }
832 #endif
Services API.
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:806
char * standard
Definition: services.h:157
GList * inflight_ops
Definition: services.c:58
#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:1093
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:884
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: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:890
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:850
#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:500
int mainloop_child_timeout(mainloop_child_t *child)
Definition: mainloop.c:878
char * stderr_data
Definition: services.h:173