This source file includes following definitions.
- svc_read_output
- dispatch_stdout
- dispatch_stderr
- pipe_out_done
- pipe_err_done
- set_ocf_env
- set_ocf_env_with_prefix
- add_action_env_vars
- recurring_action_timer
- operation_finalize
- operation_finished
- services_handle_exec_error
- action_launch_child
- sigchld_handler
- action_synced_wait
- services_os_action_execute
- services_os_get_directory_list
- resources_os_list_lsb_agents
- resources_os_list_ocf_providers
- resources_os_list_ocf_agents
- resources_os_list_nagios_agents
1
2
3
4
5
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 <string.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23
24 #ifdef HAVE_SYS_SIGNALFD_H
25 #include <sys/signalfd.h>
26 #endif
27
28 #include "crm/crm.h"
29 #include "crm/common/mainloop.h"
30 #include "crm/services.h"
31
32 #include "services_private.h"
33
34 #if SUPPORT_CIBSECRETS
35 # include "crm/common/cib_secrets.h"
36 #endif
37
38 static gboolean
39 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
40 {
41 char *data = NULL;
42 int rc = 0, len = 0;
43 char buf[500];
44 static const size_t buf_read_len = sizeof(buf) - 1;
45
46
47 if (fd < 0) {
48 crm_trace("No fd for %s", op->id);
49 return FALSE;
50 }
51
52 if (is_stderr && op->stderr_data) {
53 len = strlen(op->stderr_data);
54 data = op->stderr_data;
55 crm_trace("Reading %s stderr into offset %d", op->id, len);
56
57 } else if (is_stderr == FALSE && op->stdout_data) {
58 len = strlen(op->stdout_data);
59 data = op->stdout_data;
60 crm_trace("Reading %s stdout into offset %d", op->id, len);
61
62 } else {
63 crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
64 }
65
66 do {
67 rc = read(fd, buf, buf_read_len);
68 if (rc > 0) {
69 crm_trace("Got %d chars: %.80s", rc, buf);
70 buf[rc] = 0;
71 data = realloc_safe(data, len + rc + 1);
72 len += sprintf(data + len, "%s", buf);
73
74 } else if (errno != EINTR) {
75
76
77
78 rc = FALSE;
79 break;
80 }
81
82 } while (rc == buf_read_len || rc < 0);
83
84 if (is_stderr) {
85 op->stderr_data = data;
86 } else {
87 op->stdout_data = data;
88 }
89
90 return rc;
91 }
92
93 static int
94 dispatch_stdout(gpointer userdata)
95 {
96 svc_action_t *op = (svc_action_t *) userdata;
97
98 return svc_read_output(op->opaque->stdout_fd, op, FALSE);
99 }
100
101 static int
102 dispatch_stderr(gpointer userdata)
103 {
104 svc_action_t *op = (svc_action_t *) userdata;
105
106 return svc_read_output(op->opaque->stderr_fd, op, TRUE);
107 }
108
109 static void
110 pipe_out_done(gpointer user_data)
111 {
112 svc_action_t *op = (svc_action_t *) user_data;
113
114 crm_trace("%p", op);
115
116 op->opaque->stdout_gsource = NULL;
117 if (op->opaque->stdout_fd > STDOUT_FILENO) {
118 close(op->opaque->stdout_fd);
119 }
120 op->opaque->stdout_fd = -1;
121 }
122
123 static void
124 pipe_err_done(gpointer user_data)
125 {
126 svc_action_t *op = (svc_action_t *) user_data;
127
128 op->opaque->stderr_gsource = NULL;
129 if (op->opaque->stderr_fd > STDERR_FILENO) {
130 close(op->opaque->stderr_fd);
131 }
132 op->opaque->stderr_fd = -1;
133 }
134
135 static struct mainloop_fd_callbacks stdout_callbacks = {
136 .dispatch = dispatch_stdout,
137 .destroy = pipe_out_done,
138 };
139
140 static struct mainloop_fd_callbacks stderr_callbacks = {
141 .dispatch = dispatch_stderr,
142 .destroy = pipe_err_done,
143 };
144
145 static void
146 set_ocf_env(const char *key, const char *value, gpointer user_data)
147 {
148 if (setenv(key, value, 1) != 0) {
149 crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
150 }
151 }
152
153 static void
154 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
155 {
156 char buffer[500];
157
158 snprintf(buffer, sizeof(buffer), "OCF_RESKEY_%s", (char *)key);
159 set_ocf_env(buffer, value, user_data);
160 }
161
162
163
164
165
166
167
168 static void
169 add_action_env_vars(const svc_action_t *op)
170 {
171 if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF) == FALSE) {
172 return;
173 }
174
175 if (op->params) {
176 g_hash_table_foreach(op->params, set_ocf_env_with_prefix, NULL);
177 }
178
179 set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
180 set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
181 set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
182 set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
183
184 if (op->rsc) {
185 set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
186 }
187
188 if (op->agent != NULL) {
189 set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
190 }
191
192
193 if (op->provider != NULL) {
194 set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
195 }
196 }
197
198 gboolean
199 recurring_action_timer(gpointer data)
200 {
201 svc_action_t *op = data;
202
203 crm_debug("Scheduling another invocation of %s", op->id);
204
205
206 free(op->stdout_data);
207 op->stdout_data = NULL;
208 free(op->stderr_data);
209 op->stderr_data = NULL;
210 op->opaque->repeat_timer = 0;
211
212 services_action_async(op, NULL);
213 return FALSE;
214 }
215
216
217 gboolean
218 operation_finalize(svc_action_t * op)
219 {
220 int recurring = 0;
221
222 if (op->interval) {
223 if (op->cancel) {
224 op->status = PCMK_LRM_OP_CANCELLED;
225 cancel_recurring_action(op);
226 } else {
227 recurring = 1;
228 op->opaque->repeat_timer = g_timeout_add(op->interval,
229 recurring_action_timer, (void *)op);
230 }
231 }
232
233 if (op->opaque->callback) {
234 op->opaque->callback(op);
235 }
236
237 op->pid = 0;
238
239 services_untrack_op(op);
240
241 if (!recurring && op->synchronous == FALSE) {
242
243
244
245
246 services_action_free(op);
247 return TRUE;
248 }
249
250 services_action_cleanup(op);
251 return FALSE;
252 }
253
254 static void
255 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
256 {
257 svc_action_t *op = mainloop_child_userdata(p);
258 char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid);
259
260 mainloop_clear_child_userdata(p);
261 op->status = PCMK_LRM_OP_DONE;
262 CRM_ASSERT(op->pid == pid);
263
264 crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
265 if (op->opaque->stderr_gsource) {
266
267
268
269 crm_trace("%s dispatching stderr", prefix);
270 dispatch_stderr(op);
271 crm_trace("%s: %p", op->id, op->stderr_data);
272 mainloop_del_fd(op->opaque->stderr_gsource);
273 op->opaque->stderr_gsource = NULL;
274 }
275
276 if (op->opaque->stdout_gsource) {
277
278
279
280 crm_trace("%s dispatching stdout", prefix);
281 dispatch_stdout(op);
282 crm_trace("%s: %p", op->id, op->stdout_data);
283 mainloop_del_fd(op->opaque->stdout_gsource);
284 op->opaque->stdout_gsource = NULL;
285 }
286
287 if (signo) {
288 if (mainloop_child_timeout(p)) {
289 crm_warn("%s - timed out after %dms", prefix, op->timeout);
290 op->status = PCMK_LRM_OP_TIMEOUT;
291 op->rc = PCMK_OCF_TIMEOUT;
292
293 } else {
294 do_crm_log_unlikely((op->cancel) ? LOG_INFO : LOG_WARNING,
295 "%s - terminated with signal %d", prefix, signo);
296 op->status = PCMK_LRM_OP_ERROR;
297 op->rc = PCMK_OCF_SIGNAL;
298 }
299
300 } else {
301 op->rc = exitcode;
302 crm_debug("%s - exited with rc=%d", prefix, exitcode);
303 }
304
305 free(prefix);
306 prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
307 crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
308
309 free(prefix);
310 prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
311 crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
312
313 free(prefix);
314 operation_finalize(op);
315 }
316
317
318
319
320
321
322
323
324
325
326 static void
327 services_handle_exec_error(svc_action_t * op, int error)
328 {
329 int rc_not_installed, rc_insufficient_priv, rc_exec_error;
330
331
332 if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB)
333 && safe_str_eq(op->action, "status")) {
334
335 rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
336 rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
337 rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
338
339 #if SUPPORT_NAGIOS
340 } else if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
341 rc_not_installed = NAGIOS_NOT_INSTALLED;
342 rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
343 rc_exec_error = PCMK_OCF_EXEC_ERROR;
344 #endif
345
346 } else {
347 rc_not_installed = PCMK_OCF_NOT_INSTALLED;
348 rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
349 rc_exec_error = PCMK_OCF_EXEC_ERROR;
350 }
351
352 switch (error) {
353 case ENOENT:
354 case EISDIR:
355 case ENOTDIR:
356 case EINVAL:
357 case ENOEXEC:
358 op->rc = rc_not_installed;
359 op->status = PCMK_LRM_OP_NOT_INSTALLED;
360 break;
361 case EACCES:
362 case EPERM:
363 op->rc = rc_insufficient_priv;
364 op->status = PCMK_LRM_OP_ERROR;
365 break;
366 default:
367 op->rc = rc_exec_error;
368 op->status = PCMK_LRM_OP_ERROR;
369 }
370 }
371
372 static void
373 action_launch_child(svc_action_t *op)
374 {
375 int lpc;
376
377
378
379
380
381
382 signal(SIGPIPE, SIG_DFL);
383
384 #if defined(HAVE_SCHED_SETSCHEDULER)
385 if (sched_getscheduler(0) != SCHED_OTHER) {
386 struct sched_param sp;
387
388 memset(&sp, 0, sizeof(sp));
389 sp.sched_priority = 0;
390
391 if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
392 crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
393 }
394 }
395 #endif
396 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
397 crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
398 }
399
400
401
402
403
404 setpgid(0, 0);
405
406
407 for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
408 close(lpc);
409 }
410
411 #if SUPPORT_CIBSECRETS
412 if (replace_secret_params(op->rsc, op->params) < 0) {
413
414 if (safe_str_eq(op->action,"stop")) {
415
416 crm_info("proceeding with the stop operation for %s", op->rsc);
417
418 } else {
419 crm_err("failed to get secrets for %s, "
420 "considering resource not configured", op->rsc);
421 _exit(PCMK_OCF_NOT_CONFIGURED);
422 }
423 }
424 #endif
425
426 add_action_env_vars(op);
427
428
429 if (op->opaque->uid && (geteuid() == 0)) {
430 if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
431 crm_perror(LOG_ERR, "setting group to %d", op->opaque->gid);
432 _exit(PCMK_OCF_NOT_CONFIGURED);
433 }
434 if (setuid(op->opaque->uid) < 0) {
435 crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
436 _exit(PCMK_OCF_NOT_CONFIGURED);
437 }
438
439 }
440
441
442 execvp(op->opaque->exec, op->opaque->args);
443
444
445 services_handle_exec_error(op, errno);
446
447 _exit(op->rc);
448 }
449
450 #ifndef HAVE_SYS_SIGNALFD_H
451 static int sigchld_pipe[2] = { -1, -1 };
452
453 static void
454 sigchld_handler()
455 {
456 if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
457 crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
458 }
459 }
460 #endif
461
462 static void
463 action_synced_wait(svc_action_t * op, sigset_t *mask)
464 {
465 int status = 0;
466 int timeout = op->timeout;
467 int sfd = -1;
468 time_t start = -1;
469 struct pollfd fds[3];
470 int wait_rc = 0;
471
472 #ifdef HAVE_SYS_SIGNALFD_H
473 sfd = signalfd(-1, mask, SFD_NONBLOCK);
474 if (sfd < 0) {
475 crm_perror(LOG_ERR, "signalfd() failed");
476 }
477 #else
478 sfd = sigchld_pipe[0];
479 #endif
480
481 fds[0].fd = op->opaque->stdout_fd;
482 fds[0].events = POLLIN;
483 fds[0].revents = 0;
484
485 fds[1].fd = op->opaque->stderr_fd;
486 fds[1].events = POLLIN;
487 fds[1].revents = 0;
488
489 fds[2].fd = sfd;
490 fds[2].events = POLLIN;
491 fds[2].revents = 0;
492
493 crm_trace("Waiting for %d", op->pid);
494 start = time(NULL);
495 do {
496 int poll_rc = poll(fds, 3, timeout);
497
498 if (poll_rc > 0) {
499 if (fds[0].revents & POLLIN) {
500 svc_read_output(op->opaque->stdout_fd, op, FALSE);
501 }
502
503 if (fds[1].revents & POLLIN) {
504 svc_read_output(op->opaque->stderr_fd, op, TRUE);
505 }
506
507 if (fds[2].revents & POLLIN) {
508 #ifdef HAVE_SYS_SIGNALFD_H
509 struct signalfd_siginfo fdsi;
510 ssize_t s;
511
512 s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
513 if (s != sizeof(struct signalfd_siginfo)) {
514 crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
515
516 } else if (fdsi.ssi_signo == SIGCHLD) {
517 #else
518 if (1) {
519
520 char ch;
521 while (read(sfd, &ch, 1) == 1) ;
522 #endif
523 wait_rc = waitpid(op->pid, &status, WNOHANG);
524
525 if (wait_rc > 0) {
526 break;
527
528 } else if (wait_rc < 0){
529 if (errno == ECHILD) {
530
531 break;
532
533 } else {
534
535 wait_rc = 0;
536 }
537 crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
538 }
539 }
540 }
541
542 } else if (poll_rc == 0) {
543 timeout = 0;
544 break;
545
546 } else if (poll_rc < 0) {
547 if (errno != EINTR) {
548 crm_perror(LOG_ERR, "poll() failed");
549 break;
550 }
551 }
552
553 timeout = op->timeout - (time(NULL) - start) * 1000;
554
555 } while ((op->timeout < 0 || timeout > 0));
556
557 crm_trace("Child done: %d", op->pid);
558 if (wait_rc <= 0) {
559 op->rc = PCMK_OCF_UNKNOWN_ERROR;
560
561 if (op->timeout > 0 && timeout <= 0) {
562 op->status = PCMK_LRM_OP_TIMEOUT;
563 crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
564
565 } else {
566 op->status = PCMK_LRM_OP_ERROR;
567 }
568
569
570
571 if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
572 if (kill(op->pid, SIGKILL)) {
573 crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
574 }
575
576 while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) ;
577 }
578
579 } else if (WIFEXITED(status)) {
580 op->status = PCMK_LRM_OP_DONE;
581 op->rc = WEXITSTATUS(status);
582 crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
583
584 } else if (WIFSIGNALED(status)) {
585 int signo = WTERMSIG(status);
586
587 op->status = PCMK_LRM_OP_ERROR;
588 crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
589 }
590 #ifdef WCOREDUMP
591 if (WCOREDUMP(status)) {
592 crm_err("Managed %s process %d dumped core", op->id, op->pid);
593 }
594 #endif
595
596 svc_read_output(op->opaque->stdout_fd, op, FALSE);
597 svc_read_output(op->opaque->stderr_fd, op, TRUE);
598
599 close(op->opaque->stdout_fd);
600 close(op->opaque->stderr_fd);
601
602 #ifdef HAVE_SYS_SIGNALFD_H
603 close(sfd);
604 #endif
605 }
606
607
608
609 gboolean
610 services_os_action_execute(svc_action_t * op)
611 {
612 int stdout_fd[2];
613 int stderr_fd[2];
614 int rc;
615 struct stat st;
616 sigset_t *pmask;
617
618 #ifdef HAVE_SYS_SIGNALFD_H
619 sigset_t mask;
620 sigset_t old_mask;
621 #define sigchld_cleanup() do { \
622 if (sigismember(&old_mask, SIGCHLD) == 0) { \
623 if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \
624 crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \
625 } \
626 } \
627 } while (0)
628 #else
629 struct sigaction sa;
630 struct sigaction old_sa;
631 #define sigchld_cleanup() do { \
632 if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \
633 crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \
634 } \
635 close(sigchld_pipe[0]); \
636 close(sigchld_pipe[1]); \
637 sigchld_pipe[0] = sigchld_pipe[1] = -1; \
638 } while(0)
639 #endif
640
641
642 if(stat(op->opaque->exec, &st) != 0) {
643 rc = errno;
644 crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
645 services_handle_exec_error(op, rc);
646 if (!op->synchronous) {
647 return operation_finalize(op);
648 }
649 return FALSE;
650 }
651
652 if (pipe(stdout_fd) < 0) {
653 rc = errno;
654
655 crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
656
657 services_handle_exec_error(op, rc);
658 if (!op->synchronous) {
659 return operation_finalize(op);
660 }
661 return FALSE;
662 }
663
664 if (pipe(stderr_fd) < 0) {
665 rc = errno;
666
667 close(stdout_fd[0]);
668 close(stdout_fd[1]);
669
670 crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
671
672 services_handle_exec_error(op, rc);
673 if (!op->synchronous) {
674 return operation_finalize(op);
675 }
676 return FALSE;
677 }
678
679 if (op->synchronous) {
680 #ifdef HAVE_SYS_SIGNALFD_H
681 sigemptyset(&mask);
682 sigaddset(&mask, SIGCHLD);
683 sigemptyset(&old_mask);
684
685 if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
686 crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
687 }
688
689 pmask = &mask;
690 #else
691 if(pipe(sigchld_pipe) == -1) {
692 crm_perror(LOG_ERR, "pipe() failed");
693 }
694
695 rc = crm_set_nonblocking(sigchld_pipe[0]);
696 if (rc < 0) {
697 crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
698 pcmk_strerror(rc), rc);
699 }
700 rc = crm_set_nonblocking(sigchld_pipe[1]);
701 if (rc < 0) {
702 crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
703 pcmk_strerror(rc), rc);
704 }
705
706 sa.sa_handler = sigchld_handler;
707 sa.sa_flags = 0;
708 sigemptyset(&sa.sa_mask);
709 if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
710 crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
711 }
712
713 pmask = NULL;
714 #endif
715 }
716
717 op->pid = fork();
718 switch (op->pid) {
719 case -1:
720 rc = errno;
721
722 close(stdout_fd[0]);
723 close(stdout_fd[1]);
724 close(stderr_fd[0]);
725 close(stderr_fd[1]);
726
727 crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
728 services_handle_exec_error(op, rc);
729 if (!op->synchronous) {
730 return operation_finalize(op);
731 }
732
733 sigchld_cleanup();
734 return FALSE;
735
736 case 0:
737 close(stdout_fd[0]);
738 close(stderr_fd[0]);
739 if (STDOUT_FILENO != stdout_fd[1]) {
740 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
741 crm_err("dup2() failed (stdout)");
742 }
743 close(stdout_fd[1]);
744 }
745 if (STDERR_FILENO != stderr_fd[1]) {
746 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
747 crm_err("dup2() failed (stderr)");
748 }
749 close(stderr_fd[1]);
750 }
751
752 if (op->synchronous) {
753 sigchld_cleanup();
754 }
755
756 action_launch_child(op);
757 CRM_ASSERT(0);
758 }
759
760
761 close(stdout_fd[1]);
762 close(stderr_fd[1]);
763
764 op->opaque->stdout_fd = stdout_fd[0];
765 rc = crm_set_nonblocking(op->opaque->stdout_fd);
766 if (rc < 0) {
767 crm_warn("Could not set child output non-blocking: %s "
768 CRM_XS " rc=%d",
769 pcmk_strerror(rc), rc);
770 }
771
772 op->opaque->stderr_fd = stderr_fd[0];
773 rc = crm_set_nonblocking(op->opaque->stderr_fd);
774 if (rc < 0) {
775 crm_warn("Could not set child error output non-blocking: %s "
776 CRM_XS " rc=%d",
777 pcmk_strerror(rc), rc);
778 }
779
780 if (op->synchronous) {
781 action_synced_wait(op, pmask);
782 sigchld_cleanup();
783 } else {
784
785 crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
786 mainloop_child_add_with_flags(op->pid,
787 op->timeout,
788 op->id,
789 op,
790 (op->flags & SVC_ACTION_LEAVE_GROUP) ? mainloop_leave_pid_group : 0,
791 operation_finished);
792
793
794 op->opaque->stdout_gsource = mainloop_add_fd(op->id,
795 G_PRIORITY_LOW,
796 op->opaque->stdout_fd, op, &stdout_callbacks);
797
798 op->opaque->stderr_gsource = mainloop_add_fd(op->id,
799 G_PRIORITY_LOW,
800 op->opaque->stderr_fd, op, &stderr_callbacks);
801
802 services_add_inflight_op(op);
803 }
804
805 return TRUE;
806 }
807
808 GList *
809 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
810 {
811 GList *list = NULL;
812 struct dirent **namelist;
813 int entries = 0, lpc = 0;
814 char buffer[PATH_MAX];
815
816 entries = scandir(root, &namelist, NULL, alphasort);
817 if (entries <= 0) {
818 return list;
819 }
820
821 for (lpc = 0; lpc < entries; lpc++) {
822 struct stat sb;
823
824 if ('.' == namelist[lpc]->d_name[0]) {
825 free(namelist[lpc]);
826 continue;
827 }
828
829 snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
830
831 if (stat(buffer, &sb)) {
832 continue;
833 }
834
835 if (S_ISDIR(sb.st_mode)) {
836 if (files) {
837 free(namelist[lpc]);
838 continue;
839 }
840
841 } else if (S_ISREG(sb.st_mode)) {
842 if (files == FALSE) {
843 free(namelist[lpc]);
844 continue;
845
846 } else if (executable
847 && (sb.st_mode & S_IXUSR) == 0
848 && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
849 free(namelist[lpc]);
850 continue;
851 }
852 }
853
854 list = g_list_append(list, strdup(namelist[lpc]->d_name));
855
856 free(namelist[lpc]);
857 }
858
859 free(namelist);
860 return list;
861 }
862
863 GList *
864 resources_os_list_lsb_agents(void)
865 {
866 return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
867 }
868
869 GList *
870 resources_os_list_ocf_providers(void)
871 {
872 return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
873 }
874
875 GList *
876 resources_os_list_ocf_agents(const char *provider)
877 {
878 GList *gIter = NULL;
879 GList *result = NULL;
880 GList *providers = NULL;
881
882 if (provider) {
883 char buffer[500];
884
885 snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
886 return get_directory_list(buffer, TRUE, TRUE);
887 }
888
889 providers = resources_os_list_ocf_providers();
890 for (gIter = providers; gIter != NULL; gIter = gIter->next) {
891 GList *tmp1 = result;
892 GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
893
894 if (tmp2) {
895 result = g_list_concat(tmp1, tmp2);
896 }
897 }
898 g_list_free_full(providers, free);
899 return result;
900 }
901
902 #if SUPPORT_NAGIOS
903 GList *
904 resources_os_list_nagios_agents(void)
905 {
906 GList *plugin_list = NULL;
907 GList *result = NULL;
908 GList *gIter = NULL;
909
910 plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
911
912
913 for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
914 const char *plugin = gIter->data;
915 char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
916 struct stat st;
917
918 if (stat(metadata, &st) == 0) {
919 result = g_list_append(result, strdup(plugin));
920 }
921
922 free(metadata);
923 }
924 g_list_free_full(plugin_list, free);
925 return result;
926 }
927 #endif