supervise-daemon: add support for a fifo
This will allow us to signal the daemon we are supervising as well as send other commands to the supervisor in the future. This fixes #227.
This commit is contained in:
		@@ -57,6 +57,11 @@
 | 
			
		||||
.Ar daemon
 | 
			
		||||
.Fl r , -chroot
 | 
			
		||||
.Ar chrootpath
 | 
			
		||||
.Nm
 | 
			
		||||
.Fl s , -signal
 | 
			
		||||
.Ar signal
 | 
			
		||||
.Fl r , -chroot
 | 
			
		||||
.Ar chrootpath
 | 
			
		||||
.Sh DESCRIPTION
 | 
			
		||||
.Nm
 | 
			
		||||
provides a consistent method of starting, stopping and restarting
 | 
			
		||||
@@ -64,11 +69,8 @@ daemons. If
 | 
			
		||||
.Fl K , -stop
 | 
			
		||||
is not provided, then we assume we are starting the daemon.
 | 
			
		||||
.Nm
 | 
			
		||||
only works with daemons which do not fork. Also, it uses its own pid
 | 
			
		||||
file, so the daemon should not write a pid file, or the pid file passed
 | 
			
		||||
to 
 | 
			
		||||
.Nm
 | 
			
		||||
should not be the one the daemon writes.
 | 
			
		||||
only works with daemons which do not fork. If your daemon has options to
 | 
			
		||||
tell it not to fork, it should be configured to not fork.
 | 
			
		||||
.Pp
 | 
			
		||||
Here are the options to specify the daemon and how it should start or stop:
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ static struct pam_conv conv = { NULL, NULL};
 | 
			
		||||
 | 
			
		||||
const char *applet = NULL;
 | 
			
		||||
const char *extraopts = NULL;
 | 
			
		||||
const char *getoptstring = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:Su:1:2:3" \
 | 
			
		||||
const char *getoptstring = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:s:Su:1:2:3" \
 | 
			
		||||
	getoptstring_COMMON;
 | 
			
		||||
