aboutsummaryrefslogtreecommitdiff
path: root/runit
diff options
context:
space:
mode:
Diffstat (limited to 'runit')
-rw-r--r--runit/chpst.c13
-rw-r--r--runit/runsv.c95
-rw-r--r--runit/sv.c170
-rw-r--r--runit/svlogd.c13
4 files changed, 171 insertions, 120 deletions
diff --git a/runit/chpst.c b/runit/chpst.c
index 846c846d3..ee3a33153 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -463,6 +463,13 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
463 xchroot(root); 463 xchroot(root);
464 } 464 }
465 465
466 /* nice should be done before xsetuid */
467 if (opt & OPT_n) {
468 errno = 0;
469 if (nice(xatoi(nicestr)) == -1)
470 bb_perror_msg_and_die("nice");
471 }
472
466 if (opt & OPT_u) { 473 if (opt & OPT_u) {
467 if (setgroups(1, &ugid.gid) == -1) 474 if (setgroups(1, &ugid.gid) == -1)
468 bb_perror_msg_and_die("setgroups"); 475 bb_perror_msg_and_die("setgroups");
@@ -470,12 +477,6 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
470 xsetuid(ugid.uid); 477 xsetuid(ugid.uid);
471 } 478 }
472 479
473 if (opt & OPT_n) {
474 errno = 0;
475 if (nice(xatoi(nicestr)) == -1)
476 bb_perror_msg_and_die("nice");
477 }
478
479 if (opt & OPT_0) 480 if (opt & OPT_0)
480 close(STDIN_FILENO); 481 close(STDIN_FILENO);
481 if (opt & OPT_1) 482 if (opt & OPT_1)
diff --git a/runit/runsv.c b/runit/runsv.c
index e0e31508a..939653d12 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -134,9 +134,13 @@ static void fatal2x_cannot(const char *m1, const char *m2)
134 bb_error_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2); 134 bb_error_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2);
135 /* was exiting 111 */ 135 /* was exiting 111 */
136} 136}
137static void warn2_cannot(const char *m1, const char *m2)
138{
139 bb_perror_msg("%s: warning: can't %s%s", dir, m1, m2);
140}
137static void warn_cannot(const char *m) 141static void warn_cannot(const char *m)
138{ 142{
139 bb_perror_msg("%s: warning: cannot %s", dir, m); 143 warn2_cannot(m, "");
140} 144}
141 145
142static void s_child(int sig_no UNUSED_PARAM) 146static void s_child(int sig_no UNUSED_PARAM)
@@ -165,10 +169,25 @@ static void update_status(struct svdir *s)
165 ssize_t sz; 169 ssize_t sz;
166 int fd; 170 int fd;
167 svstatus_t status; 171 svstatus_t status;
172 const char *fstatus ="log/supervise/status";
173 const char *fstatusnew ="log/supervise/status.new";
174 const char *f_stat ="log/supervise/stat";
175 const char *fstatnew ="log/supervise/stat.new";
176 const char *fpid ="log/supervise/pid";
177 const char *fpidnew ="log/supervise/pid.new";
178
179 if (!s->islog) {
180 fstatus += 4;
181 fstatusnew += 4;
182 f_stat += 4;
183 fstatnew += 4;
184 fpid += 4;
185 fpidnew += 4;
186 }
168 187
169 /* pid */ 188 /* pid */
170 if (pidchanged) { 189 if (pidchanged) {
171 fd = open_trunc_or_warn("supervise/pid.new"); 190 fd = open_trunc_or_warn(fpidnew);
172 if (fd < 0) 191 if (fd < 0)
173 return; 192 return;
174 if (s->pid) { 193 if (s->pid) {
@@ -177,14 +196,13 @@ static void update_status(struct svdir *s)
177 write(fd, spid, size); 196 write(fd, spid, size);
178 } 197 }
179 close(fd); 198 close(fd);
180 if (rename_or_warn("supervise/pid.new", 199 if (rename_or_warn(fpidnew, fpid))
181 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
182 return; 200 return;
183 pidchanged = 0; 201 pidchanged = 0;
184 } 202 }
185 203
186 /* stat */ 204 /* stat */
187 fd = open_trunc_or_warn("supervise/stat.new"); 205 fd = open_trunc_or_warn(fstatnew);
188 if (fd < -1) 206 if (fd < -1)
189 return; 207 return;
190 208
@@ -220,8 +238,7 @@ static void update_status(struct svdir *s)
220 close(fd); 238 close(fd);
221 } 239 }
222 240
223 rename_or_warn("supervise/stat.new", 241 rename_or_warn(fstatnew, f_stat);
224 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
225 242
226 /* supervise compatibility */ 243 /* supervise compatibility */
227 memset(&status, 0, sizeof(status)); 244 memset(&status, 0, sizeof(status));
@@ -237,18 +254,17 @@ static void update_status(struct svdir *s)
237 if (s->ctrl & C_TERM) 254 if (s->ctrl & C_TERM)
238 status.got_term = 1; 255 status.got_term = 1;
239 status.run_or_finish = s->state; 256 status.run_or_finish = s->state;
240 fd = open_trunc_or_warn("supervise/status.new"); 257 fd = open_trunc_or_warn(fstatusnew);
241 if (fd < 0) 258 if (fd < 0)
242 return; 259 return;
243 sz = write(fd, &status, sizeof(status)); 260 sz = write(fd, &status, sizeof(status));
244 close(fd); 261 close(fd);
245 if (sz != sizeof(status)) { 262 if (sz != sizeof(status)) {
246 warn_cannot("write supervise/status.new"); 263 warn2_cannot("write ", fstatusnew);
247 unlink("supervise/status.new"); 264 unlink(fstatusnew);
248 return; 265 return;
249 } 266 }
250 rename_or_warn("supervise/status.new", 267 rename_or_warn(fstatusnew, fstatus);
251 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
252} 268}
253 269
254static unsigned custom(struct svdir *s, char c) 270static unsigned custom(struct svdir *s, char c)
@@ -266,26 +282,26 @@ static unsigned custom(struct svdir *s, char c)
266 if (st.st_mode & S_IXUSR) { 282 if (st.st_mode & S_IXUSR) {
267 pid = vfork(); 283 pid = vfork();
268 if (pid == -1) { 284 if (pid == -1) {
269 warn_cannot("vfork for control/?"); 285 warn2_cannot("vfork for ", a);
270 return 0; 286 return 0;
271 } 287 }
272 if (pid == 0) { 288 if (pid == 0) {
273 /* child */ 289 /* child */
274 if (haslog && dup2(logpipe.wr, 1) == -1) 290 if (haslog && dup2(logpipe.wr, 1) == -1)
275 warn_cannot("setup stdout for control/?"); 291 warn2_cannot("setup stdout for ", a);
276 execl(a, a, (char *) NULL); 292 execl(a, a, (char *) NULL);
277 fatal_cannot("run control/?"); 293 fatal2_cannot("run ", a);
278 } 294 }
279 /* parent */ 295 /* parent */
280 if (safe_waitpid(pid, &w, 0) == -1) { 296 if (safe_waitpid(pid, &w, 0) == -1) {
281 warn_cannot("wait for child control/?"); 297 warn2_cannot("wait for child ", a);
282 return 0; 298 return 0;
283 } 299 }
284 return WEXITSTATUS(w) == 0; 300 return WEXITSTATUS(w) == 0;
285 } 301 }
286 } else { 302 } else {
287 if (errno != ENOENT) 303 if (errno != ENOENT)
288 warn_cannot("stat control/?"); 304 warn2_cannot("stat ", a);
289 } 305 }
290 return 0; 306 return 0;
291} 307}
@@ -387,13 +403,13 @@ static int ctrl(struct svdir *s, char c)
387 case 'd': /* down */ 403 case 'd': /* down */
388 s->sd_want = W_DOWN; 404 s->sd_want = W_DOWN;
389 update_status(s); 405 update_status(s);
390 if (s->pid && s->state != S_FINISH) 406 if (s->state == S_RUN)
391 stopservice(s); 407 stopservice(s);
392 break; 408 break;
393 case 'u': /* up */ 409 case 'u': /* up */
394 s->sd_want = W_UP; 410 s->sd_want = W_UP;
395 update_status(s); 411 update_status(s);
396 if (s->pid == 0) 412 if (s->state == S_DOWN)
397 startservice(s); 413 startservice(s);
398 break; 414 break;
399 case 'x': /* exit */ 415 case 'x': /* exit */
@@ -403,22 +419,22 @@ static int ctrl(struct svdir *s, char c)
403 update_status(s); 419 update_status(s);
404 /* FALLTHROUGH */ 420 /* FALLTHROUGH */
405 case 't': /* sig term */ 421 case 't': /* sig term */
406 if (s->pid && s->state != S_FINISH) 422 if (s->state == S_RUN)
407 stopservice(s); 423 stopservice(s);
408 break; 424 break;
409 case 'k': /* sig kill */ 425 case 'k': /* sig kill */
410 if (s->pid && !custom(s, c)) 426 if ((s->state == S_RUN) && !custom(s, c))
411 kill(s->pid, SIGKILL); 427 kill(s->pid, SIGKILL);
412 s->state = S_DOWN; 428 s->state = S_DOWN;
413 break; 429 break;
414 case 'p': /* sig pause */ 430 case 'p': /* sig pause */
415 if (s->pid && !custom(s, c)) 431 if ((s->state == S_RUN) && !custom(s, c))
416 kill(s->pid, SIGSTOP); 432 kill(s->pid, SIGSTOP);
417 s->ctrl |= C_PAUSE; 433 s->ctrl |= C_PAUSE;
418 update_status(s); 434 update_status(s);
419 break; 435 break;
420 case 'c': /* sig cont */ 436 case 'c': /* sig cont */
421 if (s->pid && !custom(s, c)) 437 if ((s->state == S_RUN) && !custom(s, c))
422 kill(s->pid, SIGCONT); 438 kill(s->pid, SIGCONT);
423 s->ctrl &= ~C_PAUSE; 439 s->ctrl &= ~C_PAUSE;
424 update_status(s); 440 update_status(s);
@@ -426,7 +442,7 @@ static int ctrl(struct svdir *s, char c)
426 case 'o': /* once */ 442 case 'o': /* once */
427 s->sd_want = W_DOWN; 443 s->sd_want = W_DOWN;
428 update_status(s); 444 update_status(s);
429 if (!s->pid) 445 if (s->state == S_DOWN)
430 startservice(s); 446 startservice(s);
431 break; 447 break;
432 case 'a': /* sig alarm */ 448 case 'a': /* sig alarm */
@@ -450,11 +466,26 @@ static int ctrl(struct svdir *s, char c)
450 } 466 }
451 return 1; 467 return 1;
452 sendsig: 468 sendsig:
453 if (s->pid && !custom(s, c)) 469 if ((s->state == S_RUN) && !custom(s, c))
454 kill(s->pid, sig); 470 kill(s->pid, sig);
455 return 1; 471 return 1;
456} 472}
457 473
474static void open_control(const char *f, struct svdir *s)
475{
476 struct stat st;
477 mkfifo(f, 0600);
478 if (stat(f, &st) == -1)
479 fatal2_cannot("stat ", f);
480 if (!S_ISFIFO(st.st_mode))
481 bb_error_msg_and_die("%s: fatal: %s exists but is not a fifo", dir, f);
482 s->fdcontrol = xopen(f, O_RDONLY|O_NDELAY);
483 close_on_exec_on(s->fdcontrol);
484 s->fdcontrolwrite = xopen(f, O_WRONLY|O_NDELAY);
485 close_on_exec_on(s->fdcontrolwrite);
486 update_status(s);
487}
488
458int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 489int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
459int runsv_main(int argc UNUSED_PARAM, char **argv) 490int runsv_main(int argc UNUSED_PARAM, char **argv)
460{ 491{
@@ -554,19 +585,9 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
554 close_on_exec_on(svd[1].fdlock); 585 close_on_exec_on(svd[1].fdlock);
555 } 586 }
556 587
557 mkfifo("log/supervise/control"+4, 0600); 588 open_control("log/supervise/control"+4, &svd[0]);
558 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
559 close_on_exec_on(svd[0].fdcontrol);
560 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
561 close_on_exec_on(svd[0].fdcontrolwrite);
562 update_status(&svd[0]);
563 if (haslog) { 589 if (haslog) {
564 mkfifo("log/supervise/control", 0600); 590 open_control("log/supervise/control", &svd[1]);
565 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
566 close_on_exec_on(svd[1].fdcontrol);
567 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
568 close_on_exec_on(svd[1].fdcontrolwrite);
569 update_status(&svd[1]);
570 } 591 }
571 mkfifo("log/supervise/ok"+4, 0600); 592 mkfifo("log/supervise/ok"+4, 0600);
572 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY); 593 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
diff --git a/runit/sv.c b/runit/sv.c
index 9e2132259..faa31d4fa 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
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/ 26*/
27 27
28/* Taken from http://smarden.sunsite.dk/runit/sv.8.html: 28/* Taken from http://smarden.org/runit/sv.8.html:
29 29
30sv - control and manage services monitored by runsv 30sv - control and manage services monitored by runsv
31 31
@@ -36,17 +36,13 @@ The sv program reports the current status and controls the state of services
36monitored by the runsv(8) supervisor. 36monitored by the runsv(8) supervisor.
37 37
38services consists of one or more arguments, each argument naming a directory 38services consists of one or more arguments, each argument naming a directory
39service used by runsv(8). If service doesn't start with a dot or slash, 39service used by runsv(8). If service doesn't start with a dot or slash and
40it is searched in the default services directory /var/service/, otherwise 40doesn't end with a slash, it is searched in the default services directory
41relative to the current directory. 41/var/service/, otherwise relative to the current directory.
42 42
43command is one of up, down, status, once, pause, cont, hup, alarm, interrupt, 43command is one of up, down, status, once, pause, cont, hup, alarm, interrupt,
441, 2, term, kill, or exit, or start, stop, restart, shutdown, force-stop, 441, 2, term, kill, or exit, or start, stop, reload, restart, shutdown,
45force-reload, force-restart, force-shutdown. 45force-stop, force-reload, force-restart, force-shutdown, try-restart.
46
47The sv program can be sym-linked to /etc/init.d/ to provide an LSB init
48script interface. The service to be controlled then is specified by the
49base name of the "init script".
50 46
51status 47status
52 Report the current status of the service, and the appendant log service 48 Report the current status of the service, and the appendant log service
@@ -66,9 +62,9 @@ exit
66 If the service is running, send it the TERM signal, and the CONT signal. 62 If the service is running, send it the TERM signal, and the CONT signal.
67 Do not restart the service. If the service is down, and no log service 63 Do not restart the service. If the service is down, and no log service
68 exists, runsv(8) exits. If the service is down and a log service exists, 64 exists, runsv(8) exits. If the service is down and a log service exists,
69 send the TERM signal to the log service. If the log service is down, 65 runsv(8) closes the standard input of the log service and waits for it to
70 runsv(8) exits. This command is ignored if it is given to an appendant 66 terminate. If the log service is down, runsv(8) exits. This command is
71 log service. 67 ignored if it is given to an appendant log service.
72 68
73sv actually looks only at the first character of above commands. 69sv actually looks only at the first character of above commands.
74 70
@@ -85,6 +81,8 @@ start
85stop 81stop
86 Same as down, but wait up to 7 seconds for the service to become down. 82 Same as down, but wait up to 7 seconds for the service to become down.
87 Then report the status or timeout. 83 Then report the status or timeout.
84reload
85 Same as hup, and additionally report the status afterwards.
88restart 86restart
89 Send the commands term, cont, and up to the service, and wait up to 87 Send the commands term, cont, and up to the service, and wait up to
90 7 seconds for the service to restart. Then report the status or timeout. 88 7 seconds for the service to restart. Then report the status or timeout.
@@ -112,6 +110,9 @@ force-shutdown
112 Same as exit, but wait up to 7 seconds for the runsv(8) process to 110 Same as exit, but wait up to 7 seconds for the runsv(8) process to
113 terminate. Then report the status, and on timeout send the service 111 terminate. Then report the status, and on timeout send the service
114 the kill command. 112 the kill command.
113try-restart
114 if the service is running, send it the term and cont commands, and wait up to
115 7 seconds for the service to restart. Then report the status or timeout.
115 116
116Additional Commands 117Additional Commands
117 118
@@ -126,8 +127,8 @@ check
126Options 127Options
127 128
128-v 129-v
129 wait up to 7 seconds for the command to take effect. 130 If the command is up, down, term, once, cont, or exit, then wait up to 7
130 Then report the status or timeout. 131 seconds for the command to take effect. Then report the status or timeout.
131-w sec 132-w sec
132 Override the default timeout of 7 seconds with sec seconds. Implies -v. 133 Override the default timeout of 7 seconds with sec seconds. Implies -v.
133 134
@@ -192,6 +193,7 @@ struct globals {
192/* "Bernstein" time format: unix + 0x400000000000000aULL */ 193/* "Bernstein" time format: unix + 0x400000000000000aULL */
193 uint64_t tstart, tnow; 194 uint64_t tstart, tnow;
194 svstatus_t svstatus; 195 svstatus_t svstatus;
196 unsigned islog;
195} FIX_ALIASING; 197} FIX_ALIASING;
196#define G (*(struct globals*)bb_common_bufsiz1) 198#define G (*(struct globals*)bb_common_bufsiz1)
197#define acts (G.acts ) 199#define acts (G.acts )
@@ -200,6 +202,7 @@ struct globals {
200#define tstart (G.tstart ) 202#define tstart (G.tstart )
201#define tnow (G.tnow ) 203#define tnow (G.tnow )
202#define svstatus (G.svstatus ) 204#define svstatus (G.svstatus )
205#define islog (G.islog )
203#define INIT_G() do { setup_common_bufsiz(); } while (0) 206#define INIT_G() do { setup_common_bufsiz(); } while (0)
204 207
205 208
@@ -215,7 +218,7 @@ static void fatal_cannot(const char *m1)
215 218
216static void out(const char *p, const char *m1) 219static void out(const char *p, const char *m1)
217{ 220{
218 printf("%s%s: %s", p, *service, m1); 221 printf("%s%s%s: %s", p, *service, islog ? "/log" : "", m1);
219 if (errno) { 222 if (errno) {
220 printf(": %s", strerror(errno)); 223 printf(": %s", strerror(errno));
221 } 224 }
@@ -300,15 +303,14 @@ static unsigned svstatus_print(const char *m)
300 } 303 }
301 pid = SWAP_LE32(svstatus.pid_le32); 304 pid = SWAP_LE32(svstatus.pid_le32);
302 timestamp = SWAP_BE64(svstatus.time_be64); 305 timestamp = SWAP_BE64(svstatus.time_be64);
303 if (pid) { 306 switch (svstatus.run_or_finish) {
304 switch (svstatus.run_or_finish) { 307 case 0: printf("down: "); break;
305 case 1: printf("run: "); break; 308 case 1: printf("run: "); break;
306 case 2: printf("finish: "); break; 309 case 2: printf("finish: "); break;
307 }
308 printf("%s: (pid %d) ", m, pid);
309 } else {
310 printf("down: %s: ", m);
311 } 310 }
311 printf("%s: ", m);
312 if (svstatus.run_or_finish)
313 printf("(pid %d) ", pid);
312 diff = tnow - timestamp; 314 diff = tnow - timestamp;
313 printf("%us", (diff < 0 ? 0 : diff)); 315 printf("%us", (diff < 0 ? 0 : diff));
314 if (pid) { 316 if (pid) {
@@ -331,16 +333,21 @@ static int status(const char *unused UNUSED_PARAM)
331 return 0; 333 return 0;
332 334
333 r = svstatus_print(*service); 335 r = svstatus_print(*service);
336 islog = 1;
334 if (chdir("log") == -1) { 337 if (chdir("log") == -1) {
335 if (errno != ENOENT) { 338 if (errno != ENOENT) {
336 printf("; log: "WARN"can't change to log service directory: %s", 339 printf("; ");
337 strerror(errno)); 340 warn("can't change directory");
338 } 341 } else
339 } else if (svstatus_get()) { 342 bb_putchar('\n');
343 } else {
340 printf("; "); 344 printf("; ");
341 svstatus_print("log"); 345 if (svstatus_get()) {
346 r = svstatus_print("log");
347 bb_putchar('\n');
348 }
342 } 349 }
343 bb_putchar('\n'); /* will also flush the output */ 350 islog = 0;
344 return r; 351 return r;
345} 352}
346 353
@@ -379,35 +386,53 @@ static int check(const char *a)
379 r = svstatus_get(); 386 r = svstatus_get();
380 if (r == -1) 387 if (r == -1)
381 return -1; 388 return -1;
382 if (r == 0) { 389 while (*a) {
383 if (*a == 'x') 390 if (r == 0) {
384 return 1; 391 if (*a == 'x')
385 return -1; 392 return 1;
386 } 393 return -1;
387 pid_le32 = svstatus.pid_le32; 394 }
388 switch (*a) { 395 pid_le32 = svstatus.pid_le32;
389 case 'x': 396 switch (*a) {
390 return 0; 397 case 'x':
391 case 'u':
392 if (!pid_le32 || svstatus.run_or_finish != 1) return 0;
393 if (!checkscript()) return 0;
394 break;
395 case 'd':
396 if (pid_le32) return 0;
397 break;
398 case 'c':
399 if (pid_le32 && !checkscript()) return 0;
400 break;
401 case 't':
402 if (!pid_le32 && svstatus.want == 'd') break;
403 timestamp = SWAP_BE64(svstatus.time_be64);
404 if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
405 return 0;
406 break;
407 case 'o':
408 timestamp = SWAP_BE64(svstatus.time_be64);
409 if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
410 return 0; 398 return 0;
399 case 'u':
400 if (!pid_le32 || svstatus.run_or_finish != 1)
401 return 0;
402 if (!checkscript())
403 return 0;
404 break;
405 case 'd':
406 if (pid_le32 || svstatus.run_or_finish != 0)
407 return 0;
408 break;
409 case 'C':
410 if (pid_le32 && !checkscript())
411 return 0;
412 break;
413 case 't':
414 case 'k':
415 if (!pid_le32 && svstatus.want == 'd')
416 break;
417 timestamp = SWAP_BE64(svstatus.time_be64);
418 if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
419 return 0;
420 break;
421 case 'o':
422 timestamp = SWAP_BE64(svstatus.time_be64);
423 if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
424 return 0;
425 break;
426 case 'p':
427 if (pid_le32 && !svstatus.paused)
428 return 0;
429 break;
430 case 'c':
431 if (pid_le32 && svstatus.paused)
432 return 0;
433 break;
434 }
435 ++a;
411 } 436 }
412 printf(OK); 437 printf(OK);
413 svstatus_print(*service); 438 svstatus_print(*service);
@@ -419,14 +444,10 @@ static int control(const char *a)
419{ 444{
420 int fd, r, l; 445 int fd, r, l;
421 446
422/* Is it an optimization?
423 It causes problems with "sv o SRV; ...; sv d SRV"
424 ('d' is not passed to SRV because its .want == 'd'):
425 if (svstatus_get() <= 0) 447 if (svstatus_get() <= 0)
426 return -1; 448 return -1;
427 if (svstatus.want == *a) 449 if (svstatus.want == *a && (*a != 'd' || svstatus.got_term == 1))
428 return 0; 450 return 0;
429*/
430 fd = open("supervise/control", O_WRONLY|O_NDELAY); 451 fd = open("supervise/control", O_WRONLY|O_NDELAY);
431 if (fd == -1) { 452 if (fd == -1) {
432 if (errno != ENODEV) 453 if (errno != ENODEV)
@@ -516,17 +537,23 @@ static int sv(char **argv)
516 acts = "tc"; 537 acts = "tc";
517 kll = 1; 538 kll = 1;
518 break; 539 break;
540 case 't':
541 if (str_equal(action, "try-restart")) {
542 acts = "tc";
543 break;
544 }
519 case 'c': 545 case 'c':
520 if (str_equal(action, "check")) { 546 if (str_equal(action, "check")) {
521 act = NULL; 547 act = NULL;
522 acts = "c"; 548 acts = "C";
523 break; 549 break;
524 } 550 }
525 case 'u': case 'd': case 'o': case 't': case 'p': case 'h': 551 case 'u': case 'd': case 'o': case 'p': case 'h':
526 case 'a': case 'i': case 'k': case 'q': case '1': case '2': 552 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
527 action[1] = '\0'; 553 action[1] = '\0';
528 acts = action; 554 acts = action;
529 if (!verbose) cbk = NULL; 555 if (!verbose)
556 cbk = NULL;
530 break; 557 break;
531 case 's': 558 case 's':
532 if (str_equal(action, "shutdown")) { 559 if (str_equal(action, "shutdown")) {
@@ -550,6 +577,10 @@ static int sv(char **argv)
550 acts = "tcu"; 577 acts = "tcu";
551 break; 578 break;
552 } 579 }
580 if (str_equal(action, "reload")) {
581 acts = "h";
582 break;
583 }
553 bb_show_usage(); 584 bb_show_usage();
554 case 'f': 585 case 'f':
555 if (str_equal(action, "force-reload")) { 586 if (str_equal(action, "force-reload")) {
@@ -578,7 +609,9 @@ static int sv(char **argv)
578 609
579 service = argv; 610 service = argv;
580 while ((x = *service) != NULL) { 611 while ((x = *service) != NULL) {
581 if (x[0] != '/' && x[0] != '.') { 612 if (x[0] != '/' && x[0] != '.'
613 && x[0] != '\0' && x[strlen(x) - 1] != '/'
614 ) {
582 if (chdir(varservice) == -1) 615 if (chdir(varservice) == -1)
583 goto chdir_failed_0; 616 goto chdir_failed_0;
584 } 617 }
@@ -688,12 +721,7 @@ int svc_main(int argc UNUSED_PARAM, char **argv)
688 /* getopt32() was already called: 721 /* getopt32() was already called:
689 * reset the libc getopt() function, which keeps internal state. 722 * reset the libc getopt() function, which keeps internal state.
690 */ 723 */
691#ifdef __GLIBC__ 724 GETOPT_RESET();
692 optind = 0;
693#else /* BSD style */
694 optind = 1;
695 /* optreset = 1; */
696#endif
697 725
698 do { 726 do {
699 if (opts & 1) { 727 if (opts & 1) {
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 3ed13b67b..795bf48bb 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -137,9 +137,9 @@ log message, you can use a pattern like this instead
137//kbuild:lib-$(CONFIG_SVLOGD) += svlogd.o 137//kbuild:lib-$(CONFIG_SVLOGD) += svlogd.o
138 138
139//usage:#define svlogd_trivial_usage 139//usage:#define svlogd_trivial_usage
140//usage: "[-ttv] [-r C] [-R CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..." 140//usage: "[-tttv] [-r C] [-R CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..."
141//usage:#define svlogd_full_usage "\n\n" 141//usage:#define svlogd_full_usage "\n\n"
142//usage: "Continuously read log data from stdin and write to rotated log files in DIRs" 142//usage: "Read log data from stdin and write to rotated log files in DIRs"
143//usage: "\n" 143//usage: "\n"
144//usage: "\n""DIR/config file modifies behavior:" 144//usage: "\n""DIR/config file modifies behavior:"
145//usage: "\n""sSIZE - when to rotate logs" 145//usage: "\n""sSIZE - when to rotate logs"
@@ -339,17 +339,18 @@ static unsigned pmatch(const char *p, const char *s, unsigned len)
339/*** ex fmt_ptime.[ch] ***/ 339/*** ex fmt_ptime.[ch] ***/
340 340
341/* NUL terminated */ 341/* NUL terminated */
342static void fmt_time_human_30nul(char *s) 342static void fmt_time_human_30nul(char *s, char dt_delim)
343{ 343{
344 struct tm *ptm; 344 struct tm *ptm;
345 struct timeval tv; 345 struct timeval tv;
346 346
347 gettimeofday(&tv, NULL); 347 gettimeofday(&tv, NULL);
348 ptm = gmtime(&tv.tv_sec); 348 ptm = gmtime(&tv.tv_sec);
349 sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000", 349 sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000",
350 (unsigned)(1900 + ptm->tm_year), 350 (unsigned)(1900 + ptm->tm_year),
351 (unsigned)(ptm->tm_mon + 1), 351 (unsigned)(ptm->tm_mon + 1),
352 (unsigned)(ptm->tm_mday), 352 (unsigned)(ptm->tm_mday),
353 dt_delim,
353 (unsigned)(ptm->tm_hour), 354 (unsigned)(ptm->tm_hour),
354 (unsigned)(ptm->tm_min), 355 (unsigned)(ptm->tm_min),
355 (unsigned)(ptm->tm_sec), 356 (unsigned)(ptm->tm_sec),
@@ -1160,8 +1161,8 @@ int svlogd_main(int argc, char **argv)
1160 if (timestamp) { 1161 if (timestamp) {
1161 if (timestamp == 1) 1162 if (timestamp == 1)
1162 fmt_time_bernstein_25(stamp); 1163 fmt_time_bernstein_25(stamp);
1163 else /* 2: */ 1164 else /* 2+: */
1164 fmt_time_human_30nul(stamp); 1165 fmt_time_human_30nul(stamp, timestamp == 2 ? '_' : 'T');
1165 printlen += 26; 1166 printlen += 26;
1166 printptr -= 26; 1167 printptr -= 26;
1167 memcpy(printptr, stamp, 25); 1168 memcpy(printptr, stamp, 25);