pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
services_linux.c
Go to the documentation of this file.
1/*
2 * Copyright 2010-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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
33static void close_pipe(int fildes[]);
34
35/* We have two alternative ways of handling SIGCHLD when synchronously waiting
36 * for spawned processes to complete. Both rely on polling a file descriptor to
37 * discover SIGCHLD events.
38 *
39 * If sys/signalfd.h is available (e.g. on Linux), we call signalfd() to
40 * generate the file descriptor. Otherwise, we use the "self-pipe trick"
41 * (opening a pipe and writing a byte to it when SIGCHLD is received).
42 */
43#ifdef HAVE_SYS_SIGNALFD_H
44
45// signalfd() implementation
46
47#include <sys/signalfd.h>
48
49// Everything needed to manage SIGCHLD handling
50struct sigchld_data_s {
51 sigset_t mask; // Signals to block now (including SIGCHLD)
52 sigset_t old_mask; // Previous set of blocked signals
53};
54
55// Initialize SIGCHLD data and prepare for use
56static bool
57sigchld_setup(struct sigchld_data_s *data)
58{
59 sigemptyset(&(data->mask));
60 sigaddset(&(data->mask), SIGCHLD);
61
62 sigemptyset(&(data->old_mask));
63
64 // Block SIGCHLD (saving previous set of blocked signals to restore later)
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// Get a file descriptor suitable for polling for SIGCHLD events
74static int
75sigchld_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// Close a file descriptor returned by sigchld_open()
90static void
91sigchld_close(int fd)
92{
93 if (fd > 0) {
94 close(fd);
95 }
96}
97
98// Return true if SIGCHLD was received from polled fd
99static bool
100sigchld_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// Do anything needed after done waiting for SIGCHLD
120static void
121sigchld_cleanup(struct sigchld_data_s *data)
122{
123 // Restore the original set of blocked signals
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 // HAVE_SYS_SIGNALFD_H not defined
132
133// Self-pipe implementation (see above for function descriptions)
134
135struct sigchld_data_s {
136 int pipe_fd[2]; // Pipe file descriptors
137 struct sigaction sa; // Signal handling info (with SIGCHLD)
138 struct sigaction old_sa; // Previous signal handling info
139};
140
141// We need a global to use in the signal handler
142volatile struct sigchld_data_s *last_sigchld_data = NULL;
143
144static void
145sigchld_handler()
146{
147 // We received a SIGCHLD, so trigger pipe polling
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
156static bool
157sigchld_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 // Set SIGCHLD handler
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 // Remember data for use in signal handler
191 return true;
192}
193
194static int
195sigchld_open(struct sigchld_data_s *data)
196{
197 CRM_CHECK(data != NULL, return -1);
198 return data->pipe_fd[0];
199}
200
201static void
202sigchld_close(int fd)
203{
204 // Pipe will be closed in sigchld_cleanup()
205 return;
206}
207
208static bool
209sigchld_received(int fd)
210{
211 char ch;
212
213 if (fd < 0) {
214 return false;
215 }
216
217 // Clear out the self-pipe
218 while (read(fd, &ch, 1) == 1) /*omit*/;
219 return true;
220}
221
222static void
223sigchld_cleanup(struct sigchld_data_s *data)
224{
225 // Restore the previous SIGCHLD handler
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
242static void
243close_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
255static gboolean
256svc_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 /* error or EOF
293 * Cleanup happens in pipe_done()
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
310static int
311dispatch_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
318static int
319dispatch_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
326static void
327pipe_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
340static void
341pipe_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
352static struct mainloop_fd_callbacks stdout_callbacks = {
353 .dispatch = dispatch_stdout,
354 .destroy = pipe_out_done,
355};
356
357static struct mainloop_fd_callbacks stderr_callbacks = {
358 .dispatch = dispatch_stderr,
359 .destroy = pipe_err_done,
360};
361
362static void
363set_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
370static void
371set_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
379static void
380set_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
404static void
405add_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; /* we deal with alert handler */
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", PCMK_OCF_MAJOR_VERSION, NULL);
424 set_ocf_env("OCF_RA_VERSION_MINOR", PCMK_OCF_MINOR_VERSION, 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 /* Notes: this is not added to specification yet. Sept 10,2004 */
437 if (op->provider != NULL) {
438 set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
439 }
440}
441
442static void
443pipe_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
466static void
467pipe_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
475gboolean
477{
478 svc_action_t *op = data;
479
480 crm_debug("Scheduling another invocation of %s", op->id);
481
482 /* Clean out the old result */
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/* Returns FALSE if 'op' should be free'd by the caller */
494gboolean
496{
497 int recurring = 0;
498
499 if (op->interval_ms) {
500 if (op->cancel) {
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
517
518 if (!recurring && op->synchronous == FALSE) {
519 /*
520 * If this is a recurring action, do not free explicitly.
521 * It will get freed whenever the action gets cancelled.
522 */
524 return TRUE;
525 }
526
528 return FALSE;
529}
530
531static void
532close_op_input(svc_action_t *op)
533{
534 if (op->opaque->stdin_fd >= 0) {
535 close(op->opaque->stdin_fd);
536 }
537}
538
539static void
540finish_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// Log an operation's stdout and stderr
567static void
568log_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
578static void
579operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
580{
582
584 CRM_ASSERT(op->pid == pid);
585
586 /* Depending on the priority the mainloop gives the stdout and stderr
587 * file descriptors, this function could be called before everything has
588 * been read from them, so force a final read now.
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);
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);
603 op->rc = PCMK_OCF_TIMEOUT;
604
605 } else if (op->cancel) {
606 /* If an in-flight recurring operation was killed because it was
607 * cancelled, don't treat that as a failure.
608 */
609 crm_info("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
610 op->id, op->pid, strsignal(signo), signo);
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);
618 op->rc = PCMK_OCF_SIGNAL;
619 }
620
621 log_op_output(op);
623}
624
634void
636{
637 int rc_not_installed, rc_insufficient_priv, rc_exec_error;
638
639 /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
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) { /* see execve(2), stat(2) and fork(2) */
661 case ENOENT: /* No such file or directory */
662 case EISDIR: /* Is a directory */
663 case ENOTDIR: /* Path component is not a directory */
664 case EINVAL: /* Invalid executable format */
665 case ENOEXEC: /* Invalid executable format */
666 op->rc = rc_not_installed;
668 break;
669 case EACCES: /* permission denied (various errors) */
670 case EPERM: /* permission denied (various errors) */
671 op->rc = rc_insufficient_priv;
673 break;
674 default:
675 op->rc = rc_exec_error;
677 }
678}
679
680static void
681action_launch_child(svc_action_t *op)
682{
683 /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
684 * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
685 * We do not want this to be inherited by the child process. By resetting this the signal
686 * to the default behavior, we avoid some potential odd problems that occur during OCF
687 * scripts when SIGPIPE is ignored by the environment. */
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 /* Man: The call setpgrp() is equivalent to setpgid(0,0)
707 * _and_ compiles on BSD variants too
708 * need to investigate if it works the same too.
709 */
710 setpgid(0, 0);
711
713
714#if SUPPORT_CIBSECRETS
716 /* replacing secrets failed! */
717 if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
718 /* don't fail on stop! */
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);
725 }
726 }
727#endif
728
729 add_action_env_vars(op);
730
731 /* Become the desired user */
732 if (op->opaque->uid && (geteuid() == 0)) {
733
734 // If requested, set effective group
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);
738 }
739
740 // Erase supplementary group list
741 // (We could do initgroups() if we kept a copy of the username)
742 if (setgroups(0, NULL) < 0) {
743 crm_perror(LOG_ERR, "Could not set child groups");
745 }
746
747 // Set effective user
748 if (setuid(op->opaque->uid) < 0) {
749 crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
751 }
752 }
753
754 /* execute the RA */
755 execvp(op->opaque->exec, op->opaque->args);
756
757 /* Most cases should have been already handled by stat() */
759
760 _exit(op->rc);
761}
762
763static void
764action_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 // Child process exited or doesn't exist
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; // Act as if process is still running
810 }
811 }
812
813 } else if (poll_rc == 0) {
814 // Poll timed out with no descriptors ready
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) {
832
833 if (op->timeout > 0 && timeout <= 0) {
835 crm_warn("%s[%d] timed out after %dms",
836 op->id, op->pid, op->timeout);
837
838 } else {
840 }
841
842 /* If only child hasn't been successfully waited for, yet.
843 This is to limit killing wrong target a bit more. */
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 /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
850 while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
851 }
852
853 } else if (WIFEXITED(status)) {
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
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/* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
878/* For a synchronous 'op', returns FALSE if 'op' fails */
879gboolean
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 /* Fail fast */
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);
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);
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);
920 if (!op->synchronous) {
921 return operation_finalize(op);
922 }
923 return FALSE;
924 }
925
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);
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);
962 if (!op->synchronous) {
963 return operation_finalize(op);
964 }
965
966 sigchld_cleanup(&data);
967 return FALSE;
968
969 case 0: /* Child */
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); /* action_launch_child is effectively noreturn */
1007 }
1008
1009 /* Only the parent reaches here */
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];
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];
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 // using buffer behind non-blocking-fd here - that could be improved
1035 // as long as no other standard uses stdin_fd assume stonith
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 // as long as we are handling parameters directly in here just close
1044 close(op->opaque->stdin_fd);
1045 op->opaque->stdin_fd = -1;
1046 }
1047
1048 // after fds are setup properly and before we plug anything into mainloop
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);
1059 op->timeout,
1060 op->id,
1061 op,
1063 operation_finished);
1064
1065
1067 G_PRIORITY_LOW,
1068 op->opaque->stdout_fd, op, &stdout_callbacks);
1069
1071 G_PRIORITY_LOW,
1072 op->opaque->stderr_fd, op, &stderr_callbacks);
1073
1075 }
1076
1077 return TRUE;
1078}
1079
1080static GList *
1081services_os_get_single_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
1135GList *
1136services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
1137{
1138 GList *result = NULL;
1139 char *dirs = strdup(root);
1140 char *dir = NULL;
1141
1142 if (pcmk__str_empty(dirs)) {
1143 free(dirs);
1144 return result;
1145 }
1146
1147 for (dir = strtok(dirs, ":"); dir != NULL; dir = strtok(NULL, ":")) {
1148 GList *tmp = services_os_get_single_directory_list(dir, files, executable);
1149
1150 if (tmp) {
1151 result = g_list_concat(result, tmp);
1152 }
1153 }
1154
1155 free(dirs);
1156
1157 return result;
1158}
1159
1160static GList *
1161services_os_get_directory_list_provider(const char *root, const char *provider, gboolean files, gboolean executable)
1162{
1163 GList *result = NULL;
1164 char *dirs = strdup(root);
1165 char *dir = NULL;
1166 char buffer[PATH_MAX];
1167
1168 if (pcmk__str_empty(dirs)) {
1169 free(dirs);
1170 return result;
1171 }
1172
1173 for (dir = strtok(dirs, ":"); dir != NULL; dir = strtok(NULL, ":")) {
1174 GList *tmp = NULL;
1175
1176 sprintf(buffer, "%s/%s", dir, provider);
1177 tmp = services_os_get_single_directory_list(buffer, files, executable);
1178
1179 if (tmp) {
1180 result = g_list_concat(result, tmp);
1181 }
1182 }
1183
1184 free(dirs);
1185
1186 return result;
1187}
1188
1189GList *
1191{
1192 return get_directory_list(OCF_RA_PATH, FALSE, TRUE);
1193}
1194
1195GList *
1196resources_os_list_ocf_agents(const char *provider)
1197{
1198 GList *gIter = NULL;
1199 GList *result = NULL;
1200 GList *providers = NULL;
1201
1202 if (provider) {
1203 return services_os_get_directory_list_provider(OCF_RA_PATH, provider, TRUE, TRUE);
1204 }
1205
1206 providers = resources_os_list_ocf_providers();
1207 for (gIter = providers; gIter != NULL; gIter = gIter->next) {
1208 GList *tmp1 = result;
1209 GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
1210
1211 if (tmp2) {
1212 result = g_list_concat(tmp1, tmp2);
1213 }
1214 }
1215 g_list_free_full(providers, free);
1216 return result;
1217}
1218
1219gboolean
1220services__ocf_agent_exists(const char *provider, const char *agent)
1221{
1222 gboolean rc = FALSE;
1223 struct stat st;
1224 char *dirs = strdup(OCF_RA_PATH);
1225 char *dir = NULL;
1226 char *buf = NULL;
1227
1228 if (provider == NULL || agent == NULL || pcmk__str_empty(dirs)) {
1229 free(dirs);
1230 return rc;
1231 }
1232
1233 for (dir = strtok(dirs, ":"); dir != NULL; dir = strtok(NULL, ":")) {
1234 buf = crm_strdup_printf("%s/%s/%s", dir, provider, agent);
1235 if (stat(buf, &st) == 0) {
1236 free(buf);
1237 rc = TRUE;
1238 break;
1239 }
1240
1241 free(buf);
1242 }
1243
1244 free(dirs);
1245
1246 return rc;
1247}
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:31
#define PCMK_OCF_MAJOR_VERSION
Definition agents.h:40
@ pcmk_ra_cap_stdin
Definition agents.h:52
#define PCMK_OCF_MINOR_VERSION
Definition agents.h:41
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition cib_secrets.c:96
int pcmk__set_nonblocking(int fd)
Definition io.c:517
void pcmk__close_fds_in_child(bool)
Definition io.c:558
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
#define OCF_RA_PATH
Definition config.h:468
#define OCF_ROOT_DIR
Definition config.h:471
char data[0]
Definition cpg.c:10
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define CRM_XS
Definition logging.h:54
#define crm_log_output(level, prefix, output)
Definition logging.h:117
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:301
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
Wrappers for and extensions to glib mainloop.
struct mainloop_child_s mainloop_child_t
Definition mainloop.h:33
int mainloop_child_timeout(mainloop_child_t *child)
Definition mainloop.c:1047
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:1271
void * mainloop_child_userdata(mainloop_child_t *child)
Definition mainloop.c:1053
void mainloop_del_fd(mainloop_io_t *client)
Definition mainloop.c:1019
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:32
@ mainloop_leave_pid_group
Definition mainloop.h:28
void mainloop_clear_child_userdata(mainloop_child_t *child)
Definition mainloop.c:1059
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition mainloop.c:975
unsigned int timeout
Definition pcmk_fence.c:32
stonith_t * st
Definition pcmk_fence.c:28
int rc
Definition pcmk_fence.c:35
int setenv(const char *name, const char *value, int why)
int alphasort(const void *dirent1, const void *dirent2)
const char * pcmk_strerror(int rc)
Definition results.c:58
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:420
@ PCMK_OCF_INSUFFICIENT_PRIV
Definition results.h:155
@ PCMK_OCF_NOT_CONFIGURED
Definition results.h:157
@ PCMK_OCF_SIGNAL
Definition results.h:171
@ PCMK_OCF_NOT_INSTALLED
Definition results.h:156
@ PCMK_OCF_UNKNOWN_ERROR
Definition results.h:152
@ PCMK_OCF_EXEC_ERROR
Definition results.h:169
@ PCMK_OCF_OK
Definition results.h:151
@ PCMK_OCF_TIMEOUT
Definition results.h:175
@ pcmk_rc_ok
Definition results.h:142
void services_untrack_op(svc_action_t *op)
Definition services.c:770
gboolean cancel_recurring_action(svc_action_t *op)
Definition services.c:565
void services_add_inflight_op(svc_action_t *op)
Definition services.c:749
Services API.
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition services.h:48
@ PCMK_LRM_OP_DONE
Definition services.h:89
@ PCMK_LRM_OP_NOT_INSTALLED
Definition services.h:96
@ PCMK_LRM_OP_TIMEOUT
Definition services.h:91
@ PCMK_LRM_OP_CANCELLED
Definition services.h:90
@ PCMK_LRM_OP_ERROR
Definition services.h:93
@ SVC_ACTION_LEAVE_GROUP
Definition services.h:114
@ PCMK_LSB_STATUS_NOT_INSTALLED
Definition services.h:82
@ PCMK_LSB_STATUS_INSUFFICIENT_PRIV
Definition services.h:83
@ PCMK_LSB_STATUS_UNKNOWN
Definition services.h:79
@ NAGIOS_INSUFFICIENT_PRIV
Definition services.h:108
@ NAGIOS_NOT_INSTALLED
Definition services.h:109
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Definition services.c:813
#define PCMK_OCF_REASON_PREFIX
Definition services.h:55
void services_action_free(svc_action_t *op)
Definition services.c:513
#define PCMK_RESOURCE_CLASS_OCF
Definition services.h:43
void services_action_cleanup(svc_action_t *op)
Definition services.c:474
#define PCMK_RESOURCE_CLASS_LSB
Definition services.h:45
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:953
volatile struct sigchld_data_s * last_sigchld_data
gboolean operation_finalize(svc_action_t *op)
void services__handle_exec_error(svc_action_t *op, int error)
gboolean services__ocf_agent_exists(const char *provider, const char *agent)
GList * resources_os_list_ocf_providers(void)
gboolean recurring_action_timer(gpointer data)
gboolean services_os_action_execute(svc_action_t *op)
GList * resources_os_list_ocf_agents(const char *provider)
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
@ pcmk__str_casei
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition mainloop.h:137
char * args[MAX_ARGC]
void(* fork_callback)(svc_action_t *op)
mainloop_io_t * stdout_gsource
mainloop_io_t * stderr_gsource
void(* callback)(svc_action_t *op)
char * id
Definition services.h:120
char * provider
Definition services.h:126
char * agent
Definition services.h:127
char * standard
Definition services.h:125
char * rsc
Definition services.h:121
char * action
Definition services.h:122
enum svc_action_flags flags
Definition services.h:142
char * stderr_data
Definition services.h:144
GHashTable * params
Definition services.h:130
int synchronous
Definition services.h:141
char * stdout_data
Definition services.h:145
guint interval_ms
Definition services.h:123
svc_action_private_t * opaque
Definition services.h:155