blob: 051e64e67627da281db29335418cab5b64187aab [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
39service used by runsv(8). If service doesn?t start with a dot or slash,
40it 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
75status
76 Same as status.
77start
78 Same as up, but wait up to 7 seconds for the command to take effect.
79 Then report the status or timeout. If the script ./check exists in
80 the service directory, sv runs this script to check whether the service
81 is up and available; it's considered to be available if ./check exits
82 with 0.
83stop
84 Same as down, but wait up to 7 seconds for the service to become down.
85 Then report the status or timeout.
86restart
87 Send the commands term, cont, and up to the service, and wait up to
88 7 seconds for the service to restart. Then report the status or timeout.
89 If the script ./check exists in the service directory, sv runs this script
90 to check whether the service is up and available again; it's considered
91 to be available if ./check exits with 0.
92shutdown
93 Same as exit, but wait up to 7 seconds for the runsv(8) process
94 to terminate. Then report the status or timeout.
95force-stop
96 Same as down, but wait up to 7 seconds for the service to become down.
97 Then report the status, and on timeout send the service the kill command.
98force-reload
99 Send the service the term and cont commands, and wait up to
100 7 seconds for the service to restart. Then report the status,
101 and on timeout send the service the kill command.
102force-restart
103 Send the service the term, cont and up commands, and wait up to
104 7 seconds for the service to restart. Then report the status, and
105 on timeout send the service the kill command. If the script ./check
106 exists in the service directory, sv runs this script to check whether
107 the service is up and available again; it?s considered to be available
108 if ./check exits with 0.
109force-shutdown
110 Same as exit, but wait up to 7 seconds for the runsv(8) process to
111 terminate. Then report the status, and on timeout send the service
112 the kill command.
113
114Additional Commands
115
116check
117 Check for the service to be in the state that's been requested. Wait up to
118 7 seconds for the service to reach the requested state, then report
119 the status or timeout. If the requested state of the service is up,
120 and the script ./check exists in the service directory, sv runs
121 this script to check whether the service is up and running;
122 it's considered to be up if ./check exits with 0.
123
124Options
125
126-v
127 wait up to 7 seconds for the command to take effect.
128 Then report the status or timeout.
129-w sec
130 Override the default timeout of 7 seconds with sec seconds. Implies -v.
131
132Environment
133
134SVDIR
135 The environment variable $SVDIR overrides the default services directory
136 /var/service.
137SVWAIT
138 The environment variable $SVWAIT overrides the default 7 seconds to wait
139 for a command to take effect. It is overridden by the -w option.
140
141Exit Codes
142 sv exits 0, if the command was successfully sent to all services, and,
143 if it was told to wait, the command has taken effect to all services.
144
145 For each service that caused an error (e.g. the directory is not
146 controlled by a runsv(8) process, or sv timed out while waiting),
147 sv increases the exit code by one and exits non zero. The maximum
148 is 99. sv exits 100 on error.
149*/
150
Denis Vlasenko04c63862006-11-17 18:58:49 +0000151/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
152/* TODO: depends on runit_lib.c - review and reduce/eliminate */
153
154#include <sys/poll.h>
155#include <sys/file.h>
156#include "busybox.h"
157#include "runit_lib.h"
158
Denis Vlasenko322661d2007-01-29 23:43:52 +0000159static const char *acts;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000160static char **service;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000161static unsigned rc;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000162static struct taia tstart, tnow;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000163static char svstatus[20];
164
165#define usage() bb_show_usage()
166
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000167static void fatal_cannot(const char *m1) ATTRIBUTE_NORETURN;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000168static void fatal_cannot(const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000169{
170 bb_perror_msg("fatal: cannot %s", m1);
171 _exit(151);
172}
173
Denis Vlasenko322661d2007-01-29 23:43:52 +0000174static void out(const char *p, const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000175{
176 printf("%s%s: %s", p, *service, m1);
177 if (errno) {
178 printf(": %s", strerror(errno));
179 }
180 puts(""); /* will also flush the output */
181}
182
Denis Vlasenko04c63862006-11-17 18:58:49 +0000183#define WARN "warning: "
184#define OK "ok: "
Denis Vlasenko04c63862006-11-17 18:58:49 +0000185
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000186static void fail(const char *m1) {
187 ++rc;
188 out("fail: ", m1);
189}
190static void failx(const char *m1) {
191 errno = 0;
192 fail(m1);
193}
194static void warn_cannot(const char *m1) {
195 ++rc;
196 out("warning: cannot ", m1);
197}
198static void warnx_cannot(const char *m1) {
199 errno = 0;
200 warn_cannot(m1);
201}
202static void ok(const char *m1) {
203 errno = 0;
204 out(OK, m1);
205}
Denis Vlasenko04c63862006-11-17 18:58:49 +0000206
207static int svstatus_get(void)
208{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000209 int fd, r;
210
Denis Vlasenko322661d2007-01-29 23:43:52 +0000211 fd = open_write("supervise/ok");
212 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000213 if (errno == ENODEV) {
214 *acts == 'x' ? ok("runsv not running")
215 : failx("runsv not running");
216 return 0;
217 }
218 warn_cannot("open supervise/ok");
219 return -1;
220 }
221 close(fd);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000222 fd = open_read("supervise/status");
223 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000224 warn_cannot("open supervise/status");
225 return -1;
226 }
227 r = read(fd, svstatus, 20);
228 close(fd);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000229 switch (r) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000230 case 20: break;
231 case -1: warn_cannot("read supervise/status"); return -1;
232 default: warnx_cannot("read supervise/status: bad format"); return -1;
233 }
234 return 1;
235}
236
Denis Vlasenko322661d2007-01-29 23:43:52 +0000237static unsigned svstatus_print(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000238{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000239 long diff;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000240 int pid;
241 int normallyup = 0;
242 struct stat s;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000243 struct tai tstatus;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000244
Denis Vlasenko04c63862006-11-17 18:58:49 +0000245 if (stat("down", &s) == -1) {
246 if (errno != ENOENT) {
247 bb_perror_msg(WARN"cannot stat %s/down", *service);
248 return 0;
249 }
250 normallyup = 1;
251 }
252 pid = (unsigned char) svstatus[15];
253 pid <<= 8; pid += (unsigned char)svstatus[14];
254 pid <<= 8; pid += (unsigned char)svstatus[13];
255 pid <<= 8; pid += (unsigned char)svstatus[12];
256 tai_unpack(svstatus, &tstatus);
257 if (pid) {
258 switch (svstatus[19]) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000259 case 1: printf("run: "); break;
260 case 2: printf("finish: "); break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000261 }
262 printf("%s: (pid %d) ", m, pid);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000263 } else {
264 printf("down: %s: ", m);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000265 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000266 diff = tnow.sec.x - tstatus.x;
267 printf("%lds", (diff < 0 ? 0L : diff));
268 if (pid) {
269 if (!normallyup) printf(", normally down");
Denis Vlasenkod55a3622007-03-12 23:14:42 +0000270 if (svstatus[16]) printf(", paused");
271 if (svstatus[17] == 'd') printf(", want down");
272 if (svstatus[18]) printf(", got TERM");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000273 } else {
274 if (normallyup) printf(", normally up");
Denis Vlasenkod55a3622007-03-12 23:14:42 +0000275 if (svstatus[17] == 'u') printf(", want up");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000276 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000277 return pid ? 1 : 2;
278}
279
Denis Vlasenko322661d2007-01-29 23:43:52 +0000280static int status(const char *unused)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000281{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000282 int r;
283
Denis Vlasenko04c63862006-11-17 18:58:49 +0000284 r = svstatus_get();
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000285 switch (r) { case -1: case 0: return 0; }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000286
Denis Vlasenko04c63862006-11-17 18:58:49 +0000287 r = svstatus_print(*service);
288 if (chdir("log") == -1) {
289 if (errno != ENOENT) {
290 printf("; log: "WARN"cannot change to log service directory: %s",
291 strerror(errno));
292 }
293 } else if (svstatus_get()) {
294 printf("; ");
295 svstatus_print("log");
296 }
297 puts(""); /* will also flush the output */
298 return r;
299}
300
301static int checkscript(void)
302{
303 char *prog[2];
304 struct stat s;
305 int pid, w;
306
307 if (stat("check", &s) == -1) {
308 if (errno == ENOENT) return 1;
309 bb_perror_msg(WARN"cannot stat %s/check", *service);
310 return 0;
311 }
312 /* if (!(s.st_mode & S_IXUSR)) return 1; */
313 if ((pid = fork()) == -1) {
314 bb_perror_msg(WARN"cannot fork for %s/check", *service);
315 return 0;
316 }
317 if (!pid) {
Denis Vlasenko322661d2007-01-29 23:43:52 +0000318 prog[0] = (char*)"./check";
319 prog[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000320 close(1);
321 execve("check", prog, environ);
322 bb_perror_msg(WARN"cannot run %s/check", *service);
323 _exit(0);
324 }
325 while (wait_pid(&w, pid) == -1) {
326 if (errno == EINTR) continue;
327 bb_perror_msg(WARN"cannot wait for child %s/check", *service);
328 return 0;
329 }
330 return !wait_exitcode(w);
331}
332
Denis Vlasenko322661d2007-01-29 23:43:52 +0000333static int check(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000334{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000335 int r;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000336 unsigned pid;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000337 struct tai tstatus;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000338
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000339 r = svstatus_get();
340 if (r == -1)
341 return -1;
342 if (r == 0) {
343 if (*a == 'x')
344 return 1;
345 return -1;
346 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000347 pid = (unsigned char)svstatus[15];
348 pid <<= 8; pid += (unsigned char)svstatus[14];
349 pid <<= 8; pid += (unsigned char)svstatus[13];
350 pid <<= 8; pid += (unsigned char)svstatus[12];
351 switch (*a) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000352 case 'x':
353 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000354 case 'u':
355 if (!pid || svstatus[19] != 1) return 0;
356 if (!checkscript()) return 0;
357 break;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000358 case 'd':
359 if (pid) return 0;
360 break;
361 case 'c':
362 if (pid && !checkscript()) return 0;
363 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000364 case 't':
365 if (!pid && svstatus[17] == 'd') break;
366 tai_unpack(svstatus, &tstatus);
367 if ((tstart.sec.x > tstatus.x) || !pid || svstatus[18] || !checkscript())
368 return 0;
369 break;
370 case 'o':
371 tai_unpack(svstatus, &tstatus);
372 if ((!pid && tstart.sec.x > tstatus.x) || (pid && svstatus[17] != 'd'))
373 return 0;
374 }
Denis Vlasenko322661d2007-01-29 23:43:52 +0000375 printf(OK);
376 svstatus_print(*service);
377 puts(""); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000378 return 1;
379}
380
Denis Vlasenko322661d2007-01-29 23:43:52 +0000381static int control(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000382{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000383 int fd, r;
384
Denis Vlasenko04c63862006-11-17 18:58:49 +0000385 if (svstatus_get() <= 0) return -1;
386 if (svstatus[17] == *a) return 0;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000387 fd = open_write("supervise/control");
388 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000389 if (errno != ENODEV)
390 warn_cannot("open supervise/control");
391 else
392 *a == 'x' ? ok("runsv not running") : failx("runsv not running");
393 return -1;
394 }
395 r = write(fd, a, strlen(a));
396 close(fd);
397 if (r != strlen(a)) {
398 warn_cannot("write to supervise/control");
399 return -1;
400 }
401 return 1;
402}
403
Denis Vlasenko06af2162007-02-03 17:28:39 +0000404int sv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000405int sv_main(int argc, char **argv)
406{
407 unsigned opt;
408 unsigned i, want_exit;
409 char *x;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000410 char *action;
411 const char *varservice = "/var/service/";
412 unsigned services;
413 char **servicex;
414 unsigned long waitsec = 7;
415 smallint kll = 0;
416 smallint verbose = 0;
417 int (*act)(const char*);
418 int (*cbk)(const char*);
419 int curdir;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000420
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000421 xfunc_error_retval = 100;
422
423 x = getenv("SVDIR");
424 if (x) varservice = x;
425 x = getenv("SVWAIT");
426 if (x) waitsec = xatoul(x);
427
428 opt = getopt32(argc, argv, "w:v", &x);
429 if (opt & 1) waitsec = xatoul(x); // -w
430 if (opt & 2) verbose = 1; // -v
431 argc -= optind;
432 argv += optind;
433 action = *argv++;
434 if (!action || !*argv) usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000435 service = argv;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000436 services = argc - 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000437
Denis Vlasenko322661d2007-01-29 23:43:52 +0000438 taia_now(&tnow);
439 tstart = tnow;
440 curdir = open_read(".");
441 if (curdir == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000442 fatal_cannot("open current directory");
443
Denis Vlasenko322661d2007-01-29 23:43:52 +0000444 act = &control;
445 acts = "s";
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000446 cbk = &check;
447
Denis Vlasenko04c63862006-11-17 18:58:49 +0000448 switch (*action) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000449 case 'x':
450 case 'e':
451 acts = "x";
452 if (!verbose) cbk = NULL;
453 break;
454 case 'X':
455 case 'E':
456 acts = "x";
457 kll = 1;
458 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000459 case 'D':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000460 acts = "d";
461 kll = 1;
462 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000463 case 'T':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000464 acts = "tc";
465 kll = 1;
466 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000467 case 'c':
468 if (!str_diff(action, "check")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000469 act = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000470 acts = "c";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000471 break;
472 }
473 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
474 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000475 action[1] = '\0';
476 acts = action;
477 if (!verbose) cbk = NULL;
478 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000479 case 's':
480 if (!str_diff(action, "shutdown")) {
481 acts = "x";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000482 break;
483 }
484 if (!str_diff(action, "start")) {
485 acts = "u";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000486 break;
487 }
488 if (!str_diff(action, "stop")) {
489 acts = "d";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000490 break;
491 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000492 /* "status" */
Denis Vlasenko322661d2007-01-29 23:43:52 +0000493 act = &status;
494 cbk = NULL;
495 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000496 case 'r':
497 if (!str_diff(action, "restart")) {
498 acts = "tcu";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000499 break;
500 }
501 usage();
502 case 'f':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000503 if (!str_diff(action, "force-reload")) {
504 acts = "tc";
505 kll = 1;
506 break;
507 }
508 if (!str_diff(action, "force-restart")) {
509 acts = "tcu";
510 kll = 1;
511 break;
512 }
513 if (!str_diff(action, "force-shutdown")) {
514 acts = "x";
515 kll = 1;
516 break;
517 }
518 if (!str_diff(action, "force-stop")) {
519 acts = "d";
520 kll = 1;
521 break;
522 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000523 default:
524 usage();
525 }
526
527 servicex = service;
528 for (i = 0; i < services; ++i) {
529 if ((**service != '/') && (**service != '.')) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000530 if (chdir(varservice) == -1)
531 goto chdir_failed_0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000532 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000533 if (chdir(*service) == -1) {
534 chdir_failed_0:
535 fail("cannot change to service directory");
536 goto nullify_service_0;
537 }
538 if (act && (act(acts) == -1)) {
539 nullify_service_0:
540 *service = NULL;
541 }
542 if (fchdir(curdir) == -1)
543 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000544 service++;
545 }
546
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000547 if (cbk) while (1) {
548 //struct taia tdiff;
549 long diff;
550
551 //taia_sub(&tdiff, &tnow, &tstart);
552 diff = tnow.sec.x - tstart.sec.x;
553 service = servicex;
554 want_exit = 1;
555 for (i = 0; i < services; ++i, ++service) {
556 if (!*service)
557 continue;
558 if ((**service != '/') && (**service != '.')) {
559 if (chdir(varservice) == -1)
560 goto chdir_failed;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000561 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000562 if (chdir(*service) == -1) {
563 chdir_failed:
564 fail("cannot change to service directory");
565 goto nullify_service;
566 }
567 if (cbk(acts) != 0)
568 goto nullify_service;
569 want_exit = 0;
570 if (diff >= waitsec) {
571 printf(kll ? "kill: " : "timeout: ");
572 if (svstatus_get() > 0) {
573 svstatus_print(*service);
574 ++rc;
575 }
576 puts(""); /* will also flush the output */
577 if (kll)
578 control("k");
579 nullify_service:
580 *service = NULL;
581 }
582 if (fchdir(curdir) == -1)
583 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000584 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000585 if (want_exit) break;
586 usleep(420000);
587 taia_now(&tnow);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000588 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000589 return rc > 99 ? 99 : rc;
590}