This source file includes following definitions.
- sigchld_setup
- sigchld_open
- sigchld_close
- sigchld_received
- sigchld_cleanup
- sigchld_handler
- sigchld_setup
- sigchld_open
- sigchld_close
- sigchld_received
- sigchld_cleanup
- close_pipe
- svc_read_output
- dispatch_stdout
- dispatch_stderr
- pipe_out_done
- pipe_err_done
- set_ocf_env
- set_ocf_env_with_prefix
- set_alert_env
- add_action_env_vars
- pipe_in_single_parameter
- pipe_in_action_stdin_parameters
- recurring_action_timer
- operation_finalize
- close_op_input
- finish_op_output
- log_op_output
- operation_finished
- services_handle_exec_error
- action_launch_child
- action_synced_wait
- services_os_action_execute
- services_os_get_directory_list
- resources_os_list_ocf_providers
- resources_os_list_ocf_agents
- services__ocf_agent_exists
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/wait.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <grp.h>
23 #include <string.h>
24 #include <sys/time.h>
25 #include <sys/resource.h>
26
27 #include "crm/crm.h"
28 #include "crm/common/mainloop.h"
29 #include "crm/services.h"
30
31 #include "services_private.h"
32
33 static void close_pipe(int fildes[]);
34
35
36
37
38
39
40
41
42
43 #ifdef HAVE_SYS_SIGNALFD_H
44
45
46
47 #include <sys/signalfd.h>
48
49
50 struct sigchld_data_s {
51 sigset_t mask;
52 sigset_t old_mask;
53 };
54
55
56 static bool
57 sigchld_setup(struct sigchld_data_s *data)
58 {
59 sigemptyset(&(data->mask));
60 sigaddset(&(data->mask), SIGCHLD);
61
62 sigemptyset(&(data->old_mask));
63
64
65 if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) {
66 crm_err("Wait for child process completion failed: %s "
67 CRM_XS " source=sigprocmask", pcmk_strerror(errno));
68 return false;
69 }
70 return true;
71 }
72
73
74 static int
75 sigchld_open(struct sigchld_data_s *data)
76 {
77 int fd;
78
79 CRM_CHECK(data != NULL, return -1);
80
81 fd = signalfd(-1, &(data->mask), SFD_NONBLOCK);
82 if (fd < 0) {
83 crm_err("Wait for child process completion failed: %s "
84 CRM_XS " source=signalfd", pcmk_strerror(errno));
85 }
86 return fd;
87 }
88
89
90 static void
91 sigchld_close(int fd)
92 {
93 if (fd > 0) {
94 close(fd);
95 }
96 }
97
98
99 static bool
100 sigchld_received(int fd)
101 {
102 struct signalfd_siginfo fdsi;
103 ssize_t s;
104
105 if (fd < 0) {
106 return false;
107 }
108 s = read(fd, &fdsi, sizeof(struct signalfd_siginfo));
109 if (s != sizeof(struct signalfd_siginfo)) {
110 crm_err("Wait for child process completion failed: %s "
111 CRM_XS " source=read", pcmk_strerror(errno));
112
113 } else if (fdsi.ssi_signo == SIGCHLD) {
114 return true;
115 }
116 return false;
117 }
118
119
120 static void
121 sigchld_cleanup(struct sigchld_data_s *data)
122 {
123
124 if ((sigismember(&(data->old_mask), SIGCHLD) == 0)
125 && (sigprocmask(SIG_UNBLOCK, &(data->mask), NULL) < 0)) {
126 crm_warn("Could not clean up after child process completion: %s",
127 pcmk_strerror(errno));
128 }
129 }
130
131 #else
132
133
134
135 struct sigchld_data_s {
136 int pipe_fd[2];
137 struct sigaction sa;
138 struct sigaction old_sa;
139 };
140
141
142 volatile struct sigchld_data_s *last_sigchld_data = NULL;
143
144 static void
145 sigchld_handler()
146 {
147
148 if ((last_sigchld_data != NULL)
149 && (last_sigchld_data->pipe_fd[1] >= 0)
150 && (write(last_sigchld_data->pipe_fd[1], "", 1) == -1)) {
151 crm_err("Wait for child process completion failed: %s "
152 CRM_XS " source=write", pcmk_strerror(errno));
153 }
154 }
155
156 static bool
157 sigchld_setup(struct sigchld_data_s *data)
158 {
159 int rc;
160
161 data->pipe_fd[0] = data->pipe_fd[1] = -1;
162
163 if (pipe(data->pipe_fd) == -1) {
164 crm_err("Wait for child process completion failed: %s "
165 CRM_XS " source=pipe", pcmk_strerror(errno));
166 return false;
167 }
168
169 rc = pcmk__set_nonblocking(data->pipe_fd[0]);
170 if (rc != pcmk_rc_ok) {
171 crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
172 pcmk_rc_str(rc), rc);
173 }
174 rc = pcmk__set_nonblocking(data->pipe_fd[1]);
175 if (rc != pcmk_rc_ok) {
176 crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
177 pcmk_rc_str(rc), rc);
178 }
179
180
181 data->sa.sa_handler = sigchld_handler;
182 data->sa.sa_flags = 0;
183 sigemptyset(&(data->sa.sa_mask));
184 if (sigaction(SIGCHLD, &(data->sa), &(data->old_sa)) < 0) {
185 crm_err("Wait for child process completion failed: %s "
186 CRM_XS " source=sigaction", pcmk_strerror(errno));
187 }
188
189
190 last_sigchld_data = data;
191 return true;
192 }
193
194 static int
195 sigchld_open(struct sigchld_data_s *data)
196 {
197 CRM_CHECK(data != NULL, return -1);
198 return data->pipe_fd[0];
199 }
200
201 static void
202 sigchld_close(int fd)
203 {
204
205 return;
206 }
207
208 static bool
209 sigchld_received(int fd)
210 {
211 char ch;
212
213 if (fd < 0) {
214 return false;
215 }
216
217
218 while (read(fd, &ch, 1) == 1) ;
219 return true;
220 }
221
222 static void
223 sigchld_cleanup(struct sigchld_data_s *data)
224 {
225
226 if (sigaction(SIGCHLD, &(data->old_sa), NULL) < 0) {
227 crm_warn("Could not clean up after child process completion: %s",
228 pcmk_strerror(errno));
229 }
230
231 close_pipe(data->pipe_fd);
232 }
233
234 #endif
235
236
237
238
239
240
241
242 static void
243 close_pipe(int fildes[])
244 {
245 if (fildes[0] >= 0) {
246 close(fildes[0]);
247 fildes[0] = -1;
248 }
249 if (fildes[1] >= 0) {
250 close(fildes[1]);
251 fildes[1] = -1;
252 }
253 }
254
255 static gboolean
256 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
257 {
258 char *data = NULL;
259 int rc = 0, len = 0;
260 char buf[500];
261 static const size_t buf_read_len = sizeof(buf) - 1;
262
263
264 if (fd < 0) {
265 crm_trace("No fd for %s", op->id);
266 return FALSE;
267 }
268
269 if (is_stderr && op->stderr_data) {
270 len = strlen(op->stderr_data);
271 data = op->stderr_data;
272 crm_trace("Reading %s stderr into offset %d", op->id, len);
273
274 } else if (is_stderr == FALSE && op->stdout_data) {
275 len = strlen(op->stdout_data);
276 data = op->stdout_data;
277 crm_trace("Reading %s stdout into offset %d", op->id, len);
278
279 } else {
280 crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
281 }
282
283 do {
284 rc = read(fd, buf, buf_read_len);
285 if (rc > 0) {
286 buf[rc] = 0;
287 crm_trace("Got %d chars: %.80s", rc, buf);
288 data = pcmk__realloc(data, len + rc + 1);
289 len += sprintf(data + len, "%s", buf);
290
291 } else if (errno != EINTR) {
292
293
294
295 rc = FALSE;
296 break;
297 }
298
299 } while (rc == buf_read_len || rc < 0);
300
301 if (is_stderr) {
302 op->stderr_data = data;
303 } else {
304 op->stdout_data = data;
305 }
306
307 return rc;
308 }
309
310 static int
311 dispatch_stdout(gpointer userdata)
312 {
313 svc_action_t *op = (svc_action_t *) userdata;
314
315 return svc_read_output(op->opaque->stdout_fd, op, FALSE);
316 }
317
318 static int
319 dispatch_stderr(gpointer userdata)
320 {
321 svc_action_t *op = (svc_action_t *) userdata;
322
323 return svc_read_output(op->opaque->stderr_fd, op, TRUE);
324 }
325
326 static void
327 pipe_out_done(gpointer user_data)
328 {
329 svc_action_t *op = (svc_action_t *) user_data;
330
331 crm_trace("%p", op);
332
333 op->opaque->stdout_gsource = NULL;
334 if (op->opaque->stdout_fd > STDOUT_FILENO) {
335 close(op->opaque->stdout_fd);
336 }
337 op->opaque->stdout_fd = -1;
338 }
339
340 static void
341 pipe_err_done(gpointer user_data)
342 {
343 svc_action_t *op = (svc_action_t *) user_data;
344
345 op->opaque->stderr_gsource = NULL;
346 if (op->opaque->stderr_fd > STDERR_FILENO) {
347 close(op->opaque->stderr_fd);
348 }
349 op->opaque->stderr_fd = -1;
350 }
351
352 static struct mainloop_fd_callbacks stdout_callbacks = {
353 .dispatch = dispatch_stdout,
354 .destroy = pipe_out_done,
355 };
356
357 static struct mainloop_fd_callbacks stderr_callbacks = {
358 .dispatch = dispatch_stderr,
359 .destroy = pipe_err_done,
360 };
361
362 static void
363 set_ocf_env(const char *key, const char *value, gpointer user_data)
364 {
365 if (setenv(key, value, 1) != 0) {
366 crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
367 }
368 }
369
370 static void
371 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
372 {
373 char buffer[500];
374
375 snprintf(buffer, sizeof(buffer), strcmp(key, "OCF_CHECK_LEVEL") != 0 ? "OCF_RESKEY_%s" : "%s", (char *)key);
376 set_ocf_env(buffer, value, user_data);
377 }
378
379 static void
380 set_alert_env(gpointer key, gpointer value, gpointer user_data)
381 {
382 int rc;
383
384 if (value != NULL) {
385 rc = setenv(key, value, 1);
386 } else {
387 rc = unsetenv(key);
388 }
389
390 if (rc < 0) {
391 crm_perror(LOG_ERR, "setenv %s=%s",
392 (char*)key, (value? (char*)value : ""));
393 } else {
394 crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
395 }
396 }
397
398
399
400
401
402
403
404 static void
405 add_action_env_vars(const svc_action_t *op)
406 {
407 void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
408 if (op->agent == NULL) {
409 env_setter = set_alert_env;
410
411 } else if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
412 env_setter = set_ocf_env_with_prefix;
413 }
414
415 if (env_setter != NULL && op->params != NULL) {
416 g_hash_table_foreach(op->params, env_setter, NULL);
417 }
418
419 if (env_setter == NULL || env_setter == set_alert_env) {
420 return;
421 }
422
423 set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
424 set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
425 set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
426 set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
427
428 if (op->rsc) {
429 set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
430 }
431
432 if (op->agent != NULL) {
433 set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
434 }
435
436
437 if (op->provider != NULL) {
438 set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
439 }
440 }
441
442 static void
443 pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
444 {
445 svc_action_t *op = user_data;
446 char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value);
447 int ret, total = 0, len = strlen(buffer);
448
449 do {
450 errno = 0;
451 ret = write(op->opaque->stdin_fd, buffer + total, len - total);
452 if (ret > 0) {
453 total += ret;
454 }
455
456 } while ((errno == EINTR) && (total < len));
457 free(buffer);
458 }
459
460
461
462
463
464
465
466 static void
467 pipe_in_action_stdin_parameters(const svc_action_t *op)
468 {
469 crm_debug("sending args");
470 if (op->params) {
471 g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op);
472 }
473 }
474
475 gboolean
476 recurring_action_timer(gpointer data)
477 {
478 svc_action_t *op = data;
479
480 crm_debug("Scheduling another invocation of %s", op->id);
481
482
483 free(op->stdout_data);
484 op->stdout_data = NULL;
485 free(op->stderr_data);
486 op->stderr_data = NULL;
487 op->opaque->repeat_timer = 0;
488
489 services_action_async(op, NULL);
490 return FALSE;
491 }
492
493
494 gboolean
495 operation_finalize(svc_action_t * op)
496 {
497 int recurring = 0;
498
499 if (op->interval_ms) {
500 if (op->cancel) {
501 op->status = PCMK_LRM_OP_CANCELLED;
502 cancel_recurring_action(op);
503 } else {
504 recurring = 1;
505 op->opaque->repeat_timer = g_timeout_add(op->interval_ms,
506 recurring_action_timer, (void *)op);
507 }
508 }
509
510 if (op->opaque->callback) {
511 op->opaque->callback(op);
512 }
513
514 op->pid = 0;
515
516 services_untrack_op(op);
517
518 if (!recurring && op->synchronous == FALSE) {
519
520
521
522
523 services_action_free(op);
524 return TRUE;
525 }
526
527 services_action_cleanup(op);
528 return FALSE;
529 }
530
531 static void
532 close_op_input(svc_action_t *op)
533 {
534 if (op->opaque->stdin_fd >= 0) {
535 close(op->opaque->stdin_fd);
536 }
537 }
538
539 static void
540 finish_op_output(svc_action_t *op, bool is_stderr)
541 {
542 mainloop_io_t **source;
543 int fd;
544
545 if (is_stderr) {
546 source = &(op->opaque->stderr_gsource);
547 fd = op->opaque->stderr_fd;
548 } else {
549 source = &(op->opaque->stdout_gsource);
550 fd = op->opaque->stdout_fd;
551 }
552
553 if (op->synchronous || *source) {
554 crm_trace("Finish reading %s[%d] %s",
555 op->id, op->pid, (is_stderr? "stdout" : "stderr"));
556 svc_read_output(fd, op, is_stderr);
557 if (op->synchronous) {
558 close(fd);
559 } else {
560 mainloop_del_fd(*source);
561 *source = NULL;
562 }
563 }
564 }
565
566
567 static void
568 log_op_output(svc_action_t *op)
569 {
570 char *prefix = crm_strdup_printf("%s[%d] error output", op->id, op->pid);
571
572 crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
573 strcpy(prefix + strlen(prefix) - strlen("error output"), "output");
574 crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
575 free(prefix);
576 }
577
578 static void
579 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
580 {
581 svc_action_t *op = mainloop_child_userdata(p);
582
583 mainloop_clear_child_userdata(p);
584 CRM_ASSERT(op->pid == pid);
585
586
587
588
589
590 finish_op_output(op, true);
591 finish_op_output(op, false);
592
593 close_op_input(op);
594
595 if (signo == 0) {
596 crm_debug("%s[%d] exited with status %d", op->id, op->pid, exitcode);
597 op->status = PCMK_LRM_OP_DONE;
598 op->rc = exitcode;
599
600 } else if (mainloop_child_timeout(p)) {
601 crm_warn("%s[%d] timed out after %dms", op->id, op->pid, op->timeout);
602 op->status = PCMK_LRM_OP_TIMEOUT;
603 op->rc = PCMK_OCF_TIMEOUT;
604
605 } else if (op->cancel) {
606
607
608
609 crm_info("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
610 op->id, op->pid, strsignal(signo), signo);
611 op->status = PCMK_LRM_OP_CANCELLED;
612 op->rc = PCMK_OCF_OK;
613
614 } else {
615 crm_warn("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
616 op->id, op->pid, strsignal(signo), signo);
617 op->status = PCMK_LRM_OP_ERROR;
618 op->rc = PCMK_OCF_SIGNAL;
619 }
620
621 log_op_output(op);
622 operation_finalize(op);
623 }
624
625
626
627
628
629
630
631
632
633
634 static void
635 services_handle_exec_error(svc_action_t * op, int error)
636 {
637 int rc_not_installed, rc_insufficient_priv, rc_exec_error;
638
639
640 if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
641 && pcmk__str_eq(op->action, "status", pcmk__str_casei)) {
642
643 rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
644 rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
645 rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
646
647 #if SUPPORT_NAGIOS
648 } else if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
649 rc_not_installed = NAGIOS_NOT_INSTALLED;
650 rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
651 rc_exec_error = PCMK_OCF_EXEC_ERROR;
652 #endif
653
654 } else {
655 rc_not_installed = PCMK_OCF_NOT_INSTALLED;
656 rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
657 rc_exec_error = PCMK_OCF_EXEC_ERROR;
658 }
659
660 switch (error) {
661 case ENOENT:
662 case EISDIR:
663 case ENOTDIR:
664 case EINVAL:
665 case ENOEXEC:
666 op->rc = rc_not_installed;
667 op->status = PCMK_LRM_OP_NOT_INSTALLED;
668 break;
669 case EACCES:
670 case EPERM:
671 op->rc = rc_insufficient_priv;
672 op->status = PCMK_LRM_OP_ERROR;
673 break;
674 default:
675 op->rc = rc_exec_error;
676 op->status = PCMK_LRM_OP_ERROR;
677 }
678 }
679
680 static void
681 action_launch_child(svc_action_t *op)
682 {
683
684
685
686
687
688 signal(SIGPIPE, SIG_DFL);
689
690 #if defined(HAVE_SCHED_SETSCHEDULER)
691 if (sched_getscheduler(0) != SCHED_OTHER) {
692 struct sched_param sp;
693
694 memset(&sp, 0, sizeof(sp));
695 sp.sched_priority = 0;
696
697 if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
698 crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
699 }
700 }
701 #endif
702 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
703 crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
704 }
705
706
707
708
709
710 setpgid(0, 0);
711
712 pcmk__close_fds_in_child(false);
713
714 #if SUPPORT_CIBSECRETS
715 if (pcmk__substitute_secrets(op->rsc, op->params) != pcmk_rc_ok) {
716
717 if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
718
719 crm_info("proceeding with the stop operation for %s", op->rsc);
720
721 } else {
722 crm_err("failed to get secrets for %s, "
723 "considering resource not configured", op->rsc);
724 _exit(PCMK_OCF_NOT_CONFIGURED);
725 }
726 }
727 #endif
728
729 add_action_env_vars(op);
730
731
732 if (op->opaque->uid && (geteuid() == 0)) {
733
734
735 if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
736 crm_perror(LOG_ERR, "Could not set child group to %d", op->opaque->gid);
737 _exit(PCMK_OCF_NOT_CONFIGURED);
738 }
739
740
741
742 if (setgroups(0, NULL) < 0) {
743 crm_perror(LOG_ERR, "Could not set child groups");
744 _exit(PCMK_OCF_NOT_CONFIGURED);
745 }
746
747
748 if (setuid(op->opaque->uid) < 0) {
749 crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
750 _exit(PCMK_OCF_NOT_CONFIGURED);
751 }
752 }
753
754
755 execvp(op->opaque->exec, op->opaque->args);
756
757
758 services_handle_exec_error(op, errno);
759
760 _exit(op->rc);
761 }
762
763 static void
764 action_synced_wait(svc_action_t *op, struct sigchld_data_s *data)
765 {
766 int status = 0;
767 int timeout = op->timeout;
768 time_t start = -1;
769 struct pollfd fds[3];
770 int wait_rc = 0;
771
772 fds[0].fd = op->opaque->stdout_fd;
773 fds[0].events = POLLIN;
774 fds[0].revents = 0;
775
776 fds[1].fd = op->opaque->stderr_fd;
777 fds[1].events = POLLIN;
778 fds[1].revents = 0;
779
780 fds[2].fd = sigchld_open(data);
781 fds[2].events = POLLIN;
782 fds[2].revents = 0;
783
784 crm_trace("Waiting for %s[%d]", op->id, op->pid);
785 start = time(NULL);
786 do {
787 int poll_rc = poll(fds, 3, timeout);
788
789 if (poll_rc > 0) {
790 if (fds[0].revents & POLLIN) {
791 svc_read_output(op->opaque->stdout_fd, op, FALSE);
792 }
793
794 if (fds[1].revents & POLLIN) {
795 svc_read_output(op->opaque->stderr_fd, op, TRUE);
796 }
797
798 if ((fds[2].revents & POLLIN) && sigchld_received(fds[2].fd)) {
799 wait_rc = waitpid(op->pid, &status, WNOHANG);
800
801 if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) {
802
803 break;
804
805 } else if (wait_rc < 0) {
806 crm_warn("Wait for completion of %s[%d] failed: %s "
807 CRM_XS " source=waitpid",
808 op->id, op->pid, pcmk_strerror(errno));
809 wait_rc = 0;
810 }
811 }
812
813 } else if (poll_rc == 0) {
814
815 timeout = 0;
816 break;
817
818 } else if ((poll_rc < 0) && (errno != EINTR)) {
819 crm_err("Wait for completion of %s[%d] failed: %s "
820 CRM_XS " source=poll",
821 op->id, op->pid, pcmk_strerror(errno));
822 break;
823 }
824
825 timeout = op->timeout - (time(NULL) - start) * 1000;
826
827 } while ((op->timeout < 0 || timeout > 0));
828
829 crm_trace("Stopped waiting for %s[%d]", op->id, op->pid);
830 if (wait_rc <= 0) {
831 op->rc = PCMK_OCF_UNKNOWN_ERROR;
832
833 if (op->timeout > 0 && timeout <= 0) {
834 op->status = PCMK_LRM_OP_TIMEOUT;
835 crm_warn("%s[%d] timed out after %dms",
836 op->id, op->pid, op->timeout);
837
838 } else {
839 op->status = PCMK_LRM_OP_ERROR;
840 }
841
842
843
844 if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
845 if (kill(op->pid, SIGKILL)) {
846 crm_warn("Could not kill rogue child %s[%d]: %s",
847 op->id, op->pid, pcmk_strerror(errno));
848 }
849
850 while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) ;
851 }
852
853 } else if (WIFEXITED(status)) {
854 op->status = PCMK_LRM_OP_DONE;
855 op->rc = WEXITSTATUS(status);
856 crm_info("%s[%d] exited with status %d", op->id, op->pid, op->rc);
857
858 } else if (WIFSIGNALED(status)) {
859 int signo = WTERMSIG(status);
860
861 op->status = PCMK_LRM_OP_ERROR;
862 crm_err("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
863 op->id, op->pid, strsignal(signo), signo);
864 }
865 #ifdef WCOREDUMP
866 if (WCOREDUMP(status)) {
867 crm_err("%s[%d] dumped core", op->id, op->pid);
868 }
869 #endif
870
871 finish_op_output(op, true);
872 finish_op_output(op, false);
873 close_op_input(op);
874 sigchld_close(fds[2].fd);
875 }
876
877
878
879 gboolean
880 services_os_action_execute(svc_action_t * op)
881 {
882 int stdout_fd[2];
883 int stderr_fd[2];
884 int stdin_fd[2] = {-1, -1};
885 int rc;
886 struct stat st;
887 struct sigchld_data_s data;
888
889
890 if(stat(op->opaque->exec, &st) != 0) {
891 rc = errno;
892 crm_warn("Cannot execute '%s': %s " CRM_XS " stat rc=%d",
893 op->opaque->exec, pcmk_strerror(rc), rc);
894 services_handle_exec_error(op, rc);
895 if (!op->synchronous) {
896 return operation_finalize(op);
897 }
898 return FALSE;
899 }
900
901 if (pipe(stdout_fd) < 0) {
902 rc = errno;
903 crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
904 op->opaque->exec, pcmk_strerror(rc), rc);
905 services_handle_exec_error(op, rc);
906 if (!op->synchronous) {
907 return operation_finalize(op);
908 }
909 return FALSE;
910 }
911
912 if (pipe(stderr_fd) < 0) {
913 rc = errno;
914
915 close_pipe(stdout_fd);
916
917 crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
918 op->opaque->exec, pcmk_strerror(rc), rc);
919 services_handle_exec_error(op, rc);
920 if (!op->synchronous) {
921 return operation_finalize(op);
922 }
923 return FALSE;
924 }
925
926 if (pcmk_is_set(pcmk_get_ra_caps(op->standard), pcmk_ra_cap_stdin)) {
927 if (pipe(stdin_fd) < 0) {
928 rc = errno;
929
930 close_pipe(stdout_fd);
931 close_pipe(stderr_fd);
932
933 crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
934 op->opaque->exec, pcmk_strerror(rc), rc);
935 services_handle_exec_error(op, rc);
936 if (!op->synchronous) {
937 return operation_finalize(op);
938 }
939 return FALSE;
940 }
941 }
942
943 if (op->synchronous && !sigchld_setup(&data)) {
944 close_pipe(stdin_fd);
945 close_pipe(stdout_fd);
946 close_pipe(stderr_fd);
947 sigchld_cleanup(&data);
948 return FALSE;
949 }
950
951 op->pid = fork();
952 switch (op->pid) {
953 case -1:
954 rc = errno;
955 close_pipe(stdin_fd);
956 close_pipe(stdout_fd);
957 close_pipe(stderr_fd);
958
959 crm_err("Cannot execute '%s': %s " CRM_XS " fork rc=%d",
960 op->opaque->exec, pcmk_strerror(rc), rc);
961 services_handle_exec_error(op, rc);
962 if (!op->synchronous) {
963 return operation_finalize(op);
964 }
965
966 sigchld_cleanup(&data);
967 return FALSE;
968
969 case 0:
970 close(stdout_fd[0]);
971 close(stderr_fd[0]);
972 if (stdin_fd[1] >= 0) {
973 close(stdin_fd[1]);
974 }
975 if (STDOUT_FILENO != stdout_fd[1]) {
976 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
977 crm_warn("Can't redirect output from '%s': %s "
978 CRM_XS " errno=%d",
979 op->opaque->exec, pcmk_strerror(errno), errno);
980 }
981 close(stdout_fd[1]);
982 }
983 if (STDERR_FILENO != stderr_fd[1]) {
984 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
985 crm_warn("Can't redirect error output from '%s': %s "
986 CRM_XS " errno=%d",
987 op->opaque->exec, pcmk_strerror(errno), errno);
988 }
989 close(stderr_fd[1]);
990 }
991 if ((stdin_fd[0] >= 0) &&
992 (STDIN_FILENO != stdin_fd[0])) {
993 if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
994 crm_warn("Can't redirect input to '%s': %s "
995 CRM_XS " errno=%d",
996 op->opaque->exec, pcmk_strerror(errno), errno);
997 }
998 close(stdin_fd[0]);
999 }
1000
1001 if (op->synchronous) {
1002 sigchld_cleanup(&data);
1003 }
1004
1005 action_launch_child(op);
1006 CRM_ASSERT(0);
1007 }
1008
1009
1010 close(stdout_fd[1]);
1011 close(stderr_fd[1]);
1012 if (stdin_fd[0] >= 0) {
1013 close(stdin_fd[0]);
1014 }
1015
1016 op->opaque->stdout_fd = stdout_fd[0];
1017 rc = pcmk__set_nonblocking(op->opaque->stdout_fd);
1018 if (rc != pcmk_rc_ok) {
1019 crm_warn("Could not set '%s' output non-blocking: %s "
1020 CRM_XS " rc=%d",
1021 op->opaque->exec, pcmk_rc_str(rc), rc);
1022 }
1023
1024 op->opaque->stderr_fd = stderr_fd[0];
1025 rc = pcmk__set_nonblocking(op->opaque->stderr_fd);
1026 if (rc != pcmk_rc_ok) {
1027 crm_warn("Could not set '%s' error output non-blocking: %s "
1028 CRM_XS " rc=%d",
1029 op->opaque->exec, pcmk_rc_str(rc), rc);
1030 }
1031
1032 op->opaque->stdin_fd = stdin_fd[1];
1033 if (op->opaque->stdin_fd >= 0) {
1034
1035
1036 rc = pcmk__set_nonblocking(op->opaque->stdin_fd);
1037 if (rc != pcmk_rc_ok) {
1038 crm_warn("Could not set '%s' input non-blocking: %s "
1039 CRM_XS " fd=%d,rc=%d", op->opaque->exec,
1040 pcmk_rc_str(rc), op->opaque->stdin_fd, rc);
1041 }
1042 pipe_in_action_stdin_parameters(op);
1043
1044 close(op->opaque->stdin_fd);
1045 op->opaque->stdin_fd = -1;
1046 }
1047
1048
1049 if (op->opaque->fork_callback) {
1050 op->opaque->fork_callback(op);
1051 }
1052
1053 if (op->synchronous) {
1054 action_synced_wait(op, &data);
1055 sigchld_cleanup(&data);
1056 } else {
1057 crm_trace("Waiting async for '%s'[%d]", op->opaque->exec, op->pid);
1058 mainloop_child_add_with_flags(op->pid,
1059 op->timeout,
1060 op->id,
1061 op,
1062 (op->flags & SVC_ACTION_LEAVE_GROUP) ? mainloop_leave_pid_group : 0,
1063 operation_finished);
1064
1065
1066 op->opaque->stdout_gsource = mainloop_add_fd(op->id,
1067 G_PRIORITY_LOW,
1068 op->opaque->stdout_fd, op, &stdout_callbacks);
1069
1070 op->opaque->stderr_gsource = mainloop_add_fd(op->id,
1071 G_PRIORITY_LOW,
1072 op->opaque->stderr_fd, op, &stderr_callbacks);
1073
1074 services_add_inflight_op(op);
1075 }
1076
1077 return TRUE;
1078 }
1079
1080 GList *
1081 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
1082 {
1083 GList *list = NULL;
1084 struct dirent **namelist;
1085 int entries = 0, lpc = 0;
1086 char buffer[PATH_MAX];
1087
1088 entries = scandir(root, &namelist, NULL, alphasort);
1089 if (entries <= 0) {
1090 return list;
1091 }
1092
1093 for (lpc = 0; lpc < entries; lpc++) {
1094 struct stat sb;
1095
1096 if ('.' == namelist[lpc]->d_name[0]) {
1097 free(namelist[lpc]);
1098 continue;
1099 }
1100
1101 snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
1102
1103 if (stat(buffer, &sb)) {
1104 continue;
1105 }
1106
1107 if (S_ISDIR(sb.st_mode)) {
1108 if (files) {
1109 free(namelist[lpc]);
1110 continue;
1111 }
1112
1113 } else if (S_ISREG(sb.st_mode)) {
1114 if (files == FALSE) {
1115 free(namelist[lpc]);
1116 continue;
1117
1118 } else if (executable
1119 && (sb.st_mode & S_IXUSR) == 0
1120 && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
1121 free(namelist[lpc]);
1122 continue;
1123 }
1124 }
1125
1126 list = g_list_append(list, strdup(namelist[lpc]->d_name));
1127
1128 free(namelist[lpc]);
1129 }
1130
1131 free(namelist);
1132 return list;
1133 }
1134
1135 GList *
1136 resources_os_list_ocf_providers(void)
1137 {
1138 return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
1139 }
1140
1141 GList *
1142 resources_os_list_ocf_agents(const char *provider)
1143 {
1144 GList *gIter = NULL;
1145 GList *result = NULL;
1146 GList *providers = NULL;
1147
1148 if (provider) {
1149 char buffer[500];
1150
1151 snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
1152 return get_directory_list(buffer, TRUE, TRUE);
1153 }
1154
1155 providers = resources_os_list_ocf_providers();
1156 for (gIter = providers; gIter != NULL; gIter = gIter->next) {
1157 GList *tmp1 = result;
1158 GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
1159
1160 if (tmp2) {
1161 result = g_list_concat(tmp1, tmp2);
1162 }
1163 }
1164 g_list_free_full(providers, free);
1165 return result;
1166 }
1167
1168 gboolean
1169 services__ocf_agent_exists(const char *provider, const char *agent)
1170 {
1171 char *buf = NULL;
1172 gboolean rc = FALSE;
1173 struct stat st;
1174
1175 if (provider == NULL || agent == NULL) {
1176 return rc;
1177 }
1178
1179 buf = crm_strdup_printf(OCF_ROOT_DIR "/resource.d/%s/%s", provider, agent);
1180 if (stat(buf, &st) == 0) {
1181 rc = TRUE;
1182 }
1183
1184 free(buf);
1185 return rc;
1186 }