Compare commits

..

8 Commits

Author SHA1 Message Date
William Hubbs
b475396134 Update ChangeLog 2017-10-24 17:02:45 -05:00
William Hubbs
e7b1d898ca supervise-daemon: fix build issue for >=glibc-2.26
X-Gentoo-Bug: 635334
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=635334
2017-10-24 17:02:14 -05:00
William Hubbs
5cd09a6f44 version 0.34.1 2017-10-24 17:00:57 -05:00
William Hubbs
f3c70bf5b5 Update ChangeLog 2017-10-24 10:42:11 -05:00
William Hubbs
f5acc66db7 rc_find_pids: ignore pids that are not in our pid namespace
X-Gentoo-Bug: 634634
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=634634
2017-10-24 10:37:37 -05:00
William Hubbs
fdce4769f2 supervise-daemon: multiple fixes
- Harden against dying by handling all signals that would terminate the
program and adding --reexec support
- factor the supervisor into its own function
- fix test for whether we are already running
2017-10-24 10:26:18 -05:00
William Hubbs
35b1996704 supervise-daemon: elevate some log messages to warnings
Prior to this change, we were logging unexpected terminations of daemons
we were supervising at the info level. This change moves the logs to
warnings.
2017-10-18 18:07:50 -05:00
William Hubbs
3c8e7ed255 version 0.34 2017-10-13 16:10:57 -05:00
6 changed files with 415 additions and 259 deletions

View File

@@ -1,4 +1,45 @@
commit 8122e2d8f4fa8538e62f6a5e6b7306afcfc23c1c commit e7b1d898ca7896d6443ba1e5167eb6bcf3f92929
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
supervise-daemon: fix build issue for >=glibc-2.26
X-Gentoo-Bug: 635334
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=635334
commit 5cd09a6f44aa7d16ab7de1453e37d01448426031
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
version 0.34.1
commit f3c70bf5b5aa18e8dc94d4949f05568e0741c5cb
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
Update ChangeLog
commit f5acc66db7d1a0bfad6a40eefc0240b80f52df94
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
rc_find_pids: ignore pids that are not in our pid namespace
X-Gentoo-Bug: 634634
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=634634
commit fdce4769f2e0f4175163ffa181c7b3b2192f7b22
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
supervise-daemon: multiple fixes
- Harden against dying by handling all signals that would terminate the
program and adding --reexec support
- factor the supervisor into its own function
- fix test for whether we are already running
commit 35b1996704f6635bb29ea3604410e133209e6432
Author: William Hubbs <w.d.hubbs@gmail.com> Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com> Commit: William Hubbs <w.d.hubbs@gmail.com>
@@ -8,11 +49,11 @@ Commit: William Hubbs <w.d.hubbs@gmail.com>
we were supervising at the info level. This change moves the logs to we were supervising at the info level. This change moves the logs to
warnings. warnings.
commit ff07754be27e20a4d272661b071b63b435018b51 commit 3c8e7ed255edb8df0d548d6ce514544d5422cbf0
Author: William Hubbs <w.d.hubbs@gmail.com> Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com> Commit: William Hubbs <w.d.hubbs@gmail.com>
version 0.33.1 version 0.34
commit acaed1f910a2a00fdd5b6aeab752c552075a7292 commit acaed1f910a2a00fdd5b6aeab752c552075a7292
Author: William Hubbs <w.d.hubbs@gmail.com> Author: William Hubbs <w.d.hubbs@gmail.com>
@@ -1443,12 +1484,3 @@ Commit: William Hubbs <w.d.hubbs@gmail.com>
X-Gentoo-Bug: 487208 X-Gentoo-Bug: 487208
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=487208 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=487208
commit 4fd144c0a6526963c70f18cb34a65354c2f0a48c
Author: William Hubbs <w.d.hubbs@gmail.com>
Commit: William Hubbs <w.d.hubbs@gmail.com>
src/rc/rc-misc.c: report error if call to flock() fails
X-Gentoo-Bug: 597390
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=597390

View File

@@ -1,3 +1,3 @@
NAME= openrc NAME= openrc
VERSION= 0.33.1 VERSION= 0.34.1
PKG= ${NAME}-${VERSION} PKG= ${NAME}-${VERSION}

