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