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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20