16 #include <sys/types.h>
25 #include <sys/resource.h>
33 static void close_pipe(
int fildes[]);
43 #ifdef HAVE_SYS_SIGNALFD_H
47 #include <sys/signalfd.h>
50 struct sigchld_data_s {
57 sigchld_setup(
struct sigchld_data_s *
data)
59 sigemptyset(&(data->mask));
60 sigaddset(&(data->mask), SIGCHLD);
62 sigemptyset(&(data->old_mask));
65 if (sigprocmask(SIG_BLOCK, &(data->mask), &(data->old_mask)) < 0) {
66 crm_err(
"Wait for child process completion failed: %s "
75 sigchld_open(
struct sigchld_data_s *data)
81 fd = signalfd(-1, &(data->mask), SFD_NONBLOCK);
83 crm_err(
"Wait for child process completion failed: %s "
100 sigchld_received(
int fd)
102 struct signalfd_siginfo fdsi;
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 "
113 }
else if (fdsi.ssi_signo == SIGCHLD) {
121 sigchld_cleanup(
struct sigchld_data_s *data)
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",
131 #else // HAVE_SYS_SIGNALFD_H not defined
135 struct sigchld_data_s {
138 struct sigaction old_sa;
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 "
157 sigchld_setup(
struct sigchld_data_s *data)
161 data->pipe_fd[0] = data->pipe_fd[1] = -1;
163 if (pipe(data->pipe_fd) == -1) {
164 crm_err(
"Wait for child process completion failed: %s "
171 crm_warn(
"Could not set pipe input non-blocking: %s " CRM_XS " rc=%d",
176 crm_warn(
"Could not set pipe output non-blocking: %s " CRM_XS " rc=%d",
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 "
190 last_sigchld_data =
data;
195 sigchld_open(
struct sigchld_data_s *data)
198 return data->pipe_fd[0];
202 sigchld_close(
int fd)
209 sigchld_received(
int fd)
218 while (read(fd, &ch, 1) == 1) ;
223 sigchld_cleanup(
struct sigchld_data_s *data)
226 if (sigaction(SIGCHLD, &(data->old_sa), NULL) < 0) {
227 crm_warn(
"Could not clean up after child process completion: %s",
231 close_pipe(data->pipe_fd);
243 close_pipe(
int fildes[])
245 if (fildes[0] >= 0) {
249 if (fildes[1] >= 0) {
256 svc_read_output(
int fd,
svc_action_t * op,
bool is_stderr)
261 static const size_t buf_read_len =
sizeof(buf) - 1;
272 crm_trace(
"Reading %s stderr into offset %d", op->
id, len);
274 }
else if (is_stderr == FALSE && op->
stdout_data) {
277 crm_trace(
"Reading %s stdout into offset %d", op->
id, len);
280 crm_trace(
"Reading %s %s into offset %d", op->
id, is_stderr?
"stderr":
"stdout", len);
284 rc = read(fd, buf, buf_read_len);
287 crm_trace(
"Got %d chars: %.80s", rc, buf);
288 data = pcmk__realloc(data, len + rc + 1);
289 len += sprintf(data + len,
"%s", buf);
291 }
else if (errno != EINTR) {
299 }
while (rc == buf_read_len || rc < 0);
311 dispatch_stdout(gpointer userdata)
319 dispatch_stderr(gpointer userdata)
327 pipe_out_done(gpointer user_data)
341 pipe_err_done(gpointer user_data)
354 .destroy = pipe_out_done,
359 .destroy = pipe_err_done,
363 set_ocf_env(
const char *key,
const char *value, gpointer user_data)
365 if (
setenv(key, value, 1) != 0) {
366 crm_perror(LOG_ERR,
"setenv failed for key:%s and value:%s", key, value);
371 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
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);
380 set_alert_env(gpointer key, gpointer value, gpointer user_data)
385 rc =
setenv(key, value, 1);
392 (
char*)key, (value? (
char*)value :
""));
394 crm_trace(
"setenv %s=%s", (
char*)key, (value? (
char*)value :
""));
407 void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
408 if (op->
agent == NULL) {
409 env_setter = set_alert_env;
412 env_setter = set_ocf_env_with_prefix;
415 if (env_setter != NULL && op->
params != NULL) {
416 g_hash_table_foreach(op->
params, env_setter, NULL);
419 if (env_setter == NULL || env_setter == set_alert_env) {
429 set_ocf_env(
"OCF_RESOURCE_INSTANCE", op->
rsc, NULL);
432 if (op->
agent != NULL) {
433 set_ocf_env(
"OCF_RESOURCE_TYPE", op->
agent, NULL);
438 set_ocf_env(
"OCF_RESOURCE_PROVIDER", op->
provider, NULL);
443 pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data)
447 int ret, total = 0, len = strlen(buffer);
456 }
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);
555 op->
id, op->
pid, (is_stderr?
"stdout" :
"stderr"));
556 svc_read_output(fd, op, is_stderr);
573 strcpy(prefix + strlen(prefix) - strlen(
"error output"),
"output");
590 finish_op_output(op,
true);
591 finish_op_output(op,
false);
596 crm_debug(
"%s[%d] exited with status %d", op->
id, op->
pid, exitcode);
610 op->
id, op->
pid, strsignal(signo), signo);
616 op->
id, op->
pid, strsignal(signo), signo);
637 int rc_not_installed, rc_insufficient_priv, rc_exec_error;
666 op->
rc = rc_not_installed;
671 op->
rc = rc_insufficient_priv;
675 op->
rc = rc_exec_error;
688 signal(SIGPIPE, SIG_DFL);
690 #if defined(HAVE_SCHED_SETSCHEDULER)
691 if (sched_getscheduler(0) != SCHED_OTHER) {
692 struct sched_param sp;
694 memset(&sp, 0,
sizeof(sp));
695 sp.sched_priority = 0;
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);
702 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
703 crm_perror(LOG_ERR,
"Could not reset process priority to 0 for %s", op->
id);
714 #if SUPPORT_CIBSECRETS
719 crm_info(
"proceeding with the stop operation for %s", op->
rsc);
722 crm_err(
"failed to get secrets for %s, "
723 "considering resource not configured", op->
rsc);
729 add_action_env_vars(op);
732 if (op->
opaque->
uid && (geteuid() == 0)) {
742 if (setgroups(0, NULL) < 0) {
743 crm_perror(LOG_ERR,
"Could not set child groups");
764 action_synced_wait(
svc_action_t *op,
struct sigchld_data_s *data)
769 struct pollfd fds[3];
773 fds[0].events = POLLIN;
777 fds[1].events = POLLIN;
780 fds[2].fd = sigchld_open(data);
781 fds[2].events = POLLIN;
787 int poll_rc = poll(fds, 3, timeout);
790 if (fds[0].revents & POLLIN) {
794 if (fds[1].revents & POLLIN) {
798 if ((fds[2].revents & POLLIN) && sigchld_received(fds[2].fd)) {
799 wait_rc = waitpid(op->
pid, &status, WNOHANG);
801 if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) {
805 }
else if (wait_rc < 0) {
806 crm_warn(
"Wait for completion of %s[%d] failed: %s "
813 }
else if (poll_rc == 0) {
818 }
else if ((poll_rc < 0) && (errno != EINTR)) {
819 crm_err(
"Wait for completion of %s[%d] failed: %s "
825 timeout = op->
timeout - (time(NULL) - start) * 1000;
827 }
while ((op->
timeout < 0 || timeout > 0));
833 if (op->
timeout > 0 && timeout <= 0) {
835 crm_warn(
"%s[%d] timed out after %dms",
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",
850 while (waitpid(op->
pid, &status, 0) == (pid_t) -1 && errno == EINTR) ;
853 }
else if (WIFEXITED(status)) {
855 op->
rc = WEXITSTATUS(status);
858 }
else if (WIFSIGNALED(status)) {
859 int signo = WTERMSIG(status);
863 op->
id, op->
pid, strsignal(signo), signo);
866 if (WCOREDUMP(status)) {
871 finish_op_output(op,
true);
872 finish_op_output(op,
false);
874 sigchld_close(fds[2].fd);
884 int stdin_fd[2] = {-1, -1};
887 struct sigchld_data_s data;
901 if (pipe(stdout_fd) < 0) {
903 crm_err(
"Cannot execute '%s': %s " CRM_XS " pipe(stdout) rc=%d",
912 if (pipe(stderr_fd) < 0) {
915 close_pipe(stdout_fd);
917 crm_err(
"Cannot execute '%s': %s " CRM_XS " pipe(stderr) rc=%d",
927 if (pipe(stdin_fd) < 0) {
930 close_pipe(stdout_fd);
931 close_pipe(stderr_fd);
933 crm_err(
"Cannot execute '%s': %s " CRM_XS " pipe(stdin) rc=%d",
944 close_pipe(stdin_fd);
945 close_pipe(stdout_fd);
946 close_pipe(stderr_fd);
947 sigchld_cleanup(&data);
955 close_pipe(stdin_fd);
956 close_pipe(stdout_fd);
957 close_pipe(stderr_fd);
966 sigchld_cleanup(&data);
972 if (stdin_fd[1] >= 0) {
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 "
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 "
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 "
1002 sigchld_cleanup(&data);
1005 action_launch_child(op);
1010 close(stdout_fd[1]);
1011 close(stderr_fd[1]);
1012 if (stdin_fd[0] >= 0) {
1019 crm_warn(
"Could not set '%s' output non-blocking: %s "
1027 crm_warn(
"Could not set '%s' error output non-blocking: %s "
1038 crm_warn(
"Could not set '%s' input non-blocking: %s "
1042 pipe_in_action_stdin_parameters(op);
1054 action_synced_wait(op, &data);
1055 sigchld_cleanup(&data);
1063 operation_finished);
1081 services_os_get_single_directory_list(
const char *root, gboolean files, gboolean executable)
1084 struct dirent **namelist;
1085 int entries = 0, lpc = 0;
1086 char buffer[PATH_MAX];
1088 entries = scandir(root, &namelist, NULL,
alphasort);
1093 for (lpc = 0; lpc < entries; lpc++) {
1096 if (
'.' == namelist[lpc]->d_name[0]) {
1097 free(namelist[lpc]);
1101 snprintf(buffer,
sizeof(buffer),
"%s/%s", root, namelist[lpc]->d_name);
1103 if (stat(buffer, &sb)) {
1107 if (S_ISDIR(sb.st_mode)) {
1109 free(namelist[lpc]);
1113 }
else if (S_ISREG(sb.st_mode)) {
1114 if (files == FALSE) {
1115 free(namelist[lpc]);
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]);
1126 list = g_list_append(list, strdup(namelist[lpc]->d_name));
1128 free(namelist[lpc]);
1138 GList *result = NULL;
1139 char *dirs = strdup(root);
1142 if (pcmk__str_empty(dirs)) {
1147 for (dir = strtok(dirs,
":"); dir != NULL; dir = strtok(NULL,
":")) {
1148 GList *tmp = services_os_get_single_directory_list(dir, files, executable);
1151 result = g_list_concat(result, tmp);
1161 services_os_get_directory_list_provider(
const char *root,
const char *provider, gboolean files, gboolean executable)
1163 GList *result = NULL;
1164 char *dirs = strdup(root);
1166 char buffer[PATH_MAX];
1168 if (pcmk__str_empty(dirs)) {
1173 for (dir = strtok(dirs,
":"); dir != NULL; dir = strtok(NULL,
":")) {
1176 sprintf(buffer,
"%s/%s", dir, provider);
1177 tmp = services_os_get_single_directory_list(buffer, files, executable);
1180 result = g_list_concat(result, tmp);
1198 GList *gIter = NULL;
1199 GList *result = NULL;
1200 GList *providers = NULL;
1203 return services_os_get_directory_list_provider(
OCF_RA_PATH, provider, TRUE, TRUE);
1207 for (gIter = providers; gIter != NULL; gIter = gIter->next) {
1208 GList *tmp1 = result;
1212 result = g_list_concat(tmp1, tmp2);
1215 g_list_free_full(providers, free);
1222 gboolean rc = FALSE;
1228 if (provider == NULL || agent == NULL || pcmk__str_empty(dirs)) {
1233 for (dir = strtok(dirs,
":"); dir != NULL; dir = strtok(NULL,
":")) {
1235 if (stat(buf, &st) == 0) {
#define CRM_CHECK(expr, failure_action)
const char * pcmk_strerror(int rc)
void services_action_free(svc_action_t *op)
gboolean services__ocf_agent_exists(const char *provider, const char *agent)
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
#define crm_log_output(level, prefix, output)
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
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 pcmk__close_fds_in_child(bool)
void(* fork_callback)(svc_action_t *op)
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(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
gboolean services_os_action_execute(svc_action_t *op)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Wrappers for and extensions to glib mainloop.
void services_action_cleanup(svc_action_t *op)
enum svc_action_flags flags
#define crm_warn(fmt, args...)
#define PCMK_RESOURCE_CLASS_OCF
gboolean cancel_recurring_action(svc_action_t *op)
svc_action_private_t * opaque
#define crm_debug(fmt, args...)
void * mainloop_child_userdata(mainloop_child_t *child)
gboolean operation_finalize(svc_action_t *op)
#define crm_trace(fmt, args...)
#define PCMK_OCF_MAJOR_VERSION
int setenv(const char *name, const char *value, int why)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
void(* callback)(svc_action_t *op)
#define PCMK_OCF_MINOR_VERSION
#define PCMK_OCF_REASON_PREFIX
void services_add_inflight_op(svc_action_t *op)
void services_untrack_op(svc_action_t *op)
#define PCMK_RESOURCE_CLASS_NAGIOS
#define PCMK_RESOURCE_CLASS_LSB
#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)
GList * get_directory_list(const char *root, gboolean files, gboolean executable)
Get a list of files or directories in a given path.
void services__handle_exec_error(svc_action_t *op, int error)
mainloop_io_t * stdout_gsource
void mainloop_del_fd(mainloop_io_t *client)
struct sigchld_data_s * last_sigchld_data
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
#define crm_info(fmt, args...)
int pcmk__set_nonblocking(int fd)
int mainloop_child_timeout(mainloop_child_t *child)