const struct option longopts[] = {
 | 
			
		||||
	{ "healthcheck-timer",        1, NULL, 'a'},
 | 
			
		||||
@@ -86,6 +86,7 @@ const struct option longopts[] = {
 | 
			
		||||
	{ "respawn-period",        1, NULL, 'P'},
 | 
			
		||||
	{ "retry",       1, NULL, 'R'},
 | 
			
		||||
	{ "chroot",       1, NULL, 'r'},
 | 
			
		||||
	{ "signal",       1, NULL, 's'},
 | 
			
		||||
	{ "start",        0, NULL, 'S'},
 | 
			
		||||
	{ "user",         1, NULL, 'u'},
 | 
			
		||||
	{ "stdout",       1, NULL, '1'},
 | 
			
		||||
@@ -109,6 +110,7 @@ const char * const longopts_help[] = {
 | 
			
		||||
	"Set respawn time period",
 | 
			
		||||
	"Retry schedule to use when stopping",
 | 
			
		||||
	"Chroot to this directory",
 | 
			
		||||
	"Send a signal to the daemon",
 | 
			
		||||
	"Start daemon",
 | 
			
		||||
	"Change the process user",
 | 
			
		||||
	"Redirect stdout to file",
 | 
			
		||||
@@ -142,6 +144,8 @@ static int respawn_count = 0;
 | 
			
		||||
static int respawn_delay = 0;
 | 
			
		||||
static int respawn_max = 10;
 | 
			
		||||
static int respawn_period = 5;
 | 
			
		||||
static char *fifopath = NULL;
 | 
			
		||||
static int fifo_fd = 0;
 | 
			
		||||
static char *pidfile = NULL;
 | 
			
		||||
static char *svcname = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -439,10 +443,14 @@ static void child_process(char *exec, char **argv)
 | 
			
		||||
static void supervisor(char *exec, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
	char buf[2048];
 | 
			
		||||
	char cmd[2048];
 | 
			
		||||
	int count;
 | 
			
		||||
	int health_status;
 | 
			
		||||
	int healthcheck_respawn;
 | 
			
		||||
	int i;
 | 
			
		||||
	int nkilled;
 | 
			
		||||
	int sig_send;
 | 
			
		||||
	pid_t health_pid;
 | 
			
		||||
	pid_t wait_pid;
 | 
			
		||||
	sigset_t old_signals;
 | 
			
		||||
@@ -489,9 +497,29 @@ static void supervisor(char *exec, char **argv)
 | 
			
		||||
		alarm(healthcheckdelay);
 | 
			
		||||
	else if (healthchecktimer)
 | 
			
		||||
		alarm(healthchecktimer);
 | 
			
		||||
 fifo_fd = open(fifopath, O_RDONLY |O_NONBLOCK);
 | 
			
		||||
	while (!exiting) {
 | 
			
		||||
		healthcheck_respawn = 0;
 | 
			
		||||
		wait_pid = waitpid(child_pid, &i, 0);
 | 
			
		||||
		wait_pid = waitpid(child_pid, &i, WNOHANG);
 | 
			
		||||
		memset(buf, 0, sizeof(buf));
 | 
			
		||||
		if (fifo_fd >= 0) {
 | 
			
		||||
			count = read(fifo_fd, buf, sizeof(buf) - 1);
 | 
			
		||||
			if (count != -1)
 | 
			
		||||
				buf[count] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (strlen(buf) > 0) {
 | 
			
		||||
			syslog(LOG_DEBUG, "Received %s from fifo", buf);
 | 
			
		||||
			if (strncasecmp(buf, "sig", 3) == 0) {
 | 
			
		||||
				if ((sscanf(buf, "%s %d", cmd, &sig_send) == 2)
 | 
			
		||||
						&& (sig_send >= 0 && sig_send < NSIG)) {
 | 
			
		||||
					syslog(LOG_INFO, "Sending signal %d to %d", sig_send,
 | 
			
		||||
							child_pid);
 | 
			
		||||
					if (kill(child_pid, sig_send) == -1)
 | 
			
		||||
						syslog(LOG_ERR, "Unable to send signal %d to %d",
 | 
			
		||||
								sig_send, child_pid);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (do_healthcheck) {
 | 
			
		||||
			do_healthcheck = 0;
 | 
			
		||||
			alarm(0);
 | 
			
		||||
@@ -578,6 +606,8 @@ static void supervisor(char *exec, char **argv)
 | 
			
		||||
 | 
			
		||||
	if (pidfile && exists(pidfile))
 | 
			
		||||
		unlink(pidfile);
 | 
			
		||||
	if (fifopath && exists(fifopath))
 | 
			
		||||
		unlink(fifopath);
 | 
			
		||||
	if (svcname) {
 | 
			
		||||
		rc_service_daemon_set(svcname, exec, (const char *const *)argv,
 | 
			
		||||
				pidfile, false);
 | 
			
		||||
@@ -595,6 +625,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	bool start = false;
 | 
			
		||||
	bool stop = false;
 | 
			
		||||
	bool reexec = false;
 | 
			
		||||
	bool sendsig = false;
 | 
			
		||||
	char *exec = NULL;
 | 
			
		||||
	char *retry = NULL;
 | 
			
		||||
	int sig = SIGTERM;
 | 
			
		||||
@@ -700,6 +731,10 @@ int main(int argc, char **argv)
 | 
			
		||||
				eerrorx("Invalid respawn-period value '%s'", optarg);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 's':  /* --signal */
 | 
			
		||||
			sig = parse_signal(applet, optarg);
 | 
			
		||||
			sendsig = true;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'S':  /* --start */
 | 
			
		||||
			start = true;
 | 
			
		||||
			break;
 | 
			
		||||
@@ -818,6 +853,10 @@ int main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	umask(numask);
 | 
			
		||||
	xasprintf(&pidfile, "/var/run/supervise-%s.pid", svcname);
 | 
			
		||||
	xasprintf(&fifopath, "%s/supervise-%s.ctl", RC_SVCDIR, svcname);
 | 
			
		||||
	if (mkfifo(fifopath, 0600) == -1 && errno != EEXIST)
 | 
			
		||||
		eerrorx("%s: unable to create control fifo: %s",
 | 
			
		||||
				applet, strerror(errno));
 | 
			
		||||
 | 
			
		||||
	if (reexec) {
 | 
			
		||||
		str = rc_service_value_get(svcname, "argc");
 | 
			
		||||
@@ -989,5 +1028,18 @@ int main(int argc, char **argv)
 | 
			
		||||
			rc_service_mark(svcname, RC_SERVICE_STOPPED);
 | 
			
		||||
		}
 | 
			
		||||
		exit(EXIT_SUCCESS);
 | 
			
		||||
	} else if (sendsig) {
 | 
			
		||||
		fifo_fd = open(fifopath, O_WRONLY |O_NONBLOCK);
 | 
			
		||||
		if (fifo_fd < 0)
 | 
			
		||||
			eerrorx("%s: unable to open control fifo %s", applet, strerror(errno));
 | 
			
		||||
		xasprintf(&str, "sig %d", sig);
 | 
			
		||||
		x = write(fifo_fd, str, strlen(str));
 | 
			
		||||
		if (x == -1) {
 | 
			
		||||
			free(tmp);
 | 
			
		||||
			eerrorx("%s: error writing to control fifo: %s", applet,
 | 
			
		||||
					strerror(errno));
 | 
			
		||||
		}
 | 
			
		||||
		free(tmp);
 | 
			
		||||
		exit(EXIT_SUCCESS);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user