summaryrefslogtreecommitdiff
path: root/runit
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-02 01:19:09 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-02 01:19:09 +0000
commit7fca91a3de3570ae0b3bec0d58fafb4ab90a95cd (patch)
tree1d080d94ca40d7cf24ff6a02525176ac7054dee6 /runit
parent8bb21af72cfac5301eeeb7593837be4960d2b316 (diff)
downloadbusybox-w32-7fca91a3de3570ae0b3bec0d58fafb4ab90a95cd.tar.gz
busybox-w32-7fca91a3de3570ae0b3bec0d58fafb4ab90a95cd.tar.bz2
busybox-w32-7fca91a3de3570ae0b3bec0d58fafb4ab90a95cd.zip
sv: fix incorrect option parsing and reduce size
Diffstat (limited to 'runit')
-rw-r--r--runit/sv.c296
1 files changed, 176 insertions, 120 deletions
diff --git a/runit/sv.c b/runit/sv.c
index 6b154c1a8..2af9f6604 100644
--- a/runit/sv.c
+++ b/runit/sv.c
@@ -6,27 +6,15 @@
6#include "busybox.h" 6#include "busybox.h"
7#include "runit_lib.h" 7#include "runit_lib.h"
8 8
9static char *action;
10static const char *acts; 9static const char *acts;
11static const char *varservice = "/var/service/";
12static char **service; 10static char **service;
13static char **servicex;
14static unsigned services;
15static unsigned rc; 11static unsigned rc;
16static unsigned verbose; 12static struct taia tstart, tnow;
17static unsigned long waitsec = 7;
18static unsigned kll;
19static struct taia tstart, tnow, tdiff;
20static struct tai tstatus;
21
22static int (*act)(const char*);
23static int (*cbk)(const char*);
24
25static int curdir, fd, r;
26static char svstatus[20]; 13static char svstatus[20];
27 14
28#define usage() bb_show_usage() 15#define usage() bb_show_usage()
29 16
17static void fatal_cannot(const char *m1) ATTRIBUTE_NORETURN;
30static void fatal_cannot(const char *m1) 18static void fatal_cannot(const char *m1)
31{ 19{
32 bb_perror_msg("fatal: cannot %s", m1); 20 bb_perror_msg("fatal: cannot %s", m1);
@@ -42,23 +30,34 @@ static void out(const char *p, const char *m1)
42 puts(""); /* will also flush the output */ 30 puts(""); /* will also flush the output */
43} 31}
44 32
45#define FAIL "fail: "
46#define WARN "warning: " 33#define WARN "warning: "
47#define OK "ok: " 34#define OK "ok: "
48#define RUN "run: "
49#define FINISH "finish: "
50#define DOWN "down: "
51#define TIMEOUT "timeout: "
52#define KILL "kill: "
53 35
54static void fail(const char *m1) { ++rc; out(FAIL, m1); } 36static void fail(const char *m1) {
55static void failx(const char *m1) { errno = 0; fail(m1); } 37 ++rc;
56static void warn_cannot(const char *m1) { ++rc; out("warning: cannot ", m1); } 38 out("fail: ", m1);
57static void warnx_cannot(const char *m1) { errno = 0; warn_cannot(m1); } 39}
58static void ok(const char *m1) { errno = 0; out(OK, m1); } 40static void failx(const char *m1) {
41 errno = 0;
42 fail(m1);
43}
44static void warn_cannot(const char *m1) {
45 ++rc;
46 out("warning: cannot ", m1);
47}
48static void warnx_cannot(const char *m1) {
49 errno = 0;
50 warn_cannot(m1);
51}
52static void ok(const char *m1) {
53 errno = 0;
54 out(OK, m1);
55}
59 56
60static int svstatus_get(void) 57static int svstatus_get(void)
61{ 58{
59 int fd, r;
60
62 fd = open_write("supervise/ok"); 61 fd = open_write("supervise/ok");
63 if (fd == -1) { 62 if (fd == -1) {
64 if (errno == ENODEV) { 63 if (errno == ENODEV) {
@@ -87,9 +86,11 @@ static int svstatus_get(void)
87 86
88static unsigned svstatus_print(const char *m) 87static unsigned svstatus_print(const char *m)
89{ 88{
89 long diff;
90 int pid; 90 int pid;
91 int normallyup = 0; 91 int normallyup = 0;
92 struct stat s; 92 struct stat s;
93 struct tai tstatus;
93 94
94 if (stat("down", &s) == -1) { 95 if (stat("down", &s) == -1) {
95 if (errno != ENOENT) { 96 if (errno != ENOENT) {
@@ -105,17 +106,20 @@ static unsigned svstatus_print(const char *m)
105 tai_unpack(svstatus, &tstatus); 106 tai_unpack(svstatus, &tstatus);
106 if (pid) { 107 if (pid) {
107 switch (svstatus[19]) { 108 switch (svstatus[19]) {
108 case 1: printf(RUN); break; 109 case 1: printf("run: "); break;
109 case 2: printf(FINISH); break; 110 case 2: printf("finish: "); break;
110 } 111 }
111 printf("%s: (pid %d) ", m, pid); 112 printf("%s: (pid %d) ", m, pid);
113 } else {
114 printf("down: %s: ", m);
112 } 115 }
113 else { 116 diff = tnow.sec.x - tstatus.x;
114 printf(DOWN"%s: ", m); 117 printf("%lds", (diff < 0 ? 0L : diff));
118 if (pid) {
119 if (!normallyup) printf(", normally down");
120 } else {
121 if (normallyup) printf(", normally up");
115 } 122 }
116 printf("%lus", (unsigned long)(tnow.sec.x < tstatus.x ? 0 : tnow.sec.x-tstatus.x));
117 if (pid && !normallyup) printf(", normally down");
118 if (!pid && normallyup) printf(", normally up");
119 if (pid && svstatus[16]) printf(", paused"); 123 if (pid && svstatus[16]) printf(", paused");
120 if (!pid && (svstatus[17] == 'u')) printf(", want up"); 124 if (!pid && (svstatus[17] == 'u')) printf(", want up");
121 if (pid && (svstatus[17] == 'd')) printf(", want down"); 125 if (pid && (svstatus[17] == 'd')) printf(", want down");
@@ -125,8 +129,11 @@ static unsigned svstatus_print(const char *m)
125 129
126static int status(const char *unused) 130static int status(const char *unused)
127{ 131{
132 int r;
133
128 r = svstatus_get(); 134 r = svstatus_get();
129 switch (r) { case -1: case 0: return 0; } 135 switch (r) { case -1: case 0: return 0; }
136
130 r = svstatus_print(*service); 137 r = svstatus_print(*service);
131 if (chdir("log") == -1) { 138 if (chdir("log") == -1) {
132 if (errno != ENOENT) { 139 if (errno != ENOENT) {
@@ -175,22 +182,35 @@ static int checkscript(void)
175 182
176static int check(const char *a) 183static int check(const char *a)
177{ 184{
185 int r;
178 unsigned pid; 186 unsigned pid;
187 struct tai tstatus;
179 188
180 if ((r = svstatus_get()) == -1) return -1; 189 r = svstatus_get();
181 if (r == 0) { if (*a == 'x') return 1; return -1; } 190 if (r == -1)
191 return -1;
192 if (r == 0) {
193 if (*a == 'x')
194 return 1;
195 return -1;
196 }
182 pid = (unsigned char)svstatus[15]; 197 pid = (unsigned char)svstatus[15];
183 pid <<= 8; pid += (unsigned char)svstatus[14]; 198 pid <<= 8; pid += (unsigned char)svstatus[14];
184 pid <<= 8; pid += (unsigned char)svstatus[13]; 199 pid <<= 8; pid += (unsigned char)svstatus[13];
185 pid <<= 8; pid += (unsigned char)svstatus[12]; 200 pid <<= 8; pid += (unsigned char)svstatus[12];
186 switch (*a) { 201 switch (*a) {
187 case 'x': return 0; 202 case 'x':
203 return 0;
188 case 'u': 204 case 'u':
189 if (!pid || svstatus[19] != 1) return 0; 205 if (!pid || svstatus[19] != 1) return 0;
190 if (!checkscript()) return 0; 206 if (!checkscript()) return 0;
191 break; 207 break;
192 case 'd': if (pid) return 0; break; 208 case 'd':
193 case 'c': if (pid) if (!checkscript()) return 0; break; 209 if (pid) return 0;
210 break;
211 case 'c':
212 if (pid && !checkscript()) return 0;
213 break;
194 case 't': 214 case 't':
195 if (!pid && svstatus[17] == 'd') break; 215 if (!pid && svstatus[17] == 'd') break;
196 tai_unpack(svstatus, &tstatus); 216 tai_unpack(svstatus, &tstatus);
@@ -210,6 +230,8 @@ static int check(const char *a)
210 230
211static int control(const char *a) 231static int control(const char *a)
212{ 232{
233 int fd, r;
234
213 if (svstatus_get() <= 0) return -1; 235 if (svstatus_get() <= 0) return -1;
214 if (svstatus[17] == *a) return 0; 236 if (svstatus[17] == *a) return 0;
215 fd = open_write("supervise/control"); 237 fd = open_write("supervise/control");
@@ -234,25 +256,33 @@ int sv_main(int argc, char **argv)
234 unsigned opt; 256 unsigned opt;
235 unsigned i, want_exit; 257 unsigned i, want_exit;
236 char *x; 258 char *x;
259 char *action;
260 const char *varservice = "/var/service/";
261 unsigned services;
262 char **servicex;
263 unsigned long waitsec = 7;
264 smallint kll = 0;
265 smallint verbose = 0;
266 int (*act)(const char*);
267 int (*cbk)(const char*);
268 int curdir;
237 269
238 for (i = strlen(*argv); i; --i) 270 xfunc_error_retval = 100;
239 if ((*argv)[i-1] == '/') 271
240 break; 272 x = getenv("SVDIR");
241 *argv += i; 273 if (x) varservice = x;
242 service = argv; 274 x = getenv("SVWAIT");
243 services = 1; 275 if (x) waitsec = xatoul(x);
244 if ((x = getenv("SVDIR"))) varservice = x; 276
245 if ((x = getenv("SVWAIT"))) waitsec = xatoul(x); 277 opt = getopt32(argc, argv, "w:v", &x);
246 /* TODO: V can be handled internally by getopt_ulflags */ 278 if (opt & 1) waitsec = xatoul(x); // -w
247 opt = getopt32(argc, argv, "w:vV", &x); 279 if (opt & 2) verbose = 1; // -v
248 if (opt & 1) waitsec = xatoul(x); 280 argc -= optind;
249 if (opt & 2) verbose = 1; 281 argv += optind;
250 if (opt & 4) usage(); 282 action = *argv++;
251 if (!(action = *argv++)) usage(); 283 if (!action || !*argv) usage();
252 --argc;
253 service = argv; 284 service = argv;
254 services = argc; 285 services = argc - 1;
255 if (!*service) usage();
256 286
257 taia_now(&tnow); 287 taia_now(&tnow);
258 tstart = tnow; 288 tstart = tnow;
@@ -262,62 +292,83 @@ int sv_main(int argc, char **argv)
262 292
263 act = &control; 293 act = &control;
264 acts = "s"; 294 acts = "s";
265 if (verbose) 295 cbk = &check;
266 cbk = &check; 296
267 switch (*action) { 297 switch (*action) {
268 case 'x': case 'e': 298 case 'x':
269 acts = "x"; break; 299 case 'e':
270 case 'X': case 'E': 300 acts = "x";
271 acts = "x"; kll = 1; cbk = &check; break; 301 if (!verbose) cbk = NULL;
302 break;
303 case 'X':
304 case 'E':
305 acts = "x";
306 kll = 1;
307 break;
272 case 'D': 308 case 'D':
273 acts = "d"; kll = 1; cbk = &check; break; 309 acts = "d";
310 kll = 1;
311 break;
274 case 'T': 312 case 'T':
275 acts = "tc"; kll = 1; cbk = &check; break; 313 acts = "tc";
314 kll = 1;
315 break;
276 case 'c': 316 case 'c':
277 if (!str_diff(action, "check")) { 317 if (!str_diff(action, "check")) {
278 act = 0; 318 act = NULL;
279 acts = "c"; 319 acts = "c";
280 cbk = &check;
281 break; 320 break;
282 } 321 }
283 case 'u': case 'd': case 'o': case 't': case 'p': case 'h': 322 case 'u': case 'd': case 'o': case 't': case 'p': case 'h':
284 case 'a': case 'i': case 'k': case 'q': case '1': case '2': 323 case 'a': case 'i': case 'k': case 'q': case '1': case '2':
285 action[1] = 0; acts = action; break; 324 action[1] = '\0';
325 acts = action;
326 if (!verbose) cbk = NULL;
327 break;
286 case 's': 328 case 's':
287 if (!str_diff(action, "shutdown")) { 329 if (!str_diff(action, "shutdown")) {
288 acts = "x"; 330 acts = "x";
289 cbk = &check;
290 break; 331 break;
291 } 332 }
292 if (!str_diff(action, "start")) { 333 if (!str_diff(action, "start")) {
293 acts = "u"; 334 acts = "u";
294 cbk = &check;
295 break; 335 break;
296 } 336 }
297 if (!str_diff(action, "stop")) { 337 if (!str_diff(action, "stop")) {
298 acts = "d"; 338 acts = "d";
299 cbk = &check;
300 break; 339 break;
301 } 340 }
341 /* "status" */
302 act = &status; 342 act = &status;
303 cbk = NULL; 343 cbk = NULL;
304 break; 344 break;
305 case 'r': 345 case 'r':
306 if (!str_diff(action, "restart")) { 346 if (!str_diff(action, "restart")) {
307 acts = "tcu"; 347 acts = "tcu";
308 cbk = &check;
309 break; 348 break;
310 } 349 }
311 usage(); 350 usage();
312 case 'f': 351 case 'f':
313 if (!str_diff(action, "force-reload")) 352 if (!str_diff(action, "force-reload")) {
314 { acts = "tc"; kll = 1; cbk = &check; break; } 353 acts = "tc";
315 if (!str_diff(action, "force-restart")) 354 kll = 1;
316 { acts = "tcu"; kll = 1; cbk = &check; break; } 355 break;
317 if (!str_diff(action, "force-shutdown")) 356 }
318 { acts = "x"; kll = 1; cbk = &check; break; } 357 if (!str_diff(action, "force-restart")) {
319 if (!str_diff(action, "force-stop")) 358 acts = "tcu";
320 { acts = "d"; kll = 1; cbk = &check; break; } 359 kll = 1;
360 break;
361 }
362 if (!str_diff(action, "force-shutdown")) {
363 acts = "x";
364 kll = 1;
365 break;
366 }
367 if (!str_diff(action, "force-stop")) {
368 acts = "d";
369 kll = 1;
370 break;
371 }
321 default: 372 default:
322 usage(); 373 usage();
323 } 374 }
@@ -325,59 +376,64 @@ int sv_main(int argc, char **argv)
325 servicex = service; 376 servicex = service;
326 for (i = 0; i < services; ++i) { 377 for (i = 0; i < services; ++i) {
327 if ((**service != '/') && (**service != '.')) { 378 if ((**service != '/') && (**service != '.')) {
328 if ((chdir(varservice) == -1) || (chdir(*service) == -1)) { 379 if (chdir(varservice) == -1)
329 fail("cannot change to service directory"); 380 goto chdir_failed_0;
330 *service = 0; 381 }
331 } 382 if (chdir(*service) == -1) {
332 } else if (chdir(*service) == -1) { 383 chdir_failed_0:
333 fail("cannot change to service directory"); 384 fail("cannot change to service directory");
334 *service = 0; 385 goto nullify_service_0;
386 }
387 if (act && (act(acts) == -1)) {
388 nullify_service_0:
389 *service = NULL;
335 } 390 }
336 if (*service) if (act && (act(acts) == -1)) *service = 0; 391 if (fchdir(curdir) == -1)
337 if (fchdir(curdir) == -1) fatal_cannot("change to original directory"); 392 fatal_cannot("change to original directory");
338 service++; 393 service++;
339 } 394 }
340 395
341 if (*cbk) { 396 if (cbk) while (1) {
342 for (;;) { 397 //struct taia tdiff;
343//TODO: tdiff resolution is way too high. seconds will be enough 398 long diff;
344 taia_sub(&tdiff, &tnow, &tstart); 399
345 service = servicex; want_exit = 1; 400 //taia_sub(&tdiff, &tnow, &tstart);
346 for (i = 0; i < services; ++i, ++service) { 401 diff = tnow.sec.x - tstart.sec.x;
347 if (!*service) 402 service = servicex;
348 continue; 403 want_exit = 1;
349 if ((**service != '/') && (**service != '.')) { 404 for (i = 0; i < services; ++i, ++service) {
350 if (chdir(varservice) == -1) 405 if (!*service)
351 goto chdir_failed; 406 continue;
352 } 407 if ((**service != '/') && (**service != '.')) {
353 if (chdir(*service) == -1) { 408 if (chdir(varservice) == -1)
409 goto chdir_failed;
410 }
411 if (chdir(*service) == -1) {
354 chdir_failed: 412 chdir_failed:
355 fail("cannot change to service directory"); 413 fail("cannot change to service directory");
356 goto nullify_service; 414 goto nullify_service;
415 }
416 if (cbk(acts) != 0)
417 goto nullify_service;
418 want_exit = 0;
419 if (diff >= waitsec) {
420 printf(kll ? "kill: " : "timeout: ");
421 if (svstatus_get() > 0) {
422 svstatus_print(*service);
423 ++rc;
357 } 424 }
358 if (cbk(acts) != 0) 425 puts(""); /* will also flush the output */
359 goto nullify_service; 426 if (kll)
360 want_exit = 0; 427 control("k");
361 //if (taia_approx(&tdiff) > waitsec)
362 if (tdiff.sec.x >= waitsec) {
363 kll ? printf(KILL) : printf(TIMEOUT);
364 if (svstatus_get() > 0) {
365 svstatus_print(*service);
366 ++rc;
367 }
368 puts(""); /* will also flush the output */
369 if (kll)
370 control("k");
371 nullify_service: 428 nullify_service:
372 *service = NULL; 429 *service = NULL;
373 }
374 if (fchdir(curdir) == -1)
375 fatal_cannot("change to original directory");
376 } 430 }
377 if (want_exit) break; 431 if (fchdir(curdir) == -1)
378 usleep(420000); 432 fatal_cannot("change to original directory");
379 taia_now(&tnow);
380 } 433 }
434 if (want_exit) break;
435 usleep(420000);
436 taia_now(&tnow);
381 } 437 }
382 return rc > 99 ? 99 : rc; 438 return rc > 99 ? 99 : rc;
383} 439}