Line data Source code
1 : /*
2 : * Copyright 2010-2023 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 : #include "crm/services_internal.h"
31 :
32 : #include "services_private.h"
33 :
34 : static void close_pipe(int fildes[]);
35 :
36 : /* We have two alternative ways of handling SIGCHLD when synchronously waiting
37 : * for spawned processes to complete. Both rely on polling a file descriptor to
38 : * discover SIGCHLD events.
39 : *
40 : * If sys/signalfd.h is available (e.g. on Linux), we call signalfd() to
41 : * generate the file descriptor. Otherwise, we use the "self-pipe trick"
42 : * (opening a pipe and writing a byte to it when SIGCHLD is received).
43 : */
44 : #ifdef HAVE_SYS_SIGNALFD_H
45 :
46 : // signalfd() implementation
47 :
48 : #include <sys/signalfd.h>
49 :
50 : // Everything needed to manage SIGCHLD handling
51 : struct sigchld_data_s {
52 : sigset_t mask; // Signals to block now (including SIGCHLD)
53 : sigset_t old_mask; // Previous set of blocked signals
54 : bool ignored; // If SIGCHLD for another child has been ignored
55 : };
56 :
57 : // Initialize SIGCHLD data and prepare for use
58 : static bool
59 0 : sigchld_setup(struct sigchld_data_s *data)
60 : {
61 0 : sigemptyset(&(data->mask));
62 0 : sigaddset(&(data->mask), SIGCHLD);
63 :
64 0 : sigemptyset(&(data->old_mask));
65 :
66 : // Block SIGCHLD (saving previous set of blocked signals to restore later)
67 0 : if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) {
68 0 : crm_info("Wait for child process completion failed: %s "
69 : CRM_XS " source=sigprocmask", pcmk_rc_str(errno));
70 0 : return false;
71 : }
72 :
73 0 : data->ignored = false;
74 :
75 0 : return true;
76 : }
77 :
78 : // Get a file descriptor suitable for polling for SIGCHLD events
79 : static int
80 0 : sigchld_open(struct sigchld_data_s *data)
81 : {
82 : int fd;
83 :
84 0 : CRM_CHECK(data != NULL, return -1);
85 :
86 0 : fd = signalfd(-1, &(data->mask), SFD_NONBLOCK);
87 0 : if (fd < 0) {
88 0 : crm_info("Wait for child process completion failed: %s "
89 : CRM_XS " source=signalfd", pcmk_rc_str(errno));
90 : }
91 0 : return fd;
92 : }
93 :
94 : // Close a file descriptor returned by sigchld_open()
95 : static void
96 0 : sigchld_close(int fd)
97 : {
98 0 : if (fd > 0) {
99 0 : close(fd);
100 : }
101 0 : }
102 :
103 : // Return true if SIGCHLD was received from polled fd
104 : static bool
105 0 : sigchld_received(int fd, int pid, struct sigchld_data_s *data)
106 : {
107 : struct signalfd_siginfo fdsi;
108 : ssize_t s;
109 :
110 0 : if (fd < 0) {
111 0 : return false;
112 : }
113 0 : s = read(fd, &fdsi, sizeof(struct signalfd_siginfo));
114 0 : if (s != sizeof(struct signalfd_siginfo)) {
115 0 : crm_info("Wait for child process completion failed: %s "
116 : CRM_XS " source=read", pcmk_rc_str(errno));
117 :
118 0 : } else if (fdsi.ssi_signo == SIGCHLD) {
119 0 : if (fdsi.ssi_pid == pid) {
120 0 : return true;
121 :
122 : } else {
123 : /* This SIGCHLD is for another child. We have to ignore it here but
124 : * will still need to resend it after this synchronous action has
125 : * completed and SIGCHLD has been restored to be handled by the
126 : * previous SIGCHLD handler, so that it will be handled.
127 : */
128 0 : data->ignored = true;
129 0 : return false;
130 : }
131 : }
132 0 : return false;
133 : }
134 :
135 : // Do anything needed after done waiting for SIGCHLD
136 : static void
137 0 : sigchld_cleanup(struct sigchld_data_s *data)
138 : {
139 : // Restore the original set of blocked signals
140 0 : if ((sigismember(&(data->old_mask), SIGCHLD) == 0)
141 0 : && (sigprocmask(SIG_UNBLOCK, &(data->mask), NULL) < 0)) {
142 0 : crm_warn("Could not clean up after child process completion: %s",
143 : pcmk_rc_str(errno));
144 : }
145 :
146 : // Resend any ignored SIGCHLD for other children so that they'll be handled.
147 0 : if (data->ignored && kill(getpid(), SIGCHLD) != 0) {
148 0 : crm_warn("Could not resend ignored SIGCHLD to ourselves: %s",
149 : pcmk_rc_str(errno));
150 : }
151 0 : }
152 :
153 : #else // HAVE_SYS_SIGNALFD_H not defined
154 :
155 : // Self-pipe implementation (see above for function descriptions)
156 :
157 : struct sigchld_data_s {
158 : int pipe_fd[2]; // Pipe file descriptors
159 : struct sigaction sa; // Signal handling info (with SIGCHLD)
160 : struct sigaction old_sa; // Previous signal handling info
161 : bool ignored; // If SIGCHLD for another child has been ignored
162 : };
163 :
164 : // We need a global to use in the signal handler
165 : volatile struct sigchld_data_s *last_sigchld_data = NULL;
166 :
167 : static void
168 : sigchld_handler(void)
169 : {
170 : // We received a SIGCHLD, so trigger pipe polling
171 : if ((last_sigchld_data != NULL)
172 : && (last_sigchld_data->pipe_fd[1] >= 0)
173 : && (write(last_sigchld_data->pipe_fd[1], "", 1) == -1)) {
174 : crm_info("Wait for child process completion failed: %s "
175 : CRM_XS " source=write", pcmk_rc_str(errno));
176 : }
177 : }
178 :
179 : static bool
180 : sigchld_setup(struct sigchld_data_s *data)
181 : {
182 : int rc;
183 :
184 : data->pipe_fd[0] = data->pipe_fd[1] = -1;
185 :
186 : if (pipe(data->pipe_fd) == -1) {
187 : crm_info("Wait for child process completion failed: %s "
188 : CRM_XS " source=pipe", pcmk_rc_str(errno));
189 : return false;
190 : }
191 :
192 : rc = pcmk__set_nonblocking(data->pipe_fd[0]);
193 : if (rc != pcmk_rc_ok) {
194 : crm_info("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
195 : pcmk_rc_str(rc), rc);
196 : }
197 : rc = pcmk__set_nonblocking(data->pipe_fd[1]);
198 : if (rc != pcmk_rc_ok) {
199 : crm_info("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
200 : pcmk_rc_str(rc), rc);
201 : }
202 :
203 : // Set SIGCHLD handler
204 : data->sa.sa_handler = (sighandler_t) sigchld_handler;
205 : data->sa.sa_flags = 0;
206 : sigemptyset(&(data->sa.sa_mask));
207 : if (sigaction(SIGCHLD, &(data->sa), &(data->old_sa)) < 0) {
208 : crm_info("Wait for child process completion failed: %s "
209 : CRM_XS " source=sigaction", pcmk_rc_str(errno));
210 : }
211 :
212 : data->ignored = false;
213 :
214 : // Remember data for use in signal handler
215 : last_sigchld_data = data;
216 : return true;
217 : }
218 :
219 : static int
220 : sigchld_open(struct sigchld_data_s *data)
221 : {
222 : CRM_CHECK(data != NULL, return -1);
223 : return data->pipe_fd[0];
224 : }
225 :
226 : static void
227 : sigchld_close(int fd)
228 : {
229 : // Pipe will be closed in sigchld_cleanup()
230 : return;
231 : }
232 :
233 : static bool
234 : sigchld_received(int fd, int pid, struct sigchld_data_s *data)
235 : {
236 : char ch;
237 :
238 : if (fd < 0) {
239 : return false;
240 : }
241 :
242 : // Clear out the self-pipe
243 : while (read(fd, &ch, 1) == 1) /*omit*/;
244 : return true;
245 : }
246 :
247 : static void
248 : sigchld_cleanup(struct sigchld_data_s *data)
249 : {
250 : // Restore the previous SIGCHLD handler
251 : if (sigaction(SIGCHLD, &(data->old_sa), NULL) < 0) {
252 : crm_warn("Could not clean up after child process completion: %s",
253 : pcmk_rc_str(errno));
254 : }
255 :
256 : close_pipe(data->pipe_fd);
257 :
258 : // Resend any ignored SIGCHLD for other children so that they'll be handled.
259 : if (data->ignored && kill(getpid(), SIGCHLD) != 0) {
260 : crm_warn("Could not resend ignored SIGCHLD to ourselves: %s",
261 : pcmk_rc_str(errno));
262 : }
263 : }
264 :
265 : #endif
266 :
267 : /*!
268 : * \internal
269 : * \brief Close the two file descriptors of a pipe
270 : *
271 : * \param[in,out] fildes Array of file descriptors opened by pipe()
272 : */
273 : static void
274 0 : close_pipe(int fildes[])
275 : {
276 0 : if (fildes[0] >= 0) {
277 0 : close(fildes[0]);
278 0 : fildes[0] = -1;
279 : }
280 0 : if (fildes[1] >= 0) {
281 0 : close(fildes[1]);
282 0 : fildes[1] = -1;
283 : }
284 0 : }
285 :
286 : static gboolean
287 0 : svc_read_output(int fd, svc_action_t * op, bool is_stderr)
288 : {
289 0 : char *data = NULL;
290 0 : int rc = 0, len = 0;
291 : char buf[500];
292 : static const size_t buf_read_len = sizeof(buf) - 1;
293 :
294 :
295 0 : if (fd < 0) {
296 0 : crm_trace("No fd for %s", op->id);
297 0 : return FALSE;
298 : }
299 :
300 0 : if (is_stderr && op->stderr_data) {
301 0 : len = strlen(op->stderr_data);
302 0 : data = op->stderr_data;
303 0 : crm_trace("Reading %s stderr into offset %d", op->id, len);
304 :
305 0 : } else if (is_stderr == FALSE && op->stdout_data) {
306 0 : len = strlen(op->stdout_data);
307 0 : data = op->stdout_data;
308 0 : crm_trace("Reading %s stdout into offset %d", op->id, len);
309 :
310 : } else {
311 0 : crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
312 : }
313 :
314 : do {
315 0 : rc = read(fd, buf, buf_read_len);
316 0 : if (rc > 0) {
317 0 : buf[rc] = 0;
318 0 : crm_trace("Got %d chars: %.80s", rc, buf);
319 0 : data = pcmk__realloc(data, len + rc + 1);
320 0 : len += sprintf(data + len, "%s", buf);
321 :
322 0 : } else if (errno != EINTR) {
323 : /* error or EOF
324 : * Cleanup happens in pipe_done()
325 : */
326 0 : rc = FALSE;
327 0 : break;
328 : }
329 :
330 0 : } while (rc == buf_read_len || rc < 0);
331 :
332 0 : if (is_stderr) {
333 0 : op->stderr_data = data;
334 : } else {
335 0 : op->stdout_data = data;
336 : }
337 :
338 0 : return rc;
339 : }
340 :
341 : static int
342 0 : dispatch_stdout(gpointer userdata)
343 : {
344 0 : svc_action_t *op = (svc_action_t *) userdata;
345 :
346 0 : return svc_read_output(op->opaque->stdout_fd, op, FALSE);
347 : }
348 :
349 : static int
350 0 : dispatch_stderr(gpointer userdata)
351 : {
352 0 : svc_action_t *op = (svc_action_t *) userdata;
353 :
354 0 : return svc_read_output(op->opaque->stderr_fd, op, TRUE);
355 : }
356 :
357 : static void
358 0 : pipe_out_done(gpointer user_data)
359 : {
360 0 : svc_action_t *op = (svc_action_t *) user_data;
361 :
362 0 : crm_trace("%p", op);
363 :
364 0 : op->opaque->stdout_gsource = NULL;
365 0 : if (op->opaque->stdout_fd > STDOUT_FILENO) {
366 0 : close(op->opaque->stdout_fd);
367 : }
368 0 : op->opaque->stdout_fd = -1;
369 0 : }
370 :
371 : static void
372 0 : pipe_err_done(gpointer user_data)
373 : {
374 0 : svc_action_t *op = (svc_action_t *) user_data;
375 :
376 0 : op->opaque->stderr_gsource = NULL;
377 0 : if (op->opaque->stderr_fd > STDERR_FILENO) {
378 0 : close(op->opaque->stderr_fd);
379 : }
380 0 : op->opaque->stderr_fd = -1;
381 0 : }
382 :
383 : static struct mainloop_fd_callbacks stdout_callbacks = {
384 : .dispatch = dispatch_stdout,
385 : .destroy = pipe_out_done,
386 : };
387 :
388 : static struct mainloop_fd_callbacks stderr_callbacks = {
389 : .dispatch = dispatch_stderr,
390 : .destroy = pipe_err_done,
391 : };
392 :
393 : static void
394 0 : set_ocf_env(const char *key, const char *value, gpointer user_data)
395 : {
396 0 : if (setenv(key, value, 1) != 0) {
397 0 : crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
398 : }
399 0 : }
400 :
401 : static void
402 0 : set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
403 : {
404 : char buffer[500];
405 :
406 0 : snprintf(buffer, sizeof(buffer), strcmp(key, "OCF_CHECK_LEVEL") != 0 ? "OCF_RESKEY_%s" : "%s", (char *)key);
407 0 : set_ocf_env(buffer, value, user_data);
408 0 : }
409 :
410 : static void
411 0 : set_alert_env(gpointer key, gpointer value, gpointer user_data)
412 : {
413 : int rc;
414 :
415 0 : if (value != NULL) {
416 0 : rc = setenv(key, value, 1);
417 : } else {
418 0 : rc = unsetenv(key);
419 : }
420 :
421 0 : if (rc < 0) {
422 0 : crm_perror(LOG_ERR, "setenv %s=%s",
423 : (char*)key, (value? (char*)value : ""));
424 : } else {
425 0 : crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
426 : }
427 0 : }
428 :
429 : /*!
430 : * \internal
431 : * \brief Add environment variables suitable for an action
432 : *
433 : * \param[in] op Action to use
434 : */
435 : static void
436 0 : add_action_env_vars(const svc_action_t *op)
437 : {
438 0 : void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
439 0 : if (op->agent == NULL) {
440 0 : env_setter = set_alert_env; /* we deal with alert handler */
441 :
442 0 : } else if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
443 0 : env_setter = set_ocf_env_with_prefix;
444 : }
445 :
446 0 : if (env_setter != NULL && op->params != NULL) {
447 0 : g_hash_table_foreach(op->params, env_setter, NULL);
448 : }
449 :
450 0 : if (env_setter == NULL || env_setter == set_alert_env) {
451 0 : return;
452 : }
453 :
454 0 : set_ocf_env("OCF_RA_VERSION_MAJOR", PCMK_OCF_MAJOR_VERSION, NULL);
455 0 : set_ocf_env("OCF_RA_VERSION_MINOR", PCMK_OCF_MINOR_VERSION, NULL);
456 0 : set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
457 0 : set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
458 :
459 0 : if (op->rsc) {
460 0 : set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
461 : }
462 :
463 0 : if (op->agent != NULL) {
464 0 : set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
465 : }
466 :
467 : /* Notes: this is not added to specification yet. Sept 10,2004 */
468 0 : if (op->provider != NULL) {
469 0 : set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
470 : }
471 : }
472 :
473 : static void
474 0 : pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
475 : {
476 0 : svc_action_t *op = user_data;
477 0 : char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value);
478 0 : int ret, total = 0, len = strlen(buffer);
479 :
480 : do {
481 0 : errno = 0;
482 0 : ret = write(op->opaque->stdin_fd, buffer + total, len - total);
483 0 : if (ret > 0) {
484 0 : total += ret;
485 : }
486 :
487 0 : } while ((errno == EINTR) && (total < len));
488 0 : free(buffer);
489 0 : }
490 :
491 : /*!
492 : * \internal
493 : * \brief Pipe parameters in via stdin for action
494 : *
495 : * \param[in] op Action to use
496 : */
497 : static void
498 0 : pipe_in_action_stdin_parameters(const svc_action_t *op)
499 : {
500 0 : if (op->params) {
501 0 : g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op);
502 : }
503 0 : }
504 :
505 : gboolean
506 0 : recurring_action_timer(gpointer data)
507 : {
508 0 : svc_action_t *op = data;
509 :
510 0 : crm_debug("Scheduling another invocation of %s", op->id);
511 :
512 : /* Clean out the old result */
513 0 : free(op->stdout_data);
514 0 : op->stdout_data = NULL;
515 0 : free(op->stderr_data);
516 0 : op->stderr_data = NULL;
517 0 : op->opaque->repeat_timer = 0;
518 :
519 0 : services_action_async(op, NULL);
520 0 : return FALSE;
521 : }
522 :
523 : /*!
524 : * \internal
525 : * \brief Finalize handling of an asynchronous operation
526 : *
527 : * Given a completed asynchronous operation, cancel or reschedule it as
528 : * appropriate if recurring, call its callback if registered, stop tracking it,
529 : * and clean it up.
530 : *
531 : * \param[in,out] op Operation to finalize
532 : *
533 : * \return Standard Pacemaker return code
534 : * \retval EINVAL Caller supplied NULL or invalid \p op
535 : * \retval EBUSY Uncanceled recurring action has only been cleaned up
536 : * \retval pcmk_rc_ok Action has been freed
537 : *
538 : * \note If the return value is not pcmk_rc_ok, the caller is responsible for
539 : * freeing the action.
540 : */
541 : int
542 0 : services__finalize_async_op(svc_action_t *op)
543 : {
544 0 : CRM_CHECK((op != NULL) && !(op->synchronous), return EINVAL);
545 :
546 0 : if (op->interval_ms != 0) {
547 : // Recurring operations must be either cancelled or rescheduled
548 0 : if (op->cancel) {
549 0 : services__set_cancelled(op);
550 0 : cancel_recurring_action(op);
551 : } else {
552 0 : op->opaque->repeat_timer = g_timeout_add(op->interval_ms,
553 : recurring_action_timer,
554 : (void *) op);
555 : }
556 : }
557 :
558 0 : if (op->opaque->callback != NULL) {
559 0 : op->opaque->callback(op);
560 : }
561 :
562 : // Stop tracking the operation (as in-flight or blocked)
563 0 : op->pid = 0;
564 0 : services_untrack_op(op);
565 :
566 0 : if ((op->interval_ms != 0) && !(op->cancel)) {
567 : // Do not free recurring actions (they will get freed when cancelled)
568 0 : services_action_cleanup(op);
569 0 : return EBUSY;
570 : }
571 :
572 0 : services_action_free(op);
573 0 : return pcmk_rc_ok;
574 : }
575 :
576 : static void
577 0 : close_op_input(svc_action_t *op)
578 : {
579 0 : if (op->opaque->stdin_fd >= 0) {
580 0 : close(op->opaque->stdin_fd);
581 : }
582 0 : }
583 :
584 : static void
585 0 : finish_op_output(svc_action_t *op, bool is_stderr)
586 : {
587 : mainloop_io_t **source;
588 : int fd;
589 :
590 0 : if (is_stderr) {
591 0 : source = &(op->opaque->stderr_gsource);
592 0 : fd = op->opaque->stderr_fd;
593 : } else {
594 0 : source = &(op->opaque->stdout_gsource);
595 0 : fd = op->opaque->stdout_fd;
596 : }
597 :
598 0 : if (op->synchronous || *source) {
599 0 : crm_trace("Finish reading %s[%d] %s",
600 : op->id, op->pid, (is_stderr? "stderr" : "stdout"));
601 0 : svc_read_output(fd, op, is_stderr);
602 0 : if (op->synchronous) {
603 0 : close(fd);
604 : } else {
605 0 : mainloop_del_fd(*source);
606 0 : *source = NULL;
607 : }
608 : }
609 0 : }
610 :
611 : // Log an operation's stdout and stderr
612 : static void
613 0 : log_op_output(svc_action_t *op)
614 : {
615 0 : char *prefix = crm_strdup_printf("%s[%d] error output", op->id, op->pid);
616 :
617 : /* The library caller has better context to know how important the output
618 : * is, so log it at info and debug severity here. They can log it again at
619 : * higher severity if appropriate.
620 : */
621 0 : crm_log_output(LOG_INFO, prefix, op->stderr_data);
622 0 : strcpy(prefix + strlen(prefix) - strlen("error output"), "output");
623 0 : crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
624 0 : free(prefix);
625 0 : }
626 :
627 : // Truncate exit reasons at this many characters
628 : #define EXIT_REASON_MAX_LEN 128
629 :
630 : static void
631 0 : parse_exit_reason_from_stderr(svc_action_t *op)
632 : {
633 0 : const char *reason_start = NULL;
634 0 : const char *reason_end = NULL;
635 0 : const int prefix_len = strlen(PCMK_OCF_REASON_PREFIX);
636 :
637 0 : if ((op->stderr_data == NULL) ||
638 : // Only OCF agents have exit reasons in stderr
639 0 : !pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_none)) {
640 0 : return;
641 : }
642 :
643 : // Find the last occurrence of the magic string indicating an exit reason
644 0 : for (const char *cur = strstr(op->stderr_data, PCMK_OCF_REASON_PREFIX);
645 0 : cur != NULL; cur = strstr(cur, PCMK_OCF_REASON_PREFIX)) {
646 :
647 0 : cur += prefix_len; // Skip over magic string
648 0 : reason_start = cur;
649 : }
650 :
651 0 : if ((reason_start == NULL) || (reason_start[0] == '\n')
652 0 : || (reason_start[0] == '\0')) {
653 0 : return; // No or empty exit reason
654 : }
655 :
656 : // Exit reason goes to end of line (or end of output)
657 0 : reason_end = strchr(reason_start, '\n');
658 0 : if (reason_end == NULL) {
659 0 : reason_end = reason_start + strlen(reason_start);
660 : }
661 :
662 : // Limit size of exit reason to something reasonable
663 0 : if (reason_end > (reason_start + EXIT_REASON_MAX_LEN)) {
664 0 : reason_end = reason_start + EXIT_REASON_MAX_LEN;
665 : }
666 :
667 0 : free(op->opaque->exit_reason);
668 0 : op->opaque->exit_reason = strndup(reason_start, reason_end - reason_start);
669 : }
670 :
671 : /*!
672 : * \internal
673 : * \brief Process the completion of an asynchronous child process
674 : *
675 : * \param[in,out] p Child process that completed
676 : * \param[in] pid Process ID of child
677 : * \param[in] core (Unused)
678 : * \param[in] signo Signal that interrupted child, if any
679 : * \param[in] exitcode Exit status of child process
680 : */
681 : static void
682 0 : async_action_complete(mainloop_child_t *p, pid_t pid, int core, int signo,
683 : int exitcode)
684 : {
685 0 : svc_action_t *op = mainloop_child_userdata(p);
686 :
687 0 : mainloop_clear_child_userdata(p);
688 0 : CRM_CHECK(op->pid == pid,
689 : services__set_result(op, services__generic_error(op),
690 : PCMK_EXEC_ERROR, "Bug in mainloop handling");
691 : return);
692 :
693 : /* Depending on the priority the mainloop gives the stdout and stderr
694 : * file descriptors, this function could be called before everything has
695 : * been read from them, so force a final read now.
696 : */
697 0 : finish_op_output(op, true);
698 0 : finish_op_output(op, false);
699 :
700 0 : close_op_input(op);
701 :
702 0 : if (signo == 0) {
703 0 : crm_debug("%s[%d] exited with status %d", op->id, op->pid, exitcode);
704 0 : services__set_result(op, exitcode, PCMK_EXEC_DONE, NULL);
705 0 : log_op_output(op);
706 0 : parse_exit_reason_from_stderr(op);
707 :
708 0 : } else if (mainloop_child_timeout(p)) {
709 0 : const char *kind = services__action_kind(op);
710 :
711 0 : crm_info("%s %s[%d] timed out after %s",
712 : kind, op->id, op->pid, pcmk__readable_interval(op->timeout));
713 0 : services__format_result(op, services__generic_error(op),
714 : PCMK_EXEC_TIMEOUT,
715 : "%s did not complete within %s",
716 0 : kind, pcmk__readable_interval(op->timeout));
717 :
718 0 : } else if (op->cancel) {
719 : /* If an in-flight recurring operation was killed because it was
720 : * cancelled, don't treat that as a failure.
721 : */
722 0 : crm_info("%s[%d] terminated with signal %d (%s)",
723 : op->id, op->pid, signo, strsignal(signo));
724 0 : services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_CANCELLED, NULL);
725 :
726 : } else {
727 0 : crm_info("%s[%d] terminated with signal %d (%s)",
728 : op->id, op->pid, signo, strsignal(signo));
729 0 : services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
730 : "%s interrupted by %s signal",
731 : services__action_kind(op), strsignal(signo));
732 : }
733 :
734 0 : services__finalize_async_op(op);
735 : }
736 :
737 : /*!
738 : * \internal
739 : * \brief Return agent standard's exit status for "generic error"
740 : *
741 : * When returning an internal error for an action, a value that is appropriate
742 : * to the action's agent standard must be used. This function returns a value
743 : * appropriate for errors in general.
744 : *
745 : * \param[in] op Action that error is for
746 : *
747 : * \return Exit status appropriate to agent standard
748 : * \note Actions without a standard will get PCMK_OCF_UNKNOWN_ERROR.
749 : */
750 : int
751 0 : services__generic_error(const svc_action_t *op)
752 : {
753 0 : if ((op == NULL) || (op->standard == NULL)) {
754 0 : return PCMK_OCF_UNKNOWN_ERROR;
755 : }
756 :
757 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
758 0 : && pcmk__str_eq(op->action, PCMK_ACTION_STATUS, pcmk__str_casei)) {
759 :
760 0 : return PCMK_LSB_STATUS_UNKNOWN;
761 : }
762 :
763 : #if SUPPORT_NAGIOS
764 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
765 0 : return NAGIOS_STATE_UNKNOWN;
766 : }
767 : #endif
768 :
769 0 : return PCMK_OCF_UNKNOWN_ERROR;
770 : }
771 :
772 : /*!
773 : * \internal
774 : * \brief Return agent standard's exit status for "not installed"
775 : *
776 : * When returning an internal error for an action, a value that is appropriate
777 : * to the action's agent standard must be used. This function returns a value
778 : * appropriate for "not installed" errors.
779 : *
780 : * \param[in] op Action that error is for
781 : *
782 : * \return Exit status appropriate to agent standard
783 : * \note Actions without a standard will get PCMK_OCF_UNKNOWN_ERROR.
784 : */
785 : int
786 0 : services__not_installed_error(const svc_action_t *op)
787 : {
788 0 : if ((op == NULL) || (op->standard == NULL)) {
789 0 : return PCMK_OCF_UNKNOWN_ERROR;
790 : }
791 :
792 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
793 0 : && pcmk__str_eq(op->action, PCMK_ACTION_STATUS, pcmk__str_casei)) {
794 :
795 0 : return PCMK_LSB_STATUS_NOT_INSTALLED;
796 : }
797 :
798 : #if SUPPORT_NAGIOS
799 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
800 0 : return NAGIOS_STATE_UNKNOWN;
801 : }
802 : #endif
803 :
804 0 : return PCMK_OCF_NOT_INSTALLED;
805 : }
806 :
807 : /*!
808 : * \internal
809 : * \brief Return agent standard's exit status for "insufficient privileges"
810 : *
811 : * When returning an internal error for an action, a value that is appropriate
812 : * to the action's agent standard must be used. This function returns a value
813 : * appropriate for "insufficient privileges" errors.
814 : *
815 : * \param[in] op Action that error is for
816 : *
817 : * \return Exit status appropriate to agent standard
818 : * \note Actions without a standard will get PCMK_OCF_UNKNOWN_ERROR.
819 : */
820 : int
821 0 : services__authorization_error(const svc_action_t *op)
822 : {
823 0 : if ((op == NULL) || (op->standard == NULL)) {
824 0 : return PCMK_OCF_UNKNOWN_ERROR;
825 : }
826 :
827 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
828 0 : && pcmk__str_eq(op->action, PCMK_ACTION_STATUS, pcmk__str_casei)) {
829 :
830 0 : return PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
831 : }
832 :
833 : #if SUPPORT_NAGIOS
834 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
835 0 : return NAGIOS_INSUFFICIENT_PRIV;
836 : }
837 : #endif
838 :
839 0 : return PCMK_OCF_INSUFFICIENT_PRIV;
840 : }
841 :
842 : /*!
843 : * \internal
844 : * \brief Return agent standard's exit status for "not configured"
845 : *
846 : * When returning an internal error for an action, a value that is appropriate
847 : * to the action's agent standard must be used. This function returns a value
848 : * appropriate for "not configured" errors.
849 : *
850 : * \param[in] op Action that error is for
851 : * \param[in] is_fatal Whether problem is cluster-wide instead of only local
852 : *
853 : * \return Exit status appropriate to agent standard
854 : * \note Actions without a standard will get PCMK_OCF_UNKNOWN_ERROR.
855 : */
856 : int
857 0 : services__configuration_error(const svc_action_t *op, bool is_fatal)
858 : {
859 0 : if ((op == NULL) || (op->standard == NULL)) {
860 0 : return PCMK_OCF_UNKNOWN_ERROR;
861 : }
862 :
863 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
864 0 : && pcmk__str_eq(op->action, PCMK_ACTION_STATUS, pcmk__str_casei)) {
865 :
866 0 : return PCMK_LSB_NOT_CONFIGURED;
867 : }
868 :
869 : #if SUPPORT_NAGIOS
870 0 : if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
871 0 : return NAGIOS_STATE_UNKNOWN;
872 : }
873 : #endif
874 :
875 0 : return is_fatal? PCMK_OCF_NOT_CONFIGURED : PCMK_OCF_INVALID_PARAM;
876 : }
877 :
878 :
879 : /*!
880 : * \internal
881 : * \brief Set operation rc and status per errno from stat(), fork() or execvp()
882 : *
883 : * \param[in,out] op Operation to set rc and status for
884 : * \param[in] error Value of errno after system call
885 : *
886 : * \return void
887 : */
888 : void
889 0 : services__handle_exec_error(svc_action_t * op, int error)
890 : {
891 0 : const char *name = op->opaque->exec;
892 :
893 0 : if (name == NULL) {
894 0 : name = op->agent;
895 0 : if (name == NULL) {
896 0 : name = op->id;
897 : }
898 : }
899 :
900 0 : switch (error) { /* see execve(2), stat(2) and fork(2) */
901 0 : case ENOENT: /* No such file or directory */
902 : case EISDIR: /* Is a directory */
903 : case ENOTDIR: /* Path component is not a directory */
904 : case EINVAL: /* Invalid executable format */
905 : case ENOEXEC: /* Invalid executable format */
906 0 : services__format_result(op, services__not_installed_error(op),
907 : PCMK_EXEC_NOT_INSTALLED, "%s: %s",
908 : name, pcmk_rc_str(error));
909 0 : break;
910 0 : case EACCES: /* permission denied (various errors) */
911 : case EPERM: /* permission denied (various errors) */
912 0 : services__format_result(op, services__authorization_error(op),
913 : PCMK_EXEC_ERROR, "%s: %s",
914 : name, pcmk_rc_str(error));
915 0 : break;
916 0 : default:
917 0 : services__set_result(op, services__generic_error(op),
918 : PCMK_EXEC_ERROR, pcmk_rc_str(error));
919 : }
920 0 : }
921 :
922 : /*!
923 : * \internal
924 : * \brief Exit a child process that failed before executing agent
925 : *
926 : * \param[in] op Action that failed
927 : * \param[in] exit_status Exit status code to use
928 : * \param[in] exit_reason Exit reason to output if for OCF agent
929 : */
930 : static void
931 0 : exit_child(const svc_action_t *op, int exit_status, const char *exit_reason)
932 : {
933 0 : if ((op != NULL) && (exit_reason != NULL)
934 0 : && pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF,
935 : pcmk__str_none)) {
936 0 : fprintf(stderr, PCMK_OCF_REASON_PREFIX "%s\n", exit_reason);
937 : }
938 0 : _exit(exit_status);
939 : }
940 :
941 : static void
942 0 : action_launch_child(svc_action_t *op)
943 : {
944 : int rc;
945 :
946 : /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
947 : * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well.
948 : * We do not want this to be inherited by the child process. By resetting this the signal
949 : * to the default behavior, we avoid some potential odd problems that occur during OCF
950 : * scripts when SIGPIPE is ignored by the environment. */
951 0 : signal(SIGPIPE, SIG_DFL);
952 :
953 : #if defined(HAVE_SCHED_SETSCHEDULER)
954 0 : if (sched_getscheduler(0) != SCHED_OTHER) {
955 : struct sched_param sp;
956 :
957 0 : memset(&sp, 0, sizeof(sp));
958 0 : sp.sched_priority = 0;
959 :
960 0 : if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
961 0 : crm_info("Could not reset scheduling policy for %s", op->id);
962 : }
963 : }
964 : #endif
965 0 : if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
966 0 : crm_info("Could not reset process priority for %s", op->id);
967 : }
968 :
969 : /* Man: The call setpgrp() is equivalent to setpgid(0,0)
970 : * _and_ compiles on BSD variants too
971 : * need to investigate if it works the same too.
972 : */
973 0 : setpgid(0, 0);
974 :
975 0 : pcmk__close_fds_in_child(false);
976 :
977 : /* It would be nice if errors in this function could be reported as
978 : * execution status (for example, PCMK_EXEC_NO_SECRETS for the secrets error
979 : * below) instead of exit status. However, we've already forked, so
980 : * exit status is all we have. At least for OCF actions, we can output an
981 : * exit reason for the parent to parse.
982 : */
983 :
984 : #if SUPPORT_CIBSECRETS
985 : rc = pcmk__substitute_secrets(op->rsc, op->params);
986 : if (rc != pcmk_rc_ok) {
987 : if (pcmk__str_eq(op->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
988 : crm_info("Proceeding with stop operation for %s "
989 : "despite being unable to load CIB secrets (%s)",
990 : op->rsc, pcmk_rc_str(rc));
991 : } else {
992 : crm_err("Considering %s unconfigured "
993 : "because unable to load CIB secrets: %s",
994 : op->rsc, pcmk_rc_str(rc));
995 : exit_child(op, services__configuration_error(op, false),
996 : "Unable to load CIB secrets");
997 : }
998 : }
999 : #endif
1000 :
1001 0 : add_action_env_vars(op);
1002 :
1003 : /* Become the desired user */
1004 0 : if (op->opaque->uid && (geteuid() == 0)) {
1005 :
1006 : // If requested, set effective group
1007 0 : if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
1008 0 : crm_err("Considering %s unauthorized because could not set "
1009 : "child group to %d: %s",
1010 : op->id, op->opaque->gid, strerror(errno));
1011 0 : exit_child(op, services__authorization_error(op),
1012 : "Could not set group for child process");
1013 : }
1014 :
1015 : // Erase supplementary group list
1016 : // (We could do initgroups() if we kept a copy of the username)
1017 0 : if (setgroups(0, NULL) < 0) {
1018 0 : crm_err("Considering %s unauthorized because could not "
1019 : "clear supplementary groups: %s", op->id, strerror(errno));
1020 0 : exit_child(op, services__authorization_error(op),
1021 : "Could not clear supplementary groups for child process");
1022 : }
1023 :
1024 : // Set effective user
1025 0 : if (setuid(op->opaque->uid) < 0) {
1026 0 : crm_err("Considering %s unauthorized because could not set user "
1027 : "to %d: %s", op->id, op->opaque->uid, strerror(errno));
1028 0 : exit_child(op, services__authorization_error(op),
1029 : "Could not set user for child process");
1030 : }
1031 : }
1032 :
1033 : // Execute the agent (doesn't return if successful)
1034 0 : execvp(op->opaque->exec, op->opaque->args);
1035 :
1036 : // An earlier stat() should have avoided most possible errors
1037 0 : rc = errno;
1038 0 : services__handle_exec_error(op, rc);
1039 0 : crm_err("Unable to execute %s: %s", op->id, strerror(rc));
1040 0 : exit_child(op, op->rc, "Child process was unable to execute file");
1041 0 : }
1042 :
1043 : /*!
1044 : * \internal
1045 : * \brief Wait for synchronous action to complete, and set its result
1046 : *
1047 : * \param[in,out] op Action to wait for
1048 : * \param[in,out] data Child signal data
1049 : */
1050 : static void
1051 0 : wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data)
1052 : {
1053 0 : int status = 0;
1054 0 : int timeout = op->timeout;
1055 0 : time_t start = time(NULL);
1056 : struct pollfd fds[3];
1057 0 : int wait_rc = 0;
1058 0 : const char *wait_reason = NULL;
1059 :
1060 0 : fds[0].fd = op->opaque->stdout_fd;
1061 0 : fds[0].events = POLLIN;
1062 0 : fds[0].revents = 0;
1063 :
1064 0 : fds[1].fd = op->opaque->stderr_fd;
1065 0 : fds[1].events = POLLIN;
1066 0 : fds[1].revents = 0;
1067 :
1068 0 : fds[2].fd = sigchld_open(data);
1069 0 : fds[2].events = POLLIN;
1070 0 : fds[2].revents = 0;
1071 :
1072 0 : crm_trace("Waiting for %s[%d]", op->id, op->pid);
1073 : do {
1074 0 : int poll_rc = poll(fds, 3, timeout);
1075 :
1076 0 : wait_reason = NULL;
1077 :
1078 0 : if (poll_rc > 0) {
1079 0 : if (fds[0].revents & POLLIN) {
1080 0 : svc_read_output(op->opaque->stdout_fd, op, FALSE);
1081 : }
1082 :
1083 0 : if (fds[1].revents & POLLIN) {
1084 0 : svc_read_output(op->opaque->stderr_fd, op, TRUE);
1085 : }
1086 :
1087 0 : if ((fds[2].revents & POLLIN)
1088 0 : && sigchld_received(fds[2].fd, op->pid, data)) {
1089 0 : wait_rc = waitpid(op->pid, &status, WNOHANG);
1090 :
1091 0 : if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) {
1092 : // Child process exited or doesn't exist
1093 : break;
1094 :
1095 0 : } else if (wait_rc < 0) {
1096 0 : wait_reason = pcmk_rc_str(errno);
1097 0 : crm_info("Wait for completion of %s[%d] failed: %s "
1098 : CRM_XS " source=waitpid",
1099 : op->id, op->pid, wait_reason);
1100 0 : wait_rc = 0; // Act as if process is still running
1101 :
1102 : #ifndef HAVE_SYS_SIGNALFD_H
1103 : } else {
1104 : /* The child hasn't exited, so this SIGCHLD could be for
1105 : * another child. We have to ignore it here but will still
1106 : * need to resend it after this synchronous action has
1107 : * completed and SIGCHLD has been restored to be handled by
1108 : * the previous handler, so that it will be handled.
1109 : */
1110 : data->ignored = true;
1111 : #endif
1112 : }
1113 : }
1114 :
1115 0 : } else if (poll_rc == 0) {
1116 : // Poll timed out with no descriptors ready
1117 0 : timeout = 0;
1118 0 : break;
1119 :
1120 0 : } else if ((poll_rc < 0) && (errno != EINTR)) {
1121 0 : wait_reason = pcmk_rc_str(errno);
1122 0 : crm_info("Wait for completion of %s[%d] failed: %s "
1123 : CRM_XS " source=poll", op->id, op->pid, wait_reason);
1124 0 : break;
1125 : }
1126 :
1127 0 : timeout = op->timeout - (time(NULL) - start) * 1000;
1128 :
1129 0 : } while ((op->timeout < 0 || timeout > 0));
1130 :
1131 0 : crm_trace("Stopped waiting for %s[%d]", op->id, op->pid);
1132 0 : finish_op_output(op, true);
1133 0 : finish_op_output(op, false);
1134 0 : close_op_input(op);
1135 0 : sigchld_close(fds[2].fd);
1136 :
1137 0 : if (wait_rc <= 0) {
1138 :
1139 0 : if ((op->timeout > 0) && (timeout <= 0)) {
1140 0 : services__format_result(op, services__generic_error(op),
1141 : PCMK_EXEC_TIMEOUT,
1142 : "%s did not exit within specified timeout",
1143 : services__action_kind(op));
1144 0 : crm_info("%s[%d] timed out after %dms",
1145 : op->id, op->pid, op->timeout);
1146 :
1147 : } else {
1148 0 : services__set_result(op, services__generic_error(op),
1149 : PCMK_EXEC_ERROR, wait_reason);
1150 : }
1151 :
1152 : /* If only child hasn't been successfully waited for, yet.
1153 : This is to limit killing wrong target a bit more. */
1154 0 : if ((wait_rc == 0) && (waitpid(op->pid, &status, WNOHANG) == 0)) {
1155 0 : if (kill(op->pid, SIGKILL)) {
1156 0 : crm_warn("Could not kill rogue child %s[%d]: %s",
1157 : op->id, op->pid, pcmk_rc_str(errno));
1158 : }
1159 : /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
1160 0 : while ((waitpid(op->pid, &status, 0) == (pid_t) -1)
1161 0 : && (errno == EINTR)) {
1162 : /* keep waiting */;
1163 : }
1164 : }
1165 :
1166 0 : } else if (WIFEXITED(status)) {
1167 0 : services__set_result(op, WEXITSTATUS(status), PCMK_EXEC_DONE, NULL);
1168 0 : parse_exit_reason_from_stderr(op);
1169 0 : crm_info("%s[%d] exited with status %d", op->id, op->pid, op->rc);
1170 :
1171 0 : } else if (WIFSIGNALED(status)) {
1172 0 : int signo = WTERMSIG(status);
1173 :
1174 0 : services__format_result(op, services__generic_error(op),
1175 : PCMK_EXEC_ERROR, "%s interrupted by %s signal",
1176 : services__action_kind(op), strsignal(signo));
1177 0 : crm_info("%s[%d] terminated with signal %d (%s)",
1178 : op->id, op->pid, signo, strsignal(signo));
1179 :
1180 : #ifdef WCOREDUMP
1181 0 : if (WCOREDUMP(status)) {
1182 0 : crm_warn("%s[%d] dumped core", op->id, op->pid);
1183 : }
1184 : #endif
1185 :
1186 : } else {
1187 : // Shouldn't be possible to get here
1188 0 : services__set_result(op, services__generic_error(op), PCMK_EXEC_ERROR,
1189 : "Unable to wait for child to complete");
1190 : }
1191 0 : }
1192 :
1193 : /*!
1194 : * \internal
1195 : * \brief Execute an action whose standard uses executable files
1196 : *
1197 : * \param[in,out] op Action to execute
1198 : *
1199 : * \return Standard Pacemaker return value
1200 : * \retval EBUSY Recurring operation could not be initiated
1201 : * \retval pcmk_rc_error Synchronous action failed
1202 : * \retval pcmk_rc_ok Synchronous action succeeded, or asynchronous action
1203 : * should not be freed (because it's pending or because
1204 : * it failed to execute and was already freed)
1205 : *
1206 : * \note If the return value for an asynchronous action is not pcmk_rc_ok, the
1207 : * caller is responsible for freeing the action.
1208 : */
1209 : int
1210 0 : services__execute_file(svc_action_t *op)
1211 : {
1212 : int stdout_fd[2];
1213 : int stderr_fd[2];
1214 0 : int stdin_fd[2] = {-1, -1};
1215 : int rc;
1216 : struct stat st;
1217 : struct sigchld_data_s data;
1218 :
1219 : // Catch common failure conditions early
1220 0 : if (stat(op->opaque->exec, &st) != 0) {
1221 0 : rc = errno;
1222 0 : crm_info("Cannot execute '%s': %s " CRM_XS " stat rc=%d",
1223 : op->opaque->exec, pcmk_rc_str(rc), rc);
1224 0 : services__handle_exec_error(op, rc);
1225 0 : goto done;
1226 : }
1227 :
1228 0 : if (pipe(stdout_fd) < 0) {
1229 0 : rc = errno;
1230 0 : crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
1231 : op->opaque->exec, pcmk_rc_str(rc), rc);
1232 0 : services__handle_exec_error(op, rc);
1233 0 : goto done;
1234 : }
1235 :
1236 0 : if (pipe(stderr_fd) < 0) {
1237 0 : rc = errno;
1238 :
1239 0 : close_pipe(stdout_fd);
1240 :
1241 0 : crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
1242 : op->opaque->exec, pcmk_rc_str(rc), rc);
1243 0 : services__handle_exec_error(op, rc);
1244 0 : goto done;
1245 : }
1246 :
1247 0 : if (pcmk_is_set(pcmk_get_ra_caps(op->standard), pcmk_ra_cap_stdin)) {
1248 0 : if (pipe(stdin_fd) < 0) {
1249 0 : rc = errno;
1250 :
1251 0 : close_pipe(stdout_fd);
1252 0 : close_pipe(stderr_fd);
1253 :
1254 0 : crm_info("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
1255 : op->opaque->exec, pcmk_rc_str(rc), rc);
1256 0 : services__handle_exec_error(op, rc);
1257 0 : goto done;
1258 : }
1259 : }
1260 :
1261 0 : if (op->synchronous && !sigchld_setup(&data)) {
1262 0 : close_pipe(stdin_fd);
1263 0 : close_pipe(stdout_fd);
1264 0 : close_pipe(stderr_fd);
1265 0 : sigchld_cleanup(&data);
1266 0 : services__set_result(op, services__generic_error(op), PCMK_EXEC_ERROR,
1267 : "Could not manage signals for child process");
1268 0 : goto done;
1269 : }
1270 :
1271 0 : op->pid = fork();
1272 0 : switch (op->pid) {
1273 0 : case -1:
1274 0 : rc = errno;
1275 0 : close_pipe(stdin_fd);
1276 0 : close_pipe(stdout_fd);
1277 0 : close_pipe(stderr_fd);
1278 :
1279 0 : crm_info("Cannot execute '%s': %s " CRM_XS " fork rc=%d",
1280 : op->opaque->exec, pcmk_rc_str(rc), rc);
1281 0 : services__handle_exec_error(op, rc);
1282 0 : if (op->synchronous) {
1283 0 : sigchld_cleanup(&data);
1284 : }
1285 0 : goto done;
1286 : break;
1287 :
1288 0 : case 0: /* Child */
1289 0 : close(stdout_fd[0]);
1290 0 : close(stderr_fd[0]);
1291 0 : if (stdin_fd[1] >= 0) {
1292 0 : close(stdin_fd[1]);
1293 : }
1294 0 : if (STDOUT_FILENO != stdout_fd[1]) {
1295 0 : if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1296 0 : crm_warn("Can't redirect output from '%s': %s "
1297 : CRM_XS " errno=%d",
1298 : op->opaque->exec, pcmk_rc_str(errno), errno);
1299 : }
1300 0 : close(stdout_fd[1]);
1301 : }
1302 0 : if (STDERR_FILENO != stderr_fd[1]) {
1303 0 : if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
1304 0 : crm_warn("Can't redirect error output from '%s': %s "
1305 : CRM_XS " errno=%d",
1306 : op->opaque->exec, pcmk_rc_str(errno), errno);
1307 : }
1308 0 : close(stderr_fd[1]);
1309 : }
1310 0 : if ((stdin_fd[0] >= 0) &&
1311 0 : (STDIN_FILENO != stdin_fd[0])) {
1312 0 : if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1313 0 : crm_warn("Can't redirect input to '%s': %s "
1314 : CRM_XS " errno=%d",
1315 : op->opaque->exec, pcmk_rc_str(errno), errno);
1316 : }
1317 0 : close(stdin_fd[0]);
1318 : }
1319 :
1320 0 : if (op->synchronous) {
1321 0 : sigchld_cleanup(&data);
1322 : }
1323 :
1324 0 : action_launch_child(op);
1325 0 : CRM_ASSERT(0); /* action_launch_child is effectively noreturn */
1326 : }
1327 :
1328 : /* Only the parent reaches here */
1329 0 : close(stdout_fd[1]);
1330 0 : close(stderr_fd[1]);
1331 0 : if (stdin_fd[0] >= 0) {
1332 0 : close(stdin_fd[0]);
1333 : }
1334 :
1335 0 : op->opaque->stdout_fd = stdout_fd[0];
1336 0 : rc = pcmk__set_nonblocking(op->opaque->stdout_fd);
1337 0 : if (rc != pcmk_rc_ok) {
1338 0 : crm_info("Could not set '%s' output non-blocking: %s "
1339 : CRM_XS " rc=%d",
1340 : op->opaque->exec, pcmk_rc_str(rc), rc);
1341 : }
1342 :
1343 0 : op->opaque->stderr_fd = stderr_fd[0];
1344 0 : rc = pcmk__set_nonblocking(op->opaque->stderr_fd);
1345 0 : if (rc != pcmk_rc_ok) {
1346 0 : crm_info("Could not set '%s' error output non-blocking: %s "
1347 : CRM_XS " rc=%d",
1348 : op->opaque->exec, pcmk_rc_str(rc), rc);
1349 : }
1350 :
1351 0 : op->opaque->stdin_fd = stdin_fd[1];
1352 0 : if (op->opaque->stdin_fd >= 0) {
1353 : // using buffer behind non-blocking-fd here - that could be improved
1354 : // as long as no other standard uses stdin_fd assume stonith
1355 0 : rc = pcmk__set_nonblocking(op->opaque->stdin_fd);
1356 0 : if (rc != pcmk_rc_ok) {
1357 0 : crm_info("Could not set '%s' input non-blocking: %s "
1358 : CRM_XS " fd=%d,rc=%d", op->opaque->exec,
1359 : pcmk_rc_str(rc), op->opaque->stdin_fd, rc);
1360 : }
1361 0 : pipe_in_action_stdin_parameters(op);
1362 : // as long as we are handling parameters directly in here just close
1363 0 : close(op->opaque->stdin_fd);
1364 0 : op->opaque->stdin_fd = -1;
1365 : }
1366 :
1367 : // after fds are setup properly and before we plug anything into mainloop
1368 0 : if (op->opaque->fork_callback) {
1369 0 : op->opaque->fork_callback(op);
1370 : }
1371 :
1372 0 : if (op->synchronous) {
1373 0 : wait_for_sync_result(op, &data);
1374 0 : sigchld_cleanup(&data);
1375 0 : goto done;
1376 : }
1377 :
1378 0 : crm_trace("Waiting async for '%s'[%d]", op->opaque->exec, op->pid);
1379 0 : mainloop_child_add_with_flags(op->pid, op->timeout, op->id, op,
1380 0 : pcmk_is_set(op->flags, SVC_ACTION_LEAVE_GROUP)? mainloop_leave_pid_group : 0,
1381 : async_action_complete);
1382 :
1383 0 : op->opaque->stdout_gsource = mainloop_add_fd(op->id,
1384 : G_PRIORITY_LOW,
1385 0 : op->opaque->stdout_fd, op,
1386 : &stdout_callbacks);
1387 0 : op->opaque->stderr_gsource = mainloop_add_fd(op->id,
1388 : G_PRIORITY_LOW,
1389 0 : op->opaque->stderr_fd, op,
1390 : &stderr_callbacks);
1391 0 : services_add_inflight_op(op);
1392 0 : return pcmk_rc_ok;
1393 :
1394 0 : done:
1395 0 : if (op->synchronous) {
1396 0 : return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
1397 : } else {
1398 0 : return services__finalize_async_op(op);
1399 : }
1400 : }
1401 :
1402 : GList *
1403 0 : services_os_get_single_directory_list(const char *root, gboolean files, gboolean executable)
1404 : {
1405 0 : GList *list = NULL;
1406 : struct dirent **namelist;
1407 0 : int entries = 0, lpc = 0;
1408 : char buffer[PATH_MAX];
1409 :
1410 0 : entries = scandir(root, &namelist, NULL, alphasort);
1411 0 : if (entries <= 0) {
1412 0 : return list;
1413 : }
1414 :
1415 0 : for (lpc = 0; lpc < entries; lpc++) {
1416 : struct stat sb;
1417 :
1418 0 : if ('.' == namelist[lpc]->d_name[0]) {
1419 0 : free(namelist[lpc]);
1420 0 : continue;
1421 : }
1422 :
1423 0 : snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
1424 :
1425 0 : if (stat(buffer, &sb)) {
1426 0 : continue;
1427 : }
1428 :
1429 0 : if (S_ISDIR(sb.st_mode)) {
1430 0 : if (files) {
1431 0 : free(namelist[lpc]);
1432 0 : continue;
1433 : }
1434 :
1435 0 : } else if (S_ISREG(sb.st_mode)) {
1436 0 : if (files == FALSE) {
1437 0 : free(namelist[lpc]);
1438 0 : continue;
1439 :
1440 0 : } else if (executable
1441 0 : && (sb.st_mode & S_IXUSR) == 0
1442 0 : && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
1443 0 : free(namelist[lpc]);
1444 0 : continue;
1445 : }
1446 : }
1447 :
1448 0 : list = g_list_append(list, strdup(namelist[lpc]->d_name));
1449 :
1450 0 : free(namelist[lpc]);
1451 : }
1452 :
1453 0 : free(namelist);
1454 0 : return list;
1455 : }
1456 :
1457 : GList *
1458 0 : services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
1459 : {
1460 0 : GList *result = NULL;
1461 0 : char *dirs = strdup(root);
1462 0 : char *dir = NULL;
1463 :
1464 0 : if (pcmk__str_empty(dirs)) {
1465 0 : free(dirs);
1466 0 : return result;
1467 : }
1468 :
1469 0 : for (dir = strtok(dirs, ":"); dir != NULL; dir = strtok(NULL, ":")) {
1470 0 : GList *tmp = services_os_get_single_directory_list(dir, files, executable);
1471 :
1472 0 : if (tmp) {
1473 0 : result = g_list_concat(result, tmp);
1474 : }
1475 : }
1476 :
1477 0 : free(dirs);
1478 :
1479 0 : return result;
1480 : }
|