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

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