1 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
2 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
9 static const char *acts;
10 static char **service;
12 static struct taia tstart, tnow;
13 static char svstatus[20];
15 #define usage() bb_show_usage()
17 static void fatal_cannot(const char *m1) ATTRIBUTE_NORETURN;
18 static void fatal_cannot(const char *m1)
20 bb_perror_msg("fatal: cannot %s", m1);
24 static void out(const char *p, const char *m1)
26 printf("%s%s: %s", p, *service, m1);
28 printf(": %s", strerror(errno));
30 puts(""); /* will also flush the output */
33 #define WARN "warning: "
36 static void fail(const char *m1) {
40 static void failx(const char *m1) {
44 static void warn_cannot(const char *m1) {
46 out("warning: cannot ", m1);
48 static void warnx_cannot(const char *m1) {
52 static void ok(const char *m1) {
57 static int svstatus_get(void)
61 fd = open_write("supervise/ok");
63 if (errno == ENODEV) {
64 *acts == 'x' ? ok("runsv not running")
65 : failx("runsv not running");
68 warn_cannot("open supervise/ok");
72 fd = open_read("supervise/status");
74 warn_cannot("open supervise/status");
77 r = read(fd, svstatus, 20);
81 case -1: warn_cannot("read supervise/status"); return -1;
82 default: warnx_cannot("read supervise/status: bad format"); return -1;
87 static unsigned svstatus_print(const char *m)
95 if (stat("down", &s) == -1) {
96 if (errno != ENOENT) {
97 bb_perror_msg(WARN"cannot stat %s/down", *service);
102 pid = (unsigned char) svstatus[15];
103 pid <<= 8; pid += (unsigned char)svstatus[14];
104 pid <<= 8; pid += (unsigned char)svstatus[13];
105 pid <<= 8; pid += (unsigned char)svstatus[12];
106 tai_unpack(svstatus, &tstatus);
108 switch (svstatus[19]) {
109 case 1: printf("run: "); break;
110 case 2: printf("finish: "); break;
112 printf("%s: (pid %d) ", m, pid);
114 printf("down: %s: ", m);
116 diff = tnow.sec.x - tstatus.x;
117 printf("%lds", (diff < 0 ? 0L : diff));
119 if (!normallyup) printf(", normally down");
121 if (normallyup) printf(", normally up");
123 if (pid && svstatus[16]) printf(", paused");
124 if (!pid && (svstatus[17] == 'u')) printf(", want up");
125 if (pid && (svstatus[17] == 'd')) printf(", want down");
126 if (pid && svstatus[18]) printf(", got TERM");
130 static int status(const char *unused)
135 switch (r) { case -1: case 0: return 0; }
137 r = svstatus_print(*service);
138 if (chdir("log") == -1) {
139 if (errno != ENOENT) {
140 printf("; log: "WARN"cannot change to log service directory: %s",
143 } else if (svstatus_get()) {
145 svstatus_print("log");
147 puts(""); /* will also flush the output */
151 static int checkscript(void)
157 if (stat("check", &s) == -1) {
158 if (errno == ENOENT) return 1;
159 bb_perror_msg(WARN"cannot stat %s/check", *service);
162 /* if (!(s.st_mode & S_IXUSR)) return 1; */
163 if ((pid = fork()) == -1) {
164 bb_perror_msg(WARN"cannot fork for %s/check", *service);
168 prog[0] = (char*)"./check";
171 execve("check", prog, environ);
172 bb_perror_msg(WARN"cannot run %s/check", *service);
175 while (wait_pid(&w, pid) == -1) {
176 if (errno == EINTR) continue;
177 bb_perror_msg(WARN"cannot wait for child %s/check", *service);
180 return !wait_exitcode(w);
183 static int check(const char *a)
197 pid = (unsigned char)svstatus[15];
198 pid <<= 8; pid += (unsigned char)svstatus[14];
199 pid <<= 8; pid += (unsigned char)svstatus[13];
200 pid <<= 8; pid += (unsigned char)svstatus[12];
205 if (!pid || svstatus[19] != 1) return 0;
206 if (!checkscript()) return 0;
212 if (pid && !checkscript()) return 0;
215 if (!pid && svstatus[17] == 'd') break;
216 tai_unpack(svstatus, &tstatus);
217 if ((tstart.sec.x > tstatus.x) || !pid || svstatus[18] || !checkscript())
221 tai_unpack(svstatus, &tstatus);
222 if ((!pid && tstart.sec.x > tstatus.x) || (pid && svstatus[17] != 'd'))
226 svstatus_print(*service);
227 puts(""); /* will also flush the output */
231 static int control(const char *a)
235 if (svstatus_get() <= 0) return -1;
236 if (svstatus[17] == *a) return 0;
237 fd = open_write("supervise/control");
240 warn_cannot("open supervise/control");
242 *a == 'x' ? ok("runsv not running") : failx("runsv not running");
245 r = write(fd, a, strlen(a));
247 if (r != strlen(a)) {
248 warn_cannot("write to supervise/control");
254 int sv_main(int argc, char **argv);
255 int sv_main(int argc, char **argv)
258 unsigned i, want_exit;
261 const char *varservice = "/var/service/";
264 unsigned long waitsec = 7;
266 smallint verbose = 0;
267 int (*act)(const char*);
268 int (*cbk)(const char*);
271 xfunc_error_retval = 100;
274 if (x) varservice = x;
275 x = getenv("SVWAIT");
276 if (x) waitsec = xatoul(x);
278 opt = getopt32(argc, argv, "w:v", &x);
279 if (opt & 1) waitsec = xatoul(x); // -w
280 if (opt & 2) verbose = 1; // -v
284 if (!action || !*argv) usage();
290 curdir = open_read(".");
292 fatal_cannot("open current directory");
302 if (!verbose) cbk = NULL;
318 if (!str_diff(action, "check")) {
323 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
324 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
327 if (!verbose) cbk = NULL;
330 if (!str_diff(action, "shutdown")) {
334 if (!str_diff(action, "start")) {
338 if (!str_diff(action, "stop")) {
347 if (!str_diff(action, "restart")) {
353 if (!str_diff(action, "force-reload")) {
358 if (!str_diff(action, "force-restart")) {
363 if (!str_diff(action, "force-shutdown")) {
368 if (!str_diff(action, "force-stop")) {
378 for (i = 0; i < services; ++i) {
379 if ((**service != '/') && (**service != '.')) {
380 if (chdir(varservice) == -1)
383 if (chdir(*service) == -1) {
385 fail("cannot change to service directory");
386 goto nullify_service_0;
388 if (act && (act(acts) == -1)) {
392 if (fchdir(curdir) == -1)
393 fatal_cannot("change to original directory");
401 //taia_sub(&tdiff, &tnow, &tstart);
402 diff = tnow.sec.x - tstart.sec.x;
405 for (i = 0; i < services; ++i, ++service) {
408 if ((**service != '/') && (**service != '.')) {
409 if (chdir(varservice) == -1)
412 if (chdir(*service) == -1) {
414 fail("cannot change to service directory");
415 goto nullify_service;
418 goto nullify_service;
420 if (diff >= waitsec) {
421 printf(kll ? "kill: " : "timeout: ");
422 if (svstatus_get() > 0) {
423 svstatus_print(*service);
426 puts(""); /* will also flush the output */
432 if (fchdir(curdir) == -1)
433 fatal_cannot("change to original directory");
435 if (want_exit) break;
439 return rc > 99 ? 99 : rc;