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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20