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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20