blob: 9181fff75366a53987a4f5a4ca0b5f74f01bcafc [file] [log] [blame]
Denis Vlasenko8a164052007-03-12 23:34:52 +00001/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Taken from http://smarden.sunsite.dk/runit/sv.8.html:
29
30sv - control and manage services monitored by runsv
31
32sv [-v] [-w sec] command services
33/etc/init.d/service [-w sec] command
34
35The sv program reports the current status and controls the state of services
36monitored by the runsv(8) supervisor.
37
38services consists of one or more arguments, each argument naming a directory
Denis Vlasenkof223efb2007-08-03 10:58:12 +000039service used by runsv(8). If service doesn't start with a dot or slash,
Denis Vlasenko8a164052007-03-12 23:34:52 +000040it is searched in the default services directory /var/service/, otherwise
41relative to the current directory.
42
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,
45force-reload, force-restart, force-shutdown.
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
51status
52 Report the current status of the service, and the appendant log service
53 if available, to standard output.
54up
55 If the service is not running, start it. If the service stops, restart it.
56down
57 If the service is running, send it the TERM signal, and the CONT signal.
58 If ./run exits, start ./finish if it exists. After it stops, do not
59 restart service.
60once
61 If the service is not running, start it. Do not restart it if it stops.
62pause cont hup alarm interrupt quit 1 2 term kill
63 If the service is running, send it the STOP, CONT, HUP, ALRM, INT, QUIT,
64 USR1, USR2, TERM, or KILL signal respectively.
65exit
66 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
68 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,
70 runsv(8) exits. This command is ignored if it is given to an appendant
71 log service.
72
73sv actually looks only at the first character of above commands.
74
Denis Vlasenkof223efb2007-08-03 10:58:12 +000075Commands compatible to LSB init script actions:
76
Denis Vlasenko8a164052007-03-12 23:34:52 +000077status
78 Same as status.
79start
80 Same as up, but wait up to 7 seconds for the command to take effect.
81 Then report the status or timeout. If the script ./check exists in
82 the service directory, sv runs this script to check whether the service
83 is up and available; it's considered to be available if ./check exits
84 with 0.
85stop
86 Same as down, but wait up to 7 seconds for the service to become down.
87 Then report the status or timeout.
88restart
89 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.
91 If the script ./check exists in the service directory, sv runs this script
92 to check whether the service is up and available again; it's considered
93 to be available if ./check exits with 0.
94shutdown
95 Same as exit, but wait up to 7 seconds for the runsv(8) process
96 to terminate. Then report the status or timeout.
97force-stop
98 Same as down, but wait up to 7 seconds for the service to become down.
99 Then report the status, and on timeout send the service the kill command.
100force-reload
101 Send the service the term and cont commands, and wait up to
102 7 seconds for the service to restart. Then report the status,
103 and on timeout send the service the kill command.
104force-restart
105 Send the service the term, cont and up commands, and wait up to
106 7 seconds for the service to restart. Then report the status, and
107 on timeout send the service the kill command. If the script ./check
108 exists in the service directory, sv runs this script to check whether
Denis Vlasenkof223efb2007-08-03 10:58:12 +0000109 the service is up and available again; it's considered to be available
Denis Vlasenko8a164052007-03-12 23:34:52 +0000110 if ./check exits with 0.
111force-shutdown
112 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
114 the kill command.
115
116Additional Commands
117
118check
119 Check for the service to be in the state that's been requested. Wait up to
120 7 seconds for the service to reach the requested state, then report
121 the status or timeout. If the requested state of the service is up,
122 and the script ./check exists in the service directory, sv runs
123 this script to check whether the service is up and running;
124 it's considered to be up if ./check exits with 0.
125
126Options
127
128-v
129 wait up to 7 seconds for the command to take effect.
130 Then report the status or timeout.
131-w sec
132 Override the default timeout of 7 seconds with sec seconds. Implies -v.
133
134Environment
135
136SVDIR
137 The environment variable $SVDIR overrides the default services directory
138 /var/service.
139SVWAIT
140 The environment variable $SVWAIT overrides the default 7 seconds to wait
141 for a command to take effect. It is overridden by the -w option.
142
143Exit Codes
144 sv exits 0, if the command was successfully sent to all services, and,
145 if it was told to wait, the command has taken effect to all services.
146
147 For each service that caused an error (e.g. the directory is not
148 controlled by a runsv(8) process, or sv timed out while waiting),
149 sv increases the exit code by one and exits non zero. The maximum
150 is 99. sv exits 100 on error.
151*/
152
Denis Vlasenko04c63862006-11-17 18:58:49 +0000153/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
154/* TODO: depends on runit_lib.c - review and reduce/eliminate */
155
156#include <sys/poll.h>
157#include <sys/file.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +0000158#include "libbb.h"
Denis Vlasenko04c63862006-11-17 18:58:49 +0000159#include "runit_lib.h"
160
Denis Vlasenko322661d2007-01-29 23:43:52 +0000161static const char *acts;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000162static char **service;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000163static unsigned rc;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000164static struct taia tstart, tnow;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000165static char svstatus[20];
166
167#define usage() bb_show_usage()
168
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000169static void fatal_cannot(const char *m1) ATTRIBUTE_NORETURN;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000170static void fatal_cannot(const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000171{
172 bb_perror_msg("fatal: cannot %s", m1);
173 _exit(151);
174}
175
Denis Vlasenko322661d2007-01-29 23:43:52 +0000176static void out(const char *p, const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000177{
178 printf("%s%s: %s", p, *service, m1);
179 if (errno) {
180 printf(": %s", strerror(errno));
181 }
182 puts(""); /* will also flush the output */
183}
184
Denis Vlasenko04c63862006-11-17 18:58:49 +0000185#define WARN "warning: "
186#define OK "ok: "
Denis Vlasenko04c63862006-11-17 18:58:49 +0000187
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000188static void fail(const char *m1)
189{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000190 ++rc;
191 out("fail: ", m1);
192}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000193static void failx(const char *m1)
194{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000195 errno = 0;
196 fail(m1);
197}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000198static void warn_cannot(const char *m1)
199{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000200 ++rc;
201 out("warning: cannot ", m1);
202}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000203static void warnx_cannot(const char *m1)
204{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000205 errno = 0;
206 warn_cannot(m1);
207}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000208static void ok(const char *m1)
209{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000210 errno = 0;
211 out(OK, m1);
212}
Denis Vlasenko04c63862006-11-17 18:58:49 +0000213
214static int svstatus_get(void)
215{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000216 int fd, r;
217
Denis Vlasenko322661d2007-01-29 23:43:52 +0000218 fd = open_write("supervise/ok");
219 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000220 if (errno == ENODEV) {
221 *acts == 'x' ? ok("runsv not running")
222 : failx("runsv not running");
223 return 0;
224 }
225 warn_cannot("open supervise/ok");
226 return -1;
227 }
228 close(fd);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000229 fd = open_read("supervise/status");
230 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000231 warn_cannot("open supervise/status");
232 return -1;
233 }
234 r = read(fd, svstatus, 20);
235 close(fd);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000236 switch (r) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000237 case 20: break;
238 case -1: warn_cannot("read supervise/status"); return -1;
239 default: warnx_cannot("read supervise/status: bad format"); return -1;
240 }
241 return 1;
242}
243
Denis Vlasenko322661d2007-01-29 23:43:52 +0000244static unsigned svstatus_print(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000245{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000246 long diff;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000247 int pid;
248 int normallyup = 0;
249 struct stat s;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000250 struct tai tstatus;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000251
Denis Vlasenko04c63862006-11-17 18:58:49 +0000252 if (stat("down", &s) == -1) {
253 if (errno != ENOENT) {
254 bb_perror_msg(WARN"cannot stat %s/down", *service);
255 return 0;
256 }
257 normallyup = 1;
258 }
259 pid = (unsigned char) svstatus[15];
260 pid <<= 8; pid += (unsigned char)svstatus[14];
261 pid <<= 8; pid += (unsigned char)svstatus[13];
262 pid <<= 8; pid += (unsigned char)svstatus[12];
263 tai_unpack(svstatus, &tstatus);
264 if (pid) {
265 switch (svstatus[19]) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000266 case 1: printf("run: "); break;
267 case 2: printf("finish: "); break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000268 }
269 printf("%s: (pid %d) ", m, pid);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000270 } else {
271 printf("down: %s: ", m);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000272 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000273 diff = tnow.sec.x - tstatus.x;
274 printf("%lds", (diff < 0 ? 0L : diff));
275 if (pid) {
276 if (!normallyup) printf(", normally down");
Denis Vlasenkod55a3622007-03-12 23:14:42 +0000277 if (svstatus[16]) printf(", paused");
278 if (svstatus[17] == 'd') printf(", want down");
279 if (svstatus[18]) printf(", got TERM");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000280 } else {
281 if (normallyup) printf(", normally up");
Denis Vlasenkod55a3622007-03-12 23:14:42 +0000282 if (svstatus[17] == 'u') printf(", want up");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000283 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000284 return pid ? 1 : 2;
285}
286
Denis Vlasenko322661d2007-01-29 23:43:52 +0000287static int status(const char *unused)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000288{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000289 int r;
290
Denis Vlasenko04c63862006-11-17 18:58:49 +0000291 r = svstatus_get();
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000292 switch (r) { case -1: case 0: return 0; }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000293
Denis Vlasenko04c63862006-11-17 18:58:49 +0000294 r = svstatus_print(*service);
295 if (chdir("log") == -1) {
296 if (errno != ENOENT) {
297 printf("; log: "WARN"cannot change to log service directory: %s",
298 strerror(errno));
299 }
300 } else if (svstatus_get()) {
301 printf("; ");
302 svstatus_print("log");
303 }
304 puts(""); /* will also flush the output */
305 return r;
306}
307
308static int checkscript(void)
309{
310 char *prog[2];
311 struct stat s;
312 int pid, w;
313
314 if (stat("check", &s) == -1) {
315 if (errno == ENOENT) return 1;
316 bb_perror_msg(WARN"cannot stat %s/check", *service);
317 return 0;
318 }
319 /* if (!(s.st_mode & S_IXUSR)) return 1; */
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000320 prog[0] = (char*)"./check";
321 prog[1] = NULL;
322 pid = spawn(prog);
323 if (pid <= 0) {
324 bb_perror_msg(WARN"cannot %s child %s/check", "run", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000325 return 0;
326 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000327 while (wait_pid(&w, pid) == -1) {
328 if (errno == EINTR) continue;
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000329 bb_perror_msg(WARN"cannot %s child %s/check", "wait for", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000330 return 0;
331 }
332 return !wait_exitcode(w);
333}
334
Denis Vlasenko322661d2007-01-29 23:43:52 +0000335static int check(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000336{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000337 int r;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000338 unsigned pid;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000339 struct tai tstatus;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000340
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000341 r = svstatus_get();
342 if (r == -1)
343 return -1;
344 if (r == 0) {
345 if (*a == 'x')
346 return 1;
347 return -1;
348 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000349 pid = (unsigned char)svstatus[15];
350 pid <<= 8; pid += (unsigned char)svstatus[14];
351 pid <<= 8; pid += (unsigned char)svstatus[13];
352 pid <<= 8; pid += (unsigned char)svstatus[12];
353 switch (*a) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000354 case 'x':
355 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000356 case 'u':
357 if (!pid || svstatus[19] != 1) return 0;
358 if (!checkscript()) return 0;
359 break;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000360 case 'd':
361 if (pid) return 0;
362 break;
363 case 'c':
364 if (pid && !checkscript()) return 0;
365 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000366 case 't':
367 if (!pid && svstatus[17] == 'd') break;
368 tai_unpack(svstatus, &tstatus);
369 if ((tstart.sec.x > tstatus.x) || !pid || svstatus[18] || !checkscript())
370 return 0;
371 break;
372 case 'o':
373 tai_unpack(svstatus, &tstatus);
374 if ((!pid && tstart.sec.x > tstatus.x) || (pid && svstatus[17] != 'd'))
375 return 0;
376 }
Denis Vlasenko322661d2007-01-29 23:43:52 +0000377 printf(OK);
378 svstatus_print(*service);
379 puts(""); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000380 return 1;
381}
382
Denis Vlasenko322661d2007-01-29 23:43:52 +0000383static int control(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000384{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000385 int fd, r;
386
Denis Vlasenko04c63862006-11-17 18:58:49 +0000387 if (svstatus_get() <= 0) return -1;
388 if (svstatus[17] == *a) return 0;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000389 fd = open_write("supervise/control");
390 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000391 if (errno != ENODEV)
392 warn_cannot("open supervise/control");
393 else
394 *a == 'x' ? ok("runsv not running") : failx("runsv not running");
395 return -1;
396 }
397 r = write(fd, a, strlen(a));
398 close(fd);
399 if (r != strlen(a)) {
400 warn_cannot("write to supervise/control");
401 return -1;
402 }
403 return 1;
404}
405
Denis Vlasenko06af2162007-02-03 17:28:39 +0000406int sv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000407int sv_main(int argc, char **argv)
408{
409 unsigned opt;
410 unsigned i, want_exit;
411 char *x;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000412 char *action;
413 const char *varservice = "/var/service/";
414 unsigned services;
415 char **servicex;
416 unsigned long waitsec = 7;
417 smallint kll = 0;
418 smallint verbose = 0;
419 int (*act)(const char*);
420 int (*cbk)(const char*);
421 int curdir;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000422
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000423 xfunc_error_retval = 100;
424
425 x = getenv("SVDIR");
426 if (x) varservice = x;
427 x = getenv("SVWAIT");
428 if (x) waitsec = xatoul(x);
429
430 opt = getopt32(argc, argv, "w:v", &x);
431 if (opt & 1) waitsec = xatoul(x); // -w
432 if (opt & 2) verbose = 1; // -v
433 argc -= optind;
434 argv += optind;
435 action = *argv++;
436 if (!action || !*argv) usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000437 service = argv;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000438 services = argc - 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000439
Denis Vlasenko322661d2007-01-29 23:43:52 +0000440 taia_now(&tnow);
441 tstart = tnow;
442 curdir = open_read(".");
443 if (curdir == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000444 fatal_cannot("open current directory");
445
Denis Vlasenko322661d2007-01-29 23:43:52 +0000446 act = &control;
447 acts = "s";
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000448 cbk = &check;
449
Denis Vlasenko04c63862006-11-17 18:58:49 +0000450 switch (*action) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000451 case 'x':
452 case 'e':
453 acts = "x";
454 if (!verbose) cbk = NULL;
455 break;
456 case 'X':
457 case 'E':
458 acts = "x";
459 kll = 1;
460 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000461 case 'D':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000462 acts = "d";
463 kll = 1;
464 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000465 case 'T':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000466 acts = "tc";
467 kll = 1;
468 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000469 case 'c':
470 if (!str_diff(action, "check")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000471 act = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000472 acts = "c";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000473 break;
474 }
475 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
476 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000477 action[1] = '\0';
478 acts = action;
479 if (!verbose) cbk = NULL;
480 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000481 case 's':
482 if (!str_diff(action, "shutdown")) {
483 acts = "x";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000484 break;
485 }
486 if (!str_diff(action, "start")) {
487 acts = "u";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000488 break;
489 }
490 if (!str_diff(action, "stop")) {
491 acts = "d";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000492 break;
493 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000494 /* "status" */
Denis Vlasenko322661d2007-01-29 23:43:52 +0000495 act = &status;
496 cbk = NULL;
497 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000498 case 'r':
499 if (!str_diff(action, "restart")) {
500 acts = "tcu";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000501 break;
502 }
503 usage();
504 case 'f':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000505 if (!str_diff(action, "force-reload")) {
506 acts = "tc";
507 kll = 1;
508 break;
509 }
510 if (!str_diff(action, "force-restart")) {
511 acts = "tcu";
512 kll = 1;
513 break;
514 }
515 if (!str_diff(action, "force-shutdown")) {
516 acts = "x";
517 kll = 1;
518 break;
519 }
520 if (!str_diff(action, "force-stop")) {
521 acts = "d";
522 kll = 1;
523 break;
524 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000525 default:
526 usage();
527 }
528
529 servicex = service;
530 for (i = 0; i < services; ++i) {
531 if ((**service != '/') && (**service != '.')) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000532 if (chdir(varservice) == -1)
533 goto chdir_failed_0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000534 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000535 if (chdir(*service) == -1) {
536 chdir_failed_0:
537 fail("cannot change to service directory");
538 goto nullify_service_0;
539 }
540 if (act && (act(acts) == -1)) {
541 nullify_service_0:
542 *service = NULL;
543 }
544 if (fchdir(curdir) == -1)
545 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000546 service++;
547 }
548
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000549 if (cbk) while (1) {
550 //struct taia tdiff;
551 long diff;
552
553 //taia_sub(&tdiff, &tnow, &tstart);
554 diff = tnow.sec.x - tstart.sec.x;
555 service = servicex;
556 want_exit = 1;
557 for (i = 0; i < services; ++i, ++service) {
558 if (!*service)
559 continue;
560 if ((**service != '/') && (**service != '.')) {
561 if (chdir(varservice) == -1)
562 goto chdir_failed;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000563 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000564 if (chdir(*service) == -1) {
565 chdir_failed:
566 fail("cannot change to service directory");
567 goto nullify_service;
568 }
569 if (cbk(acts) != 0)
570 goto nullify_service;
571 want_exit = 0;
572 if (diff >= waitsec) {
573 printf(kll ? "kill: " : "timeout: ");
574 if (svstatus_get() > 0) {
575 svstatus_print(*service);
576 ++rc;
577 }
578 puts(""); /* will also flush the output */
579 if (kll)
580 control("k");
581 nullify_service:
582 *service = NULL;
583 }
584 if (fchdir(curdir) == -1)
585 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000586 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000587 if (want_exit) break;
588 usleep(420000);
589 taia_now(&tnow);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000590 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000591 return rc > 99 ? 99 : rc;
592}