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. operation_finalize
  26. close_op_input
  27. finish_op_output
  28. log_op_output
  29. operation_finished
  30. services_handle_exec_error
  31. action_launch_child
  32. action_synced_wait
  33. services_os_action_execute
  34. services_os_get_directory_list
  35. resources_os_list_ocf_providers
  36. resources_os_list_ocf_agents
  37. services__ocf_agent_exists

   1 /*
   2  * Copyright 2010-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <sys/types.h>
  17 #include <sys/stat.h>
  18 #include <sys/wait.h>
  19 #include <errno.h>
  20 #include <unistd.h>
  21 #include <dirent.h>
  22 #include <grp.h>
  23 #include <string.h>
  24 #include <sys/time.h>
  25 #include <sys/resource.h>
  26 
  27 #include "crm/crm.h"
  28 #include "crm/common/mainloop.h"
  29 #include "crm/services.h"
  30 
  31 #include "services_private.h"
  32 
  33 static void close_pipe(int fildes[]);
  34 
  35 /* We have two alternative ways of handling SIGCHLD when synchronously waiting
  36  * for spawned processes to complete. Both rely on polling a file descriptor to
  37  * discover SIGCHLD events.
  38  *
  39  * If sys/signalfd.h is available (e.g. on Linux), we call signalfd() to
  40  * generate the file descriptor. Otherwise, we use the "self-pipe trick"
  41  * (opening a pipe and writing a byte to it when SIGCHLD is received).
  42  */
  43 #ifdef HAVE_SYS_SIGNALFD_H
  44 
  45 // signalfd() implementation
  46 
  47 #include <sys/signalfd.h>
  48 
  49 // Everything needed to manage SIGCHLD handling
  50 struct sigchld_data_s {
  51     sigset_t mask;      // Signals to block now (including SIGCHLD)
  52     sigset_t old_mask;  // Previous set of blocked signals
  53 };
  54 
  55 // Initialize SIGCHLD data and prepare for use
  56 static bool
  57 sigchld_setup(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59     sigemptyset(&(data->mask));
  60     sigaddset(&(data->mask), SIGCHLD);
  61 
  62     sigemptyset(&(data->old_mask));
  63 
  64     // Block SIGCHLD (saving previous set of blocked signals to restore later)
  65     if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) {
  66         crm_err("Wait for child process completion failed: %s "
  67                 CRM_XS " source=sigprocmask", pcmk_strerror(errno));
  68         return false;
  69     }
  70     return true;
  71 }
  72 
  73 // Get a file descriptor suitable for polling for SIGCHLD events
  74 static int
  75 sigchld_open(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     int fd;
  78 
  79     CRM_CHECK(data != NULL, return -1);
  80 
  81     fd = signalfd(-1, &(data->mask), SFD_NONBLOCK);
  82     if (fd < 0) {
  83         crm_err("Wait for child process completion failed: %s "
  84                 CRM_XS " source=signalfd", pcmk_strerror(errno));
  85     }
  86     return fd;
  87 }
  88 
  89 // Close a file descriptor returned by sigchld_open()
  90 static void
  91 sigchld_close(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93     if (fd > 0) {
  94         close(fd);
  95     }
  96 }
  97 
  98 // Return true if SIGCHLD was received from polled fd
  99 static bool
 100 sigchld_received(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     struct signalfd_siginfo fdsi;
 103     ssize_t s;
 104 
 105     if (fd < 0) {
 106         return false;
 107     }
 108     s = read(fd, &fdsi, sizeof(struct signalfd_siginfo));
 109     if (s != sizeof(struct signalfd_siginfo)) {
 110         crm_err("Wait for child process completion failed: %s "
 111                 CRM_XS " source=read", pcmk_strerror(errno));
 112 
 113     } else if (fdsi.ssi_signo == SIGCHLD) {
 114         return true;
 115     }
 116     return false;
 117 }
 118 
 119 // Do anything needed after done waiting for SIGCHLD
 120 static void
 121 sigchld_cleanup(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123     // Restore the original set of blocked signals
 124     if ((sigismember(&(data->old_mask), SIGCHLD) == 0)
 125         && (sigprocmask(SIG_UNBLOCK, &(data->mask), NULL) < 0)) {
 126         crm_warn("Could not clean up after child process completion: %s",
 127                  pcmk_strerror(errno));
 128     }
 129 }
 130 
 131 #else // HAVE_SYS_SIGNALFD_H not defined
 132 
 133 // Self-pipe implementation (see above for function descriptions)
 134 
 135 struct sigchld_data_s {
 136     int pipe_fd[2];             // Pipe file descriptors
 137     struct sigaction sa;        // Signal handling info (with SIGCHLD)
 138     struct sigaction old_sa;    // Previous signal handling info
 139 };
 140 
 141 // We need a global to use in the signal handler
 142 volatile struct sigchld_data_s *last_sigchld_data = NULL;
 143 
 144 static void
 145 sigchld_handler()
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147     // We received a SIGCHLD, so trigger pipe polling
 148     if ((last_sigchld_data != NULL)
 149         && (last_sigchld_data->pipe_fd[1] >= 0)
 150         && (write(last_sigchld_data->pipe_fd[1], "", 1) == -1)) {
 151         crm_err("Wait for child process completion failed: %s "
 152                 CRM_XS " source=write", pcmk_strerror(errno));
 153     }
 154 }
 155 
 156 static bool
 157 sigchld_setup(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159     int rc;
 160 
 161     data->pipe_fd[0] = data->pipe_fd[1] = -1;
 162 
 163     if (pipe(data->pipe_fd) == -1) {
 164         crm_err("Wait for child process completion failed: %s "
 165                 CRM_XS " source=pipe", pcmk_strerror(errno));
 166         return false;
 167     }
 168 
 169     rc = pcmk__set_nonblocking(data->pipe_fd[0]);
 170     if (rc != pcmk_rc_ok) {
 171         crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
 172                  pcmk_rc_str(rc), rc);
 173     }
 174     rc = pcmk__set_nonblocking(data->pipe_fd[1]);
 175     if (rc != pcmk_rc_ok) {
 176         crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
 177                  pcmk_rc_str(rc), rc);
 178     }
 179 
 180     // Set SIGCHLD handler
 181     data->sa.sa_handler = sigchld_handler;
 182     data->sa.sa_flags = 0;
 183     sigemptyset(&(data->sa.sa_mask));
 184     if (sigaction(SIGCHLD, &(data->sa), &(data->old_sa)) < 0) {
 185         crm_err("Wait for child process completion failed: %s "
 186                 CRM_XS " source=sigaction", pcmk_strerror(errno));
 187     }
 188 
 189     // Remember data for use in signal handler
 190     last_sigchld_data = data;
 191     return true;
 192 }
 193 
 194 static int
 195 sigchld_open(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197     CRM_CHECK(data != NULL, return -1);
 198     return data->pipe_fd[0];
 199 }
 200 
 201 static void
 202 sigchld_close(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204     // Pipe will be closed in sigchld_cleanup()
 205     return;
 206 }
 207 
 208 static bool
 209 sigchld_received(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 210 {
 211     char ch;
 212 
 213     if (fd < 0) {
 214         return false;
 215     }
 216 
 217     // Clear out the self-pipe
 218     while (read(fd, &ch, 1) == 1) /*omit*/;
 219     return true;
 220 }
 221 
 222 static void
 223 sigchld_cleanup(struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225     // Restore the previous SIGCHLD handler
 226     if (sigaction(SIGCHLD, &(data->old_sa), NULL) < 0) {
 227         crm_warn("Could not clean up after child process completion: %s",
 228                  pcmk_strerror(errno));
 229     }
 230 
 231     close_pipe(data->pipe_fd);
 232 }
 233 
 234 #endif
 235 
 236 /*!
 237  * \internal
 238  * \brief Close the two file descriptors of a pipe
 239  *
 240  * \param[in] fildes  Array of file descriptors opened by pipe()
 241  */
 242 static void
 243 close_pipe(int fildes[])
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245     if (fildes[0] >= 0) {
 246         close(fildes[0]);
 247         fildes[0] = -1;
 248     }
 249     if (fildes[1] >= 0) {
 250         close(fildes[1]);
 251         fildes[1] = -1;
 252     }
 253 }
 254 
 255 static gboolean
 256 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258     char *data = NULL;
 259     int rc = 0, len = 0;
 260     char buf[500];
 261     static const size_t buf_read_len = sizeof(buf) - 1;
 262 
 263 
 264     if (fd < 0) {
 265         crm_trace("No fd for %s", op->id);
 266         return FALSE;
 267     }
 268 
 269     if (is_stderr && op->stderr_data) {
 270         len = strlen(op->stderr_data);
 271         data = op->stderr_data;
 272         crm_trace("Reading %s stderr into offset %d", op->id, len);
 273 
 274     } else if (is_stderr == FALSE && op->stdout_data) {
 275         len = strlen(op->stdout_data);
 276         data = op->stdout_data;
 277         crm_trace("Reading %s stdout into offset %d", op->id, len);
 278 
 279     } else {
 280         crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
 281     }
 282 
 283     do {
 284         rc = read(fd, buf, buf_read_len);
 285         if (rc > 0) {
 286             buf[rc] = 0;
 287             crm_trace("Got %d chars: %.80s", rc, buf);
 288             data = pcmk__realloc(data, len + rc + 1);
 289             len += sprintf(data + len, "%s", buf);
 290 
 291         } else if (errno != EINTR) {
 292             /* error or EOF
 293              * Cleanup happens in pipe_done()
 294              */
 295             rc = FALSE;
 296             break;
 297         }
 298 
 299     } while (rc == buf_read_len || rc < 0);
 300 
 301     if (is_stderr) {
 302         op->stderr_data = data;
 303     } else {
 304         op->stdout_data = data;
 305     }
 306 
 307     return rc;
 308 }
 309 
 310 static int
 311 dispatch_stdout(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 312 {
 313     svc_action_t *op = (svc_action_t *) userdata;
 314 
 315     return svc_read_output(op->opaque->stdout_fd, op, FALSE);
 316 }
 317 
 318 static int
 319 dispatch_stderr(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321     svc_action_t *op = (svc_action_t *) userdata;
 322 
 323     return svc_read_output(op->opaque->stderr_fd, op, TRUE);
 324 }
 325 
 326 static void
 327 pipe_out_done(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329     svc_action_t *op = (svc_action_t *) user_data;
 330 
 331     crm_trace("%p", op);
 332 
 333     op->opaque->stdout_gsource = NULL;
 334     if (op->opaque->stdout_fd > STDOUT_FILENO) {
 335         close(op->opaque->stdout_fd);
 336     }
 337     op->opaque->stdout_fd = -1;
 338 }
 339 
 340 static void
 341 pipe_err_done(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 342 {
 343     svc_action_t *op = (svc_action_t *) user_data;
 344 
 345     op->opaque->stderr_gsource = NULL;
 346     if (op->opaque->stderr_fd > STDERR_FILENO) {
 347         close(op->opaque->stderr_fd);
 348     }
 349     op->opaque->stderr_fd = -1;
 350 }
 351 
 352 static struct mainloop_fd_callbacks stdout_callbacks = {
 353     .dispatch = dispatch_stdout,
 354     .destroy = pipe_out_done,
 355 };
 356 
 357 static struct mainloop_fd_callbacks stderr_callbacks = {
 358     .dispatch = dispatch_stderr,
 359     .destroy = pipe_err_done,
 360 };
 361 
 362 static void
 363 set_ocf_env(const char *key, const char *value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 364 {
 365     if (setenv(key, value, 1) != 0) {
 366         crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
 367     }
 368 }
 369 
 370 static void
 371 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373     char buffer[500];
 374 
 375     snprintf(buffer, sizeof(buffer), strcmp(key, "OCF_CHECK_LEVEL") != 0 ? "OCF_RESKEY_%s" : "%s", (char *)key);
 376     set_ocf_env(buffer, value, user_data);
 377 }
 378 
 379 static void
 380 set_alert_env(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 381 {
 382     int rc;
 383 
 384     if (value != NULL) {
 385         rc = setenv(key, value, 1);
 386     } else {
 387         rc = unsetenv(key);
 388     }
 389 
 390     if (rc < 0) {
 391         crm_perror(LOG_ERR, "setenv %s=%s",
 392                   (char*)key, (value? (char*)value : ""));
 393     } else {
 394         crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
 395     }
 396 }
 397 
 398 /*!
 399  * \internal
 400  * \brief Add environment variables suitable for an action
 401  *
 402  * \param[in] op  Action to use
 403  */
 404 static void
 405 add_action_env_vars(const svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 406 {
 407     void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
 408     if (op->agent == NULL) {
 409         env_setter = set_alert_env;  /* we deal with alert handler */
 410 
 411     } else if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
 412         env_setter = set_ocf_env_with_prefix;
 413     }
 414 
 415     if (env_setter != NULL && op->params != NULL) {
 416         g_hash_table_foreach(op->params, env_setter, NULL);
 417     }
 418 
 419     if (env_setter == NULL || env_setter == set_alert_env) {
 420         return;
 421     }
 422 
 423     set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
 424     set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
 425     set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
 426     set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
 427 
 428     if (op->rsc) {
 429         set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
 430     }
 431 
 432     if (op->agent != NULL) {
 433         set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
 434     }
 435 
 436     /* Notes: this is not added to specification yet. Sept 10,2004 */
 437     if (op->provider != NULL) {
 438         set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
 439     }
 440 }
 441 
 442 static void
 443 pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445     svc_action_t *op = user_data;
 446     char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value);
 447     int ret, total = 0, len = strlen(buffer);
 448 
 449     do {
 450         errno = 0;
 451         ret = write(op->opaque->stdin_fd, buffer + total, len - total);
 452         if (ret > 0) {
 453             total += ret;
 454         }
 455 
 456     } while ((errno == EINTR) && (total < len));
 457     free(buffer);
 458 }
 459 
 460 /*!
 461  * \internal
 462  * \brief Pipe parameters in via stdin for action
 463  *
 464  * \param[in] op  Action to use
 465  */
 466 static void
 467 pipe_in_action_stdin_parameters(const svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 468 {
 469     crm_debug("sending args");
 470     if (op->params) {
 471         g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op);
 472     }
 473 }
 474 
 475 gboolean
 476 recurring_action_timer(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478     svc_action_t *op = data;
 479 
 480     crm_debug("Scheduling another invocation of %s", op->id);
 481 
 482     /* Clean out the old result */
 483     free(op->stdout_data);
 484     op->stdout_data = NULL;
 485     free(op->stderr_data);
 486     op->stderr_data = NULL;
 487     op->opaque->repeat_timer = 0;
 488 
 489     services_action_async(op, NULL);
 490     return FALSE;
 491 }
 492 
 493 /* Returns FALSE if 'op' should be free'd by the caller */
 494 gboolean
 495 operation_finalize(svc_action_t * op)
     /* [previous][next][first][last][top][bottom][index][help] */
 496 {
 497     int recurring = 0;
 498 
 499     if (op->interval_ms) {
 500         if (op->cancel) {
 501             op->status = PCMK_LRM_OP_CANCELLED;
 502             cancel_recurring_action(op);
 503         } else {
 504             recurring = 1;
 505             op->opaque->repeat_timer = g_timeout_add(op->interval_ms,
 506                                                      recurring_action_timer, (void *)op);
 507         }
 508     }
 509 
 510     if (op->opaque->callback) {
 511         op->opaque->callback(op);
 512     }
 513 
 514     op->pid = 0;
 515 
 516     services_untrack_op(op);
 517 
 518     if (!recurring && op->synchronous == FALSE) {
 519         /*
 520          * If this is a recurring action, do not free explicitly.
 521          * It will get freed whenever the action gets cancelled.
 522          */
 523         services_action_free(op);
 524         return TRUE;
 525     }
 526 
 527     services_action_cleanup(op);
 528     return FALSE;
 529 }
 530 
 531 static void
 532 close_op_input(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534     if (op->opaque->stdin_fd >= 0) {
 535         close(op->opaque->stdin_fd);
 536     }
 537 }
 538 
 539 static void
 540 finish_op_output(svc_action_t *op, bool is_stderr)
     /* [previous][next][first][last][top][bottom][index][help] */
 541 {
 542     mainloop_io_t **source;
 543     int fd;
 544 
 545     if (is_stderr) {
 546         source = &(op->opaque->stderr_gsource);
 547         fd = op->opaque->stderr_fd;
 548     } else {
 549         source = &(op->opaque->stdout_gsource);
 550         fd = op->opaque->stdout_fd;
 551     }
 552 
 553     if (op->synchronous || *source) {
 554         crm_trace("Finish reading %s[%d] %s",
 555                   op->id, op->pid, (is_stderr? "stdout" : "stderr"));
 556         svc_read_output(fd, op, is_stderr);
 557         if (op->synchronous) {
 558             close(fd);
 559         } else {
 560             mainloop_del_fd(*source);
 561             *source = NULL;
 562         }
 563     }
 564 }
 565 
 566 // Log an operation's stdout and stderr
 567 static void
 568 log_op_output(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 569 {
 570     char *prefix = crm_strdup_printf("%s[%d] error output", op->id, op->pid);
 571 
 572     crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
 573     strcpy(prefix + strlen(prefix) - strlen("error output"), "output");
 574     crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
 575     free(prefix);
 576 }
 577 
 578 static void
 579 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 580 {
 581     svc_action_t *op = mainloop_child_userdata(p);
 582 
 583     mainloop_clear_child_userdata(p);
 584     CRM_ASSERT(op->pid == pid);
 585 
 586     /* Depending on the priority the mainloop gives the stdout and stderr
 587      * file descriptors, this function could be called before everything has
 588      * been read from them, so force a final read now.
 589      */
 590     finish_op_output(op, true);
 591     finish_op_output(op, false);
 592 
 593     close_op_input(op);
 594 
 595     if (signo == 0) {
 596         crm_debug("%s[%d] exited with status %d", op->id, op->pid, exitcode);
 597         op->status = PCMK_LRM_OP_DONE;
 598         op->rc = exitcode;
 599 
 600     } else if (mainloop_child_timeout(p)) {
 601         crm_warn("%s[%d] timed out after %dms", op->id, op->pid, op->timeout);
 602         op->status = PCMK_LRM_OP_TIMEOUT;
 603         op->rc = PCMK_OCF_TIMEOUT;
 604 
 605     } else if (op->cancel) {
 606         /* If an in-flight recurring operation was killed because it was
 607          * cancelled, don't treat that as a failure.
 608          */
 609         crm_info("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
 610                  op->id, op->pid, strsignal(signo), signo);
 611         op->status = PCMK_LRM_OP_CANCELLED;
 612         op->rc = PCMK_OCF_OK;
 613 
 614     } else {
 615         crm_warn("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
 616                  op->id, op->pid, strsignal(signo), signo);
 617         op->status = PCMK_LRM_OP_ERROR;
 618         op->rc = PCMK_OCF_SIGNAL;
 619     }
 620 
 621     log_op_output(op);
 622     operation_finalize(op);
 623 }
 624 
 625 /*!
 626  * \internal
 627  * \brief Set operation rc and status per errno from stat(), fork() or execvp()
 628  *
 629  * \param[in,out] op     Operation to set rc and status for
 630  * \param[in]     error  Value of errno after system call
 631  *
 632  * \return void
 633  */
 634 static void
 635 services_handle_exec_error(svc_action_t * op, int error)
     /* [previous][next][first][last][top][bottom][index][help] */
 636 {
 637     int rc_not_installed, rc_insufficient_priv, rc_exec_error;
 638 
 639     /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
 640     if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)
 641         && pcmk__str_eq(op->action, "status", pcmk__str_casei)) {
 642 
 643         rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
 644         rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
 645         rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
 646 
 647 #if SUPPORT_NAGIOS
 648     } else if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
 649         rc_not_installed = NAGIOS_NOT_INSTALLED;
 650         rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
 651         rc_exec_error = PCMK_OCF_EXEC_ERROR;
 652 #endif
 653 
 654     } else {
 655         rc_not_installed = PCMK_OCF_NOT_INSTALLED;
 656         rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
 657         rc_exec_error = PCMK_OCF_EXEC_ERROR;
 658     }
 659 
 660     switch (error) {   /* see execve(2), stat(2) and fork(2) */
 661         case ENOENT:   /* No such file or directory */
 662         case EISDIR:   /* Is a directory */
 663         case ENOTDIR:  /* Path component is not a directory */
 664         case EINVAL:   /* Invalid executable format */
 665         case ENOEXEC:  /* Invalid executable format */
 666             op->rc = rc_not_installed;
 667             op->status = PCMK_LRM_OP_NOT_INSTALLED;
 668             break;
 669         case EACCES:   /* permission denied (various errors) */
 670         case EPERM:    /* permission denied (various errors) */
 671             op->rc = rc_insufficient_priv;
 672             op->status = PCMK_LRM_OP_ERROR;
 673             break;
 674         default:
 675             op->rc = rc_exec_error;
 676             op->status = PCMK_LRM_OP_ERROR;
 677     }
 678 }
 679 
 680 static void
 681 action_launch_child(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 682 {
 683     /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
 684      * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
 685      * We do not want this to be inherited by the child process. By resetting this the signal
 686      * to the default behavior, we avoid some potential odd problems that occur during OCF
 687      * scripts when SIGPIPE is ignored by the environment. */
 688     signal(SIGPIPE, SIG_DFL);
 689 
 690 #if defined(HAVE_SCHED_SETSCHEDULER)
 691     if (sched_getscheduler(0) != SCHED_OTHER) {
 692         struct sched_param sp;
 693 
 694         memset(&sp, 0, sizeof(sp));
 695         sp.sched_priority = 0;
 696 
 697         if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
 698             crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
 699         }
 700     }
 701 #endif
 702     if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
 703         crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
 704     }
 705 
 706     /* Man: The call setpgrp() is equivalent to setpgid(0,0)
 707      * _and_ compiles on BSD variants too
 708      * need to investigate if it works the same too.
 709      */
 710     setpgid(0, 0);
 711 
 712     pcmk__close_fds_in_child(false);
 713 
 714 #if SUPPORT_CIBSECRETS
 715     if (pcmk__substitute_secrets(op->rsc, op->params) != pcmk_rc_ok) {
 716         /* replacing secrets failed! */
 717         if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
 718             /* don't fail on stop! */
 719             crm_info("proceeding with the stop operation for %s", op->rsc);
 720 
 721         } else {
 722             crm_err("failed to get secrets for %s, "
 723                     "considering resource not configured", op->rsc);
 724             _exit(PCMK_OCF_NOT_CONFIGURED);
 725         }
 726     }
 727 #endif
 728 
 729     add_action_env_vars(op);
 730 
 731     /* Become the desired user */
 732     if (op->opaque->uid && (geteuid() == 0)) {
 733 
 734         // If requested, set effective group
 735         if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
 736             crm_perror(LOG_ERR, "Could not set child group to %d", op->opaque->gid);
 737             _exit(PCMK_OCF_NOT_CONFIGURED);
 738         }
 739 
 740         // Erase supplementary group list
 741         // (We could do initgroups() if we kept a copy of the username)
 742         if (setgroups(0, NULL) < 0) {
 743             crm_perror(LOG_ERR, "Could not set child groups");
 744             _exit(PCMK_OCF_NOT_CONFIGURED);
 745         }
 746 
 747         // Set effective user
 748         if (setuid(op->opaque->uid) < 0) {
 749             crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
 750             _exit(PCMK_OCF_NOT_CONFIGURED);
 751         }
 752     }
 753 
 754     /* execute the RA */
 755     execvp(op->opaque->exec, op->opaque->args);
 756 
 757     /* Most cases should have been already handled by stat() */
 758     services_handle_exec_error(op, errno);
 759 
 760     _exit(op->rc);
 761 }
 762 
 763 static void
 764 action_synced_wait(svc_action_t *op, struct sigchld_data_s *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 765 {
 766     int status = 0;
 767     int timeout = op->timeout;
 768     time_t start = -1;
 769     struct pollfd fds[3];
 770     int wait_rc = 0;
 771 
 772     fds[0].fd = op->opaque->stdout_fd;
 773     fds[0].events = POLLIN;
 774     fds[0].revents = 0;
 775 
 776     fds[1].fd = op->opaque->stderr_fd;
 777     fds[1].events = POLLIN;
 778     fds[1].revents = 0;
 779 
 780     fds[2].fd = sigchld_open(data);
 781     fds[2].events = POLLIN;
 782     fds[2].revents = 0;
 783 
 784     crm_trace("Waiting for %s[%d]", op->id, op->pid);
 785     start = time(NULL);
 786     do {
 787         int poll_rc = poll(fds, 3, timeout);
 788 
 789         if (poll_rc > 0) {
 790             if (fds[0].revents & POLLIN) {
 791                 svc_read_output(op->opaque->stdout_fd, op, FALSE);
 792             }
 793 
 794             if (fds[1].revents & POLLIN) {
 795                 svc_read_output(op->opaque->stderr_fd, op, TRUE);
 796             }
 797 
 798             if ((fds[2].revents & POLLIN) && sigchld_received(fds[2].fd)) {
 799                 wait_rc = waitpid(op->pid, &status, WNOHANG);
 800 
 801                 if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) {
 802                     // Child process exited or doesn't exist
 803                     break;
 804 
 805                 } else if (wait_rc < 0) {
 806                     crm_warn("Wait for completion of %s[%d] failed: %s "
 807                              CRM_XS " source=waitpid",
 808                              op->id, op->pid, pcmk_strerror(errno));
 809                     wait_rc = 0; // Act as if process is still running
 810                 }
 811             }
 812 
 813         } else if (poll_rc == 0) {
 814             // Poll timed out with no descriptors ready
 815             timeout = 0;
 816             break;
 817 
 818         } else if ((poll_rc < 0) && (errno != EINTR)) {
 819             crm_err("Wait for completion of %s[%d] failed: %s "
 820                     CRM_XS " source=poll",
 821                     op->id, op->pid, pcmk_strerror(errno));
 822             break;
 823         }
 824 
 825         timeout = op->timeout - (time(NULL) - start) * 1000;
 826 
 827     } while ((op->timeout < 0 || timeout > 0));
 828 
 829     crm_trace("Stopped waiting for %s[%d]", op->id, op->pid);
 830     if (wait_rc <= 0) {
 831         op->rc = PCMK_OCF_UNKNOWN_ERROR;
 832 
 833         if (op->timeout > 0 && timeout <= 0) {
 834             op->status = PCMK_LRM_OP_TIMEOUT;
 835             crm_warn("%s[%d] timed out after %dms",
 836                      op->id, op->pid, op->timeout);
 837 
 838         } else {
 839             op->status = PCMK_LRM_OP_ERROR;
 840         }
 841 
 842         /* If only child hasn't been successfully waited for, yet.
 843            This is to limit killing wrong target a bit more. */
 844         if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
 845             if (kill(op->pid, SIGKILL)) {
 846                 crm_warn("Could not kill rogue child %s[%d]: %s",
 847                          op->id, op->pid, pcmk_strerror(errno));
 848             }
 849             /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
 850             while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
 851         }
 852 
 853     } else if (WIFEXITED(status)) {
 854         op->status = PCMK_LRM_OP_DONE;
 855         op->rc = WEXITSTATUS(status);
 856         crm_info("%s[%d] exited with status %d", op->id, op->pid, op->rc);
 857 
 858     } else if (WIFSIGNALED(status)) {
 859         int signo = WTERMSIG(status);
 860 
 861         op->status = PCMK_LRM_OP_ERROR;
 862         crm_err("%s[%d] terminated with signal: %s " CRM_XS " (%d)",
 863                 op->id, op->pid, strsignal(signo), signo);
 864     }
 865 #ifdef WCOREDUMP
 866     if (WCOREDUMP(status)) {
 867         crm_err("%s[%d] dumped core", op->id, op->pid);
 868     }
 869 #endif
 870 
 871     finish_op_output(op, true);
 872     finish_op_output(op, false);
 873     close_op_input(op);
 874     sigchld_close(fds[2].fd);
 875 }
 876 
 877 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
 878 /* For a synchronous 'op', returns FALSE if 'op' fails */
 879 gboolean
 880 services_os_action_execute(svc_action_t * op)
     /* [previous][next][first][last][top][bottom][index][help] */
 881 {
 882     int stdout_fd[2];
 883     int stderr_fd[2];
 884     int stdin_fd[2] = {-1, -1};
 885     int rc;
 886     struct stat st;
 887     struct sigchld_data_s data;
 888 
 889     /* Fail fast */
 890     if(stat(op->opaque->exec, &st) != 0) {
 891         rc = errno;
 892         crm_warn("Cannot execute '%s': %s " CRM_XS " stat rc=%d",
 893                  op->opaque->exec, pcmk_strerror(rc), rc);
 894         services_handle_exec_error(op, rc);
 895         if (!op->synchronous) {
 896             return operation_finalize(op);
 897         }
 898         return FALSE;
 899     }
 900 
 901     if (pipe(stdout_fd) < 0) {
 902         rc = errno;
 903         crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
 904                 op->opaque->exec, pcmk_strerror(rc), rc);
 905         services_handle_exec_error(op, rc);
 906         if (!op->synchronous) {
 907             return operation_finalize(op);
 908         }
 909         return FALSE;
 910     }
 911 
 912     if (pipe(stderr_fd) < 0) {
 913         rc = errno;
 914 
 915         close_pipe(stdout_fd);
 916 
 917         crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
 918                 op->opaque->exec, pcmk_strerror(rc), rc);
 919         services_handle_exec_error(op, rc);
 920         if (!op->synchronous) {
 921             return operation_finalize(op);
 922         }
 923         return FALSE;
 924     }
 925 
 926     if (pcmk_is_set(pcmk_get_ra_caps(op->standard), pcmk_ra_cap_stdin)) {
 927         if (pipe(stdin_fd) < 0) {
 928             rc = errno;
 929 
 930             close_pipe(stdout_fd);
 931             close_pipe(stderr_fd);
 932 
 933             crm_err("Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
 934                     op->opaque->exec, pcmk_strerror(rc), rc);
 935             services_handle_exec_error(op, rc);
 936             if (!op->synchronous) {
 937                 return operation_finalize(op);
 938             }
 939             return FALSE;
 940         }
 941     }
 942 
 943     if (op->synchronous && !sigchld_setup(&data)) {
 944         close_pipe(stdin_fd);
 945         close_pipe(stdout_fd);
 946         close_pipe(stderr_fd);
 947         sigchld_cleanup(&data);
 948         return FALSE;
 949     }
 950 
 951     op->pid = fork();
 952     switch (op->pid) {
 953         case -1:
 954             rc = errno;
 955             close_pipe(stdin_fd);
 956             close_pipe(stdout_fd);
 957             close_pipe(stderr_fd);
 958 
 959             crm_err("Cannot execute '%s': %s " CRM_XS " fork rc=%d",
 960                     op->opaque->exec, pcmk_strerror(rc), rc);
 961             services_handle_exec_error(op, rc);
 962             if (!op->synchronous) {
 963                 return operation_finalize(op);
 964             }
 965 
 966             sigchld_cleanup(&data);
 967             return FALSE;
 968 
 969         case 0:                /* Child */
 970             close(stdout_fd[0]);
 971             close(stderr_fd[0]);
 972             if (stdin_fd[1] >= 0) {
 973                 close(stdin_fd[1]);
 974             }
 975             if (STDOUT_FILENO != stdout_fd[1]) {
 976                 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
 977                     crm_warn("Can't redirect output from '%s': %s "
 978                              CRM_XS " errno=%d",
 979                              op->opaque->exec, pcmk_strerror(errno), errno);
 980                 }
 981                 close(stdout_fd[1]);
 982             }
 983             if (STDERR_FILENO != stderr_fd[1]) {
 984                 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
 985                     crm_warn("Can't redirect error output from '%s': %s "
 986                              CRM_XS " errno=%d",
 987                              op->opaque->exec, pcmk_strerror(errno), errno);
 988                 }
 989                 close(stderr_fd[1]);
 990             }
 991             if ((stdin_fd[0] >= 0) &&
 992                 (STDIN_FILENO != stdin_fd[0])) {
 993                 if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
 994                     crm_warn("Can't redirect input to '%s': %s "
 995                              CRM_XS " errno=%d",
 996                              op->opaque->exec, pcmk_strerror(errno), errno);
 997                 }
 998                 close(stdin_fd[0]);
 999             }
