root/lib/services/services_linux.c

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

DEFINITIONS

This source file includes following definitions.
  1. svc_read_output
  2. dispatch_stdout
  3. dispatch_stderr
  4. pipe_out_done
  5. pipe_err_done
  6. set_ocf_env
  7. set_ocf_env_with_prefix
  8. add_action_env_vars
  9. recurring_action_timer
  10. operation_finalize
  11. operation_finished
  12. services_handle_exec_error
  13. action_launch_child
  14. sigchld_handler
  15. action_synced_wait
  16. services_os_action_execute
  17. services_os_get_directory_list
  18. resources_os_list_lsb_agents
  19. resources_os_list_ocf_providers
  20. resources_os_list_ocf_agents
  21. resources_os_list_nagios_agents

   1 /*
   2  * Copyright (C) 2010-2016 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This source code is licensed under the GNU Lesser General Public License
   5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 
  10 #ifndef _GNU_SOURCE
  11 #  define _GNU_SOURCE
  12 #endif
  13 
  14 #include <sys/types.h>
  15 #include <sys/stat.h>
  16 #include <sys/wait.h>
  17 #include <errno.h>
  18 #include <unistd.h>
  19 #include <dirent.h>
  20 #include <string.h>
  21 #include <sys/time.h>
  22 #include <sys/resource.h>
  23 
  24 #ifdef HAVE_SYS_SIGNALFD_H
  25 #include <sys/signalfd.h>
  26 #endif
  27 
  28 #include "crm/crm.h"
  29 #include "crm/common/mainloop.h"
  30 #include "crm/services.h"
  31 
  32 #include "services_private.h"
  33 
  34 #if SUPPORT_CIBSECRETS
  35 #  include "crm/common/cib_secrets.h"
  36 #endif
  37 
  38 static gboolean
  39 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41     char *data = NULL;
  42     int rc = 0, len = 0;
  43     char buf[500];
  44     static const size_t buf_read_len = sizeof(buf) - 1;
  45 
  46 
  47     if (fd < 0) {
  48         crm_trace("No fd for %s", op->id);
  49         return FALSE;
  50     }
  51 
  52     if (is_stderr && op->stderr_data) {
  53         len = strlen(op->stderr_data);
  54         data = op->stderr_data;
  55         crm_trace("Reading %s stderr into offset %d", op->id, len);
  56 
  57     } else if (is_stderr == FALSE && op->stdout_data) {
  58         len = strlen(op->stdout_data);
  59         data = op->stdout_data;
  60         crm_trace("Reading %s stdout into offset %d", op->id, len);
  61 
  62     } else {
  63         crm_trace("Reading %s %s into offset %d", op->id, is_stderr?"stderr":"stdout", len);
  64     }
  65 
  66     do {
  67         rc = read(fd, buf, buf_read_len);
  68         if (rc > 0) {
  69             crm_trace("Got %d chars: %.80s", rc, buf);
  70             buf[rc] = 0;
  71             data = realloc_safe(data, len + rc + 1);
  72             len += sprintf(data + len, "%s", buf);
  73 
  74         } else if (errno != EINTR) {
  75             /* error or EOF
  76              * Cleanup happens in pipe_done()
  77              */
  78             rc = FALSE;
  79             break;
  80         }
  81 
  82     } while (rc == buf_read_len || rc < 0);
  83 
  84     if (is_stderr) {
  85         op->stderr_data = data;
  86     } else {
  87         op->stdout_data = data;
  88     }
  89 
  90     return rc;
  91 }
  92 
  93 static int
  94 dispatch_stdout(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96     svc_action_t *op = (svc_action_t *) userdata;
  97 
  98     return svc_read_output(op->opaque->stdout_fd, op, FALSE);
  99 }
 100 
 101 static int
 102 dispatch_stderr(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104     svc_action_t *op = (svc_action_t *) userdata;
 105 
 106     return svc_read_output(op->opaque->stderr_fd, op, TRUE);
 107 }
 108 
 109 static void
 110 pipe_out_done(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112     svc_action_t *op = (svc_action_t *) user_data;
 113 
 114     crm_trace("%p", op);
 115 
 116     op->opaque->stdout_gsource = NULL;
 117     if (op->opaque->stdout_fd > STDOUT_FILENO) {
 118         close(op->opaque->stdout_fd);
 119     }
 120     op->opaque->stdout_fd = -1;
 121 }
 122 
 123 static void
 124 pipe_err_done(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126     svc_action_t *op = (svc_action_t *) user_data;
 127 
 128     op->opaque->stderr_gsource = NULL;
 129     if (op->opaque->stderr_fd > STDERR_FILENO) {
 130         close(op->opaque->stderr_fd);
 131     }
 132     op->opaque->stderr_fd = -1;
 133 }
 134 
 135 static struct mainloop_fd_callbacks stdout_callbacks = {
 136     .dispatch = dispatch_stdout,
 137     .destroy = pipe_out_done,
 138 };
 139 
 140 static struct mainloop_fd_callbacks stderr_callbacks = {
 141     .dispatch = dispatch_stderr,
 142     .destroy = pipe_err_done,
 143 };
 144 
 145 static void
 146 set_ocf_env(const char *key, const char *value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148     if (setenv(key, value, 1) != 0) {
 149         crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
 150     }
 151 }
 152 
 153 static void
 154 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156     char buffer[500];
 157 
 158     snprintf(buffer, sizeof(buffer), "OCF_RESKEY_%s", (char *)key);
 159     set_ocf_env(buffer, value, user_data);
 160 }
 161 
 162 /*!
 163  * \internal
 164  * \brief Add environment variables suitable for an action
 165  *
 166  * \param[in] op  Action to use
 167  */
 168 static void
 169 add_action_env_vars(const svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171     if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF) == FALSE) {
 172         return;
 173     }
 174 
 175     if (op->params) {
 176         g_hash_table_foreach(op->params, set_ocf_env_with_prefix, NULL);
 177     }
 178 
 179     set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
 180     set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
 181     set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
 182     set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
 183 
 184     if (op->rsc) {
 185         set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
 186     }
 187 
 188     if (op->agent != NULL) {
 189         set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
 190     }
 191 
 192     /* Notes: this is not added to specification yet. Sept 10,2004 */
 193     if (op->provider != NULL) {
 194         set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
 195     }
 196 }
 197 
 198 gboolean
 199 recurring_action_timer(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201     svc_action_t *op = data;
 202 
 203     crm_debug("Scheduling another invocation of %s", op->id);
 204 
 205     /* Clean out the old result */
 206     free(op->stdout_data);
 207     op->stdout_data = NULL;
 208     free(op->stderr_data);
 209     op->stderr_data = NULL;
 210     op->opaque->repeat_timer = 0;
 211 
 212     services_action_async(op, NULL);
 213     return FALSE;
 214 }
 215 
 216 /* Returns FALSE if 'op' should be free'd by the caller */
 217 gboolean
 218 operation_finalize(svc_action_t * op)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220     int recurring = 0;
 221 
 222     if (op->interval) {
 223         if (op->cancel) {
 224             op->status = PCMK_LRM_OP_CANCELLED;
 225             cancel_recurring_action(op);
 226         } else {
 227             recurring = 1;
 228             op->opaque->repeat_timer = g_timeout_add(op->interval,
 229                                                      recurring_action_timer, (void *)op);
 230         }
 231     }
 232 
 233     if (op->opaque->callback) {
 234         op->opaque->callback(op);
 235     }
 236 
 237     op->pid = 0;
 238 
 239     services_untrack_op(op);
 240 
 241     if (!recurring && op->synchronous == FALSE) {
 242         /*
 243          * If this is a recurring action, do not free explicitly.
 244          * It will get freed whenever the action gets cancelled.
 245          */
 246         services_action_free(op);
 247         return TRUE;
 248     }
 249 
 250     services_action_cleanup(op);
 251     return FALSE;
 252 }
 253 
 254 static void
 255 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257     svc_action_t *op = mainloop_child_userdata(p);
 258     char *prefix = crm_strdup_printf("%s:%d", op->id, op->pid);
 259 
 260     mainloop_clear_child_userdata(p);
 261     op->status = PCMK_LRM_OP_DONE;
 262     CRM_ASSERT(op->pid == pid);
 263 
 264     crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
 265     if (op->opaque->stderr_gsource) {
 266         /* Make sure we have read everything from the buffer.
 267          * Depending on the priority mainloop gives the fd, operation_finished
 268          * could occur before all the reads are done.  Force the read now.*/
 269         crm_trace("%s dispatching stderr", prefix);
 270         dispatch_stderr(op);
 271         crm_trace("%s: %p", op->id, op->stderr_data);
 272         mainloop_del_fd(op->opaque->stderr_gsource);
 273         op->opaque->stderr_gsource = NULL;
 274     }
 275 
 276     if (op->opaque->stdout_gsource) {
 277         /* Make sure we have read everything from the buffer.
 278          * Depending on the priority mainloop gives the fd, operation_finished
 279          * could occur before all the reads are done.  Force the read now.*/
 280         crm_trace("%s dispatching stdout", prefix);
 281         dispatch_stdout(op);
 282         crm_trace("%s: %p", op->id, op->stdout_data);
 283         mainloop_del_fd(op->opaque->stdout_gsource);
 284         op->opaque->stdout_gsource = NULL;
 285     }
 286 
 287     if (signo) {
 288         if (mainloop_child_timeout(p)) {
 289             crm_warn("%s - timed out after %dms", prefix, op->timeout);
 290             op->status = PCMK_LRM_OP_TIMEOUT;
 291             op->rc = PCMK_OCF_TIMEOUT;
 292 
 293         } else {
 294             do_crm_log_unlikely((op->cancel) ? LOG_INFO : LOG_WARNING,
 295                                 "%s - terminated with signal %d", prefix, signo);
 296             op->status = PCMK_LRM_OP_ERROR;
 297             op->rc = PCMK_OCF_SIGNAL;
 298         }
 299 
 300     } else {
 301         op->rc = exitcode;
 302         crm_debug("%s - exited with rc=%d", prefix, exitcode);
 303     }
 304 
 305     free(prefix);
 306     prefix = crm_strdup_printf("%s:%d:stderr", op->id, op->pid);
 307     crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
 308 
 309     free(prefix);
 310     prefix = crm_strdup_printf("%s:%d:stdout", op->id, op->pid);
 311     crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
 312 
 313     free(prefix);
 314     operation_finalize(op);
 315 }
 316 
 317 /*!
 318  * \internal
 319  * \brief Set operation rc and status per errno from stat(), fork() or execvp()
 320  *
 321  * \param[in,out] op     Operation to set rc and status for
 322  * \param[in]     error  Value of errno after system call
 323  *
 324  * \return void
 325  */
 326 static void
 327 services_handle_exec_error(svc_action_t * op, int error)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329     int rc_not_installed, rc_insufficient_priv, rc_exec_error;
 330 
 331     /* Mimic the return codes for each standard as that's what we'll convert back from in get_uniform_rc() */
 332     if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_LSB)
 333         && safe_str_eq(op->action, "status")) {
 334 
 335         rc_not_installed = PCMK_LSB_STATUS_NOT_INSTALLED;
 336         rc_insufficient_priv = PCMK_LSB_STATUS_INSUFFICIENT_PRIV;
 337         rc_exec_error = PCMK_LSB_STATUS_UNKNOWN;
 338 
 339 #if SUPPORT_NAGIOS
 340     } else if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
 341         rc_not_installed = NAGIOS_NOT_INSTALLED;
 342         rc_insufficient_priv = NAGIOS_INSUFFICIENT_PRIV;
 343         rc_exec_error = PCMK_OCF_EXEC_ERROR;
 344 #endif
 345 
 346     } else {
 347         rc_not_installed = PCMK_OCF_NOT_INSTALLED;
 348         rc_insufficient_priv = PCMK_OCF_INSUFFICIENT_PRIV;
 349         rc_exec_error = PCMK_OCF_EXEC_ERROR;
 350     }
 351 
 352     switch (error) {   /* see execve(2), stat(2) and fork(2) */
 353         case ENOENT:   /* No such file or directory */
 354         case EISDIR:   /* Is a directory */
 355         case ENOTDIR:  /* Path component is not a directory */
 356         case EINVAL:   /* Invalid executable format */
 357         case ENOEXEC:  /* Invalid executable format */
 358             op->rc = rc_not_installed;
 359             op->status = PCMK_LRM_OP_NOT_INSTALLED;
 360             break;
 361         case EACCES:   /* permission denied (various errors) */
 362         case EPERM:    /* permission denied (various errors) */
 363             op->rc = rc_insufficient_priv;
 364             op->status = PCMK_LRM_OP_ERROR;
 365             break;
 366         default:
 367             op->rc = rc_exec_error;
 368             op->status = PCMK_LRM_OP_ERROR;
 369     }
 370 }
 371 
 372 static void
 373 action_launch_child(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 374 {
 375     int lpc;
 376 
 377     /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
 378      * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
 379      * We do not want this to be inherited by the child process. By resetting this the signal
 380      * to the default behavior, we avoid some potential odd problems that occur during OCF
 381      * scripts when SIGPIPE is ignored by the environment. */
 382     signal(SIGPIPE, SIG_DFL);
 383 
 384 #if defined(HAVE_SCHED_SETSCHEDULER)
 385     if (sched_getscheduler(0) != SCHED_OTHER) {
 386         struct sched_param sp;
 387 
 388         memset(&sp, 0, sizeof(sp));
 389         sp.sched_priority = 0;
 390 
 391         if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
 392             crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
 393         }
 394     }
 395 #endif
 396     if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
 397         crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
 398     }
 399 
 400     /* Man: The call setpgrp() is equivalent to setpgid(0,0)
 401      * _and_ compiles on BSD variants too
 402      * need to investigate if it works the same too.
 403      */
 404     setpgid(0, 0);
 405 
 406     /* close all descriptors except stdin/out/err and channels to logd */
 407     for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
 408         close(lpc);
 409     }
 410 
 411 #if SUPPORT_CIBSECRETS
 412     if (replace_secret_params(op->rsc, op->params) < 0) {
 413         /* replacing secrets failed! */
 414         if (safe_str_eq(op->action,"stop")) {
 415             /* don't fail on stop! */
 416             crm_info("proceeding with the stop operation for %s", op->rsc);
 417 
 418         } else {
 419             crm_err("failed to get secrets for %s, "
 420                     "considering resource not configured", op->rsc);
 421             _exit(PCMK_OCF_NOT_CONFIGURED);
 422         }
 423     }
 424 #endif
 425 
 426     add_action_env_vars(op);
 427 
 428     /* Become the desired user */
 429     if (op->opaque->uid && (geteuid() == 0)) {
 430         if (op->opaque->gid && (setgid(op->opaque->gid) < 0)) {
 431             crm_perror(LOG_ERR, "setting group to %d", op->opaque->gid);
 432             _exit(PCMK_OCF_NOT_CONFIGURED);
 433         }
 434         if (setuid(op->opaque->uid) < 0) {
 435             crm_perror(LOG_ERR, "setting user to %d", op->opaque->uid);
 436             _exit(PCMK_OCF_NOT_CONFIGURED);
 437         }
 438         /* We could do initgroups() here if we kept a copy of the username */
 439     }
 440 
 441     /* execute the RA */
 442     execvp(op->opaque->exec, op->opaque->args);
 443 
 444     /* Most cases should have been already handled by stat() */
 445     services_handle_exec_error(op, errno);
 446 
 447     _exit(op->rc);
 448 }
 449 
 450 #ifndef HAVE_SYS_SIGNALFD_H
 451 static int sigchld_pipe[2] = { -1, -1 };
 452 
 453 static void
 454 sigchld_handler()
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456     if ((sigchld_pipe[1] >= 0) && (write(sigchld_pipe[1], "", 1) == -1)) {
 457         crm_perror(LOG_TRACE, "Could not poke SIGCHLD self-pipe");
 458     }
 459 }
 460 #endif
 461 
 462 static void
 463 action_synced_wait(svc_action_t * op, sigset_t *mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465     int status = 0;
 466     int timeout = op->timeout;
 467     int sfd = -1;
 468     time_t start = -1;
 469     struct pollfd fds[3];
 470     int wait_rc = 0;
 471 
 472 #ifdef HAVE_SYS_SIGNALFD_H
 473     sfd = signalfd(-1, mask, SFD_NONBLOCK);
 474     if (sfd < 0) {
 475         crm_perror(LOG_ERR, "signalfd() failed");
 476     }
 477 #else
 478     sfd = sigchld_pipe[0];
 479 #endif
 480 
 481     fds[0].fd = op->opaque->stdout_fd;
 482     fds[0].events = POLLIN;
 483     fds[0].revents = 0;
 484 
 485     fds[1].fd = op->opaque->stderr_fd;
 486     fds[1].events = POLLIN;
 487     fds[1].revents = 0;
 488 
 489     fds[2].fd = sfd;
 490     fds[2].events = POLLIN;
 491     fds[2].revents = 0;
 492 
 493     crm_trace("Waiting for %d", op->pid);
 494     start = time(NULL);
 495     do {
 496         int poll_rc = poll(fds, 3, timeout);
 497 
 498         if (poll_rc > 0) {
 499             if (fds[0].revents & POLLIN) {
 500                 svc_read_output(op->opaque->stdout_fd, op, FALSE);
 501             }
 502 
 503             if (fds[1].revents & POLLIN) {
 504                 svc_read_output(op->opaque->stderr_fd, op, TRUE);
 505             }
 506 
 507             if (fds[2].revents & POLLIN) {
 508 #ifdef HAVE_SYS_SIGNALFD_H
 509                 struct signalfd_siginfo fdsi;
 510                 ssize_t s;
 511 
 512                 s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
 513                 if (s != sizeof(struct signalfd_siginfo)) {
 514                     crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
 515 
 516                 } else if (fdsi.ssi_signo == SIGCHLD) {
 517 #else
 518                 if (1) {
 519                     /* Clear out the sigchld pipe. */
 520                     char ch;
 521                     while (read(sfd, &ch, 1) == 1) /*omit*/;
 522 #endif
 523                     wait_rc = waitpid(op->pid, &status, WNOHANG);
 524 
 525                     if (wait_rc > 0) {
 526                         break;
 527 
 528                     } else if (wait_rc < 0){
 529                         if (errno == ECHILD) {
 530                                 /* Here, don't dare to kill and bail out... */
 531                                 break;
 532 
 533                         } else {
 534                                 /* ...otherwise pretend process still runs. */
 535                                 wait_rc = 0;
 536                         }
 537                         crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
 538                     }
 539                 }
 540             }
 541 
 542         } else if (poll_rc == 0) {
 543             timeout = 0;
 544             break;
 545 
 546         } else if (poll_rc < 0) {
 547             if (errno != EINTR) {
 548                 crm_perror(LOG_ERR, "poll() failed");
 549                 break;
 550             }
 551         }
 552 
 553         timeout = op->timeout - (time(NULL) - start) * 1000;
 554 
 555     } while ((op->timeout < 0 || timeout > 0));
 556 
 557     crm_trace("Child done: %d", op->pid);
 558     if (wait_rc <= 0) {
 559         op->rc = PCMK_OCF_UNKNOWN_ERROR;
 560 
 561         if (op->timeout > 0 && timeout <= 0) {
 562             op->status = PCMK_LRM_OP_TIMEOUT;
 563             crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
 564 
 565         } else {
 566             op->status = PCMK_LRM_OP_ERROR;
 567         }
 568 
 569         /* If only child hasn't been successfully waited for, yet.
 570            This is to limit killing wrong target a bit more. */
 571         if (wait_rc == 0 && waitpid(op->pid, &status, WNOHANG) == 0) {
 572             if (kill(op->pid, SIGKILL)) {
 573                 crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
 574             }
 575             /* Safe to skip WNOHANG here as we sent non-ignorable signal. */
 576             while (waitpid(op->pid, &status, 0) == (pid_t) -1 && errno == EINTR) /*omit*/;
 577         }
 578 
 579     } else if (WIFEXITED(status)) {
 580         op->status = PCMK_LRM_OP_DONE;
 581         op->rc = WEXITSTATUS(status);
 582         crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
 583 
 584     } else if (WIFSIGNALED(status)) {
 585         int signo = WTERMSIG(status);
 586 
 587         op->status = PCMK_LRM_OP_ERROR;
 588         crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
 589     }
 590 #ifdef WCOREDUMP
 591     if (WCOREDUMP(status)) {
 592         crm_err("Managed %s process %d dumped core", op->id, op->pid);
 593     }
 594 #endif
 595 
 596     svc_read_output(op->opaque->stdout_fd, op, FALSE);
 597     svc_read_output(op->opaque->stderr_fd, op, TRUE);
 598 
 599     close(op->opaque->stdout_fd);
 600     close(op->opaque->stderr_fd);
 601 
 602 #ifdef HAVE_SYS_SIGNALFD_H
 603     close(sfd);
 604 #endif
 605 }
 606 
 607 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
 608 /* For a synchronous 'op', returns FALSE if 'op' fails */
 609 gboolean
 610 services_os_action_execute(svc_action_t * op)
     /* [previous][next][first][last][top][bottom][index][help] */
 611 {
 612     int stdout_fd[2];
 613     int stderr_fd[2];
 614     int rc;
 615     struct stat st;
 616     sigset_t *pmask;
 617 
 618 #ifdef HAVE_SYS_SIGNALFD_H
 619     sigset_t mask;
 620     sigset_t old_mask;
 621 #define sigchld_cleanup() do {                                                \
 622     if (sigismember(&old_mask, SIGCHLD) == 0) {                               \
 623         if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) {                      \
 624             crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld");   \
 625         }                                                                     \
 626     }                                                                         \
 627 } while (0)
 628 #else
 629     struct sigaction sa;
 630     struct sigaction old_sa;
 631 #define sigchld_cleanup() do {                                                \
 632     if (sigaction(SIGCHLD, &old_sa, NULL) < 0) {                              \
 633         crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler");  \
 634     }                                                                         \
 635     close(sigchld_pipe[0]);                                                   \
 636     close(sigchld_pipe[1]);                                                   \
 637     sigchld_pipe[0] = sigchld_pipe[1] = -1;                                   \
 638 } while(0)
 639 #endif
 640 
 641     /* Fail fast */
 642     if(stat(op->opaque->exec, &st) != 0) {
 643         rc = errno;
 644         crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
 645         services_handle_exec_error(op, rc);
 646         if (!op->synchronous) {
 647             return operation_finalize(op);
 648         }
 649         return FALSE;
 650     }
 651 
 652     if (pipe(stdout_fd) < 0) {
 653         rc = errno;
 654 
 655         crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
 656 
 657         services_handle_exec_error(op, rc);
 658         if (!op->synchronous) {
 659             return operation_finalize(op);
 660         }
 661         return FALSE;
 662     }
 663 
 664     if (pipe(stderr_fd) < 0) {
 665         rc = errno;
 666 
 667         close(stdout_fd[0]);
 668         close(stdout_fd[1]);
 669 
 670         crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
 671 
 672         services_handle_exec_error(op, rc);
 673         if (!op->synchronous) {
 674             return operation_finalize(op);
 675         }
 676         return FALSE;
 677     }
 678 
 679     if (op->synchronous) {
 680 #ifdef HAVE_SYS_SIGNALFD_H
 681         sigemptyset(&mask);
 682         sigaddset(&mask, SIGCHLD);
 683         sigemptyset(&old_mask);
 684 
 685         if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
 686             crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld");
 687         }
 688 
 689         pmask = &mask;
 690 #else
 691         if(pipe(sigchld_pipe) == -1) {
 692             crm_perror(LOG_ERR, "pipe() failed");
 693         }
 694 
 695         rc = crm_set_nonblocking(sigchld_pipe[0]);
 696         if (rc < 0) {
 697             crm_warn("Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
 698                      pcmk_strerror(rc), rc);
 699         }
 700         rc = crm_set_nonblocking(sigchld_pipe[1]);
 701         if (rc < 0) {
 702             crm_warn("Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
 703                      pcmk_strerror(rc), rc);
 704         }
 705 
 706         sa.sa_handler = sigchld_handler;
 707         sa.sa_flags = 0;
 708         sigemptyset(&sa.sa_mask);
 709         if (sigaction(SIGCHLD, &sa, &old_sa) < 0) {
 710             crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler");
 711         }
 712 
 713         pmask = NULL;
 714 #endif
 715     }
 716 
 717     op->pid = fork();
 718     switch (op->pid) {
 719         case -1:
 720             rc = errno;
 721 
 722             close(stdout_fd[0]);
 723             close(stdout_fd[1]);
 724             close(stderr_fd[0]);
 725             close(stderr_fd[1]);
 726 
 727             crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
 728             services_handle_exec_error(op, rc);
 729             if (!op->synchronous) {
 730                 return operation_finalize(op);
 731             }
 732 
 733             sigchld_cleanup();
 734             return FALSE;
 735 
 736         case 0:                /* Child */
 737             close(stdout_fd[0]);
 738             close(stderr_fd[0]);
 739             if (STDOUT_FILENO != stdout_fd[1]) {
 740                 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
 741                     crm_err("dup2() failed (stdout)");
 742                 }
 743                 close(stdout_fd[1]);
 744             }
 745             if (STDERR_FILENO != stderr_fd[1]) {
 746                 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
 747                     crm_err("dup2() failed (stderr)");
 748                 }
 749                 close(stderr_fd[1]);
 750             }
 751 
 752             if (op->synchronous) {
 753                 sigchld_cleanup();
 754             }
 755 
 756             action_launch_child(op);
 757             CRM_ASSERT(0);  /* action_launch_child is effectively noreturn */
 758     }
 759 
 760     /* Only the parent reaches here */
 761     close(stdout_fd[1]);
 762     close(stderr_fd[1]);
 763 
 764     op->opaque->stdout_fd = stdout_fd[0];
 765     rc = crm_set_nonblocking(op->opaque->stdout_fd);
 766     if (rc < 0) {
 767         crm_warn("Could not set child output non-blocking: %s "
 768                  CRM_XS " rc=%d",
 769                  pcmk_strerror(rc), rc);
 770     }
 771 
 772     op->opaque->stderr_fd = stderr_fd[0];
 773     rc = crm_set_nonblocking(op->opaque->stderr_fd);
 774     if (rc < 0) {
 775         crm_warn("Could not set child error output non-blocking: %s "
 776                  CRM_XS " rc=%d",
 777                  pcmk_strerror(rc), rc);
 778     }
 779 
 780     if (op->synchronous) {
 781         action_synced_wait(op, pmask);
 782         sigchld_cleanup();
 783     } else {
 784 
 785         crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
 786         mainloop_child_add_with_flags(op->pid,
 787                                       op->timeout,
 788                                       op->id,
 789                                       op,
 790                                       (op->flags & SVC_ACTION_LEAVE_GROUP) ? mainloop_leave_pid_group : 0,
 791                                       operation_finished);
 792 
 793 
 794         op->opaque->stdout_gsource = mainloop_add_fd(op->id,
 795                                                      G_PRIORITY_LOW,
 796                                                      op->opaque->stdout_fd, op, &stdout_callbacks);
 797 
 798         op->opaque->stderr_gsource = mainloop_add_fd(op->id,
 799                                                      G_PRIORITY_LOW,
 800                                                      op->opaque->stderr_fd, op, &stderr_callbacks);
 801 
 802         services_add_inflight_op(op);
 803     }
 804 
 805     return TRUE;
 806 }
 807 
 808 GList *
 809 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
     /* [previous][next][first][last][top][bottom][index][help] */
 810 {
 811     GList *list = NULL;
 812     struct dirent **namelist;
 813     int entries = 0, lpc = 0;
 814     char buffer[PATH_MAX];
 815 
 816     entries = scandir(root, &namelist, NULL, alphasort);
 817     if (entries <= 0) {
 818         return list;
 819     }
 820 
 821     for (lpc = 0; lpc < entries; lpc++) {
 822         struct stat sb;
 823 
 824         if ('.' == namelist[lpc]->d_name[0]) {
 825             free(namelist[lpc]);
 826             continue;
 827         }
 828 
 829         snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
 830 
 831         if (stat(buffer, &sb)) {
 832             continue;
 833         }
 834 
 835         if (S_ISDIR(sb.st_mode)) {
 836             if (files) {
 837                 free(namelist[lpc]);
 838                 continue;
 839             }
 840 
 841         } else if (S_ISREG(sb.st_mode)) {
 842             if (files == FALSE) {
 843                 free(namelist[lpc]);
 844                 continue;
 845 
 846             } else if (executable
 847                        && (sb.st_mode & S_IXUSR) == 0
 848                        && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
 849                 free(namelist[lpc]);
 850                 continue;
 851             }
 852         }
 853 
 854         list = g_list_append(list, strdup(namelist[lpc]->d_name));
 855 
 856         free(namelist[lpc]);
 857     }
 858 
 859     free(namelist);
 860     return list;
 861 }
 862 
 863 GList *
 864 resources_os_list_lsb_agents(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 865 {
 866     return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
 867 }
 868 
 869 GList *
 870 resources_os_list_ocf_providers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 871 {
 872     return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
 873 }
 874 
 875 GList *
 876 resources_os_list_ocf_agents(const char *provider)
     /* [previous][next][first][last][top][bottom][index][help] */
 877 {
 878     GList *gIter = NULL;
 879     GList *result = NULL;
 880     GList *providers = NULL;
 881 
 882     if (provider) {
 883         char buffer[500];
 884 
 885         snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
 886         return get_directory_list(buffer, TRUE, TRUE);
 887     }
 888 
 889     providers = resources_os_list_ocf_providers();
 890     for (gIter = providers; gIter != NULL; gIter = gIter->next) {
 891         GList *tmp1 = result;
 892         GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
 893 
 894         if (tmp2) {
 895             result = g_list_concat(tmp1, tmp2);
 896         }
 897     }
 898     g_list_free_full(providers, free);
 899     return result;
 900 }
 901 
 902 #if SUPPORT_NAGIOS
 903 GList *
 904 resources_os_list_nagios_agents(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 905 {
 906     GList *plugin_list = NULL;
 907     GList *result = NULL;
 908     GList *gIter = NULL;
 909 
 910     plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
 911 
 912     /* Make sure both the plugin and its metadata exist */
 913     for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
 914         const char *plugin = gIter->data;
 915         char *metadata = crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
 916         struct stat st;
 917 
 918         if (stat(metadata, &st) == 0) {
 919             result = g_list_append(result, strdup(plugin));
 920         }
 921 
 922         free(metadata);
 923     }
 924     g_list_free_full(plugin_list, free);
 925     return result;
 926 }
 927 #endif

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