if (global.mode & MODE_CHECK_CONDITION)
do_check_condition(progname);
- /* set the atexit functions when not doing configuration check */
- if (!(global.mode & MODE_CHECK) && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
-
- if (global.mode & MODE_MWORKER) {
- atexit_flag = 1;
- atexit(reexec_on_failure);
- } else if (global.mode & MODE_MWORKER_WAIT) {
- atexit_flag = 1;
- atexit(exit_on_waitmode_failure);
- }
- }
-
if (change_dir && chdir(change_dir) < 0) {
ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
exit(1);
usermsgs_clr("config");
/* in wait mode, we don't try to read the configuration files */
- if (!(global.mode & MODE_MWORKER_WAIT)) {
+ if (!(global.mode & MODE_MWORKER)) {
ret = read_cfg(progname);
/* free memory to store config file content */
list_for_each_entry_safe(cfg, cfg_tmp, &cfg_cfgfiles, list)
DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
}
- if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT))
+ /* master-worker mode fork() */
+ if (global.mode & MODE_MWORKER) {
+ int worker_pid;
+ struct mworker_proc *child;
+ struct ring *tmp_startup_logs = NULL;
+
+ /* at this point the worker must have his own startup_logs buffer */
+ tmp_startup_logs = startup_logs_dup(startup_logs);
+ worker_pid = fork();
+ switch (worker_pid) {
+ case -1:
+ ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
+
+ exit(EXIT_FAILURE);
+ case 0:
+ /* in child */
+ startup_logs_free(startup_logs);
+ startup_logs = tmp_startup_logs;
+ /* This one must not be exported, it's internal! */
+ unsetenv("HAPROXY_MWORKER_REEXEC");
+ ha_random_jump96(1);
+ /* proc_self needs to point to the new forked worker in
+ * worker's context, as it's dereferenced in
+ * mworker_sockpair_register_per_thread(), called for
+ * master and for worker.
+ */
+ list_for_each_entry(child, &proc_list, list) {
+ if (child->options & PROC_O_TYPE_WORKER &&
+ child->reloads == 0 &&
+ child->pid == -1) {
+ proc_self = child;
+ break;
+ }
+ }
+
+ break;
+ default:
+ /* in parent */
+ global.mode |= MODE_MWORKER_WAIT;
+ master = 1;
+ atexit_flag = 1;
+ atexit(exit_on_waitmode_failure);
+
+ ha_notice("Initializing new worker (%d)\n", worker_pid);
+ /* find the right mworker_proc */
+ list_for_each_entry(child, &proc_list, list) {
+ if (child->reloads == 0 && child->options & PROC_O_TYPE_WORKER && child->pid == -1) {
+ child->timestamp = date.tv_sec;
+ child->pid = worker_pid;
+ child->version = strdup(haproxy_version);
+ /* at this step the fd is bound for the worker, set it to -1 so
+ * it could be close in case of errors in mworker_cleanup_proc() */
+ child->ipc_fd[1] = -1;
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (master)
mworker_create_master_cli();
if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
}
/* set the default maxconn in the master, but let it be rewritable with -n */
- if (global.mode & MODE_MWORKER_WAIT)
+ if (master)
global.maxconn = MASTER_MAXCONN;
if (cfg_maxconn > 0)
int main(int argc, char **argv)
{
int err, retry;
+ int devnullfd = -1;
struct rlimit limit;
int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
clock_adjust_now_offset();
ready_date = date;
- /* catch last warnings, which could be produced while adjusting limits
- * or preallocating fds
- */
- if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
- ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
- exit(1);
+ /* close the pidfile both in children and father */
+ if (pidfd >= 0) {
+ //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
+ close(pidfd);
}
+ /* We won't ever use this anymore */
+ ha_free(&global.pidfile);
- if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
- int ret = 0;
- int in_parent = 0;
- int devnullfd = -1;
-
- /* the father launches the required number of processes */
- if (!(global.mode & MODE_MWORKER_WAIT)) {
- struct ring *tmp_startup_logs = NULL;
-
- if (global.mode & MODE_MWORKER)
- mworker_ext_launch_all();
-
- /* at this point the worker must have his own startup_logs buffer */
- tmp_startup_logs = startup_logs_dup(startup_logs);
- ret = fork();
- if (ret < 0) {
- ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
- protocol_unbind_all();
- exit(1); /* there has been an error */
- }
- else if (ret == 0) { /* child breaks here */
- startup_logs_free(startup_logs);
- startup_logs = tmp_startup_logs;
- /* This one must not be exported, it's internal! */
- unsetenv("HAPROXY_MWORKER_REEXEC");
- ha_random_jump96(1);
- }
- else { /* parent here */
- in_parent = 1;
-
- if (global.mode & MODE_MWORKER) {
- struct mworker_proc *child;
-
- ha_notice("New worker (%d) forked\n", ret);
- /* find the right mworker_proc */
- list_for_each_entry(child, &proc_list, list) {
- if (child->reloads == 0 &&
- child->options & PROC_O_TYPE_WORKER &&
- child->pid == -1) {
- child->timestamp = date.tv_sec;
- child->pid = ret;
- child->version = strdup(haproxy_version);
- /* at this step the fd is bound for the worker, set it to -1 so
- * it could be close in case of errors in mworker_cleanup_proc() */
- child->ipc_fd[1] = -1;
- break;
- }
- }
- }
- }
-
- } else {
- /* wait mode */
- in_parent = 1;
- }
+ if (global.mode & MODE_MWORKER_WAIT) {
+ struct mworker_proc *child, *it;
- /* close the pidfile both in children and father */
- if (pidfd >= 0) {
- //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
- close(pidfd);
+ if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
+ (global.mode & MODE_DAEMON)) {
+ /* detach from the tty, this is required to properly daemonize. */
+ if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
+ stdio_quiet(-1);
+ global.mode &= ~MODE_VERBOSE;
+ global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
}
-
- /* We won't ever use this anymore */
- ha_free(&global.pidfile);
-
- if (in_parent) {
- if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
- master = 1;
-
- if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
- (global.mode & MODE_DAEMON)) {
- /* detach from the tty, this is required to properly daemonize. */
- if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
- stdio_quiet(-1);
-
- global.mode &= ~MODE_VERBOSE;
- global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
- }
-
- if (global.mode & MODE_MWORKER_WAIT) {
- /* only the wait mode handles the master CLI */
- mworker_loop();
- } else {
-
-#if defined(USE_SYSTEMD)
- if (global.tune.options & GTUNE_USE_SYSTEMD)
- sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
-#endif
- /* if not in wait mode, restore initial environment (before parsing the config) and
- * reload in wait mode to free the memory. The initial process environment should
- * be restored here, preceded by clean_env(), which do the same job as clearenv().
- * Otherwise, we will lost HAPROXY_LOAD_SUCCESS, HAPROXY_MWORKER_WAIT_ONLY and
- * HAPROXY_MWORKER_REEXEC variables, which will be set further.
- */
- if (clean_env() != 0)
- exit(EXIT_FAILURE);
-
- if (restore_env() != 0)
- exit(EXIT_FAILURE);
-
- setenv("HAPROXY_LOAD_SUCCESS", "1", 1);
- ha_notice("Loading success.\n");
- proc_self->failedreloads = 0; /* reset the number of failure */
- mworker_reexec_waitmode();
- }
- /* should never get there */
- exit(EXIT_FAILURE);
- }
+ setenv("HAPROXY_LOAD_SUCCESS", "1", 1);
+ ha_notice("Loading success.\n");
+ proc_self->failedreloads = 0; /* reset the number of failure */
+ mworker_loop();
#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
- ssl_free_dh();
+ ssl_free_dh();
#endif
- exit(0); /* parent must leave */
- }
-
- /* child must never use the atexit function */
- atexit_flag = 0;
-
+ master = 0;
/* close useless master sockets */
- if (global.mode & MODE_MWORKER) {
- struct mworker_proc *child, *it;
- master = 0;
-
- mworker_cli_proxy_stop();
-
- /* free proc struct of other processes */
- list_for_each_entry_safe(child, it, &proc_list, list) {
- /* close the FD of the master side for all
- * workers, we don't need to close the worker
- * side of other workers since it's done with
- * the bind_proc */
- if (child->ipc_fd[0] >= 0) {
- close(child->ipc_fd[0]);
- child->ipc_fd[0] = -1;
- }
- if (child->options & PROC_O_TYPE_WORKER &&
- child->reloads == 0 &&
- child->pid == -1) {
- /* keep this struct if this is our pid */
- proc_self = child;
- continue;
- }
- LIST_DELETE(&child->list);
- mworker_free_child(child);
- child = NULL;
+ mworker_cli_proxy_stop();
+
+ /* free proc struct of other processes */
+ list_for_each_entry_safe(child, it, &proc_list, list) {
+ /* close the FD of the master side for all
+ * workers, we don't need to close the worker
+ * side of other workers since it's done with
+ * the bind_proc */
+ if (child->ipc_fd[0] >= 0) {
+ close(child->ipc_fd[0]);
+ child->ipc_fd[0] = -1;
}
+ LIST_DELETE(&child->list);
+ mworker_free_child(child);
+ child = NULL;
}
+ /* master must leave */
+ exit(0);
+ }
- if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
- devnullfd = open("/dev/null", (O_RDWR | O_CLOEXEC), 0);
- if (devnullfd < 0) {
- ha_alert("Cannot open /dev/null\n");
- exit(EXIT_FAILURE);
- }
+ if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
+ devnullfd = open("/dev/null", (O_RDWR | O_CLOEXEC), 0);
+ if (devnullfd < 0) {
+ ha_alert("Cannot open /dev/null\n");
+ exit(EXIT_FAILURE);
}
+ }
- /* Must chroot and setgid/setuid in the children */
- /* chroot if needed */
- if (global.chroot != NULL) {
- if (chroot(global.chroot) == -1 || chdir("/") == -1) {
- ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
- if (nb_oldpids)
- tell_old_pids(SIGTTIN);
- protocol_unbind_all();
- exit(1);
- }
+ /* Must chroot and setgid/setuid in the children */
+ /* chroot if needed */
+ if (global.chroot != NULL) {
+ if (chroot(global.chroot) == -1 || chdir("/") == -1) {
+ ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
+ if (nb_oldpids)
+ tell_old_pids(SIGTTIN);
+ protocol_unbind_all();
+ exit(1);
}
+ }
- ha_free(&global.chroot);
- set_identity(argv[0]);
+ ha_free(&global.chroot);
+ set_identity(argv[0]);
- /*
- * This is only done in daemon mode because we might want the
- * logs on stdout in mworker mode. If we're NOT in QUIET mode,
- * we should now close the 3 first FDs to ensure that we can
- * detach from the TTY. We MUST NOT do it in other cases since
- * it would have already be done, and 0-2 would have been
- * affected to listening sockets
- */
- if ((global.mode & MODE_DAEMON) &&
- (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
- /* detach from the tty */
- stdio_quiet(devnullfd);
- global.mode &= ~MODE_VERBOSE;
- global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
- }
- pid = getpid(); /* update child's pid */
- if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
- setsid();
- fork_poller();
- }
+ /*
+ * This is only done in daemon mode because we might want the
+ * logs on stdout in mworker mode. If we're NOT in QUIET mode,
+ * we should now close the 3 first FDs to ensure that we can
+ * detach from the TTY. We MUST NOT do it in other cases since
+ * it would have already be done, and 0-2 would have been
+ * affected to listening sockets
+ */
+ if ((global.mode & MODE_DAEMON) &&
+ (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
+ /* detach from the tty */
+ stdio_quiet(devnullfd);
+ global.mode &= ~MODE_VERBOSE;
+ global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
+ }
+ pid = getpid(); /* update pid */
+ setsid();
+ fork_poller();
/* pass through every cli socket, and check if it's bound to
* the current process and if it exposes listeners sockets.
/* when multithreading we need to let only the thread 0 handle the signals */
haproxy_unblock_signals();
+#if defined(USE_SYSTEMD)
+ if (global.tune.options & GTUNE_USE_SYSTEMD)
+ sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
+#endif
/* Finally, start the poll loop for the first thread */
run_thread_poll_loop(&ha_thread_info[0]);