228 |
: failx("runsv not running"); |
: failx("runsv not running"); |
229 |
return 0; |
return 0; |
230 |
} |
} |
231 |
warn("cannot open supervise/ok"); |
warn("can't open supervise/ok"); |
232 |
return -1; |
return -1; |
233 |
} |
} |
234 |
close(fd); |
close(fd); |
235 |
fd = open_read("supervise/status"); |
fd = open_read("supervise/status"); |
236 |
if (fd == -1) { |
if (fd == -1) { |
237 |
warn("cannot open supervise/status"); |
warn("can't open supervise/status"); |
238 |
return -1; |
return -1; |
239 |
} |
} |
240 |
r = read(fd, &svstatus, 20); |
r = read(fd, &svstatus, 20); |
243 |
case 20: |
case 20: |
244 |
break; |
break; |
245 |
case -1: |
case -1: |
246 |
warn("cannot read supervise/status"); |
warn("can't read supervise/status"); |
247 |
return -1; |
return -1; |
248 |
default: |
default: |
249 |
errno = 0; |
errno = 0; |
250 |
warn("cannot read supervise/status: bad format"); |
warn("can't read supervise/status: bad format"); |
251 |
return -1; |
return -1; |
252 |
} |
} |
253 |
return 1; |
return 1; |
263 |
|
|
264 |
if (stat("down", &s) == -1) { |
if (stat("down", &s) == -1) { |
265 |
if (errno != ENOENT) { |
if (errno != ENOENT) { |
266 |
bb_perror_msg(WARN"cannot stat %s/down", *service); |
bb_perror_msg(WARN"can't stat %s/down", *service); |
267 |
return 0; |
return 0; |
268 |
} |
} |
269 |
normallyup = 1; |
normallyup = 1; |
297 |
{ |
{ |
298 |
int r; |
int r; |
299 |
|
|
300 |
r = svstatus_get(); |
if (svstatus_get() <= 0) |
301 |
switch (r) { case -1: case 0: return 0; } |
return 0; |
302 |
|
|
303 |
r = svstatus_print(*service); |
r = svstatus_print(*service); |
304 |
if (chdir("log") == -1) { |
if (chdir("log") == -1) { |
305 |
if (errno != ENOENT) { |
if (errno != ENOENT) { |
306 |
printf("; log: "WARN"cannot change to log service directory: %s", |
printf("; log: "WARN"can't change to log service directory: %s", |
307 |
strerror(errno)); |
strerror(errno)); |
308 |
} |
} |
309 |
} else if (svstatus_get()) { |
} else if (svstatus_get()) { |
322 |
|
|
323 |
if (stat("check", &s) == -1) { |
if (stat("check", &s) == -1) { |
324 |
if (errno == ENOENT) return 1; |
if (errno == ENOENT) return 1; |
325 |
bb_perror_msg(WARN"cannot stat %s/check", *service); |
bb_perror_msg(WARN"can't stat %s/check", *service); |
326 |
return 0; |
return 0; |
327 |
} |
} |
328 |
/* if (!(s.st_mode & S_IXUSR)) return 1; */ |
/* if (!(s.st_mode & S_IXUSR)) return 1; */ |
330 |
prog[1] = NULL; |
prog[1] = NULL; |
331 |
pid = spawn(prog); |
pid = spawn(prog); |
332 |
if (pid <= 0) { |
if (pid <= 0) { |
333 |
bb_perror_msg(WARN"cannot %s child %s/check", "run", *service); |
bb_perror_msg(WARN"can't %s child %s/check", "run", *service); |
334 |
return 0; |
return 0; |
335 |
} |
} |
336 |
while (safe_waitpid(pid, &w, 0) == -1) { |
while (safe_waitpid(pid, &w, 0) == -1) { |
337 |
bb_perror_msg(WARN"cannot %s child %s/check", "wait for", *service); |
bb_perror_msg(WARN"can't %s child %s/check", "wait for", *service); |
338 |
return 0; |
return 0; |
339 |
} |
} |
340 |
return !wait_exitcode(w); |
return WEXITSTATUS(w) == 0; |
341 |
} |
} |
342 |
|
|
343 |
static int check(const char *a) |
static int check(const char *a) |
344 |
{ |
{ |
345 |
int r; |
int r; |
346 |
unsigned pid; |
unsigned pid_le32; |
347 |
uint64_t timestamp; |
uint64_t timestamp; |
348 |
|
|
349 |
r = svstatus_get(); |
r = svstatus_get(); |
354 |
return 1; |
return 1; |
355 |
return -1; |
return -1; |
356 |
} |
} |
357 |
pid = SWAP_LE32(svstatus.pid_le32); |
pid_le32 = svstatus.pid_le32; |
358 |
switch (*a) { |
switch (*a) { |
359 |
case 'x': |
case 'x': |
360 |
return 0; |
return 0; |
361 |
case 'u': |
case 'u': |
362 |
if (!pid || svstatus.run_or_finish != 1) return 0; |
if (!pid_le32 || svstatus.run_or_finish != 1) return 0; |
363 |
if (!checkscript()) return 0; |
if (!checkscript()) return 0; |
364 |
break; |
break; |
365 |
case 'd': |
case 'd': |
366 |
if (pid) return 0; |
if (pid_le32) return 0; |
367 |
break; |
break; |
368 |
case 'c': |
case 'c': |
369 |
if (pid && !checkscript()) return 0; |
if (pid_le32 && !checkscript()) return 0; |
370 |
break; |
break; |
371 |
case 't': |
case 't': |
372 |
if (!pid && svstatus.want == 'd') break; |
if (!pid_le32 && svstatus.want == 'd') break; |
373 |
timestamp = SWAP_BE64(svstatus.time_be64); |
timestamp = SWAP_BE64(svstatus.time_be64); |
374 |
if ((tstart > timestamp) || !pid || svstatus.got_term || !checkscript()) |
if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript()) |
375 |
return 0; |
return 0; |
376 |
break; |
break; |
377 |
case 'o': |
case 'o': |
378 |
timestamp = SWAP_BE64(svstatus.time_be64); |
timestamp = SWAP_BE64(svstatus.time_be64); |
379 |
if ((!pid && tstart > timestamp) || (pid && svstatus.want != 'd')) |
if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd')) |
380 |
return 0; |
return 0; |
381 |
} |
} |
382 |
printf(OK); |
printf(OK); |
387 |
|
|
388 |
static int control(const char *a) |
static int control(const char *a) |
389 |
{ |
{ |
390 |
int fd, r; |
int fd, r, l; |
391 |
|
|
392 |
|
/* Is it an optimization? |
393 |
|
It causes problems with "sv o SRV; ...; sv d SRV" |
394 |
|
('d' is not passed to SRV because its .want == 'd'): |
395 |
if (svstatus_get() <= 0) |
if (svstatus_get() <= 0) |
396 |
return -1; |
return -1; |
397 |
if (svstatus.want == *a) |
if (svstatus.want == *a) |
398 |
return 0; |
return 0; |
399 |
|
*/ |
400 |
fd = open_write("supervise/control"); |
fd = open_write("supervise/control"); |
401 |
if (fd == -1) { |
if (fd == -1) { |
402 |
if (errno != ENODEV) |
if (errno != ENODEV) |
403 |
warn("cannot open supervise/control"); |
warn("can't open supervise/control"); |
404 |
else |
else |
405 |
*a == 'x' ? ok("runsv not running") : failx("runsv not running"); |
*a == 'x' ? ok("runsv not running") : failx("runsv not running"); |
406 |
return -1; |
return -1; |
407 |
} |
} |
408 |
r = write(fd, a, strlen(a)); |
l = strlen(a); |
409 |
|
r = write(fd, a, l); |
410 |
close(fd); |
close(fd); |
411 |
if (r != strlen(a)) { |
if (r != l) { |
412 |
warn("cannot write to supervise/control"); |
warn("can't write to supervise/control"); |
413 |
return -1; |
return -1; |
414 |
} |
} |
415 |
return 1; |
return 1; |
416 |
} |
} |
417 |
|
|
418 |
int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
419 |
int sv_main(int argc, char **argv) |
int sv_main(int argc UNUSED_PARAM, char **argv) |
420 |
{ |
{ |
421 |
unsigned opt; |
unsigned opt; |
|
unsigned i, want_exit; |
|
422 |
char *x; |
char *x; |
423 |
char *action; |
char *action; |
424 |
const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR; |
const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR; |
|
unsigned services; |
|
|
char **servicex; |
|
425 |
unsigned waitsec = 7; |
unsigned waitsec = 7; |
426 |
smallint kll = 0; |
smallint kll = 0; |
427 |
int verbose = 0; |
int verbose = 0; |
440 |
|
|
441 |
opt_complementary = "w+:vv"; /* -w N, -v is a counter */ |
opt_complementary = "w+:vv"; /* -w N, -v is a counter */ |
442 |
opt = getopt32(argv, "w:v", &waitsec, &verbose); |
opt = getopt32(argv, "w:v", &waitsec, &verbose); |
|
argc -= optind; |
|
443 |
argv += optind; |
argv += optind; |
444 |
action = *argv++; |
action = *argv++; |
445 |
if (!action || !*argv) bb_show_usage(); |
if (!action || !*argv) bb_show_usage(); |
|
service = argv; |
|
|
services = argc - 1; |
|
446 |
|
|
447 |
tnow = time(0) + 0x400000000000000aULL; |
tnow = time(NULL) + 0x400000000000000aULL; |
448 |
tstart = tnow; |
tstart = tnow; |
449 |
curdir = open_read("."); |
curdir = open_read("."); |
450 |
if (curdir == -1) |
if (curdir == -1) |
533 |
bb_show_usage(); |
bb_show_usage(); |
534 |
} |
} |
535 |
|
|
536 |
servicex = service; |
service = argv; |
537 |
for (i = 0; i < services; ++i) { |
while ((x = *service) != NULL) { |
538 |
if ((**service != '/') && (**service != '.')) { |
if (x[0] != '/' && x[0] != '.') { |
539 |
if (chdir(varservice) == -1) |
if (chdir(varservice) == -1) |
540 |
goto chdir_failed_0; |
goto chdir_failed_0; |
541 |
} |
} |
542 |
if (chdir(*service) == -1) { |
if (chdir(x) == -1) { |
543 |
chdir_failed_0: |
chdir_failed_0: |
544 |
fail("cannot change to service directory"); |
fail("can't change to service directory"); |
545 |
goto nullify_service_0; |
goto nullify_service_0; |
546 |
} |
} |
547 |
if (act && (act(acts) == -1)) { |
if (act && (act(acts) == -1)) { |
548 |
nullify_service_0: |
nullify_service_0: |
549 |
*service = NULL; |
*service = (char*) -1L; /* "dead" */ |
550 |
} |
} |
551 |
if (fchdir(curdir) == -1) |
if (fchdir(curdir) == -1) |
552 |
fatal_cannot("change to original directory"); |
fatal_cannot("change to original directory"); |
554 |
} |
} |
555 |
|
|
556 |
if (cbk) while (1) { |
if (cbk) while (1) { |
557 |
|
int want_exit; |
558 |
int diff; |
int diff; |
559 |
|
|
560 |
diff = tnow - tstart; |
diff = tnow - tstart; |
561 |
service = servicex; |
service = argv; |
562 |
want_exit = 1; |
want_exit = 1; |
563 |
for (i = 0; i < services; ++i, ++service) { |
while ((x = *service) != NULL) { |
564 |
if (!*service) |
if (x == (char*) -1L) /* "dead" */ |
565 |
continue; |
goto next; |
566 |
if ((**service != '/') && (**service != '.')) { |
if (x[0] != '/' && x[0] != '.') { |
567 |
if (chdir(varservice) == -1) |
if (chdir(varservice) == -1) |
568 |
goto chdir_failed; |
goto chdir_failed; |
569 |
} |
} |
570 |
if (chdir(*service) == -1) { |
if (chdir(x) == -1) { |
571 |
chdir_failed: |
chdir_failed: |
572 |
fail("cannot change to service directory"); |
fail("can't change to service directory"); |
573 |
goto nullify_service; |
goto nullify_service; |
574 |
} |
} |
575 |
if (cbk(acts) != 0) |
if (cbk(acts) != 0) |
578 |
if (diff >= waitsec) { |
if (diff >= waitsec) { |
579 |
printf(kll ? "kill: " : "timeout: "); |
printf(kll ? "kill: " : "timeout: "); |
580 |
if (svstatus_get() > 0) { |
if (svstatus_get() > 0) { |
581 |
svstatus_print(*service); |
svstatus_print(x); |
582 |
++rc; |
++rc; |
583 |
} |
} |
584 |
bb_putchar('\n'); /* will also flush the output */ |
bb_putchar('\n'); /* will also flush the output */ |
585 |
if (kll) |
if (kll) |
586 |
control("k"); |
control("k"); |
587 |
nullify_service: |
nullify_service: |
588 |
*service = NULL; |
*service = (char*) -1L; /* "dead" */ |
589 |
} |
} |
590 |
if (fchdir(curdir) == -1) |
if (fchdir(curdir) == -1) |
591 |
fatal_cannot("change to original directory"); |
fatal_cannot("change to original directory"); |
592 |
|
next: |
593 |
|
service++; |
594 |
} |
} |
595 |
if (want_exit) break; |
if (want_exit) break; |
596 |
usleep(420000); |
usleep(420000); |
597 |
tnow = time(0) + 0x400000000000000aULL; |
tnow = time(NULL) + 0x400000000000000aULL; |
598 |
} |
} |
599 |
return rc > 99 ? 99 : rc; |
return rc > 99 ? 99 : rc; |
600 |
} |
} |