[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [PATCH] sv, runsv, svlogd: update to match version 2.1.2 of runit
From:       James Byrne <james.byrne () origamienergy ! com>
Date:       2016-12-15 18:29:43
Message-ID: 1481826583-33199-1-git-send-email-james.byrne () origamienergy ! com
[Download RAW message or body]

This commit applies all the relevant changes that have been made to the
'sv', 'runsv' and 'svlogd' tools between version 1.6.0 (the version
originally imported into BusyBox) and version 2.1.2. The change logs
below are taken from the CHANGES file from runit 2.1.2. Notes in square
brackets have been added to highlight BusyBox-specific changes.

In addition, the help comments in sv.c have been updated to match
version 2.1.2 of runit, but the comments about sym-linking to
/etc/init.d/ to provide an LSB init script interface have been removed
as this is not supported in the BusyBox version.

2.1.2
Sun, 10 Aug 2014 18:01:54 +0000
  * sv.c: properly format status command's output on failure cases.
  * sv.c: support optional LSB init script actions reload and
    try-restart.
  * sv.c: fix typo that may lead to wrong output from sv when reporting
    status of multiple service directories.

2.1.1
Sun, 04 Oct 2009 20:28:38 +0000
  * sv.c: on 'down', send runsv the 'down' command properly if not yet
    done (e.g. when taken up with 'once').

    [Remove previous workaround added to BusyBox version].

2.1.0
Thu, 24 Sep 2009 22:49:33 +0000
  * runsv.c: exit with error if [log/]supervise/control exists, but is
    not a fifo.

    [Code abstracted into a separate function to make it more compact
    for BusyBox.]

1.9.0
Mon, 05 May 2008 22:00:13 +0000
  * sv.c: service name is also relative to the current directory if it
    ends with a slash.
  * runsv.c: create temporary new status files for log/supervise/
    actually in log/supervise/.

1.8.0
Fri, 21 Sep 2007 00:33:56 +0000
  * sv.c: fix race on check for down if pid is 0 and state is run or
    finish.

1.7.2
Tue, 21 Nov 2006 15:13:47 +0000
  * runsv.c: really don't act on commands in state finish; minor.

1.7.1
Sat, 04 Nov 2006 19:23:29 +0000
  * sv.c: properly wait for a service to be restarted on 'restart';
    support checks through -v for pause, cont, kill.

1.7.0
Sat, 07 Oct 2006 18:24:17 +0000
  * svlogd.c: new option -ttt: prefix log messages with sortable UTC
    timestamp YYYY-MM-DDTHH:MM:SS.xxxxx.

function                                             old     new   delta
open_control                                           -     200    +200
sv                                                  1314    1423    +109
update_status                                        654     721     +67
control                                              159     210     +51
custom                                               293     328     +35
fatal2_cannot                                          -      26     +26
svlogd_main                                         1547    1572     +25
status                                               136     160     +24
out                                                   83     105     +22
svstatus_print                                       443     451      +8
ctrl                                                 453     445      -8
startservice                                         455     441     -14
.rodata                                           156949  156932     -17
runsv_main                                          1870    1738    -132
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 8/4 up/down: 567/-171)          Total: 396
bytes
   text	   data	    bss	    dec	    hex	filename
 871350	   4158	   2144	 877652	  d6454	busybox_old
 871867	   4158	   2144	 878169	  d6659	busybox_unstripped

Signed-off-by: James Byrne <james.byrne@origamienergy.com>
---
 runit/runsv.c  |  91 +++++++++++++++++++++-------------
 runit/sv.c     | 153 +++++++++++++++++++++++++++++++++------------------------
 runit/svlogd.c |   9 ++--
 3 files changed, 149 insertions(+), 104 deletions(-)

diff --git a/runit/runsv.c b/runit/runsv.c
index e0e3150..a0caef1 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -138,6 +138,10 @@ static void warn_cannot(const char *m)
 {
 	bb_perror_msg("%s: warning: cannot %s", dir, m);
 }