View File

@@ -47,6 +47,7 @@ bool rc_conf_yesno(const char *var);
void env_filter(void); void env_filter(void);
void env_config(void); void env_config(void);
int signal_setup(int sig, void (*handler)(int)); int signal_setup(int sig, void (*handler)(int));
int signal_setup_restart(int sig, void (*handler)(int));
int svc_lock(const char *); int svc_lock(const char *);
int svc_unlock(const char *, int); int svc_unlock(const char *, int);
pid_t exec_service(const char *, const char *); pid_t exec_service(const char *, const char *);

View File

@@ -80,9 +80,12 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
DIR *procdir; DIR *procdir;
struct dirent *entry; struct dirent *entry;
FILE *fp; FILE *fp;
int rc;
bool container_pid = false; bool container_pid = false;
bool openvz_host = false; bool openvz_host = false;
char *line = NULL; char *line = NULL;
char my_ns[30];
char proc_ns[30];
size_t len = 0; size_t len = 0;
pid_t p; pid_t p;
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@@ -131,6 +134,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
} }
} }
memset(my_ns, 0, sizeof(my_ns));
memset(proc_ns, 0, sizeof(proc_ns));
if (exists("/proc/self/ns/pid")) {
rc = readlink("/proc/self/ns/pid", my_ns, sizeof(my_ns));
if (rc <= 0)
my_ns[0] = '\0';
}
while ((entry = readdir(procdir)) != NULL) { while ((entry = readdir(procdir)) != NULL) {
if (sscanf(entry->d_name, "%d", &p) != 1) if (sscanf(entry->d_name, "%d", &p) != 1)
continue; continue;
@@ -138,6 +149,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
continue; continue;
if (pid != 0 && pid != p) if (pid != 0 && pid != p)
continue; continue;
snprintf(buffer, sizeof(buffer), "/proc/%d/ns/pid", p);
if (exists(buffer)) {
rc = readlink(buffer, proc_ns, sizeof(proc_ns));
if (rc <= 0)
proc_ns[0] = '\0';
}
if (strcmp(my_ns, proc_ns))
continue;
if (uid) { if (uid) {
snprintf(buffer, sizeof(buffer), "/proc/%d", p); snprintf(buffer, sizeof(buffer), "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid) if (stat(buffer, &sb) != 0 || sb.st_uid != uid)

View File

@@ -217,6 +217,18 @@ signal_setup(int sig, void (*handler)(int))
return sigaction(sig, &sa, NULL); return sigaction(sig, &sa, NULL);
} }
int
signal_setup_restart(int sig, void (*handler)(int))
{
struct sigaction sa;
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
return sigaction(sig, &sa, NULL);
}
int int
svc_lock(const char *applet) svc_lock(const char *applet)
{ {

View File

@@ -67,7 +67,7 @@ static struct pam_conv conv = { NULL, NULL};
const char *applet = NULL; const char *applet = NULL;
const char *extraopts = NULL; const char *extraopts = NULL;
const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:" \ const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:3" \
getoptstring_COMMON; getoptstring_COMMON;
const struct option longopts[] = { const struct option longopts[] = {
{ "respawn-delay", 1, NULL, 'D'}, { "respawn-delay", 1, NULL, 'D'},
@@ -87,6 +87,7 @@ const struct option longopts[] = {
{ "user", 1, NULL, 'u'}, { "user", 1, NULL, 'u'},
{ "stdout", 1, NULL, '1'}, { "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'}, { "stderr", 1, NULL, '2'},
{ "reexec", 0, NULL, '3'},
longopts_COMMON longopts_COMMON
}; };
const char * const longopts_help[] = { const char * const longopts_help[] = {
@@ -107,6 +108,7 @@ const char * const longopts_help[] = {
"Change the process user", "Change the process user",
"Redirect stdout to file", "Redirect stdout to file",
"Redirect stderr to file", "Redirect stderr to file",
"reexec (used internally)",
longopts_help_COMMON longopts_help_COMMON
}; };
const char *usagestring = NULL; const char *usagestring = NULL;
@@ -127,6 +129,13 @@ static bool exiting = false;
#ifdef TIOCNOTTY #ifdef TIOCNOTTY
static int tty_fd = -1; static int tty_fd = -1;
#endif #endif
static pid_t child_pid;
static int respawn_count = 0;
static int respawn_delay = 0;
static int respawn_max = 10;
static int respawn_period = 5;
static char *pidfile = NULL;
static char *svcname = NULL;
extern char **environ; extern char **environ;
@@ -150,8 +159,71 @@ static void cleanup(void)
free(changeuser); free(changeuser);
} }
static void child_process(char *exec, char **argv, char *svcname, static void re_exec(void)
int start_count) {
syslog(LOG_WARNING, "Re-executing supervise-daemon");
execlp("supervise-daemon", "supervise-daemon", "--reexec", (char *) NULL);
syslog(LOG_ERR, "Unable to execute supervise-daemon: %s",
strerror(errno));
exit(EXIT_FAILURE);
}
static void handle_signal(int sig)
{
int serrno = errno;
syslog(LOG_WARNING, "caught signal %d", sig);
if (sig == SIGTERM)
exiting = true;
/* Restore errno */
errno = serrno;
if (! exiting)
re_exec();
}
static char * expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
return xstrdup(path);
opath = ppath = xstrdup(path);
if (ppath[1] != '/' && ppath[1] != '\0') {
p = strchr(ppath + 1, '/');
if (p)
*p = '\0';
pw = getpwnam(ppath + 1);
if (pw) {
home = pw->pw_dir;
ppath = p;
if (ppath)
*ppath = '/';
} else
home = NULL;
} else
ppath++;
if (!home) {
free(opath);
return xstrdup(path);
}
if (!ppath) {
free(opath);
return xstrdup(home);
}
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
free(opath);
return nh;
}
static void child_process(char *exec, char **argv)
{ {
RC_STRINGLIST *env_list; RC_STRINGLIST *env_list;
RC_STRING *env; RC_STRING *env;
@@ -176,11 +248,13 @@ static void child_process(char *exec, char **argv, char *svcname,
setsid(); setsid();
if (svcname) { if (svcname) {
start_time = time(NULL); start_time = time(NULL);
from_time_t(start_time_string, start_time); from_time_t(start_time_string, start_time);
rc_service_value_set(svcname, "start_time", start_time_string); rc_service_value_set(svcname, "start_time", start_time_string);
sprintf(start_count_string, "%i", start_count); sprintf(start_count_string, "%i", respawn_count);
rc_service_value_set(svcname, "start_count", start_count_string); rc_service_value_set(svcname, "start_count", start_count_string);
sprintf(start_count_string, "%d", getpid());
rc_service_value_set(svcname, "child_pid", start_count_string);
} }
if (nicelevel) { if (nicelevel) {
@@ -323,7 +397,7 @@ sprintf(start_count_string, "%i", start_count);
*cmdline = '\0'; *cmdline = '\0';
c = argv; c = argv;
while (*c) { while (c && *c) {
strcat(cmdline, *c); strcat(cmdline, *c);
strcat(cmdline, " "); strcat(cmdline, " ");
c++; c++;
@@ -338,108 +412,154 @@ sprintf(start_count_string, "%i", start_count);
eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno)); eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
} }
static void handle_signal(int sig) static void supervisor(char *exec, char **argv)
{ {
int serrno = errno; FILE *fp;
char signame[10] = { '\0' }; int i;
int nkilled;
time_t respawn_now= 0;
time_t first_spawn= 0;
switch (sig) { openlog(applet, LOG_PID, LOG_DAEMON);
case SIGINT: #ifndef RC_DEBUG
snprintf(signame, sizeof(signame), "SIGINT"); signal_setup_restart(SIGHUP, handle_signal);
break; signal_setup_restart(SIGINT, handle_signal);
case SIGTERM: signal_setup_restart(SIGQUIT, handle_signal);
snprintf(signame, sizeof(signame), "SIGTERM"); signal_setup_restart(SIGILL, handle_signal);
break; signal_setup_restart(SIGABRT, handle_signal);
case SIGQUIT: signal_setup_restart(SIGFPE, handle_signal);
snprintf(signame, sizeof(signame), "SIGQUIT"); signal_setup_restart(SIGSEGV, handle_signal);
break; signal_setup_restart(SIGPIPE, handle_signal);
signal_setup_restart(SIGALRM, handle_signal);
signal_setup(SIGTERM, handle_signal);
signal_setup_restart(SIGUSR1, handle_signal);
signal_setup_restart(SIGUSR2, handle_signal);
signal_setup_restart(SIGBUS, handle_signal);
signal_setup_restart(SIGPOLL, handle_signal);
signal_setup_restart(SIGPROF, handle_signal);
signal_setup_restart(SIGSYS, handle_signal);
signal_setup_restart(SIGTRAP, handle_signal);
signal_setup_restart(SIGVTALRM, handle_signal);
signal_setup_restart(SIGXCPU, handle_signal);
signal_setup_restart(SIGXFSZ, handle_signal);
#ifdef SIGEMT
signal_setup_restart(SIGEMT, handle_signal);
#endif
signal_setup_restart(SIGIO, handle_signal);
signal_setup_restart(SIGPWR, handle_signal);
#ifdef SIGUNUSED
signal_setup_restart(SIGUNUSED, handle_signal);
#endif
#ifdef SIGRTMIN
for (i = SIGRTMIN; i <= SIGRTMAX; i++)
signal_setup_restart(i, handle_signal);
#endif
#endif
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fprintf(fp, "%d\n", getpid());
fclose(fp);
if (svcname)
rc_service_daemon_set(svcname, exec, (const char * const *) argv,
pidfile, true);
/* remove the controlling tty */
#ifdef TIOCNOTTY
ioctl(tty_fd, TIOCNOTTY, 0);
close(tty_fd);
#endif
/*
* Supervisor main loop
*/
i = 0;
while (!exiting) {
wait(&i);
if (exiting) {
signal_setup(SIGCHLD, SIG_IGN);
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
nkilled = run_stop_schedule(applet, exec, NULL, child_pid, 0,
false, false, true);
if (nkilled > 0)
syslog(LOG_INFO, "killed %d processes", nkilled);
} else {
sleep(respawn_delay);
if (respawn_max > 0 && respawn_period > 0) {
respawn_now = time(NULL);
if (first_spawn == 0)
first_spawn = respawn_now;
if (respawn_now - first_spawn > respawn_period) {
respawn_count = 0;
first_spawn = 0;
} else
respawn_count++;
if (respawn_count >= respawn_max) {
syslog(LOG_WARNING,
"respawned \"%s\" too many times, exiting", exec);
exiting = true;
continue;
}
}
if (WIFEXITED(i))
syslog(LOG_WARNING, "%s, pid %d, exited with return code %d",
exec, child_pid, WEXITSTATUS(i));
else if (WIFSIGNALED(i))
syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d",
exec, child_pid, WTERMSIG(i));
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
child_process(exec, argv);
}
} }
if (*signame != 0) { if (pidfile && exists(pidfile))
syslog(LOG_INFO, "%s: caught signal %s, exiting", applet, signame); unlink(pidfile);
exiting = true; if (svcname) {
} else rc_service_daemon_set(svcname, exec, (const char *const *)argv,
syslog(LOG_INFO, "%s: caught unknown signal %d", applet, sig); pidfile, false);
rc_service_mark(svcname, RC_SERVICE_STOPPED);
/* Restore errno */
errno = serrno;
}
static char * expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
return xstrdup(path);
opath = ppath = xstrdup(path);
if (ppath[1] != '/' && ppath[1] != '\0') {
p = strchr(ppath + 1, '/');
if (p)
*p = '\0';
pw = getpwnam(ppath + 1);
if (pw) {
home = pw->pw_dir;
ppath = p;
if (ppath)
*ppath = '/';
} else
home = NULL;
} else
ppath++;
if (!home) {
free(opath);
return xstrdup(path);
} }
if (!ppath) { exit(EXIT_SUCCESS);
free(opath);
return xstrdup(home);
}
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
free(opath);
return nh;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int opt; int opt;
char **c;
int x;
bool start = false; bool start = false;
bool stop = false; bool stop = false;
bool reexec = false;
char *exec = NULL; char *exec = NULL;
char *pidfile = NULL;
char *retry = NULL; char *retry = NULL;
int nkilled;
int sig = SIGTERM; int sig = SIGTERM;
char *home = NULL; char *home = NULL;
int tid = 0; int tid = 0;
pid_t child_pid, pid; pid_t pid;
char *svcname = getenv("RC_SVCNAME");
char *tmp; char *tmp;
char *p; char *p;
char *token; char *token;
int i; int i;
int n; int n;
char exec_file[PATH_MAX]; char exec_file[PATH_MAX];
int respawn_count = 0; char name[PATH_MAX];
int respawn_delay = 0;
int respawn_max = 10;
int respawn_period = 5;
time_t respawn_now= 0;
time_t first_spawn= 0;
struct timespec ts; struct timespec ts;
struct passwd *pw; struct passwd *pw;
struct group *gr; struct group *gr;
FILE *fp; FILE *fp;
mode_t numask = 022; mode_t numask = 022;
int child_argc = 0;
char **child_argv = NULL;
char *str = NULL;
applet = basename_c(argv[0]); applet = basename_c(argv[0]);
atexit(cleanup); atexit(cleanup);
svcname = getenv("RC_SVCNAME");
if ((tmp = getenv("SSD_NICELEVEL"))) if ((tmp = getenv("SSD_NICELEVEL")))
if (sscanf(tmp, "%d", &nicelevel) != 1) if (sscanf(tmp, "%d", &nicelevel) != 1)
@@ -493,8 +613,8 @@ int main(int argc, char **argv)
case 'P': /* --respawn-period time */ case 'P': /* --respawn-period time */
n = sscanf(optarg, "%d", &respawn_period); n = sscanf(optarg, "%d", &respawn_period);
if (n != 1 || respawn_delay < 1) if (n != 1 || respawn_period < 1)
eerrorx("Invalid respawn-delay value '%s'", optarg); eerrorx("Invalid respawn-period value '%s'", optarg);
break; break;
case 'S': /* --start */ case 'S': /* --start */
@@ -590,11 +710,14 @@ int main(int argc, char **argv)
case '2': /* --stderr /path/to/stderr.logfile */ case '2': /* --stderr /path/to/stderr.logfile */
redirect_stderr = optarg; redirect_stderr = optarg;
break; break;
case '3': /* --reexec */
reexec = true;
break;
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
if (!pidfile) if (!pidfile && !reexec)
eerrorx("%s: --pidfile must be specified", applet); eerrorx("%s: --pidfile must be specified", applet);
endpwent(); endpwent();
@@ -602,74 +725,158 @@ int main(int argc, char **argv)
argv += optind; argv += optind;
exec = *argv; exec = *argv;
if (start) {
if (!exec)
eerrorx("%s: nothing to start", applet);
if (respawn_delay * respawn_max > respawn_period) {
ewarn("%s: Please increase the value of --respawn-period to more "
"than %d to avoid infinite respawning", applet,
respawn_delay * respawn_max);
}
if (retry)
parse_schedule(applet, retry, sig);
else
parse_schedule(applet, NULL, sig);
}
/* Expand ~ */ /* Expand ~ */
if (ch_dir && *ch_dir == '~') if (ch_dir && *ch_dir == '~')
ch_dir = expand_home(home, ch_dir); ch_dir = expand_home(home, ch_dir);
if (ch_root && *ch_root == '~') if (ch_root && *ch_root == '~')
ch_root = expand_home(home, ch_root); ch_root = expand_home(home, ch_root);
if (exec) {
if (*exec == '~')
exec = expand_home(home, exec);
/* Validate that the binary exists if we are starting */ umask(numask);
if (*exec == '/' || *exec == '.') {
/* Full or relative path */ if (reexec) {
if (ch_root) str = rc_service_value_get(svcname, "argc");
snprintf(exec_file, sizeof(exec_file), sscanf(str, "%d", &child_argc);
"%s/%s", ch_root, exec); child_argv = xmalloc((child_argc + 1) * sizeof(char *));
else memset(child_argv, 0, (child_argc + 1) * sizeof(char *));
snprintf(exec_file, sizeof(exec_file), for (x = 0; x < child_argc; x++) {
"%s", exec); sprintf(name, "argv_%d", x);
} else { str = rc_service_value_get(svcname, name);
/* Something in $PATH */ child_argv[x] = str;
p = tmp = xstrdup(getenv("PATH")); }
*exec_file = '\0'; free(str);
while ((token = strsep(&p, ":"))) { str = rc_service_value_get(svcname, "child_pid");
sscanf(str, "%d", &child_pid);
free(str);
exec = rc_service_value_get(svcname, "exec");
pidfile = rc_service_value_get(svcname, "pidfile");
retry = rc_service_value_get(svcname, "retry");
if (retry) {
parse_schedule(applet, retry, sig);
rc_service_value_set(svcname, "retry", retry);
} else
parse_schedule(applet, NULL, sig);
str = rc_service_value_get(svcname, "respawn_delay");
sscanf(str, "%d", &respawn_delay);
str = rc_service_value_get(svcname, "respawn_max");
sscanf(str, "%d", &respawn_max);
supervisor(exec, child_argv);
} else if (start) {
if (exec) {
if (*exec == '~')
exec = expand_home(home, exec);
/* Validate that the binary exists if we are starting */
if (*exec == '/' || *exec == '.') {
/* Full or relative path */
if (ch_root) if (ch_root)
snprintf(exec_file, sizeof(exec_file), snprintf(exec_file, sizeof(exec_file),
"%s/%s/%s", "%s/%s", ch_root, exec);
ch_root, token, exec);
else else
snprintf(exec_file, sizeof(exec_file), snprintf(exec_file, sizeof(exec_file),
"%s/%s", token, exec); "%s", exec);
if (exists(exec_file)) } else {
break; /* Something in $PATH */
p = tmp = xstrdup(getenv("PATH"));
*exec_file = '\0'; *exec_file = '\0';
while ((token = strsep(&p, ":"))) {
if (ch_root)
snprintf(exec_file, sizeof(exec_file),
"%s/%s/%s",
ch_root, token, exec);
else
snprintf(exec_file, sizeof(exec_file),
"%s/%s", token, exec);
if (exists(exec_file))
break;
*exec_file = '\0';
}
free(tmp);
} }
free(tmp); if ( !exists(exec_file))
} eerrorx("%s: %s does not exist", applet,
} *exec_file ? exec_file : exec);
if (start && !exists(exec_file)) } else
eerrorx("%s: %s does not exist", applet, eerrorx("%s: nothing to start", applet);
*exec_file ? exec_file : exec);
if (stop) { pid = get_pid(applet, pidfile);
if (pid != -1)
if (do_stop(applet, exec, (const char * const *)argv, pid, uid,
0, false, true) > 0)
eerrorx("%s: %s is already running", applet, exec);
if (respawn_delay * respawn_max > respawn_period)
ewarn("%s: Please increase the value of --respawn-period to more "
"than %d to avoid infinite respawning", applet,
respawn_delay * respawn_max);
if (retry) {
parse_schedule(applet, retry, sig);
rc_service_value_set(svcname, "retry", retry);
} else
parse_schedule(applet, NULL, sig);
einfov("Detaching to start `%s'", exec);
/* Remove existing pidfile */
if (pidfile)
unlink(pidfile);
/* Make sure we can write a pid file */
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fclose(fp);
rc_service_value_set(svcname, "pidfile", pidfile);
sprintf(name, "%i", respawn_delay);
rc_service_value_set(svcname, "respawn_delay", name);
sprintf(name, "%i", respawn_max);
rc_service_value_set(svcname, "respawn_max", name);
sprintf(name, "%i", respawn_period);
rc_service_value_set(svcname, "respawn_period", name);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid != 0)
/* first parent process, do nothing. */
exit(EXIT_SUCCESS);
#ifdef TIOCNOTTY
tty_fd = open("/dev/tty", O_RDWR);
#endif
devnull_fd = open("/dev/null", O_RDWR);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
else if (child_pid != 0) {
c = argv;
x = 0;
while (c && *c) {
snprintf(name, sizeof(name), "argv_%-d",x);
rc_service_value_set(svcname, name, *c);
x++;
c++;
}
sprintf(name, "%d", x);
rc_service_value_set(svcname, "argc", name);
rc_service_value_set(svcname, "exec", exec);
supervisor(exec, argv);
} else
child_process(exec, argv);
} else if (stop) {
pid = get_pid(applet, pidfile); pid = get_pid(applet, pidfile);
if (pid != -1) { if (pid != -1) {
i = kill(pid, SIGTERM); i = kill(pid, SIGTERM);
if (i != 0) if (i != 0)
/* We failed to send the signal */ /* We failed to send the signal */
exit(EXIT_FAILURE); ewarn("Unable to shut down the supervisor");
else {
/* wait for the supervisor to go down */ /* wait for the supervisor to go down */
while (kill(pid, 0) == 0) { while (kill(pid, 0) == 0) {
ts.tv_sec = 0; ts.tv_sec = 0;
ts.tv_nsec = 1; ts.tv_nsec = 1;
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
}
} }
} }
@@ -687,119 +894,4 @@ int main(int argc, char **argv)
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
pid = get_pid(applet, pidfile);
if (pid != -1)
if (kill(pid, 0) == 0)
eerrorx("%s: %s is already running", applet, exec);
einfov("Detaching to start `%s'", exec);
eindentv();
/* Remove existing pidfile */
if (pidfile)
unlink(pidfile);
/*
* Make sure we can write a pid file
*/
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fclose(fp);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
/* first parent process, do nothing. */
if (child_pid != 0)
exit(EXIT_SUCCESS);
#ifdef TIOCNOTTY
tty_fd = open("/dev/tty", O_RDWR);
#endif
devnull_fd = open("/dev/null", O_RDWR);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid != 0) {
/* this is the supervisor */
umask(numask);
openlog(applet, LOG_PID, LOG_DAEMON);
signal_setup(SIGTERM, handle_signal);
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fprintf(fp, "%d\n", getpid());
fclose(fp);
if (svcname)
rc_service_daemon_set(svcname, exec,
(const char * const *) argv, pidfile, true);
/* remove the controlling tty */
#ifdef TIOCNOTTY
ioctl(tty_fd, TIOCNOTTY, 0);
close(tty_fd);
#endif
/*
* Supervisor main loop
*/
i = 0;
while (!exiting) {
wait(&i);
if (exiting) {
signal_setup(SIGCHLD, SIG_IGN);
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
nkilled = run_stop_schedule(applet, exec, NULL, child_pid,
0, false, false, true);
if (nkilled > 0)
syslog(LOG_INFO, "killed %d processes", nkilled);
} else {
sleep(respawn_delay);
if (respawn_max > 0 && respawn_period > 0) {
respawn_now = time(NULL);
if (first_spawn == 0)
first_spawn = respawn_now;
if (respawn_now - first_spawn > respawn_period) {
respawn_count = 0;
first_spawn = 0;
} else
respawn_count++;
if (respawn_count >= respawn_max) {
syslog(LOG_WARNING, "respawned \"%s\" too many times, "
"exiting", exec);
exiting = true;
continue;
}
}
if (WIFEXITED(i))
syslog(LOG_WARNING, "%s, pid %d, exited with return code %d",
exec, child_pid, WEXITSTATUS(i));
else if (WIFSIGNALED(i))
syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d",
exec, child_pid, WTERMSIG(i));
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
child_process(exec, argv, svcname, respawn_count);
}
}
if (pidfile && exists(pidfile))
unlink(pidfile);
if (svcname) {
rc_service_daemon_set(svcname, exec,
(const char *const *)argv,
pidfile, false);
rc_service_mark(svcname, RC_SERVICE_STOPPED);
}
exit(EXIT_SUCCESS);
} else if (child_pid == 0)
child_process(exec, argv, svcname, respawn_count);
} }