/[baselayout]/trunk/src/runscript.c
Gentoo

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2580 - (show annotations) (download) (as text)
Thu Apr 12 10:08:42 2007 UTC (7 years, 8 months ago) by uberlord
File MIME type: text/x-csrc
File size: 28371 byte(s)
Hug getopt_long even though it's not POSIX. start-stop-daemon has always required this and all our supported platforms have it.
1 /*
2 * runscript.c
3 * Handle launching of Gentoo init scripts.
4 *
5 * Copyright 1999-2007 Gentoo Foundation
6 * Distributed under the terms of the GNU General Public License v2
7 */
8
9 #include <sys/types.h>
10 #include <sys/signal.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <dlfcn.h>
14 #include <errno.h>
15 #include <getopt.h>
16 #include <limits.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #ifndef __linux__
23 #include <libgen.h>
24 #endif
25
26 #include "einfo.h"
27 #include "rc.h"
28 #include "rc-misc.h"
29 #include "rc-plugin.h"
30 #include "strlist.h"
31
32 #define RCSCRIPT_HELP RC_LIBDIR "/sh/rc-help.sh"
33 #define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
34
35 static char *applet = NULL;
36 static char *exclusive = NULL;
37 static char *mtime_test = NULL;
38 static rc_depinfo_t *deptree = NULL;
39 static char **services = NULL;
40 static char **svclist = NULL;
41 static char **tmplist = NULL;
42 static char **providelist = NULL;
43 static char **types = NULL;
44 static char **restart_services = NULL;
45 static char **need_services = NULL;
46 static char **env = NULL;
47 static char *mycmd = NULL;
48 static char *myarg1 = NULL;
49 static char *myarg2 = NULL;
50 static char *tmp = NULL;
51 static char *softlevel = NULL;
52 static bool sighup = false;
53 static char *ibsave = NULL;
54 static bool in_background = false;
55 static rc_hook_t hook_out = 0;
56
57 extern char **environ;
58
59 #ifdef __linux__
60 static void (*selinux_run_init_old) (void);
61 static void (*selinux_run_init_new) (int argc, char **argv);
62
63 void setup_selinux (int argc, char **argv);
64 #endif
65
66 #ifdef __linux__
67 void setup_selinux (int argc, char **argv)
68 {
69 void *lib_handle = NULL;
70
71 lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
72 if (lib_handle) {
73 /* FIXME: the below code generates the warning
74 ISO C forbids assignment between function pointer and 'void *'
75 which sucks ass
76 http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html */
77 selinux_run_init_old = dlsym (lib_handle, "selinux_runscript");
78 selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2");
79
80 /* Use new run_init if it rc_exists, else fall back to old */
81 if (selinux_run_init_new)
82 selinux_run_init_new (argc, argv);
83 else if (selinux_run_init_old)
84 selinux_run_init_old ();
85 else
86 /* This shouldnt happen... probably corrupt lib */
87 eerrorx ("run_init is missing from runscript_selinux.so!");
88 }
89 }
90 #endif
91
92 static void handle_signal (int sig)
93 {
94 pid_t pid;
95 int status;
96 int serrno = errno;
97 char signame[10] = { '\0' };
98
99 switch (sig) {
100 case SIGHUP:
101 sighup = true;
102 break;
103
104 case SIGCHLD:
105 do {
106 pid = waitpid (-1, &status, WNOHANG);
107 if (pid < 0) {
108 if (errno != ECHILD)
109 eerror ("waitpid: %s", strerror (errno));
110 return;
111 }
112 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
113 break;
114
115 case SIGINT:
116 if (! signame[0])
117 snprintf (signame, sizeof (signame), "SIGINT");
118 case SIGTERM:
119 if (! signame[0])
120 snprintf (signame, sizeof (signame), "SIGTERM");
121 case SIGQUIT:
122 if (! signame[0])
123 snprintf (signame, sizeof (signame), "SIGQUIT");
124 eerrorx ("%s: caught %s, aborting", applet, signame);
125
126 default:
127 eerror ("%s: caught unknown signal %d", applet, sig);
128 }
129
130 /* Restore errno */
131 errno = serrno;
132 }
133
134 static time_t get_mtime (const char *pathname, bool follow_link)
135 {
136 struct stat buf;
137 int retval;
138
139 if (! pathname)
140 return (0);
141
142 retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
143 if (! retval)
144 return (buf.st_mtime);
145
146 errno = 0;
147 return (0);
148 }
149
150 static bool in_control ()
151 {
152 char *path;
153 time_t mtime;
154 const char *tests[] = { "starting", "started", "stopping",
155 "inactive", "wasinactive", NULL };
156 int i = 0;
157
158 if (sighup)
159 return (false);
160
161 if (! mtime_test || ! rc_exists (mtime_test))
162 return (false);
163
164 if (rc_service_state (applet, rc_service_stopped))
165 return (false);
166
167 if (! (mtime = get_mtime (mtime_test, false)))
168 return (false);
169
170 while (tests[i]) {
171 path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL);
172 if (rc_exists (path)) {
173 time_t m = get_mtime (path, false);
174 if (mtime < m && m != 0) {
175 free (path);
176 return (false);
177 }
178 }
179 free (path);
180 i++;
181 }
182
183 return (true);
184 }
185
186 static void uncoldplug (char *service)
187 {
188 char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", basename (service),
189 (char *) NULL);
190 if (rc_exists (cold) && unlink (cold) != 0)
191 eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
192 free (cold);
193 }
194
195 static void cleanup (void)
196 {
197 /* Flush our buffered output if any */
198 eflush ();
199
200 if (hook_out)
201 rc_plugin_run (hook_out, applet);
202 rc_plugin_unload ();
203
204 if (deptree)
205 rc_free_deptree (deptree);
206 if (services)
207 rc_strlist_free (services);
208 if (types)
209 rc_strlist_free (types);
210 if (svclist)
211 rc_strlist_free (svclist);
212 if (providelist)
213 rc_strlist_free (providelist);
214 if (restart_services)
215 rc_strlist_free (restart_services);
216 if (need_services)
217 rc_strlist_free (need_services);
218 if (tmplist)
219 rc_strlist_free (tmplist);
220 if (mycmd)
221 free (mycmd);
222 if (myarg1)
223 free (myarg1);
224 if (myarg2)
225 free (myarg2);
226 if (ibsave)
227 free (ibsave);
228
229 if (in_control ()) {
230 if (rc_service_state (applet, rc_service_stopping)) {
231 /* If the we're shutting down, do it cleanly */
232 if ((softlevel &&
233 rc_runlevel_stopping () &&
234 (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
235 strcmp (softlevel, RC_LEVEL_REBOOT) == 0)))
236 rc_mark_service (applet, rc_service_stopped);
237 else if (rc_service_state (applet, rc_service_wasinactive))
238 rc_mark_service (applet, rc_service_inactive);
239 else
240 rc_mark_service (applet, rc_service_started);
241 }
242 else if (rc_service_state (applet, rc_service_starting))
243 {
244 if (rc_service_state (applet, rc_service_wasinactive))
245 rc_mark_service (applet, rc_service_inactive);
246 else
247 rc_mark_service (applet, rc_service_stopped);
248 }
249 if (exclusive && rc_exists (exclusive))
250 unlink (exclusive);
251 }
252
253 if (env)
254 rc_strlist_free (env);
255
256 if (mtime_test)
257 {
258 unlink (mtime_test);
259 free (mtime_test);
260 }
261 if (exclusive)
262 free (exclusive);
263
264 if (applet)
265 free (applet);
266 }
267
268 static bool svc_exec (const char *service, const char *arg1, const char *arg2)
269 {
270 int status = 0;
271 pid_t pid;
272
273 /* We need to disable our child signal handler now so we block
274 until our script returns. */
275 signal (SIGCHLD, NULL);
276
277 pid = fork();
278
279 if (pid == -1)
280 eerrorx ("%s: fork: %s", service, strerror (errno));
281 if (pid == 0) {
282 mycmd = rc_xstrdup (service);
283 myarg1 = rc_xstrdup (arg1);
284 if (arg2)
285 myarg2 = rc_xstrdup (arg2);
286
287 if (rc_exists (RC_SVCDIR "runscript.sh")) {
288 execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2,
289 (char *) NULL);
290 eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
291 service, strerror (errno));
292 } else {
293 execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2,
294 (char *) NULL);
295 eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
296 service, strerror (errno));
297 }
298 }
299
300 do {
301 if (waitpid (pid, &status, 0) < 0) {
302 if (errno != ECHILD)
303 eerror ("waitpid: %s", strerror (errno));
304 break;
305 }
306 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
307
308 /* Done, so restore the signal handler */
309 signal (SIGCHLD, handle_signal);
310
311 if (WIFEXITED (status))
312 return (WEXITSTATUS (status) ? false : true);
313
314 return (false);
315 }
316
317 static rc_service_state_t svc_status (const char *service)
318 {
319 char status[10];
320 int (*e) (const char *fmt, ...) = &einfo;
321
322 rc_service_state_t retval = rc_service_stopped;
323
324 if (rc_service_state (service, rc_service_stopping)) {
325 snprintf (status, sizeof (status), "stopping");
326 e = &ewarn;
327 retval = rc_service_stopping;
328 } else if (rc_service_state (service, rc_service_starting)) {
329 snprintf (status, sizeof (status), "starting");
330 e = &ewarn;
331 retval = rc_service_starting;
332 } else if (rc_service_state (service, rc_service_inactive)) {
333 snprintf (status, sizeof (status), "inactive");
334 e = &ewarn;
335 retval = rc_service_inactive;
336 } else if (rc_service_state (service, rc_service_crashed)) {
337 snprintf (status, sizeof (status), "crashed");
338 e = &eerror;
339 retval = rc_service_crashed;
340 } else if (rc_service_state (service, rc_service_started)) {
341 snprintf (status, sizeof (status), "started");
342 retval = rc_service_started;
343 } else
344 snprintf (status, sizeof (status), "stopped");
345
346 e ("status: %s", status);
347 return (retval);
348 }
349
350 static void make_exclusive (const char *service)
351 {
352 char *path;
353 int i;
354
355 /* We create a fifo so that other services can wait until we complete */
356 if (! exclusive)
357 exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
358
359 if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST &&
360 (errno != EACCES || geteuid () == 0))
361 eerrorx ("%s: unable to create fifo `%s': %s",
362 applet, exclusive, strerror (errno));
363
364 path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
365 i = strlen (path) + 16;
366 mtime_test = rc_xmalloc (sizeof (char *) * i);
367 snprintf (mtime_test, i, "%s.%d", path, getpid ());
368 free (path);
369
370 if (rc_exists (mtime_test) && unlink (mtime_test) != 0) {
371 eerror ("%s: unlink `%s': %s",
372 applet, mtime_test, strerror (errno));
373 free (mtime_test);
374 mtime_test = NULL;
375 return;
376 }
377
378 if (symlink (service, mtime_test) != 0) {
379 eerror ("%s: symlink `%s' to `%s': %s",
380 applet, service, mtime_test, strerror (errno));
381 free (mtime_test);
382 mtime_test = NULL;
383 }
384 }
385
386 static void unlink_mtime_test ()
387 {
388 if (unlink (mtime_test) != 0)
389 eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno));
390 free (mtime_test);
391 mtime_test = NULL;
392 }
393
394 static void get_started_services ()
395 {
396 char *service;
397 int i;
398
399 rc_strlist_free (tmplist);
400 tmplist = rc_services_in_state (rc_service_inactive);
401
402 rc_strlist_free (restart_services);
403 restart_services = rc_services_in_state (rc_service_started);
404
405 STRLIST_FOREACH (tmplist, service, i)
406 restart_services = rc_strlist_addsort (restart_services, service);
407
408 rc_strlist_free (tmplist);
409 tmplist = NULL;
410 }
411
412 static void svc_start (const char *service, bool deps)
413 {
414 bool started;
415 bool background = false;
416 char *svc;
417 char *svc2;
418 int i;
419 int j;
420 int depoptions = RC_DEP_TRACE;
421
422 rc_plugin_run (rc_hook_service_start_in, applet);
423 hook_out = rc_hook_service_start_out;
424
425 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
426 depoptions |= RC_DEP_STRICT;
427
428 if (rc_is_env ("IN_HOTPLUG", "1") || in_background) {
429 if (! rc_service_state (service, rc_service_inactive) &&
430 ! rc_service_state (service, rc_service_stopped))
431 exit (EXIT_FAILURE);
432 background = true;
433 }
434
435 if (rc_service_state (service, rc_service_started))
436 ewarnx ("WARNING: %s has already been started", applet);
437 else if (rc_service_state (service, rc_service_starting))
438 ewarnx ("WARNING: %s is already starting", applet);
439 else if (rc_service_state (service, rc_service_stopping))
440 ewarnx ("WARNING: %s is stopping", applet);
441 else if (rc_service_state (service, rc_service_inactive) && ! background)
442 ewarnx ("WARNING: %s has already started, but is inactive", applet);
443
444 if (! rc_mark_service (service, rc_service_starting))
445 eerrorx ("ERROR: %s has been started by something else", applet);
446
447 make_exclusive (service);
448
449 if (deps) {
450 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
451 eerrorx ("failed to load deptree");
452
453 rc_strlist_free (types);
454 types = rc_strlist_add (NULL, "broken");
455 rc_strlist_free (svclist);
456 svclist = rc_strlist_add (NULL, applet);
457 rc_strlist_free (services);
458 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
459 if (services) {
460 eerrorn ("ERROR: `%s' needs ", applet);
461 STRLIST_FOREACH (services, svc, i) {
462 if (i > 0)
463 fprintf (stderr, ", ");
464 fprintf (stderr, "%s", svc);
465 }
466 exit (EXIT_FAILURE);
467 }
468 rc_strlist_free (services);
469 services = NULL;
470
471 rc_strlist_free (types);
472 types = rc_strlist_add (NULL, "ineed");
473 rc_strlist_free (need_services);
474 need_services = rc_get_depends (deptree, types, svclist,
475 softlevel, depoptions);
476 types = rc_strlist_add (types, "iuse");
477 if (! rc_runlevel_starting ()) {
478 services = rc_get_depends (deptree, types, svclist,
479 softlevel, depoptions);
480 STRLIST_FOREACH (services, svc, i)
481 if (rc_service_state (svc, rc_service_stopped))
482 rc_start_service (svc);
483
484 rc_strlist_free (services);
485 }
486
487 /* Now wait for them to start */
488 types = rc_strlist_add (types, "iafter");
489 services = rc_get_depends (deptree, types, svclist,
490 softlevel, depoptions);
491
492 /* We use tmplist to hold our scheduled by list */
493 rc_strlist_free (tmplist);
494 tmplist = NULL;
495
496 STRLIST_FOREACH (services, svc, i) {
497 if (rc_service_state (svc, rc_service_started))
498 continue;
499 if (! rc_wait_service (svc))
500 eerror ("%s: timed out waiting for %s", applet, svc);
501 if (rc_service_state (svc, rc_service_started))
502 continue;
503
504 STRLIST_FOREACH (need_services, svc2, j)
505 if (strcmp (svc, svc2) == 0) {
506 if (rc_service_state (svc, rc_service_inactive) ||
507 rc_service_state (svc, rc_service_wasinactive))
508 tmplist = rc_strlist_add (tmplist, svc);
509 else
510 eerrorx ("ERROR: cannot start %s as %s would not start",
511 applet, svc);
512 }
513 }
514
515 if (tmplist) {
516 int n = 0;
517 int len = 0;
518 char *p;
519
520 /* Set the state now, then unlink our exclusive so that
521 our scheduled list is preserved */
522 rc_mark_service (service, rc_service_stopped);
523 unlink_mtime_test ();
524
525 rc_strlist_free (types);
526 types = rc_strlist_add (NULL, "iprovide");
527 STRLIST_FOREACH (tmplist, svc, i) {
528 rc_schedule_start_service (svc, service);
529
530 rc_strlist_free (svclist);
531 svclist = rc_strlist_add (NULL, svc);
532 rc_strlist_free (providelist);
533 providelist = rc_get_depends (deptree, types, svclist,
534 softlevel, depoptions);
535 STRLIST_FOREACH (providelist, svc2, j)
536 rc_schedule_start_service (svc2, service);
537
538 len += strlen (svc) + 2;
539 n++;
540 }
541
542 len += 5;
543 tmp = rc_xmalloc (sizeof (char *) * len);
544 p = tmp;
545 STRLIST_FOREACH (tmplist, svc, i) {
546 if (i > 1) {
547 if (i == n - 1)
548 p += snprintf (p, len, " or ");
549 else
550 p += snprintf (p, len, ", ");
551 }
552 p += snprintf (p, len, "%s", svc);
553 }
554 ewarnx ("WARNING: %s is scheduled to start when %s has started",
555 applet, tmp);
556 }
557
558 rc_strlist_free (services);
559 services = NULL;
560 rc_strlist_free (types);
561 types = NULL;
562 rc_strlist_free (svclist);
563 svclist = NULL;
564 }
565
566 if (ibsave)
567 setenv ("IN_BACKGROUND", ibsave, 1);
568 rc_plugin_run (rc_hook_service_start_now, applet);
569 started = svc_exec (service, "start", NULL);
570 if (ibsave)
571 unsetenv ("IN_BACKGROUND");
572
573 if (in_control ()) {
574 if (! started) {
575 if (rc_service_state (service, rc_service_wasinactive))
576 rc_mark_service (service, rc_service_inactive);
577 else {
578 rc_mark_service (service, rc_service_stopped);
579 if (rc_runlevel_starting ())
580 rc_mark_service (service, rc_service_failed);
581 }
582 rc_plugin_run (rc_hook_service_start_done, applet);
583 eerrorx ("ERROR: %s failed to start", applet);
584 }
585 rc_mark_service (service, rc_service_started);
586 unlink_mtime_test ();
587 rc_plugin_run (rc_hook_service_start_done, applet);
588 } else {
589 rc_plugin_run (rc_hook_service_start_done, applet);
590 if (rc_service_state (service, rc_service_inactive))
591 ewarnx ("WARNING: %s has started, but is inactive", applet);
592 else
593 ewarnx ("WARNING: %s not under our control, aborting", applet);
594 }
595
596 /* Now start any scheduled services */
597 rc_strlist_free (services);
598 services = rc_services_scheduled (service);
599 STRLIST_FOREACH (services, svc, i)
600 if (rc_service_state (svc, rc_service_stopped))
601 rc_start_service (svc);
602 rc_strlist_free (services);
603 services = NULL;
604
605 /* Do the same for any services we provide */
606 rc_strlist_free (types);
607 types = rc_strlist_add (NULL, "iprovide");
608 rc_strlist_free (svclist);
609 svclist = rc_strlist_add (NULL, applet);
610 rc_strlist_free (tmplist);
611 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
612
613 STRLIST_FOREACH (tmplist, svc2, j) {
614 rc_strlist_free (services);
615 services = rc_services_scheduled (svc2);
616 STRLIST_FOREACH (services, svc, i)
617 if (rc_service_state (svc, rc_service_stopped))
618 rc_start_service (svc);
619 }
620
621 hook_out = 0;
622 rc_plugin_run (rc_hook_service_start_out, applet);
623 }
624
625 static void svc_stop (const char *service, bool deps)
626 {
627 bool stopped;
628
629 hook_out = rc_hook_service_stop_out;
630
631 if (rc_runlevel_stopping () &&
632 rc_service_state (service, rc_service_failed))
633 exit (EXIT_FAILURE);
634
635 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
636 if (! rc_service_state (service, rc_service_started) &&
637 ! rc_service_state (service, rc_service_inactive))
638 exit (EXIT_FAILURE);
639
640 if (rc_service_state (service, rc_service_stopped))
641 ewarnx ("WARNING: %s is already stopped", applet);
642 else if (rc_service_state (service, rc_service_stopping))
643 ewarnx ("WARNING: %s is already stopping", applet);
644
645 if (! rc_mark_service (service, rc_service_stopping))
646 eerrorx ("ERROR: %s has been stopped by something else", applet);
647
648 make_exclusive (service);
649
650 if (! rc_runlevel_stopping () &&
651 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
652 ewarn ("WARNING: you are stopping a boot service");
653
654 if (deps || ! rc_service_state (service, rc_service_wasinactive)) {
655 int depoptions = RC_DEP_TRACE;
656 char *svc;
657 int i;
658
659 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
660 depoptions |= RC_DEP_STRICT;
661
662 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
663 eerrorx ("failed to load deptree");
664
665 rc_strlist_free (types);
666 types = rc_strlist_add (NULL, "needsme");
667 rc_strlist_free (svclist);
668 svclist = rc_strlist_add (NULL, applet);
669 rc_strlist_free (tmplist);
670 tmplist = NULL;
671 rc_strlist_free (services);
672 services = rc_get_depends (deptree, types, svclist,
673 softlevel, depoptions);
674 rc_strlist_reverse (services);
675 STRLIST_FOREACH (services, svc, i) {
676 if (rc_service_state (svc, rc_service_started) ||
677 rc_service_state (svc, rc_service_inactive))
678 {
679 rc_wait_service (svc);
680 if (rc_service_state (svc, rc_service_started) ||
681 rc_service_state (svc, rc_service_inactive))
682 {
683 rc_stop_service (svc);
684 tmplist = rc_strlist_add (tmplist, svc);
685 }
686 }
687 }
688 rc_strlist_free (services);
689 services = NULL;
690
691 STRLIST_FOREACH (tmplist, svc, i) {
692 if (rc_service_state (svc, rc_service_stopped))
693 continue;
694
695 /* We used to loop 3 times here - maybe re-do this if needed */
696 rc_wait_service (svc);
697 if (! rc_service_state (svc, rc_service_stopped)) {
698 if (rc_runlevel_stopping ())
699 rc_mark_service (svc, rc_service_failed);
700 eerrorx ("ERROR: cannot stop %s as %s is still up",
701 applet, svc);
702 }
703 }
704 rc_strlist_free (tmplist);
705 tmplist = NULL;
706
707 /* We now wait for other services that may use us and are stopping
708 This is important when a runlevel stops */
709 types = rc_strlist_add (types, "usesme");
710 types = rc_strlist_add (types, "ibefore");
711 services = rc_get_depends (deptree, types, svclist,
712 softlevel, depoptions);
713 STRLIST_FOREACH (services, svc, i) {
714 if (rc_service_state (svc, rc_service_stopped))
715 continue;
716 rc_wait_service (svc);
717 }
718
719 rc_strlist_free (services);
720 services = NULL;
721 rc_strlist_free (types);
722 types = NULL;
723 }
724
725 if (ibsave)
726 setenv ("IN_BACKGROUND", ibsave, 1);
727 rc_plugin_run (rc_hook_service_stop_now, applet);
728 stopped = svc_exec (service, "stop", NULL);
729 if (ibsave)
730 unsetenv ("IN_BACKGROUND");
731
732 if (! in_control ()) {
733 rc_plugin_run (rc_hook_service_stop_done, applet);
734 ewarnx ("WARNING: %s not under our control, aborting", applet);
735 }
736
737 if (! stopped) {
738 if (rc_service_state (service, rc_service_wasinactive))
739 rc_mark_service (service, rc_service_inactive);
740 else
741 rc_mark_service (service, rc_service_started);
742 rc_plugin_run (rc_hook_service_stop_done, applet);
743 eerrorx ("ERROR: %s failed to stop", applet);
744 }
745
746 if (in_background)
747 rc_mark_service (service, rc_service_inactive);
748 else
749 rc_mark_service (service, rc_service_stopped);
750
751 unlink_mtime_test ();
752 rc_plugin_run (rc_hook_service_stop_done, applet);
753 hook_out = 0;
754 rc_plugin_run (rc_hook_service_stop_out, applet);
755 }
756
757 static void svc_restart (const char *service, bool deps)
758 {
759 char *svc;
760 int i;
761 bool inactive = false;
762
763 /* This is hairly and a better way needs to be found I think!
764 The issue is this - openvpn need net and dns. net can restart
765 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
766 which in turn is waiting on net which in turn is waiting on dnsmasq.
767 The work around is for resolvconf to restart it's services with --nodeps
768 which means just that. The downside is that there is a small window when
769 our status is invalid.
770 One workaround would be to introduce a new status, or status locking. */
771 if (! deps) {
772 if (rc_service_state (service, rc_service_started) ||
773 rc_service_state (service, rc_service_inactive))
774 svc_exec (service, "stop", "start");
775 else
776 svc_exec (service, "start", NULL);
777 return;
778 }
779
780 if (! rc_service_state (service, rc_service_stopped)) {
781 get_started_services ();
782 svc_stop (service, deps);
783
784 /* Flush our buffered output if any */
785 eflush ();
786 }
787
788 svc_start (service, deps);
789
790 inactive = rc_service_state (service, rc_service_inactive);
791 if (! inactive)
792 inactive = rc_service_state (service, rc_service_wasinactive);
793
794 if (inactive ||
795 rc_service_state (service, rc_service_starting) ||
796 rc_service_state (service, rc_service_started))
797 {
798 STRLIST_FOREACH (restart_services, svc, i) {
799 if (rc_service_state (svc, rc_service_stopped)) {
800 if (inactive) {
801 rc_schedule_start_service (service, svc);
802 ewarn ("WARNING: %s is scheduled to started when %s has started",
803 svc, basename (service));
804 } else
805 rc_start_service (svc);
806 }
807 }
808 }
809 }
810
811 int main (int argc, char **argv)
812 {
813 const char *service = argv[1];
814 int i;
815 bool deps = true;
816 bool doneone = false;
817 char pid[16];
818 int retval;
819 char c;
820
821 static struct option longopts[] = {
822 { "debug", 0, NULL, 'd'},
823 { "help", 0, NULL, 'h'},
824 { "nocolor", 0, NULL, 'C'},
825 { "nocolour", 0, NULL, 'C'},
826 { "nodeps", 0, NULL, 'D'},
827 { "verbose", 0, NULL, 'v'},
828 { NULL, 0, NULL, 0}
829 };
830
831 applet = strdup (basename (service));
832 atexit (cleanup);
833
834 /* Show help if insufficient args */
835 if (argc < 3) {
836 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
837 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
838 applet, strerror (errno));
839 }
840
841 #ifdef __linux__
842 /* coldplug events can trigger init scripts, but we don't want to run them
843 until after rc sysinit has completed so we punt them to the boot runlevel */
844 if (rc_exists ("/dev/.rcsysinit")) {
845 eerror ("%s: cannot run until sysvinit completes", applet);
846 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
847 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
848 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
849 symlink (service, tmp);
850 exit (EXIT_FAILURE);
851 }
852 #endif
853
854 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
855 /* Ensure our environment is pure
856 Also, add our configuration to it */
857 env = rc_filter_env ();
858 env = rc_config_env (env);
859
860 if (env) {
861 char *p;
862
863 #ifdef __linux__
864 /* clearenv isn't portable, but there's no harm in using it
865 if we have it */
866 clearenv ();
867 #else
868 char *var;
869 /* No clearenv present here then.
870 We could manipulate environ directly ourselves, but it seems that
871 some kernels bitch about this according to the environ man pages
872 so we walk though environ and call unsetenv for each value. */
873 while (environ[0]) {
874 tmp = rc_xstrdup (environ[0]);
875 p = tmp;
876 var = strsep (&p, "=");
877 unsetenv (var);
878 free (tmp);
879 }
880 tmp = NULL;
881 #endif
882
883 STRLIST_FOREACH (env, p, i)
884 putenv (p);
885
886 /* We don't free our list as that would be null in environ */
887 }
888
889 softlevel = rc_get_runlevel ();
890
891 /* If not called from RC or another service then don't be parallel */
892 unsetenv ("RC_PARALLEL_STARTUP");
893 }
894
895 setenv ("RC_ELOG", service, 1);
896 setenv ("SVCNAME", applet, 1);
897
898 /* Set an env var so that we always know our pid regardless of any
899 subshells the init script may create so that our mark_service_*
900 functions can always instruct us of this change */
901 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
902 setenv ("RC_RUNSCRIPT_PID", pid, 1);
903
904 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) {
905 char ebname[PATH_MAX];
906 char *eb;
907
908 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
909 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
910 setenv ("RC_EBUFFER", eb, 1);
911 free (eb);
912 }
913
914 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
915 that is being called and not any dependents */
916 if (getenv ("IN_BACKGROUND")) {
917 in_background = rc_is_env ("IN_BACKGROUND", "true");
918 ibsave = strdup (getenv ("IN_BACKGROUND"));
919 unsetenv ("IN_BACKGROUND");
920 }
921
922 #ifdef __linux__
923 /* Ok, we are ready to go, so setup selinux if applicable */
924 setup_selinux (argc, argv);
925 #endif
926
927 /* Right then, parse any options there may be */
928 while ((c = getopt_long (argc, argv, "dhCDNqv",
929 longopts, (int *) 0)) != -1)
930 switch (c) {
931 case 'd':
932 setenv ("RC_DEBUG", "yes", 1);
933 break;
934 case 'h':
935 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
936 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
937 applet, strerror (errno));
938 case 'C':
939 setenv ("RC_NOCOLOR", "yes", 1);
940 break;
941 case 'D':
942 deps = false;
943 break;
944 case 'q':
945 setenv ("RC_QUIET", "yes", 1);
946 break;
947 case 'v':
948 setenv ("RC_VERBOSE", "yes", 1);
949 break;
950 default:
951 exit (EXIT_FAILURE);
952 }
953
954 if (rc_is_env ("IN_HOTPLUG", "1")) {
955 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
956 eerrorx ("%s: not allowed to be hotplugged", applet);
957 }
958
959 /* Setup a signal handler */
960 signal (SIGHUP, handle_signal);
961 signal (SIGINT, handle_signal);
962 signal (SIGQUIT, handle_signal);
963 signal (SIGTERM, handle_signal);
964 signal (SIGCHLD, handle_signal);
965
966 /* Load our plugins */
967 rc_plugin_load ();
968
969 /* Now run each option */
970 retval = EXIT_SUCCESS;
971 while (optind < argc) {
972 optarg = argv[optind++];
973
974 /* Abort on a sighup here */
975 if (sighup)
976 exit (EXIT_FAILURE);
977
978 /* Export the command we're running.
979 This is important as we stamp on the restart function now but
980 some start/stop routines still need to behave differently if
981 restarting. */
982 unsetenv ("RC_CMD");
983 setenv ("RC_CMD", optarg, 1);
984
985 doneone = true;
986 if (strcmp (optarg, "conditionalrestart") == 0 ||
987 strcmp (optarg, "condrestart") == 0)
988 {
989 if (rc_service_state (service, rc_service_started))
990 svc_restart (service, deps);
991 }
992 else if (strcmp (optarg, "restart") == 0)
993 svc_restart (service, deps);
994 else if (strcmp (optarg, "start") == 0)
995 svc_start (service, deps);
996 else if (strcmp (optarg, "status") == 0) {
997 rc_service_state_t r = svc_status (service);
998 retval = (int) r;
999 } else if (strcmp (optarg, "stop") == 0) {
1000 if (in_background)
1001 get_started_services ();
1002
1003 svc_stop (service, deps);
1004
1005 if (! in_background &&
1006 ! rc_runlevel_stopping () &&
1007 rc_service_state (service, rc_service_stopped))
1008 uncoldplug (applet);
1009
1010 if (in_background &&
1011 rc_service_state (service, rc_service_inactive))
1012 {
1013 char *svc;
1014 int j;
1015 STRLIST_FOREACH (restart_services, svc, j)
1016 if (rc_service_state (svc, rc_service_stopped))
1017 rc_schedule_start_service (service, svc);
1018 }
1019 } else if (strcmp (optarg, "zap") == 0) {
1020 einfo ("Manually resetting %s to stopped state", applet);
1021 rc_mark_service (applet, rc_service_stopped);
1022 uncoldplug (applet);
1023 } else if (strcmp (optarg, "help") == 0) {
1024 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1025 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1026 applet, strerror (errno));
1027 }else
1028 svc_exec (service, optarg, NULL);
1029
1030 /* Flush our buffered output if any */
1031 eflush ();
1032
1033 /* We should ensure this list is empty after an action is done */
1034 rc_strlist_free (restart_services);
1035 restart_services = NULL;
1036 }
1037
1038 if (! doneone) {
1039 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1040 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1041 applet, strerror (errno));
1042 }
1043
1044 return (retval);
1045 }

  ViewVC Help
Powered by ViewVC 1.1.20