+static void warn2_cannot(const char *m1, const char *m2)
+{
+	bb_perror_msg("%s: warning: cannot %s%s", dir, m1, m2);
+}
 
 static void s_child(int sig_no UNUSED_PARAM)
 {
@@ -165,10 +169,25 @@ static void update_status(struct svdir *s)
 	ssize_t sz;
 	int fd;
 	svstatus_t status;
+	const char * fstatus ="log/supervise/status";
+	const char * fstatusnew ="log/supervise/status.new";
+	const char * fstat ="log/supervise/stat";
+	const char * fstatnew ="log/supervise/stat.new";
+	const char * fpid ="log/supervise/pid";
+	const char * fpidnew ="log/supervise/pid.new";
+
+	if (!s->islog) {
+		fstatus += 4;
+		fstatusnew += 4;
+		fstat += 4;
+		fstatnew += 4;
+		fpid += 4;
+		fpidnew += 4;
+	}
 
 	/* pid */
 	if (pidchanged) {
-		fd = open_trunc_or_warn("supervise/pid.new");
+		fd = open_trunc_or_warn(fpidnew);
 		if (fd < 0)
 			return;
 		if (s->pid) {
@@ -177,14 +196,13 @@ static void update_status(struct svdir *s)
 			write(fd, spid, size);
 		}
 		close(fd);
-		if (rename_or_warn("supervise/pid.new",
-				s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
+		if (rename_or_warn(fpidnew, fpid))
 			return;
 		pidchanged = 0;
 	}
 
 	/* stat */
-	fd = open_trunc_or_warn("supervise/stat.new");
+	fd = open_trunc_or_warn(fstatnew);
 	if (fd < -1)
 		return;
 
@@ -220,8 +238,7 @@ static void update_status(struct svdir *s)
 		close(fd);
 	}
 
-	rename_or_warn("supervise/stat.new",
-		s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
+	rename_or_warn(fstatnew, fstat);
 
 	/* supervise compatibility */
 	memset(&status, 0, sizeof(status));
@@ -237,18 +254,17 @@ static void update_status(struct svdir *s)
 	if (s->ctrl & C_TERM)
 		status.got_term = 1;
 	status.run_or_finish = s->state;
-	fd = open_trunc_or_warn("supervise/status.new");
+	fd = open_trunc_or_warn(fstatusnew);
 	if (fd < 0)
 		return;
 	sz = write(fd, &status, sizeof(status));
 	close(fd);
 	if (sz != sizeof(status)) {
-		warn_cannot("write supervise/status.new");
-		unlink("supervise/status.new");
+		warn2_cannot("write ", fstatusnew);
+		unlink(fstatusnew);
 		return;
 	}
-	rename_or_warn("supervise/status.new",
-		s->islog ? "log/supervise/status" : "log/supervise/status"+4);
+	rename_or_warn(fstatusnew, fstatus);
 }
 
 static unsigned custom(struct svdir *s, char c)
@@ -266,26 +282,26 @@ static unsigned custom(struct svdir *s, char c)
 		if (st.st_mode & S_IXUSR) {
 			pid = vfork();
 			if (pid == -1) {
-				warn_cannot("vfork for control/?");
+				warn2_cannot("vfork for ", a);
 				return 0;
 			}
 			if (pid == 0) {
 				/* child */
 				if (haslog && dup2(logpipe.wr, 1) == -1)
-					warn_cannot("setup stdout for control/?");
+					warn2_cannot("setup stdout for ", a);
 				execl(a, a, (char *) NULL);
 				fatal_cannot("run control/?");
 			}
 			/* parent */
 			if (safe_waitpid(pid, &w, 0) == -1) {
-				warn_cannot("wait for child control/?");
+				warn2_cannot("wait for child ", a);
 				return 0;
 			}
 			return WEXITSTATUS(w) == 0;
 		}
 	} else {
 		if (errno != ENOENT)
-			warn_cannot("stat control/?");
+			warn2_cannot("stat ", a);
 	}
 	return 0;
 }