1000 
1001             if (op->synchronous) {
1002                 sigchld_cleanup(&data);
1003             }
1004 
1005             action_launch_child(op);
1006             CRM_ASSERT(0);  /* action_launch_child is effectively noreturn */
1007     }
1008 
1009     /* Only the parent reaches here */
1010     close(stdout_fd[1]);
1011     close(stderr_fd[1]);
1012     if (stdin_fd[0] >= 0) {
1013         close(stdin_fd[0]);
1014     }
1015 
1016     op->opaque->stdout_fd = stdout_fd[0];
1017     rc = pcmk__set_nonblocking(op->opaque->stdout_fd);
1018     if (rc != pcmk_rc_ok) {
1019         crm_warn("Could not set '%s' output non-blocking: %s "
1020                  CRM_XS " rc=%d",
1021                  op->opaque->exec, pcmk_rc_str(rc), rc);
1022     }
1023 
1024     op->opaque->stderr_fd = stderr_fd[0];
1025     rc = pcmk__set_nonblocking(op->opaque->stderr_fd);
1026     if (rc != pcmk_rc_ok) {
1027         crm_warn("Could not set '%s' error output non-blocking: %s "
1028                  CRM_XS " rc=%d",
1029                  op->opaque->exec, pcmk_rc_str(rc), rc);
1030     }
1031 
1032     op->opaque->stdin_fd = stdin_fd[1];
1033     if (op->opaque->stdin_fd >= 0) {
1034         // using buffer behind non-blocking-fd here - that could be improved
1035         // as long as no other standard uses stdin_fd assume stonith
1036         rc = pcmk__set_nonblocking(op->opaque->stdin_fd);
1037         if (rc != pcmk_rc_ok) {
1038             crm_warn("Could not set '%s' input non-blocking: %s "
1039                     CRM_XS " fd=%d,rc=%d", op->opaque->exec,
1040                     pcmk_rc_str(rc), op->opaque->stdin_fd, rc);
1041         }
1042         pipe_in_action_stdin_parameters(op);
1043         // as long as we are handling parameters directly in here just close
1044         close(op->opaque->stdin_fd);
1045         op->opaque->stdin_fd = -1;
1046     }
1047 
1048     // after fds are setup properly and before we plug anything into mainloop
1049     if (op->opaque->fork_callback) {
1050         op->opaque->fork_callback(op);
1051     }
1052 
1053     if (op->synchronous) {
1054         action_synced_wait(op, &data);
1055         sigchld_cleanup(&data);
1056     } else {
1057         crm_trace("Waiting async for '%s'[%d]", op->opaque->exec, op->pid);
1058         mainloop_child_add_with_flags(op->pid,
1059                                       op->timeout,
1060                                       op->id,
1061                                       op,
1062                                       (op->flags & SVC_ACTION_LEAVE_GROUP) ? mainloop_leave_pid_group : 0,
1063                                       operation_finished);
1064 
1065 
1066         op->opaque->stdout_gsource = mainloop_add_fd(op->id,
1067                                                      G_PRIORITY_LOW,
1068                                                      op->opaque->stdout_fd, op, &stdout_callbacks);
1069 
1070         op->opaque->stderr_gsource = mainloop_add_fd(op->id,
1071                                                      G_PRIORITY_LOW,
1072                                                      op->opaque->stderr_fd, op, &stderr_callbacks);
1073 
1074         services_add_inflight_op(op);
1075     }
1076 
1077     return TRUE;
1078 }
1079 
1080 GList *
1081 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
     /* [previous][next][first][last][top][bottom][index][help] */
