blob: d52eb6d228f8fe51f442ded82728e1722847ce01 [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; */
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000313 prog[0] = (char*)"./check";
314 prog[1] = NULL;
315 pid = spawn(prog);
316 if (pid <= 0) {
317 bb_perror_msg(WARN"cannot %s child %s/check", "run", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000318 return 0;
319 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000320 while (wait_pid(&w, pid) == -1) {
321 if (errno == EINTR) continue;
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000322 bb_perror_msg(WARN"cannot %s child %s/check", "wait for", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000323 return 0;
324 }
325 return !wait_exitcode(w);
326}
327
Denis Vlasenko322661d2007-01-29 23:43:52 +0000328static int check(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000329{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000330 int r;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000331 unsigned pid;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000332 struct tai tstatus;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000333
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000334 r = svstatus_get();
335 if (r == -1)
336 return -1;
337 if (r == 0) {
338 if (*a == 'x')
339 return 1;
340 return -1;
341 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000342 pid = (unsigned char)svstatus[15];
343 pid <<= 8; pid += (unsigned char)svstatus[14];
344 pid <<= 8; pid += (unsigned char)svstatus[13];
345 pid <<= 8; pid += (unsigned char)svstatus[12];
346 switch (*a) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000347 case 'x':
348 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000349 case 'u':
350 if (!pid || svstatus[19] != 1) return 0;
351 if (!checkscript()) return 0;
352 break;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000353 case 'd':
354 if (pid) return 0;
355 break;
356 case 'c':
357 if (pid && !checkscript()) return 0;
358 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000359 case 't':
360 if (!pid && svstatus[17] == 'd') break;
361 tai_unpack(svstatus, &tstatus);
362 if ((tstart.sec.x > tstatus.x) || !pid || svstatus[18] || !checkscript())
363 return 0;
364 break;
365 case 'o':
366 tai_unpack(svstatus, &tstatus);
367 if ((!pid && tstart.sec.x > tstatus.x) || (pid && svstatus[17] != 'd'))
368 return 0;
369 }
Denis Vlasenko322661d2007-01-29 23:43:52 +0000370 printf(OK);
371 svstatus_print(*service);
372 puts(""); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000373 return 1;
374}
375
Denis Vlasenko322661d2007-01-29 23:43:52 +0000376static int control(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000377{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000378 int fd, r;
379
Denis Vlasenko04c63862006-11-17 18:58:49 +0000380 if (svstatus_get() <= 0) return -1;
381 if (svstatus[17] == *a) return 0;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000382 fd = open_write("supervise/control");
383 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000384 if (errno != ENODEV)
385 warn_cannot("open supervise/control");
386 else
387 *a == 'x' ? ok("runsv not running") : failx("runsv not running");
388 return -1;
389 }
390 r = write(fd, a, strlen(a));
391 close(fd);
392 if (r != strlen(a)) {
393 warn_cannot("write to supervise/control");
394 return -1;
395 }
396 return 1;
397}
398
Denis Vlasenko06af2162007-02-03 17:28:39 +0000399int sv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000400int sv_main(int argc, char **argv)
401{
402 unsigned opt;
403 unsigned i, want_exit;
404 char *x;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000405 char *action;
406 const char *varservice = "/var/service/";
407 unsigned services;
408 char **servicex;
409 unsigned long waitsec = 7;
410 smallint kll = 0;
411 smallint verbose = 0;
412 int (*act)(const char*);
413 int (*cbk)(const char*);
414 int curdir;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000415
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000416 xfunc_error_retval = 100;
417
418 x = getenv("SVDIR");
419 if (x) varservice = x;
420 x = getenv("SVWAIT");
421 if (x) waitsec = xatoul(x);
422
423 opt = getopt32(argc, argv, "w:v", &x);
424 if (opt & 1) waitsec = xatoul(x); // -w
425 if (opt & 2) verbose = 1; // -v
426 argc -= optind;
427 argv += optind;
428 action = *argv++;
429 if (!action || !*argv) usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000430 service = argv;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000431 services = argc - 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000432
Denis Vlasenko322661d2007-01-29 23:43:52 +0000433 taia_now(&tnow);
434 tstart = tnow;
435 curdir = open_read(".");
436 if (curdir == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000437 fatal_cannot("open current directory");
438
Denis Vlasenko322661d2007-01-29 23:43:52 +0000439 act = &control;
440 acts = "s";
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000441 cbk = &check;
442
Denis Vlasenko04c63862006-11-17 18:58:49 +0000443 switch (*action) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000444 case 'x':
445 case 'e':
446 acts = "x";
447 if (!verbose) cbk = NULL;
448 break;
449 case 'X':
450 case 'E':
451 acts = "x";
452 kll = 1;
453 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000454 case 'D':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000455 acts = "d";
456 kll = 1;
457 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000458 case 'T':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000459 acts = "tc";
460 kll = 1;
461 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000462 case 'c':
463 if (!str_diff(action, "check")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000464 act = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000465 acts = "c";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000466 break;
467 }
468 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
469 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000470 action[1] = '\0';
471 acts = action;
472 if (!verbose) cbk = NULL;
473 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000474 case 's':
475 if (!str_diff(action, "shutdown")) {
476 acts = "x";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000477 break;
478 }
479 if (!str_diff(action, "start")) {
480 acts = "u";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000481 break;
482 }
483 if (!str_diff(action, "stop")) {
484 acts = "d";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000485 break;
486 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000487 /* "status" */
Denis Vlasenko322661d2007-01-29 23:43:52 +0000488 act = &status;
489 cbk = NULL;
490 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000491 case 'r':
492 if (!str_diff(action, "restart")) {
493 acts = "tcu";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000494 break;
495 }
496 usage();
497 case 'f':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000498 if (!str_diff(action, "force-reload")) {
499 acts = "tc";
500 kll = 1;
501 break;
502 }
503 if (!str_diff(action, "force-restart")) {
504 acts = "tcu";
505 kll = 1;
506 break;
507 }
508 if (!str_diff(action, "force-shutdown")) {
509 acts = "x";
510 kll = 1;
511 break;
512 }
513 if (!str_diff(action, "force-stop")) {
514 acts = "d";
515 kll = 1;
516 break;
517 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000518 default:
519 usage();
520 }
521
522 servicex = service;
523 for (i = 0; i < services; ++i) {
524 if ((**service != '/') && (**service != '.')) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000525 if (chdir(varservice) == -1)
526 goto chdir_failed_0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000527 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000528 if (chdir(*service) == -1) {
529 chdir_failed_0:
530 fail("cannot change to service directory");
531 goto nullify_service_0;
532 }
533 if (act && (act(acts) == -1)) {
534 nullify_service_0:
535 *service = NULL;
536 }
537 if (fchdir(curdir) == -1)
538 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000539 service++;
540 }
541
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000542 if (cbk) while (1) {
543 //struct taia tdiff;
544 long diff;
545
546 //taia_sub(&tdiff, &tnow, &tstart);
547 diff = tnow.sec.x - tstart.sec.x;
548 service = servicex;
549 want_exit = 1;
550 for (i = 0; i < services; ++i, ++service) {
551 if (!*service)
552 continue;
553 if ((**service != '/') && (**service != '.')) {
554 if (chdir(varservice) == -1)
555 goto chdir_failed;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000556 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000557 if (chdir(*service) == -1) {
558 chdir_failed:
559 fail("cannot change to service directory");
560 goto nullify_service;
561 }
562 if (cbk(acts) != 0)
563 goto nullify_service;
564 want_exit = 0;
565 if (diff >= waitsec) {
566 printf(kll ? "kill: " : "timeout: ");
567 if (svstatus_get() > 0) {
568 svstatus_print(*service);
569 ++rc;
570 }
571 puts(""); /* will also flush the output */
572 if (kll)
573 control("k");
574 nullify_service:
575 *service = NULL;
576 }
577 if (fchdir(curdir) == -1)
578 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000579 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000580 if (want_exit) break;
581 usleep(420000);
582 taia_now(&tnow);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000583 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000584 return rc > 99 ? 99 : rc;
585}