Mercurial > notdcc
diff dcclib/restart.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcclib/restart.c Tue Mar 10 13:49:58 2009 +0100 @@ -0,0 +1,231 @@ +/* Distributed Checksum Clearinghouse + * + * continually restart a daemon + * + * Copyright (c) 2008 by Rhyolite Software, LLC + * + * This agreement is not applicable to any entity which sells anti-spam + * solutions to others or provides an anti-spam solution as part of a + * security solution sold to other entities, or to a private network + * which employs the DCC or uses data provided by operation of the DCC + * but does not provide corresponding data to other users. + * + * Permission to use, copy, modify, and distribute this software without + * changes for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear in all + * copies and any distributed versions or copies are either unchanged + * or not called anything similar to "DCC" or "Distributed Checksum + * Clearinghouse". + * + * Parties not eligible to receive a license under this agreement can + * obtain a commercial license to use DCC by contacting Rhyolite Software + * at sales@rhyolite.com. + * + * A commercial license would be for Distributed Checksum and Reputation + * Clearinghouse software. That software includes additional features. This + * free license for Distributed ChecksumClearinghouse Software does not in any + * way grant permision to use Distributed Checksum and Reputation Clearinghouse + * software + * + * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Rhyolite Software DCC 1.3.103-1.16 $Revision$ + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <pwd.h> +#include "dcc_clnt.h" + + +static pid_t start_pid = -1; + +static void +restart_sigterm(int sig) +{ + if (start_pid > 0 + && 0 <= kill(start_pid, sig)) + return; + exit(-1); +} + + + +#define MIN_RESTART_DELAY 5 +#define MAX_RESTART_DELAY (5*60) + +/* stay alive despite core dumps + * Restart immediately, but not more often than every MINRESTART_DELAY + * seconds. If the restarts are happening at the maximum rate, + * halve the rate. */ +void +dcc_daemon_restart(const char *rundir, void(reconn)(void)) +{ +#if defined(WIFEXITED) && defined(WTERMSIG) && defined(WIFSIGNALED) + pid_t pid; + time_t next_restart, restart_delay; + int status; + const char *etype; + DCC_PATH pidpath; + + signal(SIGHUP, restart_sigterm); + signal(SIGTERM, restart_sigterm); + signal(SIGINT, restart_sigterm); + + restart_delay = MIN_RESTART_DELAY; + next_restart = 0; + for (;;) { + start_pid = fork(); + if (!start_pid) { +#ifdef HAVE_SETPGID + if (0 > setpgid(0, 0)) + dcc_error_msg("setpgid(): %s", ERROR_STR()); +#endif + /* reconnect sockets or whatever except first time */ + if (next_restart != 0 + && reconn) + reconn(); + return; + } + + if (start_pid < 0) + dcc_logbad(EX_OSERR, "(re)start fork(): %s", + ERROR_STR()); + + next_restart = time(0)+restart_delay; + pid = waitpid(start_pid, &status, 0); + if (pid < 0) { + if (errno != EINTR) + dcc_logbad(EX_OSERR, "restart waitpid(): %s", + ERROR_STR()); + exit(0); + } + + start_pid = -1; + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + etype = "exit "; + if (status != EX_DCC_RESTART) { + if (dcc_clnt_debug) + dcc_error_msg("do not restart after" + " exit(%d)", + status); + exit(status); + } + + } else if (WIFSIGNALED(status)) { + status = WTERMSIG(status); + etype = "signal #"; + if (status != SIGILL + && status != SIGSEGV +#ifdef SIGBUS + && status != SIGBUS +#endif +#ifdef SIGXCPU + && status != SIGXCPU +#endif +#ifdef SIGFPE + && status != SIGFPE +#endif +#ifdef SIGSYS + && status != SIGSYS +#endif +#ifdef SIGTRAP + && status != SIGTRAP +#endif + && status != SIGQUIT + && status != SIGABRT) { + if (dcc_clnt_debug) + dcc_error_msg("do not restart after" + " signal %d", + status); + exit(0); + } + + } else { + dcc_logbad(EX_OSERR, "unknown exit status %#x", status); + } + + next_restart -= time(0); + if (next_restart > 0 && next_restart <= MAX_RESTART_DELAY) { + restart_delay *= 2; + if (restart_delay > MAX_RESTART_DELAY) + restart_delay = MAX_RESTART_DELAY; + + /* while we wait, become the designated target */ + dcc_error_msg("delay %d seconds to restart after %s%d", + (int)next_restart, etype, status); + dcc_pidfile(pidpath, rundir); + sleep(next_restart); + unlink(pidpath); + + } else { + restart_delay -= next_restart-1; + if (restart_delay < MIN_RESTART_DELAY) + restart_delay = MIN_RESTART_DELAY; + } + dcc_error_msg("restart after %s%d", etype, status); + } +#endif /* not POSIX */ +} + + + +/* change to the UID and GID of a daemon */ +void +dcc_daemon_su(const char *user) +{ + struct passwd *pw; + + pw = getpwnam(user); + if (!pw) { + dcc_error_msg("getpwnam(%s): %s", user, ERROR_STR()); + return; + } + + if (0 > setgid(pw->pw_gid)) + dcc_error_msg("setgid(%d %s): %s", + (int)pw->pw_gid, user, ERROR_STR()); + if (0 > setuid(pw->pw_uid)) + dcc_error_msg("setuid(%d %s): %s", + (int)pw->pw_uid, user, ERROR_STR()); +} + + + +void +dcc_pidfile(DCC_PATH pidpath, const char *rundir) +{ + FILE *f; + + snprintf(pidpath, sizeof(DCC_PATH), "%s/%s.pid", + rundir, dcc_progname); + unlink(pidpath); + f = fopen(pidpath, "w"); + if (!f) { + dcc_error_msg("fopen(%s): %s", pidpath, ERROR_STR()); + } else { +#ifdef linux + /* Linux threads are broken. Signals given the + * original process are delivered to only the + * thread that happens to have that PID. The + * sendmail libmilter thread that needs to hear + * SIGINT and other signals is known only to the milter. + * Unless you put its PID into the file, it will not hear + * the signals. That breaks scripts that need to stop dccm. + * However, signaling the process group works. */ + fprintf(f, "-%d\n", (u_int)getpgrp()); +#else + fprintf(f, "%d\n", (u_int)getpid()); +#endif + fclose(f); + } +}