blob: c87f565ccc83da02f690a1ad2236773b93ef390f [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 Vlasenko45946f82007-08-20 17:27:40 +0000164/* "Bernstein" time format: unix + 0x400000000000000aULL */
165static uint64_t tstart, tnow;
166svstatus_t svstatus;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000167
Denis Vlasenko04c63862006-11-17 18:58:49 +0000168
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 Vlasenko45946f82007-08-20 17:27:40 +0000198static void warn(const char *m1)
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000199{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000200 ++rc;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000201 /* "warning: <service>: <m1>\n" */
202 out("warning: ", m1);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000203}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000204static void ok(const char *m1)
205{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000206 errno = 0;
207 out(OK, m1);
208}
Denis Vlasenko04c63862006-11-17 18:58:49 +0000209
210static int svstatus_get(void)
211{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000212 int fd, r;
213
Denis Vlasenko322661d2007-01-29 23:43:52 +0000214 fd = open_write("supervise/ok");
215 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000216 if (errno == ENODEV) {
217 *acts == 'x' ? ok("runsv not running")
218 : failx("runsv not running");
219 return 0;
220 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000221 warn("cannot open supervise/ok");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000222 return -1;
223 }
224 close(fd);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000225 fd = open_read("supervise/status");
226 if (fd == -1) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000227 warn("cannot open supervise/status");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000228 return -1;
229 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000230 r = read(fd, &svstatus, 20);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000231 close(fd);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000232 switch (r) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000233 case 20:
234 break;
235 case -1:
236 warn("cannot read supervise/status");
237 return -1;
238 default:
239 errno = 0;
240 warn("cannot read supervise/status: bad format");
241 return -1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000242 }
243 return 1;
244}
245
Denis Vlasenko322661d2007-01-29 23:43:52 +0000246static unsigned svstatus_print(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000247{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000248 int diff;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000249 int pid;
250 int normallyup = 0;
251 struct stat s;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000252 uint64_t timestamp;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000253
Denis Vlasenko04c63862006-11-17 18:58:49 +0000254 if (stat("down", &s) == -1) {
255 if (errno != ENOENT) {
256 bb_perror_msg(WARN"cannot stat %s/down", *service);
257 return 0;
258 }
259 normallyup = 1;
260 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000261 pid = SWAP_LE32(svstatus.pid_le32);
262 timestamp = SWAP_BE64(svstatus.time_be64);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000263 if (pid) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000264 switch (svstatus.run_or_finish) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000265 case 1: printf("run: "); break;
266 case 2: printf("finish: "); break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000267 }
268 printf("%s: (pid %d) ", m, pid);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000269 } else {
270 printf("down: %s: ", m);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000271 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000272 diff = tnow - timestamp;
273 printf("%us", (diff < 0 ? 0 : diff));
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000274 if (pid) {
275 if (!normallyup) printf(", normally down");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000276 if (svstatus.paused) printf(", paused");
277 if (svstatus.want == 'd') printf(", want down");
278 if (svstatus.got_term) printf(", got TERM");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000279 } else {
280 if (normallyup) printf(", normally up");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000281 if (svstatus.want == 'u') printf(", want up");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000282 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000283 return pid ? 1 : 2;
284}
285
Denis Vlasenko322661d2007-01-29 23:43:52 +0000286static int status(const char *unused)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000287{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000288 int r;
289
Denis Vlasenko04c63862006-11-17 18:58:49 +0000290 r = svstatus_get();
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000291 switch (r) { case -1: case 0: return 0; }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000292
Denis Vlasenko04c63862006-11-17 18:58:49 +0000293 r = svstatus_print(*service);
294 if (chdir("log") == -1) {
295 if (errno != ENOENT) {
296 printf("; log: "WARN"cannot change to log service directory: %s",
297 strerror(errno));
298 }
299 } else if (svstatus_get()) {
300 printf("; ");
301 svstatus_print("log");
302 }
303 puts(""); /* will also flush the output */
304 return r;
305}
306
307static int checkscript(void)
308{
309 char *prog[2];
310 struct stat s;
311 int pid, w;
312
313 if (stat("check", &s) == -1) {
314 if (errno == ENOENT) return 1;
315 bb_perror_msg(WARN"cannot stat %s/check", *service);
316 return 0;
317 }
318 /* if (!(s.st_mode & S_IXUSR)) return 1; */
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000319 prog[0] = (char*)"./check";
320 prog[1] = NULL;
321 pid = spawn(prog);
322 if (pid <= 0) {
323 bb_perror_msg(WARN"cannot %s child %s/check", "run", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000324 return 0;
325 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000326 while (wait_pid(&w, pid) == -1) {
327 if (errno == EINTR) continue;
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000328 bb_perror_msg(WARN"cannot %s child %s/check", "wait for", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000329 return 0;
330 }
331 return !wait_exitcode(w);
332}
333
Denis Vlasenko322661d2007-01-29 23:43:52 +0000334static int check(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000335{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000336 int r;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000337 unsigned pid;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000338 uint64_t timestamp;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000339
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000340 r = svstatus_get();
341 if (r == -1)
342 return -1;
343 if (r == 0) {
344 if (*a == 'x')
345 return 1;
346 return -1;
347 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000348 pid = SWAP_LE32(svstatus.pid_le32);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000349 switch (*a) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000350 case 'x':
351 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000352 case 'u':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000353 if (!pid || svstatus.run_or_finish != 1) return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000354 if (!checkscript()) return 0;
355 break;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000356 case 'd':
357 if (pid) return 0;
358 break;
359 case 'c':
360 if (pid && !checkscript()) return 0;
361 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000362 case 't':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000363 if (!pid && svstatus.want == 'd') break;
364 timestamp = SWAP_BE64(svstatus.time_be64);
365 if ((tstart > timestamp) || !pid || svstatus.got_term || !checkscript())
Denis Vlasenko04c63862006-11-17 18:58:49 +0000366 return 0;
367 break;
368 case 'o':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000369 timestamp = SWAP_BE64(svstatus.time_be64);
370 if ((!pid && tstart > timestamp) || (pid && svstatus.want != 'd'))
Denis Vlasenko04c63862006-11-17 18:58:49 +0000371 return 0;
372 }
Denis Vlasenko322661d2007-01-29 23:43:52 +0000373 printf(OK);
374 svstatus_print(*service);
375 puts(""); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000376 return 1;
377}
378
Denis Vlasenko322661d2007-01-29 23:43:52 +0000379static int control(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000380{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000381 int fd, r;
382
Denis Vlasenko45946f82007-08-20 17:27:40 +0000383 if (svstatus_get() <= 0)
384 return -1;
385 if (svstatus.want == *a)
386 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)
Denis Vlasenko45946f82007-08-20 17:27:40 +0000390 warn("cannot open supervise/control");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000391 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)) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000398 warn("cannot write to supervise/control");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000399 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;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000414 unsigned waitsec = 7;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000415 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");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000426 if (x) waitsec = xatou(x);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000427
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000428 opt = getopt32(argv, "w:v", &x);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000429 if (opt & 1) waitsec = xatou(x); // -w
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000430 if (opt & 2) verbose = 1; // -v
431 argc -= optind;
432 argv += optind;
433 action = *argv++;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000434 if (!action || !*argv) bb_show_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 Vlasenko45946f82007-08-20 17:27:40 +0000438 tnow = time(0) + 0x400000000000000aULL;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000439 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':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000468 if (str_equal(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':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000480 if (str_equal(action, "shutdown")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000481 acts = "x";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000482 break;
483 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000484 if (str_equal(action, "start")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000485 acts = "u";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000486 break;
487 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000488 if (str_equal(action, "stop")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000489 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':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000497 if (str_equal(action, "restart")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000498 acts = "tcu";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000499 break;
500 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000501 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000502 case 'f':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000503 if (str_equal(action, "force-reload")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000504 acts = "tc";
505 kll = 1;
506 break;
507 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000508 if (str_equal(action, "force-restart")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000509 acts = "tcu";
510 kll = 1;
511 break;
512 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000513 if (str_equal(action, "force-shutdown")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000514 acts = "x";
515 kll = 1;
516 break;
517 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000518 if (str_equal(action, "force-stop")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000519 acts = "d";
520 kll = 1;
521 break;
522 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000523 default:
Denis Vlasenko45946f82007-08-20 17:27:40 +0000524 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000525 }
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) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000548 int diff;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000549
Denis Vlasenko45946f82007-08-20 17:27:40 +0000550 diff = tnow - tstart;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000551 service = servicex;
552 want_exit = 1;
553 for (i = 0; i < services; ++i, ++service) {
554 if (!*service)
555 continue;
556 if ((**service != '/') && (**service != '.')) {
557 if (chdir(varservice) == -1)
558 goto chdir_failed;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000559 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000560 if (chdir(*service) == -1) {
561 chdir_failed:
562 fail("cannot change to service directory");
563 goto nullify_service;
564 }
565 if (cbk(acts) != 0)
566 goto nullify_service;
567 want_exit = 0;
568 if (diff >= waitsec) {
569 printf(kll ? "kill: " : "timeout: ");
570 if (svstatus_get() > 0) {
571 svstatus_print(*service);
572 ++rc;
573 }
574 puts(""); /* will also flush the output */
575 if (kll)
576 control("k");
577 nullify_service:
578 *service = NULL;
579 }
580 if (fchdir(curdir) == -1)
581 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000582 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000583 if (want_exit) break;
584 usleep(420000);
Denis Vlasenko45946f82007-08-20 17:27:40 +0000585 tnow = time(0) + 0x400000000000000aULL;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000586 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000587 return rc > 99 ? 99 : rc;
588}