1082 {
1083     GList *list = NULL;
1084     struct dirent **namelist;
1085     int entries = 0, lpc = 0;
1086     char buffer[PATH_MAX];
1087 
1088     entries = scandir(root, &namelist, NULL, alphasort);
1089     if (entries <= 0) {
1090         return list;
1091     }
1092 
1093     for (lpc = 0; lpc < entries; lpc++) {
1094         struct stat sb;
1095 
1096         if ('.' == namelist[lpc]->d_name[0]) {
1097             free(namelist[lpc]);
1098             continue;
1099         }
1100 
1101         snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
1102 
1103         if (stat(buffer, &sb)) {
1104             continue;
1105         }
1106 
1107         if (S_ISDIR(sb.st_mode)) {
1108             if (files) {
1109                 free(namelist[lpc]);
1110                 continue;
1111             }
1112 
1113         } else if (S_ISREG(sb.st_mode)) {
1114             if (files == FALSE) {
1115                 free(namelist[lpc]);
1116                 continue;
1117 
1118             } else if (executable
1119                        && (sb.st_mode & S_IXUSR) == 0
1120                        && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
1121                 free(namelist[lpc]);
1122                 continue;
1123             }
1124         }
1125 
1126         list = g_list_append(list, strdup(namelist[lpc]->d_name));
1127 
1128         free(namelist[lpc]);
1129     }
1130 
1131     free(namelist);
1132     return list;
1133 }
1134 
1135 GList *
1136 resources_os_list_ocf_providers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1137 {
1138     return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
1139 }
1140 
1141 GList *
1142 resources_os_list_ocf_agents(const char *provider)
     /* [previous][next][first][last][top][bottom][index][help] */
