+++ /dev/null
-/*
- * Master Worker - program
- *
- * Copyright HAProxy Technologies - William Lallemand <wlallemand@haproxy.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <haproxy/api.h>
-#include <haproxy/cfgparse.h>
-#include <haproxy/errors.h>
-#include <haproxy/global.h>
-#include <haproxy/mworker.h>
-#include <haproxy/task.h>
-#include <haproxy/time.h>
-#include <haproxy/tools.h>
-
-
-static int use_program = 0; /* do we use the program section ? */
-
-/*
- * Launch every programs
- */
-int mworker_ext_launch_all()
-{
- int ret;
- struct mworker_proc *child;
- struct mworker_proc *tmp;
- int reexec = 0;
-
- if (!use_program)
- return 0;
-
- reexec = getenv("HAPROXY_MWORKER_REEXEC") ? 1 : 0;
-
- /* find the right mworker_proc */
- list_for_each_entry_safe(child, tmp, &proc_list, list) {
- /* need to stop progs, which were launched before reload */
- if ((child->options & PROC_O_TYPE_PROG) && (child->options & PROC_O_LEAVING))
- kill(child->pid, oldpids_sig);
-
- if (child->reloads == 0 && (child->options & PROC_O_TYPE_PROG)) {
-
- if (reexec && (!(child->options & PROC_O_START_RELOAD))) {
- struct mworker_proc *old_child;
-
- /*
- * This is a reload and we don't want to fork a
- * new program so have to remove the entry in
- * the list.
- *
- * But before that, we need to mark the
- * previous program as not leaving, if we find one.
- */
-
- list_for_each_entry(old_child, &proc_list, list) {
- if (!(old_child->options & PROC_O_TYPE_PROG) || (!(old_child->options & PROC_O_LEAVING)))
- continue;
-
- if (strcmp(old_child->id, child->id) == 0)
- old_child->options &= ~PROC_O_LEAVING;
- }
-
-
- LIST_DELETE(&child->list);
- mworker_free_child(child);
- child = NULL;
-
- continue;
- }
-
- child->timestamp = ns_to_sec(now_ns);
-
- ret = fork();
- if (ret < 0) {
- ha_alert("Cannot fork program '%s'.\n", child->id);
- exit(EXIT_FAILURE); /* there has been an error */
- } else if (ret > 0) { /* parent */
- child->pid = ret;
- ha_notice("New program '%s' (%d) forked\n", child->id, ret);
- continue;
- } else if (ret == 0) {
- /* In child */
- mworker_unblock_signals();
- mworker_cleanlisteners();
- mworker_cleantasks();
-
- /* setgid / setuid */
- if (child->gid != -1) {
- if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
- ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
- " without 'uid'/'user' is generally useless.\n", child->command[0]);
-
- if (setgid(child->gid) == -1) {
- ha_alert("[%s.main()] Cannot set gid %d.\n", child->command[0], child->gid);
- exit(1);
- }
- }
-
- if (child->uid != -1 && setuid(child->uid) == -1) {
- ha_alert("[%s.main()] Cannot set uid %d.\n", child->command[0], child->gid);
- exit(1);
- }
-
- /* This one must not be exported, it's internal! */
- unsetenv("HAPROXY_MWORKER_REEXEC");
- unsetenv("HAPROXY_PROCESSES");
- execvp(child->command[0], child->command);
-
- ha_alert("Cannot execute %s: %s\n", child->command[0], strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
- }
-
- return 0;
-
-}
-
-
-/* Configuration */
-
-int cfg_parse_program(const char *file, int linenum, char **args, int kwm)
-{
- static struct mworker_proc *ext_child = NULL;
- struct mworker_proc *child;
- int err_code = 0;
-
- if (!(global.mode & MODE_DISCOVERY))
- return err_code;
-
- if (strcmp(args[0], "program") == 0) {
- if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
- err_code |= ERR_ABORT;
- goto error;
- }
-
- if (!*args[1]) {
- ha_alert("parsing [%s:%d] : '%s' expects an <id> argument\n",
- file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
-
- ext_child = calloc(1, sizeof(*ext_child));
- if (!ext_child) {
- ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
-
- ext_child->options |= PROC_O_TYPE_PROG; /* external process */
- ext_child->command = NULL;
- ext_child->path = NULL;
- ext_child->id = NULL;
- ext_child->pid = -1;
- ext_child->reloads = 0;
- ext_child->timestamp = -1;
- ext_child->ipc_fd[0] = -1;
- ext_child->ipc_fd[1] = -1;
- ext_child->options |= PROC_O_START_RELOAD; /* restart the programs by default */
- ext_child->uid = -1;
- ext_child->gid = -1;
- LIST_INIT(&ext_child->list);
-
- list_for_each_entry(child, &proc_list, list) {
- if (child->reloads == 0 && (child->options & PROC_O_TYPE_PROG)) {
- if (strcmp(args[1], child->id) == 0) {
- ha_alert("parsing [%s:%d]: '%s' program section already exists in the configuration.\n", file, linenum, args[1]);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
- }
- }
-
- ext_child->id = strdup(args[1]);
- if (!ext_child->id) {
- ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
-
- if (!deprecated_directives_allowed) {
- ha_warning("parsing [%s:%d]: The 'program' section is deprecated and will be eventually removed, "
- "it can be still allowed by setting 'expose-deprecated-directives' keyword in the 'global' "
- "section defined before any 'program' section. Please, consider to use a process manager instead "
- "of 'program' section, such as sysvinit, systemd, supervisord or s6.\n",
- file, linenum);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
-
- LIST_APPEND(&proc_list, &ext_child->list);
-
- } else if (strcmp(args[0], "command") == 0) {
- int arg_nb = 0;
- int i = 0;
-
- if (*(args[1]) == 0) {
- ha_alert("parsing [%s:%d]: '%s' expects a command with optional arguments separated in words.\n", file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-
- while (*args[arg_nb+1])
- arg_nb++;
-
- ext_child->command = calloc(arg_nb+1, sizeof(*ext_child->command));
-
- if (!ext_child->command) {
- ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
-
- while (i < arg_nb) {
- ext_child->command[i] = strdup(args[i+1]);
- if (!ext_child->command[i]) {
- ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
- err_code |= ERR_ALERT | ERR_ABORT;
- goto error;
- }
- i++;
- }
- ext_child->command[i] = NULL;
-
- } else if (strcmp(args[0], "option") == 0) {
-
- if (*(args[1]) == '\0') {
- ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
- file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-
- if (strcmp(args[1], "start-on-reload") == 0) {
- if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
- goto error;
- if (kwm == KWM_STD)
- ext_child->options |= PROC_O_START_RELOAD;
- else if (kwm == KWM_NO)
- ext_child->options &= ~PROC_O_START_RELOAD;
- goto out;
-
- } else {
- ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
- } else if (strcmp(args[0], "user") == 0) {
- struct passwd *ext_child_user;
- if (*(args[1]) == '\0') {
- ha_alert("parsing [%s:%d]: '%s' expects a user name.\n",
- file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
- goto error;
-
- if (ext_child->uid != -1) {
- ha_alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
- err_code |= ERR_ALERT;
- goto out;
- }
-
- ext_child_user = getpwnam(args[1]);
- if (ext_child_user != NULL) {
- ext_child->uid = (int)ext_child_user->pw_uid;
- } else {
- ha_alert("parsing [%s:%d] : cannot find user id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
- err_code |= ERR_ALERT | ERR_FATAL;
- }
- } else if (strcmp(args[0], "group") == 0) {
- struct group *ext_child_group;
- if (*(args[1]) == '\0') {
- ha_alert("parsing [%s:%d]: '%s' expects a group name.\n",
- file, linenum, args[0]);
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
- goto error;
-
- if (ext_child->gid != -1) {
- ha_alert("parsing [%s:%d] : group/gid already specified. Continuing.\n", file, linenum);
- err_code |= ERR_ALERT;
- goto out;
- }
-
- ext_child_group = getgrnam(args[1]);
- if (ext_child_group != NULL) {
- ext_child->gid = (int)ext_child_group->gr_gid;
- } else {
- ha_alert("parsing [%s:%d] : cannot find group id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
- err_code |= ERR_ALERT | ERR_FATAL;
- }
- } else {
- ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "program");
- err_code |= ERR_ALERT | ERR_FATAL;
- goto error;
- }
-
- use_program = 1;
-
- return err_code;
-
-error:
- if (ext_child) {
- LIST_DELETE(&ext_child->list);
- if (ext_child->command) {
- int i;
-
- for (i = 0; ext_child->command[i]; i++) {
- ha_free(&ext_child->command[i]);
- }
- ha_free(&ext_child->command);
- }
- ha_free(&ext_child->id);
- }
-
- ha_free(&ext_child);
-
-out:
- return err_code;
-
-}
-
-REGISTER_CONFIG_SECTION("program", cfg_parse_program, NULL);
list_for_each_entry(child, &proc_list, list) {
/* careful there, we must be sure that the pid > 0, we don't want to emit a kill -1 */
- if ((child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) && (child->pid > 0))
+ if ((child->options & PROC_O_TYPE_WORKER) && (child->pid > 0))
kill(child->pid, sig);
}
}
struct mworker_proc *child;
list_for_each_entry(child, &proc_list, list) {
- if ((child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) && (!(child->options & PROC_O_LEAVING)) && (child->pid == pid))
+ if ((child->options & PROC_O_TYPE_WORKER) && (!(child->options & PROC_O_LEAVING)) && (child->pid == pid))
return 1;
}
return 0;
int ret = 0;
list_for_each_entry(child, &proc_list, list) {
- if (child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG))
+ if (child->options & PROC_O_TYPE_WORKER)
ret++;
}
if (child->options & PROC_O_TYPE_MASTER)
type = 'm';
- else if (child->options & PROC_O_TYPE_PROG)
- type = 'e';
else if (child->options &= PROC_O_TYPE_WORKER)
type = 'w';
if (type == 'm') { /* we are in the master, assign it */
proc_self = child;
child->options |= PROC_O_TYPE_MASTER;
- } else if (type == 'e') {
- child->options |= PROC_O_TYPE_PROG;
} else if (type == 'w') {
child->options |= PROC_O_TYPE_WORKER;
}
else
ha_alert("Current worker (%d) exited with code %d (%s)\n", exitpid, status, strsignal(status - 128));
}
- else if (child->options & PROC_O_TYPE_PROG)
- ha_alert("Current program '%s' (%d) exited with code %d (%s)\n", child->id, exitpid, status, (status >= 128) ? strsignal(status - 128) : "Exit");
if (status != 0 && status != 130 && status != 143) {
if (child->options & PROC_O_TYPE_WORKER) {
/* Delete fd from poller fdtab, which will close it */
fd_delete(child->ipc_fd[0]);
delete_oldpid(exitpid);
- } else if (child->options & PROC_O_TYPE_PROG) {
- /* ipc_fd[0] and ipc_fd[1] are not used for PROC_O_TYPE_PROG and kept as -1,
- * thus they are never inserted in fdtab (otherwise, BUG_ON in fd_insert if fd <0)
- */
- ha_warning("Former program '%s' (%d) exited with code %d (%s)\n", child->id, exitpid, status, (status >= 128) ? strsignal(status - 128) : "Exit");
}
}
mworker_free_child(child);
struct cli_showproc_ctx *ctx = appctx->svcctx;
char *uptime = NULL;
char *reloadtxt = NULL;
- int program_nb = 0;
if (up < 0) /* must never be negative because of clock drift */
up = 0;
free(msg);
}
- /* displays external process */
- old = 0;
- list_for_each_entry(child, &proc_list, list) {
- up = date.tv_sec - child->timestamp;
- if (up < 0) /* must never be negative because of clock drift */
- up = 0;
-
- if (!(child->options & PROC_O_TYPE_PROG))
- continue;
-
- if (child->options & PROC_O_LEAVING) {
- old++;
- continue;
- }
- if (program_nb == 0)
- chunk_appendf(&trash, "# programs\n");
- program_nb++;
- memprintf(&uptime, "%dd%02dh%02dm%02ds", up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60));
- chunk_appendf(&trash, "%-15u %-15s %-15d %-15s %-15s\n", child->pid, child->id, child->reloads, uptime, "-");
- ha_free(&uptime);
- }
-
- if (old) {
- chunk_appendf(&trash, "# old programs\n");
- list_for_each_entry(child, &proc_list, list) {
- up = date.tv_sec - child->timestamp;
- if (up < 0) /* must never be negative because of clock drift */
- up = 0;
-
- if (!(child->options & PROC_O_TYPE_PROG))
- continue;
-
- if (child->options & PROC_O_LEAVING) {
- memprintf(&uptime, "%dd%02dh%02dm%02ds", up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60));
- chunk_appendf(&trash, "%-15u %-15s %-15d %-15s %-15s\n", child->pid, child->id, child->reloads, uptime, "-");
- ha_free(&uptime);
- }
- }
- }
-
-
-
if (applet_putchk(appctx, &trash) == -1)
return 0;