@@ -387,13 +403,13 @@ static int ctrl(struct svdir *s, char c)
 	case 'd': /* down */
 		s->sd_want = W_DOWN;
 		update_status(s);
-		if (s->pid && s->state != S_FINISH)
+		if (s->state == S_RUN)
 			stopservice(s);
 		break;
 	case 'u': /* up */
 		s->sd_want = W_UP;
 		update_status(s);
-		if (s->pid == 0)
+		if (s->state == S_DOWN)
 			startservice(s);
 		break;
 	case 'x': /* exit */
@@ -403,22 +419,22 @@ static int ctrl(struct svdir *s, char c)
 		update_status(s);
 		/* FALLTHROUGH */
 	case 't': /* sig term */
-		if (s->pid && s->state != S_FINISH)
+		if (s->state == S_RUN)
 			stopservice(s);
 		break;
 	case 'k': /* sig kill */
-		if (s->pid && !custom(s, c))
+		if ((s->state == S_RUN) && !custom(s, c))
 			kill(s->pid, SIGKILL);
 		s->state = S_DOWN;
 		break;
 	case 'p': /* sig pause */
-		if (s->pid && !custom(s, c))
+		if ((s->state == S_RUN) && !custom(s, c))
 			kill(s->pid, SIGSTOP);
 		s->ctrl |= C_PAUSE;
 		update_status(s);
 		break;
 	case 'c': /* sig cont */
-		if (s->pid && !custom(s, c))
+		if ((s->state == S_RUN) && !custom(s, c))
 			kill(s->pid, SIGCONT);
 		s->ctrl &= ~C_PAUSE;
 		update_status(s);
@@ -426,7 +442,7 @@ static int ctrl(struct svdir *s, char c)
 	case 'o': /* once */
 		s->sd_want = W_DOWN;
 		update_status(s);
-		if (!s->pid)
+		if (s->state == S_DOWN)
 			startservice(s);
 		break;
 	case 'a': /* sig alarm */
@@ -450,11 +466,26 @@ static int ctrl(struct svdir *s, char c)
 	}
 	return 1;
  sendsig:
-	if (s->pid && !custom(s, c))
+	if ((s->state == S_RUN) && !custom(s, c))
 		kill(s->pid, sig);
 	return 1;
 }
 
+static void open_control(const char *f, struct svdir *s)
+{
+	struct stat st;
+	mkfifo(f, 0600);
+	if (stat(f, &st) == -1)
+		fatal2_cannot("stat ", f);
+	if (!S_ISFIFO(st.st_mode))
+		bb_error_msg_and_die("%s: fatal: %s exists but is not a fifo", dir, f);
+	s->fdcontrol = xopen(f, O_RDONLY|O_NDELAY);
+	close_on_exec_on(s->fdcontrol);
+	s->fdcontrolwrite = xopen(f, O_WRONLY|O_NDELAY);
+	close_on_exec_on(s->fdcontrolwrite);
+	update_status(s);
+}
+
 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int runsv_main(int argc UNUSED_PARAM, char **argv)
 {
@@ -554,19 +585,9 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
 		close_on_exec_on(svd[1].fdlock);
 	}
 
-	mkfifo("log/supervise/control"+4, 0600);
-	svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
-	close_on_exec_on(svd[0].fdcontrol);
-	svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
-	close_on_exec_on(svd[0].fdcontrolwrite);
-	update_status(&svd[0]);
+	open_control("log/supervise/control"+4, &svd[0]);
 	if (haslog) {
-		mkfifo("log/supervise/control", 0600);
-		svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
-		close_on_exec_on(svd[1].fdcontrol);
-		svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
-		close_on_exec_on(svd[1].fdcontrolwrite);
-		update_status(&svd[1]);
+		open_control("log/supervise/control", &svd[1]);
 	}
 	mkfifo("log/supervise/ok"+4, 0600);
 	fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
