blob: c420a91a6df41bd3c3808b373b163b77295c4131 [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 Vlasenkod18f52b2008-03-02 12:53:15 +0000153/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000154/* 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 Vlasenkob9256052007-09-28 10:29:17 +0000161struct globals {
162 const char *acts;
163 char **service;
164 unsigned rc;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000165/* "Bernstein" time format: unix + 0x400000000000000aULL */
Denis Vlasenkob9256052007-09-28 10:29:17 +0000166 uint64_t tstart, tnow;
167 svstatus_t svstatus;
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100168} FIX_ALIASING;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000169#define G (*(struct globals*)&bb_common_bufsiz1)
170#define acts (G.acts )
171#define service (G.service )
172#define rc (G.rc )
173#define tstart (G.tstart )
174#define tnow (G.tnow )
175#define svstatus (G.svstatus )
176#define INIT_G() do { } while (0)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000177
Denis Vlasenko04c63862006-11-17 18:58:49 +0000178
Denys Vlasenko05e86052010-10-13 12:53:27 +0200179#define str_equal(s,t) (!strcmp((s), (t)))
180
181
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000182static void fatal_cannot(const char *m1) NORETURN;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000183static void fatal_cannot(const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000184{
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +0000185 bb_perror_msg("fatal: can't %s", m1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000186 _exit(151);
187}
188
Denis Vlasenko322661d2007-01-29 23:43:52 +0000189static void out(const char *p, const char *m1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000190{
191 printf("%s%s: %s", p, *service, m1);
192 if (errno) {
193 printf(": %s", strerror(errno));
194 }
Denis Vlasenko4daad902007-09-27 10:20:47 +0000195 bb_putchar('\n'); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000196}
197
Denis Vlasenko04c63862006-11-17 18:58:49 +0000198#define WARN "warning: "
199#define OK "ok: "
Denis Vlasenko04c63862006-11-17 18:58:49 +0000200
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000201static void fail(const char *m1)
202{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000203 ++rc;
204 out("fail: ", m1);
205}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000206static void failx(const char *m1)
207{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000208 errno = 0;
209 fail(m1);
210}
Denis Vlasenko45946f82007-08-20 17:27:40 +0000211static void warn(const char *m1)
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000212{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000213 ++rc;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000214 /* "warning: <service>: <m1>\n" */
215 out("warning: ", m1);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000216}
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000217static void ok(const char *m1)
218{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000219 errno = 0;
220 out(OK, m1);
221}
Denis Vlasenko04c63862006-11-17 18:58:49 +0000222
223static int svstatus_get(void)
224{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000225 int fd, r;
226
Denys Vlasenko05e86052010-10-13 12:53:27 +0200227 fd = open("supervise/ok", O_WRONLY|O_NDELAY);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000228 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000229 if (errno == ENODEV) {
230 *acts == 'x' ? ok("runsv not running")
231 : failx("runsv not running");
232 return 0;
233 }
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100234 warn("can't open supervise/ok");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000235 return -1;
236 }
237 close(fd);
Denys Vlasenko05e86052010-10-13 12:53:27 +0200238 fd = open("supervise/status", O_RDONLY|O_NDELAY);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000239 if (fd == -1) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100240 warn("can't open supervise/status");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000241 return -1;
242 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000243 r = read(fd, &svstatus, 20);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000244 close(fd);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000245 switch (r) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000246 case 20:
247 break;
248 case -1:
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100249 warn("can't read supervise/status");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000250 return -1;
251 default:
252 errno = 0;
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100253 warn("can't read supervise/status: bad format");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000254 return -1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000255 }
256 return 1;
257}
258
Denis Vlasenko322661d2007-01-29 23:43:52 +0000259static unsigned svstatus_print(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000260{
Denis Vlasenko45946f82007-08-20 17:27:40 +0000261 int diff;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000262 int pid;
263 int normallyup = 0;
264 struct stat s;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000265 uint64_t timestamp;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000266
Denis Vlasenko04c63862006-11-17 18:58:49 +0000267 if (stat("down", &s) == -1) {
268 if (errno != ENOENT) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100269 bb_perror_msg(WARN"can't stat %s/down", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000270 return 0;
271 }
272 normallyup = 1;
273 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000274 pid = SWAP_LE32(svstatus.pid_le32);
275 timestamp = SWAP_BE64(svstatus.time_be64);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000276 if (pid) {
Denis Vlasenko45946f82007-08-20 17:27:40 +0000277 switch (svstatus.run_or_finish) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000278 case 1: printf("run: "); break;
279 case 2: printf("finish: "); break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000280 }
281 printf("%s: (pid %d) ", m, pid);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000282 } else {
283 printf("down: %s: ", m);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000284 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000285 diff = tnow - timestamp;
286 printf("%us", (diff < 0 ? 0 : diff));
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000287 if (pid) {
288 if (!normallyup) printf(", normally down");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000289 if (svstatus.paused) printf(", paused");
290 if (svstatus.want == 'd') printf(", want down");
291 if (svstatus.got_term) printf(", got TERM");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000292 } else {
293 if (normallyup) printf(", normally up");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000294 if (svstatus.want == 'u') printf(", want up");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000295 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000296 return pid ? 1 : 2;
297}
298
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000299static int status(const char *unused UNUSED_PARAM)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000300{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000301 int r;
302
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200303 if (svstatus_get() <= 0)
304 return 0;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000305
Denis Vlasenko04c63862006-11-17 18:58:49 +0000306 r = svstatus_print(*service);
307 if (chdir("log") == -1) {
308 if (errno != ENOENT) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100309 printf("; log: "WARN"can't change to log service directory: %s",
Denis Vlasenko04c63862006-11-17 18:58:49 +0000310 strerror(errno));
311 }
312 } else if (svstatus_get()) {
313 printf("; ");
314 svstatus_print("log");
315 }
Denis Vlasenko4daad902007-09-27 10:20:47 +0000316 bb_putchar('\n'); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000317 return r;
318}
319
320static int checkscript(void)
321{
322 char *prog[2];
323 struct stat s;
324 int pid, w;
325
326 if (stat("check", &s) == -1) {
327 if (errno == ENOENT) return 1;
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100328 bb_perror_msg(WARN"can't stat %s/check", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000329 return 0;
330 }
331 /* if (!(s.st_mode & S_IXUSR)) return 1; */
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000332 prog[0] = (char*)"./check";
333 prog[1] = NULL;
334 pid = spawn(prog);
335 if (pid <= 0) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100336 bb_perror_msg(WARN"can't %s child %s/check", "run", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000337 return 0;
338 }
Denis Vlasenkofb0eba72008-01-02 19:55:04 +0000339 while (safe_waitpid(pid, &w, 0) == -1) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100340 bb_perror_msg(WARN"can't %s child %s/check", "wait for", *service);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000341 return 0;
342 }
Denys Vlasenko8f24f982009-06-07 16:02:00 +0200343 return WEXITSTATUS(w) == 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000344}
345
Denis Vlasenko322661d2007-01-29 23:43:52 +0000346static int check(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000347{
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000348 int r;
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200349 unsigned pid_le32;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000350 uint64_t timestamp;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000351
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000352 r = svstatus_get();
353 if (r == -1)
354 return -1;
355 if (r == 0) {
356 if (*a == 'x')
357 return 1;
358 return -1;
359 }
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200360 pid_le32 = svstatus.pid_le32;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000361 switch (*a) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000362 case 'x':
363 return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000364 case 'u':
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200365 if (!pid_le32 || svstatus.run_or_finish != 1) return 0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000366 if (!checkscript()) return 0;
367 break;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000368 case 'd':
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200369 if (pid_le32) return 0;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000370 break;
371 case 'c':
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200372 if (pid_le32 && !checkscript()) return 0;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000373 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000374 case 't':
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200375 if (!pid_le32 && svstatus.want == 'd') break;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000376 timestamp = SWAP_BE64(svstatus.time_be64);
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200377 if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
Denis Vlasenko04c63862006-11-17 18:58:49 +0000378 return 0;
379 break;
380 case 'o':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000381 timestamp = SWAP_BE64(svstatus.time_be64);
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200382 if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
Denis Vlasenko04c63862006-11-17 18:58:49 +0000383 return 0;
384 }
Denis Vlasenko322661d2007-01-29 23:43:52 +0000385 printf(OK);
386 svstatus_print(*service);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000387 bb_putchar('\n'); /* will also flush the output */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000388 return 1;
389}
390
Denis Vlasenko322661d2007-01-29 23:43:52 +0000391static int control(const char *a)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000392{
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200393 int fd, r, l;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000394
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200395/* Is it an optimization?
396 It causes problems with "sv o SRV; ...; sv d SRV"
397 ('d' is not passed to SRV because its .want == 'd'):
Denis Vlasenko45946f82007-08-20 17:27:40 +0000398 if (svstatus_get() <= 0)
399 return -1;
400 if (svstatus.want == *a)
401 return 0;
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200402*/
Denys Vlasenko05e86052010-10-13 12:53:27 +0200403 fd = open("supervise/control", O_WRONLY|O_NDELAY);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000404 if (fd == -1) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000405 if (errno != ENODEV)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100406 warn("can't open supervise/control");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000407 else
408 *a == 'x' ? ok("runsv not running") : failx("runsv not running");
409 return -1;
410 }
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200411 l = strlen(a);
412 r = write(fd, a, l);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000413 close(fd);
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200414 if (r != l) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100415 warn("can't write to supervise/control");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000416 return -1;
417 }
418 return 1;
419}
420
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000421int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200422int sv_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000423{
424 unsigned opt;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000425 char *x;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000426 char *action;
Denis Vlasenkof068b3e2008-11-06 23:07:42 +0000427 const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000428 unsigned waitsec = 7;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000429 smallint kll = 0;
Denis Vlasenko1d426652008-03-17 09:09:09 +0000430 int verbose = 0;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000431 int (*act)(const char*);
432 int (*cbk)(const char*);
433 int curdir;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000434
Denis Vlasenkob9256052007-09-28 10:29:17 +0000435 INIT_G();
436
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000437 xfunc_error_retval = 100;
438
439 x = getenv("SVDIR");
440 if (x) varservice = x;
441 x = getenv("SVWAIT");
Denis Vlasenko45946f82007-08-20 17:27:40 +0000442 if (x) waitsec = xatou(x);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000443
Denis Vlasenko1d426652008-03-17 09:09:09 +0000444 opt_complementary = "w+:vv"; /* -w N, -v is a counter */
445 opt = getopt32(argv, "w:v", &waitsec, &verbose);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000446 argv += optind;
447 action = *argv++;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000448 if (!action || !*argv) bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000449
Denis Vlasenko04158e02009-02-02 10:48:06 +0000450 tnow = time(NULL) + 0x400000000000000aULL;
Denis Vlasenko322661d2007-01-29 23:43:52 +0000451 tstart = tnow;
Denys Vlasenko05e86052010-10-13 12:53:27 +0200452 curdir = open(".", O_RDONLY|O_NDELAY);
Denis Vlasenko322661d2007-01-29 23:43:52 +0000453 if (curdir == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000454 fatal_cannot("open current directory");
455
Denis Vlasenko322661d2007-01-29 23:43:52 +0000456 act = &control;
457 acts = "s";
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000458 cbk = &check;
459
Denis Vlasenko04c63862006-11-17 18:58:49 +0000460 switch (*action) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000461 case 'x':
462 case 'e':
463 acts = "x";
464 if (!verbose) cbk = NULL;
465 break;
466 case 'X':
467 case 'E':
468 acts = "x";
469 kll = 1;
470 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000471 case 'D':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000472 acts = "d";
473 kll = 1;
474 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000475 case 'T':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000476 acts = "tc";
477 kll = 1;
478 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000479 case 'c':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000480 if (str_equal(action, "check")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000481 act = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000482 acts = "c";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000483 break;
484 }
485 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
486 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000487 action[1] = '\0';
488 acts = action;
489 if (!verbose) cbk = NULL;
490 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000491 case 's':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000492 if (str_equal(action, "shutdown")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000493 acts = "x";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000494 break;
495 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000496 if (str_equal(action, "start")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000497 acts = "u";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000498 break;
499 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000500 if (str_equal(action, "stop")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000501 acts = "d";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000502 break;
503 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000504 /* "status" */
Denis Vlasenko322661d2007-01-29 23:43:52 +0000505 act = &status;
506 cbk = NULL;
507 break;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000508 case 'r':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000509 if (str_equal(action, "restart")) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000510 acts = "tcu";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000511 break;
512 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000513 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000514 case 'f':
Denis Vlasenko45946f82007-08-20 17:27:40 +0000515 if (str_equal(action, "force-reload")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000516 acts = "tc";
517 kll = 1;
518 break;
519 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000520 if (str_equal(action, "force-restart")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000521 acts = "tcu";
522 kll = 1;
523 break;
524 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000525 if (str_equal(action, "force-shutdown")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000526 acts = "x";
527 kll = 1;
528 break;
529 }
Denis Vlasenko45946f82007-08-20 17:27:40 +0000530 if (str_equal(action, "force-stop")) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000531 acts = "d";
532 kll = 1;
533 break;
534 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000535 default:
Denis Vlasenko45946f82007-08-20 17:27:40 +0000536 bb_show_usage();
Denis Vlasenko04c63862006-11-17 18:58:49 +0000537 }
538
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200539 service = argv;
540 while ((x = *service) != NULL) {
541 if (x[0] != '/' && x[0] != '.') {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000542 if (chdir(varservice) == -1)
543 goto chdir_failed_0;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000544 }
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200545 if (chdir(x) == -1) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000546 chdir_failed_0:
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100547 fail("can't change to service directory");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000548 goto nullify_service_0;
549 }
550 if (act && (act(acts) == -1)) {
551 nullify_service_0:
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200552 *service = (char*) -1L; /* "dead" */
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000553 }
554 if (fchdir(curdir) == -1)
555 fatal_cannot("change to original directory");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000556 service++;
557 }
558
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000559 if (cbk) while (1) {
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200560 int want_exit;
Denis Vlasenko45946f82007-08-20 17:27:40 +0000561 int diff;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000562
Denis Vlasenko45946f82007-08-20 17:27:40 +0000563 diff = tnow - tstart;
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200564 service = argv;
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000565 want_exit = 1;
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200566 while ((x = *service) != NULL) {
567 if (x == (char*) -1L) /* "dead" */
568 goto next;
569 if (x[0] != '/' && x[0] != '.') {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000570 if (chdir(varservice) == -1)
571 goto chdir_failed;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000572 }
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200573 if (chdir(x) == -1) {
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000574 chdir_failed:
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100575 fail("can't change to service directory");
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000576 goto nullify_service;
577 }
578 if (cbk(acts) != 0)
579 goto nullify_service;
580 want_exit = 0;
581 if (diff >= waitsec) {
582 printf(kll ? "kill: " : "timeout: ");
583 if (svstatus_get() > 0) {
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200584 svstatus_print(x);
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000585 ++rc;
586 }
Denis Vlasenko4daad902007-09-27 10:20:47 +0000587 bb_putchar('\n'); /* will also flush the output */
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000588 if (kll)
589 control("k");
590 nullify_service:
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200591 *service = (char*) -1L; /* "dead" */
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000592 }
593 if (fchdir(curdir) == -1)
594 fatal_cannot("change to original directory");
Denys Vlasenkob3ba9e22009-07-15 00:24:08 +0200595 next:
596 service++;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000597 }
Denis Vlasenko7fca91a32007-02-02 01:19:09 +0000598 if (want_exit) break;
599 usleep(420000);
Denis Vlasenko04158e02009-02-02 10:48:06 +0000600 tnow = time(NULL) + 0x400000000000000aULL;
Denis Vlasenko8c783952007-01-27 22:21:52 +0000601 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000602 return rc > 99 ? 99 : rc;
603}