16 #include <sys/types.h>    25 #include <sys/resource.h>    34 static void close_pipe(
int fildes[]);
    44 #ifdef HAVE_SYS_SIGNALFD_H    48 #include <sys/signalfd.h>    51 struct sigchld_data_s {
    58 sigchld_setup(
struct sigchld_data_s *
data)
    60     sigemptyset(&(
data->mask));
    61     sigaddset(&(
data->mask), SIGCHLD);
    63     sigemptyset(&(
data->old_mask));
    66     if (sigprocmask(SIG_BLOCK, &(
data->mask), &(
data->old_mask)) < 0) {
    67         crm_info(
"Wait for child process completion failed: %s "    76 sigchld_open(
struct sigchld_data_s *
data)
    82     fd = signalfd(-1, &(
data->mask), SFD_NONBLOCK);
    84         crm_info(
"Wait for child process completion failed: %s "   101 sigchld_received(
int fd)
   103     struct signalfd_siginfo fdsi;
   109     s = read(fd, &fdsi, 
sizeof(
struct signalfd_siginfo));
   110     if (s != 
sizeof(
struct signalfd_siginfo)) {
   111         crm_info(
"Wait for child process completion failed: %s "   114     } 
else if (fdsi.ssi_signo == SIGCHLD) {
   122 sigchld_cleanup(
struct sigchld_data_s *
data)
   125     if ((sigismember(&(
data->old_mask), SIGCHLD) == 0)
   126         && (sigprocmask(SIG_UNBLOCK, &(
data->mask), NULL) < 0)) {
   127         crm_warn(
"Could not clean up after child process completion: %s",
   132 #else // HAVE_SYS_SIGNALFD_H not defined   136 struct sigchld_data_s {
   139     struct sigaction old_sa;    
   146 sigchld_handler(
void)
   152         crm_info(
"Wait for child process completion failed: %s "   158 sigchld_setup(
struct sigchld_data_s *
data)
   162     data->pipe_fd[0] = 
data->pipe_fd[1] = -1;
   164     if (pipe(
data->pipe_fd) == -1) {
   165         crm_info(
"Wait for child process completion failed: %s "   172         crm_info(
"Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
   177         crm_info(
"Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
   183     data->sa.sa_flags = 0;
   184     sigemptyset(&(
data->sa.sa_mask));
   185     if (sigaction(SIGCHLD, &(
data->sa), &(
data->old_sa)) < 0) {
   186         crm_info(
"Wait for child process completion failed: %s "   196 sigchld_open(
struct sigchld_data_s *
data)
   199     return data->pipe_fd[0];
   203 sigchld_close(
int fd)
   210 sigchld_received(
int fd)
   219     while (read(fd, &ch, 1) == 1) ;
   224 sigchld_cleanup(
struct sigchld_data_s *
data)
   227     if (sigaction(SIGCHLD, &(
data->old_sa), NULL) < 0) {
   228         crm_warn(
"Could not clean up after child process completion: %s",
   232     close_pipe(
data->pipe_fd);
   244 close_pipe(
int fildes[])
   246     if (fildes[0] >= 0) {
   250     if (fildes[1] >= 0) {
   257 svc_read_output(
int fd, 
svc_action_t * op, 
bool is_stderr)
   262     static const size_t buf_read_len = 
sizeof(buf) - 1;
   273         crm_trace(
"Reading %s stderr into offset %d", op->
id, len);
   275     } 
else if (is_stderr == FALSE && op->
stdout_data) {
   278         crm_trace(
"Reading %s stdout into offset %d", op->
id, len);
   281         crm_trace(
"Reading %s %s into offset %d", op->
id, is_stderr?
"stderr":
"stdout", len);
   285         rc = read(fd, buf, buf_read_len);
   288             crm_trace(
"Got %d chars: %.80s", rc, buf);
   289             data = pcmk__realloc(
data, len + rc + 1);
   290             len += sprintf(
data + len, 
"%s", buf);
   292         } 
else if (errno != EINTR) {
   300     } 
while (rc == buf_read_len || rc < 0);
   312 dispatch_stdout(gpointer userdata)
   320 dispatch_stderr(gpointer userdata)
   328 pipe_out_done(gpointer user_data)
   342 pipe_err_done(gpointer user_data)
   355     .destroy = pipe_out_done,
   360     .destroy = pipe_err_done,
   364 set_ocf_env(
const char *key, 
const char *value, gpointer user_data)
   366     if (
setenv(key, value, 1) != 0) {
   367         crm_perror(LOG_ERR, 
"setenv failed for key:%s and value:%s", key, value);
   372 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
   376     snprintf(buffer, 
sizeof(buffer), strcmp(key, 
"OCF_CHECK_LEVEL") != 0 ? 
"OCF_RESKEY_%s" : 
"%s", (
char *)key);
   377     set_ocf_env(buffer, value, user_data);
   381 set_alert_env(gpointer key, gpointer value, gpointer user_data)
   386         rc = 
setenv(key, value, 1);
   393                   (
char*)key, (value? (
char*)value : 
""));
   395         crm_trace(
"setenv %s=%s", (
char*)key, (value? (
char*)value : 
""));
   408     void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
   409     if (op->
agent == NULL) {
   410         env_setter = set_alert_env;  
   413         env_setter = set_ocf_env_with_prefix;
   416     if (env_setter != NULL && op->
params != NULL) {
   417         g_hash_table_foreach(op->
params, env_setter, NULL);
   420     if (env_setter == NULL || env_setter == set_alert_env) {
   430         set_ocf_env(
"OCF_RESOURCE_INSTANCE", op->
rsc, NULL);
   433     if (op->
agent != NULL) {
   434         set_ocf_env(
"OCF_RESOURCE_TYPE", op->
agent, NULL);
   439         set_ocf_env(
"OCF_RESOURCE_PROVIDER", op->
provider, NULL);
   444 pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
   448     int ret, total = 0, len = strlen(buffer);
   457     } 
while ((errno == EINTR) && (total < len));
   471         g_hash_table_foreach(op->
params, pipe_in_single_parameter, (gpointer) op);
   480     crm_debug(
"Scheduling another invocation of %s", op->
id);
   570                   op->
id, op->
pid, (is_stderr? 
"stderr" : 
"stdout"));
   571         svc_read_output(fd, op, is_stderr);
   592     strcpy(prefix + strlen(prefix) - strlen(
"error output"), 
"output");
   598 #define EXIT_REASON_MAX_LEN 128   603     const char *reason_start = NULL;
   604     const char *reason_end = NULL;
   621     if ((reason_start == NULL) || (reason_start[0] == 
'\n')
   622         || (reason_start[0] == 
'\0')) {
   627     reason_end = strchr(reason_start, 
'\n');
   628     if (reason_end == NULL) {
   629         reason_end = reason_start + strlen(reason_start);
   667     finish_op_output(op, 
true);
   668     finish_op_output(op, 
false);
   673         crm_debug(
"%s[%d] exited with status %d", op->
id, op->
pid, exitcode);
   676         parse_exit_reason_from_stderr(op);
   681         crm_info(
"%s %s[%d] timed out after %s",
   685                                 "%s did not complete within %s",
   692         crm_info(
"%s[%d] terminated with signal %d (%s)",
   693                  op->
id, op->
pid, signo, strsignal(signo));
   697         crm_info(
"%s[%d] terminated with signal %d (%s)",
   698                  op->
id, op->
pid, signo, strsignal(signo));
   700                                 "%s interrupted by %s signal",
   723     if ((op == NULL) || (op->
standard == NULL)) {
   758     if ((op == NULL) || (op->
standard == NULL)) {
   793     if ((op == NULL) || (op->
standard == NULL)) {
   829     if ((op == NULL) || (op->
standard == NULL)) {
   901 exit_child(
const svc_action_t *op, 
int exit_status, 
const char *exit_reason)
   903     if ((op != NULL) && (exit_reason != NULL)
   921     signal(SIGPIPE, SIG_DFL);
   923 #if defined(HAVE_SCHED_SETSCHEDULER)   924     if (sched_getscheduler(0) != SCHED_OTHER) {
   925         struct sched_param sp;
   927         memset(&sp, 0, 
sizeof(sp));
   928         sp.sched_priority = 0;
   930         if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
   931             crm_info(
"Could not reset scheduling policy for %s", op->
id);
   935     if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
   936         crm_info(
"Could not reset process priority for %s", op->
id);
   954 #if SUPPORT_CIBSECRETS   958             crm_info(
"Proceeding with stop operation for %s "   959                      "despite being unable to load CIB secrets (%s)",
   962             crm_err(
"Considering %s unconfigured "   963                     "because unable to load CIB secrets: %s",
   966                        "Unable to load CIB secrets");
   971     add_action_env_vars(op);
   974     if (op->
opaque->
uid && (geteuid() == 0)) {
   978             crm_err(
"Considering %s unauthorized because could not set "   979                     "child group to %d: %s",
   982                        "Could not set group for child process");
   987         if (setgroups(0, NULL) < 0) {
   988             crm_err(
"Considering %s unauthorized because could not "   989                     "clear supplementary groups: %s", op->
id, 
strerror(errno));
   991                        "Could not clear supplementary groups for child process");
   996             crm_err(
"Considering %s unauthorized because could not set user "   999                        "Could not set user for child process");
  1010     exit_child(op, op->
rc, 
"Child process was unable to execute file");
  1025     time_t start = time(NULL);
  1026     struct pollfd fds[3];
  1028     const char *wait_reason = NULL;
  1031     fds[0].events = POLLIN;
  1035     fds[1].events = POLLIN;
  1038     fds[2].fd = sigchld_open(
data);
  1039     fds[2].events = POLLIN;
  1044         int poll_rc = poll(fds, 3, 
timeout);
  1049             if (fds[0].revents & POLLIN) {
  1053             if (fds[1].revents & POLLIN) {
  1057             if ((fds[2].revents & POLLIN) && sigchld_received(fds[2].fd)) {
  1058                 wait_rc = waitpid(op->
pid, &status, WNOHANG);
  1060                 if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) {
  1064                 } 
else if (wait_rc < 0) {
  1066                     crm_info(
"Wait for completion of %s[%d] failed: %s "  1067                              CRM_XS " source=waitpid",
  1068                              op->
id, op->
pid, wait_reason);
  1073         } 
else if (poll_rc == 0) {
  1078         } 
else if ((poll_rc < 0) && (errno != EINTR)) {
  1080             crm_info(
"Wait for completion of %s[%d] failed: %s "  1081                      CRM_XS " source=poll", op->
id, op->
pid, wait_reason);
  1090     finish_op_output(op, 
true);
  1091     finish_op_output(op, 
false);
  1093     sigchld_close(fds[2].fd);
  1100                                     "%s did not exit within specified timeout",
  1102             crm_info(
"%s[%d] timed out after %dms",
  1112         if ((wait_rc == 0) && (waitpid(op->
pid, &status, WNOHANG) == 0)) {
  1113             if (kill(op->
pid, SIGKILL)) {
  1114                 crm_warn(
"Could not kill rogue child %s[%d]: %s",
  1118             while ((waitpid(op->
pid, &status, 0) == (pid_t) -1)
  1119                    && (errno == EINTR)) {
  1124     } 
else if (WIFEXITED(status)) {
  1126         parse_exit_reason_from_stderr(op);
  1129     } 
else if (WIFSIGNALED(status)) {
  1130         int signo = WTERMSIG(status);
  1135         crm_info(
"%s[%d] terminated with signal %d (%s)",
  1136                  op->
id, op->
pid, signo, strsignal(signo));
  1139         if (WCOREDUMP(status)) {
  1147                              "Unable to wait for child to complete");
  1172     int stdin_fd[2] = {-1, -1};
  1175     struct sigchld_data_s 
data;
  1186     if (pipe(stdout_fd) < 0) {
  1188         crm_info(
"Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
  1194     if (pipe(stderr_fd) < 0) {
  1197         close_pipe(stdout_fd);
  1199         crm_info(
"Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
  1206         if (pipe(stdin_fd) < 0) {
  1209             close_pipe(stdout_fd);
  1210             close_pipe(stderr_fd);
  1220         close_pipe(stdin_fd);
  1221         close_pipe(stdout_fd);
  1222         close_pipe(stderr_fd);
  1223         sigchld_cleanup(&
data);
  1225                              "Could not manage signals for child process");
  1233             close_pipe(stdin_fd);
  1234             close_pipe(stdout_fd);
  1235             close_pipe(stderr_fd);
  1241                 sigchld_cleanup(&
data);
  1247             close(stdout_fd[0]);
  1248             close(stderr_fd[0]);
  1249             if (stdin_fd[1] >= 0) {
  1252             if (STDOUT_FILENO != stdout_fd[1]) {
  1253                 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
  1254                     crm_warn(
"Can't redirect output from '%s': %s "  1258                 close(stdout_fd[1]);
  1260             if (STDERR_FILENO != stderr_fd[1]) {
  1261                 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
  1262                     crm_warn(
"Can't redirect error output from '%s': %s "  1266                 close(stderr_fd[1]);
  1268             if ((stdin_fd[0] >= 0) &&
  1269                 (STDIN_FILENO != stdin_fd[0])) {
  1270                 if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) {
  1271                     crm_warn(
"Can't redirect input to '%s': %s "  1279                 sigchld_cleanup(&
data);
  1282             action_launch_child(op);
  1287     close(stdout_fd[1]);
  1288     close(stderr_fd[1]);
  1289     if (stdin_fd[0] >= 0) {
  1296         crm_info(
"Could not set '%s' output non-blocking: %s "  1304         crm_info(
"Could not set '%s' error output non-blocking: %s "  1315             crm_info(
"Could not set '%s' input non-blocking: %s "  1319         pipe_in_action_stdin_parameters(op);
  1331         wait_for_sync_result(op, &
data);
  1332         sigchld_cleanup(&
data);
  1339                                   async_action_complete);
  1364     struct dirent **namelist;
  1365     int entries = 0, lpc = 0;
  1366     char buffer[PATH_MAX];
  1368     entries = scandir(root, &namelist, NULL, 
alphasort);
  1373     for (lpc = 0; lpc < entries; lpc++) {
  1376         if (
'.' == namelist[lpc]->d_name[0]) {
  1377             free(namelist[lpc]);
  1381         snprintf(buffer, 
sizeof(buffer), 
"%s/%s", root, namelist[lpc]->d_name);
  1383         if (stat(buffer, &sb)) {
  1387         if (S_ISDIR(sb.st_mode)) {
  1389                 free(namelist[lpc]);
  1393         } 
else if (S_ISREG(sb.st_mode)) {
  1394             if (files == FALSE) {
  1395                 free(namelist[lpc]);
  1398             } 
else if (executable
  1399                        && (sb.st_mode & S_IXUSR) == 0
  1400                        && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
  1401                 free(namelist[lpc]);
  1406         list = g_list_append(list, strdup(namelist[lpc]->d_name));
  1408         free(namelist[lpc]);
  1419     char *dirs = strdup(root);
  1422     if (pcmk__str_empty(dirs)) {
  1427     for (dir = strtok(dirs, 
":"); dir != NULL; dir = strtok(NULL, 
":")) {
 
int rc
Exit status of action (set by library upon completion) 
 
#define CRM_CHECK(expr, failure_action)
 
void(* callback)(svc_action_t *op)
 
int pcmk__set_nonblocking(int fd)
 
const char * pcmk_strerror(int rc)
 
void services_action_free(svc_action_t *op)
 
guint interval_ms
Action interval for recurring resource actions, otherwise 0. 
 
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
 
char * standard
Resource standard for resource actions, otherwise NULL. 
 
#define crm_log_output(level, prefix, output)
 
mainloop_io_t * stderr_gsource
 
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
 
int alphasort(const void *dirent1, const void *dirent2)
 
gboolean recurring_action_timer(gpointer data)
 
struct mainloop_io_s mainloop_io_t
 
void mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *userdata, enum mainloop_child_flags, void(*callback)(mainloop_child_t *p, pid_t pid, int core, int signo, int exitcode))
 
struct mainloop_child_s mainloop_child_t
 
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
 
int services__generic_error(const svc_action_t *op)
 
#define PCMK_RESOURCE_CLASS_OCF
 
char * rsc
XML ID of resource being executed for resource actions, otherwise NULL. 
 
const char * services__action_kind(const svc_action_t *action)
 
int timeout
Action timeout (in milliseconds) 
 
Action did not complete in time. 
 
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code. 
 
char * strerror(int errnum)
 
Wrappers for and extensions to glib mainloop. 
 
char * strndup(const char *str, size_t len)
 
void services_action_cleanup(svc_action_t *op)
 
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready. 
 
volatile struct sigchld_data_s * last_sigchld_data
 
enum svc_action_flags flags
Flag group of enum svc_action_flags. 
 
#define crm_warn(fmt, args...)
 
void services__set_cancelled(svc_action_t *action)
 
gboolean cancel_recurring_action(svc_action_t *op)
 
void services__format_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *format,...) G_GNUC_PRINTF(4
 
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker. 
 
#define crm_debug(fmt, args...)
 
void * mainloop_child_userdata(mainloop_child_t *child)
 
void services_untrack_op(const svc_action_t *op)
 
Parameter invalid (in local context) 
 
char * stdout_data
Action stdout (set by library) 
 
Parameter invalid (inherently) 
 
#define crm_trace(fmt, args...)
 
#define PCMK_OCF_MAJOR_VERSION
 
int setenv(const char *name, const char *value, int why)
 
int services__finalize_async_op(svc_action_t *op)
 
int services__authorization_error(const svc_action_t *op)
 
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
 
GList * services_os_get_single_directory_list(const char *root, gboolean files, gboolean executable)
 
Object for executing external actions. 
 
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag. 
 
void services__set_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *exit_reason)
 
char * agent
Resource agent name for resource actions, otherwise NULL. 
 
Action completed, result is known. 
 
#define PCMK_OCF_MINOR_VERSION
 
Dependencies not available locally. 
 
#define PCMK_OCF_REASON_PREFIX
 
#define EXIT_REASON_MAX_LEN
 
void services_add_inflight_op(svc_action_t *op)
 
int services__not_installed_error(const svc_action_t *op)
 
void(* sighandler_t)(int)
 
char * action
Name of action being executed for resource actions, otherwise NULL. 
 
pcmk__action_result_t result
 
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr. 
 
#define crm_err(fmt, args...)
 
void mainloop_clear_child_userdata(mainloop_child_t *child)
 
#define PCMK_RESOURCE_CLASS_LSB
 
void services__handle_exec_error(svc_action_t *op, int error)
 
void pcmk__close_fds_in_child(bool)
 
mainloop_io_t * stdout_gsource
 
Agent or dependency not available locally. 
 
void mainloop_del_fd(mainloop_io_t *client)
 
const char * pcmk__readable_interval(guint interval_ms)
 
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard. 
 
#define PCMK_RESOURCE_CLASS_NAGIOS
 
int services__configuration_error(const svc_action_t *op, bool is_fatal)
 
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Request asynchronous execution of an action. 
 
char * provider
Resource provider for resource actions that require it, otherwise NULL. 
 
void(* fork_callback)(svc_action_t *op)
 
Execution failed, may be retried. 
 
#define crm_info(fmt, args...)
 
int services__execute_file(svc_action_t *op)
 
int mainloop_child_timeout(mainloop_child_t *child)
 
char * stderr_data
Action stderr (set by library)