root/lib/services/services_linux.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sigchld_setup
  2. sigchld_open
  3. sigchld_close
  4. sigchld_received
  5. sigchld_cleanup
  6. sigchld_handler
  7. sigchld_setup
  8. sigchld_open
  9. sigchld_close
  10. sigchld_received
  11. sigchld_cleanup
  12. close_pipe
  13. svc_read_output
  14. dispatch_stdout
  15. dispatch_stderr
  16. pipe_out_done
  17. pipe_err_done
  18. set_ocf_env
  19. set_ocf_env_with_prefix
  20. set_alert_env
  21. add_action_env_vars
  22. pipe_in_single_parameter
  23. pipe_in_action_stdin_parameters
  24. recurring_action_timer
  25. services__finalize_async_op
  26. close_op_input
  27. finish_op_output
  28. log_op_output
  29. parse_exit_reason_from_stderr
  30. async_action_complete
  31. services__generic_error
  32. services__not_installed_error
  33. services__authorization_error
  34. services__configuration_error
  35. services__handle_exec_error
  36. exit_child
  37. action_launch_child
  38. wait_for_sync_result
  39. services__execute_file
  40. services_os_get_single_directory_list
  41. services_os_get_directory_list

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

/* [previous][next][first][last][top][bottom][index][help] */