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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20