diff --git a/runit/sv.c b/runit/sv.c
index 9e21322..97f3935 100644
--- a/runit/sv.c
+++ b/runit/sv.c
@@ -25,7 +25,7 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-/* Taken from http://smarden.sunsite.dk/runit/sv.8.html:
+/* Taken from http://smarden.org/runit/sv.8.html:
 
 sv - control and manage services monitored by runsv
 
@@ -36,17 +36,13 @@ The sv program reports the current status and controls the state of services
 monitored by the runsv(8) supervisor.
 
 services consists of one or more arguments, each argument naming a directory
-service used by runsv(8). If service doesn't start with a dot or slash,
-it is searched in the default services directory /var/service/, otherwise
-relative to the current directory.
+service used by runsv(8). If service doesn't start with a dot or slash and
+doesn't end with a slash, it is searched in the default services directory
+/var/service/, otherwise relative to the current directory.
 
 command is one of up, down, status, once, pause, cont, hup, alarm, interrupt,
-1, 2, term, kill, or exit, or start, stop, restart, shutdown, force-stop,
-force-reload, force-restart, force-shutdown.
-
-The sv program can be sym-linked to /etc/init.d/ to provide an LSB init
-script interface. The service to be controlled then is specified by the
-base name of the "init script".
+1, 2, term, kill, or exit, or start, stop, reload, restart, shutdown,
+force-stop, force-reload, force-restart, force-shutdown, try-restart.
 
 status
     Report the current status of the service, and the appendant log service
@@ -66,9 +62,9 @@ exit
     If the service is running, send it the TERM signal, and the CONT signal.
     Do not restart the service. If the service is down, and no log service
     exists, runsv(8) exits. If the service is down and a log service exists,
-    send the TERM signal to the log service. If the log service is down,
-    runsv(8) exits. This command is ignored if it is given to an appendant
-    log service.
+    runsv(8) closes the standard input of the log service and waits for it to
+    terminate. If the log service is down, runsv(8) exits. This command is
+    ignored if it is given to an appendant log service.
 
 sv actually looks only at the first character of above commands.
 
@@ -85,6 +81,8 @@ start
 stop
     Same as down, but wait up to 7 seconds for the service to become down.
     Then report the status or timeout.
+reload
+    Same as hup, and additionally report the status afterwards.
 restart
     Send the commands term, cont, and up to the service, and wait up to
     7 seconds for the service to restart. Then report the status or timeout.
@@ -112,6 +110,9 @@ force-shutdown
     Same as exit, but wait up to 7 seconds for the runsv(8) process to
     terminate. Then report the status, and on timeout send the service
     the kill command.
+try-restart
+    if the service is running, send it the term and cont commands, and wait up to
+    7 seconds for the service to restart. Then report the status or timeout.
 
 Additional Commands
 
@@ -126,8 +127,8 @@ check
 Options
 
 -v
-    wait up to 7 seconds for the command to take effect.
-    Then report the status or timeout.
+    If the command is up, down, term, once, cont, or exit, then wait up to 7
+    seconds for the command to take effect. Then report the status or timeout.
 -w sec
     Override the default timeout of 7 seconds with sec seconds. Implies -v.
 
@@ -192,6 +193,7 @@ struct globals {
 /* "Bernstein" time format: unix + 0x400000000000000aULL */
 	uint64_t tstart, tnow;
 	svstatus_t svstatus;
+	unsigned islog;
 } FIX_ALIASING;
 #define G (*(struct globals*)bb_common_bufsiz1)
 #define acts         (G.acts        )