1143 {
1144     GList *gIter = NULL;
1145     GList *result = NULL;
1146     GList *providers = NULL;
1147 
1148     if (provider) {
1149         char buffer[500];
1150 
1151         snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
1152         return get_directory_list(buffer, TRUE, TRUE);
1153     }
1154 
1155     providers = resources_os_list_ocf_providers();
1156     for (gIter = providers; gIter != NULL; gIter = gIter->next) {
1157         GList *tmp1 = result;
1158         GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
1159 
1160         if (tmp2) {
1161             result = g_list_concat(tmp1, tmp2);
1162         }
1163     }
1164     g_list_free_full(providers, free);
1165     return result;
1166 }
1167 
1168 gboolean
1169 services__ocf_agent_exists(const char *provider, const char *agent)
     /* [previous][next][first][last][top][bottom][index][help] */
1170 {
1171     char *buf = NULL;
1172     gboolean rc = FALSE;
1173     struct stat st;
1174 
1175     if (provider == NULL || agent == NULL) {
1176         return rc;
1177     }
1178 
1179     buf = crm_strdup_printf(OCF_ROOT_DIR "/resource.d/%s/%s", provider, agent);
1180     if (stat(buf, &st) == 0) {
1181         rc = TRUE;
1182     }
1183 
1184     free(buf);
1185     return rc;
1186 }

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