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