@@ -200,6 +202,7 @@ struct globals {
 #define tstart       (G.tstart      )
 #define tnow         (G.tnow        )
 #define svstatus     (G.svstatus    )
+#define islog        (G.islog       )
 #define INIT_G() do { setup_common_bufsiz(); } while (0)
 
 
@@ -215,7 +218,7 @@ static void fatal_cannot(const char *m1)
 
 static void out(const char *p, const char *m1)
 {
-	printf("%s%s: %s", p, *service, m1);
+	printf("%s%s%s: %s", p, *service, islog ? "/log" : "", m1);
 	if (errno) {
 		printf(": %s", strerror(errno));
 	}
@@ -300,15 +303,13 @@ static unsigned svstatus_print(const char *m)
 	}
 	pid = SWAP_LE32(svstatus.pid_le32);
 	timestamp = SWAP_BE64(svstatus.time_be64);
-	if (pid) {
-		switch (svstatus.run_or_finish) {
-		case 1: printf("run: "); break;
-		case 2: printf("finish: "); break;
-		}
-		printf("%s: (pid %d) ", m, pid);
-	} else {
-		printf("down: %s: ", m);
+	switch (svstatus.run_or_finish) {
+	case 0: printf("down: "); break;
+	case 1: printf("run: "); break;
+	case 2: printf("finish: "); break;
 	}
+	printf("%s: ", m);
+	if (svstatus.run_or_finish) printf("(pid %d) ", pid);
 	diff = tnow - timestamp;
 	printf("%us", (diff < 0 ? 0 : diff));
 	if (pid) {
@@ -331,16 +332,21 @@ static int status(const char *unused UNUSED_PARAM)
 		return 0;
 
 	r = svstatus_print(*service);
+	islog = 1;
 	if (chdir("log") == -1) {
 		if (errno != ENOENT) {
-			printf("; log: "WARN"can't change to log service directory: %s",
-					strerror(errno));
+			printf("; ");
+			warn("can't change directory");
 		}
-	} else if (svstatus_get()) {
+		else bb_putchar('\n');
+	} else {
 		printf("; ");
-		svstatus_print("log");
+		if (svstatus_get()) {
+			r = svstatus_print("log");
+			bb_putchar('\n');
+		}
 	}
-	bb_putchar('\n'); /* will also flush the output */
+	islog = 0;
 	return r;
 }
 
@@ -379,35 +385,46 @@ static int check(const char *a)
 	r = svstatus_get();
 	if (r == -1)
 		return -1;
-	if (r == 0) {
-		if (*a == 'x')
-			return 1;
-		return -1;
-	}
-	pid_le32 = svstatus.pid_le32;
-	switch (*a) {
-	case 'x':
-		return 0;
-	case 'u':
-		if (!pid_le32 || svstatus.run_or_finish != 1) return 0;
-		if (!checkscript()) return 0;
-		break;
-	case 'd':
-		if (pid_le32) return 0;
-		break;
-	case 'c':
-		if (pid_le32 && !checkscript()) return 0;
-		break;
-	case 't':
-		if (!pid_le32 && svstatus.want == 'd') break;
-		timestamp = SWAP_BE64(svstatus.time_be64);
-		if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
-			return 0;
-		break;
-	case 'o':
-		timestamp = SWAP_BE64(svstatus.time_be64);
-		if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
+	while (*a) {
+		if (r == 0) {
+			if (*a == 'x')
+				return 1;
+			return -1;
+		}
+		pid_le32 = svstatus.pid_le32;
+		switch (*a) {
+		case 'x':
 			return 0;
+		case 'u':
+			if (!pid_le32 || svstatus.run_or_finish != 1) return 0;
+			if (!checkscript()) return 0;
+			break;
+		case 'd':
+			if (pid_le32 || svstatus.run_or_finish != 0) return 0;
+			break;
+		case 'C':
+			if (pid_le32 && !checkscript()) return 0;
+			break;
+		case 't':
+		case 'k':
+			if (!pid_le32 && svstatus.want == 'd') break;
+			timestamp = SWAP_BE64(svstatus.time_be64);
+			if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
+				return 0;
+			break;
+		case 'o':
+			timestamp = SWAP_BE64(svstatus.time_be64);
+			if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
+				return 0;
+			break;
+		case 'p':
+			if (pid_le32 && !svstatus.paused) return 0;
+			break;
+		case 'c':
+			if (pid_le32 && svstatus.paused) return 0;
+			break;
+		}
+		++a;
 	}
 	printf(OK);
 	svstatus_print(*service);
@@ -419,14 +436,10 @@ static int control(const char *a)
 {
 	int fd, r, l;
 
-/* Is it an optimization?
-   It causes problems with "sv o SRV; ...; sv d SRV"
-   ('d' is not passed to SRV because its .want == 'd'):
 	if (svstatus_get() <= 0)
 		return -1;
-	if (svstatus.want == *a)
+	if (svstatus.want == *a && (*a != 'd' || svstatus.got_term == 1))
 		return 0;
-*/
 	fd = open("supervise/control", O_WRONLY|O_NDELAY);
 	if (fd == -1) {
 		if (errno != ENODEV)
@@ -516,13 +529,18 @@ static int sv(char **argv)
 		acts = "tc";
 		kll = 1;
 		break;
+	case 't':
+		if (str_equal(action, "try-restart")) {
+			acts = "tc";
+			break;
+		}
 	case 'c':
 		if (str_equal(action, "check")) {
 			act = NULL;
-			acts = "c";
+			acts = "C";
 			break;
 		}
-	case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
+	case 'u': case 'd': case 'o': case 'p': case 'h':
 	case 'a': case 'i': case 'k': case 'q': case '1': case '2':
 		action[1] = '\0';
 		acts = action;
@@ -550,6 +568,10 @@ static int sv(char **argv)
 			acts = "tcu";
 			break;
 		}
+		if (str_equal(action, "reload")) {
+			acts = "h";
+			break;
+		}
 		bb_show_usage();
 	case 'f':
 		if (str_equal(action, "force-reload")) {
@@ -578,7 +600,8 @@ static int sv(char **argv)
 
 	service = argv;
 	while ((x = *service) != NULL) {
-		if (x[0] != '/' && x[0] != '.') {
+		if (x[0] != '/' && x[0] != '.' && x[0] != 0 &&
+		    x[strlen(x) - 1] != '/') {
 			if (chdir(varservice) == -1)
 				goto chdir_failed_0;
 		}
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 3ed13b6..9f4d5ed 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -339,17 +339,18 @@ static unsigned pmatch(const char *p, const char *s, unsigned len)
 /*** ex fmt_ptime.[ch] ***/
 
 /* NUL terminated */
-static void fmt_time_human_30nul(char *s)
+static void fmt_time_human_30nul(char *s, unsigned timestamp)
 {
 	struct tm *ptm;
 	struct timeval tv;
 
 	gettimeofday(&tv, NULL);
 	ptm = gmtime(&tv.tv_sec);
-	sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
+	sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000",
 		(unsigned)(1900 + ptm->tm_year),
 		(unsigned)(ptm->tm_mon + 1),
 		(unsigned)(ptm->tm_mday),
+		(timestamp == 2) ? '_' : 'T',
 		(unsigned)(ptm->tm_hour),
 		(unsigned)(ptm->tm_min),
 		(unsigned)(ptm->tm_sec),
@@ -1160,8 +1161,8 @@ int svlogd_main(int argc, char **argv)
 		if (timestamp) {
 			if (timestamp == 1)
 				fmt_time_bernstein_25(stamp);
-			else /* 2: */
-				fmt_time_human_30nul(stamp);
+			else /* 2, 3: */
+				fmt_time_human_30nul(stamp, timestamp);
 			printlen += 26;
 			printptr -= 26;
 			memcpy(printptr, stamp, 25);
-- 
2.7.4

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic