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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2573 - (show annotations) (download) (as text)
Wed Apr 11 07:15:02 2007 UTC (7 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 32615 byte(s)
Add new service hooks, remove pmake stuff from our Makefile and fix rc_services_in_state for scheduled.
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 rc_plugin_run (rc_hook_service_start_in, applet);
449 hook_out = rc_hook_service_start_out;
450
451 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
452 depoptions |= RC_DEP_STRICT;
453
454 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
455 {
456 if (! rc_service_state (service, rc_service_inactive))
457 exit (EXIT_FAILURE);
458 background = true;
459 }
460
461 if (rc_service_state (service, rc_service_started))
462 ewarnx ("WARNING: %s has already been started", applet);
463 else if (rc_service_state (service, rc_service_starting))
464 ewarnx ("WARNING: %s is already starting", applet);
465 else if (rc_service_state (service, rc_service_stopping))
466 ewarnx ("WARNING: %s is stopping", applet);
467 else if (rc_service_state (service, rc_service_inactive) && ! background)
468 ewarnx ("WARNING: %s has already started, but is inactive", applet);
469
470 if (! rc_mark_service (service, rc_service_starting))
471 eerrorx ("ERROR: %s has been started by something else", applet);
472
473 make_exclusive (service);
474
475 if (deps)
476 {
477 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
478 eerrorx ("failed to load deptree");
479
480 rc_strlist_free (types);
481 types = rc_strlist_add (NULL, "broken");
482 rc_strlist_free (svclist);
483 svclist = rc_strlist_add (NULL, applet);
484 rc_strlist_free (services);
485 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
486 if (services)
487 {
488 eerrorn ("ERROR: `%s' needs ", applet);
489 STRLIST_FOREACH (services, svc, i)
490 {
491 if (i > 0)
492 fprintf (stderr, ", ");
493 fprintf (stderr, "%s", svc);
494 }
495 exit (EXIT_FAILURE);
496 }
497 rc_strlist_free (services);
498 services = NULL;
499
500 rc_strlist_free (types);
501 types = rc_strlist_add (NULL, "ineed");
502 rc_strlist_free (need_services);
503 need_services = rc_get_depends (deptree, types, svclist,
504 softlevel, depoptions);
505 types = rc_strlist_add (types, "iuse");
506 if (! rc_runlevel_starting ())
507 {
508 services = rc_get_depends (deptree, types, svclist,
509 softlevel, depoptions);
510 STRLIST_FOREACH (services, svc, i)
511 if (rc_service_state (svc, rc_service_stopped))
512 rc_start_service (svc);
513
514 rc_strlist_free (services);
515 }
516
517 /* Now wait for them to start */
518 types = rc_strlist_add (types, "iafter");
519 services = rc_get_depends (deptree, types, svclist,
520 softlevel, depoptions);
521
522 /* We use tmplist to hold our scheduled by list */
523 rc_strlist_free (tmplist);
524 tmplist = NULL;
525
526 STRLIST_FOREACH (services, svc, i)
527 {
528 if (rc_service_state (svc, rc_service_started))
529 continue;
530 if (! rc_wait_service (svc))
531 eerror ("%s: timed out waiting for %s", applet, svc);
532 if (rc_service_state (svc, rc_service_started))
533 continue;
534
535 STRLIST_FOREACH (need_services, svc2, j)
536 if (strcmp (svc, svc2) == 0)
537 {
538 if (rc_service_state (svc, rc_service_inactive) ||
539 rc_service_state (svc, rc_service_wasinactive))
540 tmplist = rc_strlist_add (tmplist, svc);
541 else
542 eerrorx ("ERROR: cannot start %s as %s would not start",
543 applet, svc);
544 }
545 }
546
547 if (tmplist)
548 {
549 int n = 0;
550 int len = 0;
551 char *p;
552
553 /* Set the state now, then unlink our exclusive so that
554 our scheduled list is preserved */
555 rc_mark_service (service, rc_service_stopped);
556 unlink_mtime_test ();
557
558 rc_strlist_free (types);
559 types = rc_strlist_add (NULL, "iprovide");
560 STRLIST_FOREACH (tmplist, svc, i)
561 {
562 rc_schedule_start_service (svc, service);
563
564 rc_strlist_free (svclist);
565 svclist = rc_strlist_add (NULL, svc);
566 rc_strlist_free (providelist);
567 providelist = rc_get_depends (deptree, types, svclist,
568 softlevel, depoptions);
569 STRLIST_FOREACH (providelist, svc2, j)
570 rc_schedule_start_service (svc2, service);
571
572 len += strlen (svc) + 2;
573 n++;
574 }
575
576 len += 5;
577 tmp = rc_xmalloc (sizeof (char *) * len);
578 p = tmp;
579 STRLIST_FOREACH (tmplist, svc, i)
580 {
581 if (i > 1)
582 {
583 if (i == n - 1)
584 p += snprintf (p, len, " or ");
585 else
586 p += snprintf (p, len, ", ");
587 }
588 p += snprintf (p, len, "%s", svc);
589 }
590 ewarnx ("WARNING: %s is scheduled to start when %s has started",
591 applet, tmp);
592 }
593
594 rc_strlist_free (services);
595 services = NULL;
596 rc_strlist_free (types);
597 types = NULL;
598 rc_strlist_free (svclist);
599 svclist = NULL;
600 }
601
602 if (ibsave)
603 setenv ("IN_BACKGROUND", ibsave, 1);
604 rc_plugin_run (rc_hook_service_start_now, applet);
605 started = svc_exec (service, "start", NULL);
606 if (ibsave)
607 unsetenv ("IN_BACKGROUND");
608
609 if (in_control ())
610 {
611 if (! started)
612 {
613 if (rc_service_state (service, rc_service_wasinactive))
614 rc_mark_service (service, rc_service_inactive);
615 else
616 {
617 rc_mark_service (service, rc_service_stopped);
618 if (rc_runlevel_starting ())
619 rc_mark_service (service, rc_service_failed);
620 }
621 rc_plugin_run (rc_hook_service_start_done, applet);
622 eerrorx ("ERROR: %s failed to start", applet);
623 }
624 rc_mark_service (service, rc_service_started);
625 unlink_mtime_test ();
626 rc_plugin_run (rc_hook_service_start_done, applet);
627 }
628 else
629 {
630 rc_plugin_run (rc_hook_service_start_done, applet);
631 if (rc_service_state (service, rc_service_inactive))
632 ewarnx ("WARNING: %s has started, but is inactive", applet);
633 else
634 ewarnx ("WARNING: %s not under our control, aborting", applet);
635 }
636
637 /* Now start any scheduled services */
638 rc_strlist_free (services);
639 services = rc_services_scheduled (service);
640 STRLIST_FOREACH (services, svc, i)
641 if (rc_service_state (svc, rc_service_stopped))
642 rc_start_service (svc);
643 rc_strlist_free (services);
644 services = NULL;
645
646 /* Do the same for any services we provide */
647 rc_strlist_free (types);
648 types = rc_strlist_add (NULL, "iprovide");
649 rc_strlist_free (svclist);
650 svclist = rc_strlist_add (NULL, applet);
651 rc_strlist_free (tmplist);
652 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
653
654 STRLIST_FOREACH (tmplist, svc2, j)
655 {
656 rc_strlist_free (services);
657 services = rc_services_scheduled (svc2);
658 STRLIST_FOREACH (services, svc, i)
659 if (rc_service_state (svc, rc_service_stopped))
660 rc_start_service (svc);
661 }
662
663 hook_out = 0;
664 rc_plugin_run (rc_hook_service_start_out, applet);
665 }
666
667 static void svc_stop (const char *service, bool deps)
668 {
669 bool stopped;
670
671 hook_out = rc_hook_service_stop_out;
672
673 if (rc_runlevel_stopping () &&
674 rc_service_state (service, rc_service_failed))
675 exit (EXIT_FAILURE);
676
677 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
678 if (! rc_service_state (service, rc_service_started))
679 exit (EXIT_FAILURE);
680
681 if (rc_service_state (service, rc_service_stopped))
682 ewarnx ("WARNING: %s is already stopped", applet);
683 else if (rc_service_state (service, rc_service_stopping))
684 ewarnx ("WARNING: %s is already stopping", applet);
685
686 if (! rc_mark_service (service, rc_service_stopping))
687 eerrorx ("ERROR: %s has been stopped by something else", applet);
688
689 make_exclusive (service);
690
691 if (! rc_runlevel_stopping () &&
692 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
693 ewarn ("WARNING: you are stopping a boot service");
694
695 if (deps || ! rc_service_state (service, rc_service_wasinactive))
696 {
697 int depoptions = RC_DEP_TRACE;
698 char *svc;
699 int i;
700
701 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
702 depoptions |= RC_DEP_STRICT;
703
704 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
705 eerrorx ("failed to load deptree");
706
707 rc_strlist_free (types);
708 types = rc_strlist_add (NULL, "needsme");
709 rc_strlist_free (svclist);
710 svclist = rc_strlist_add (NULL, applet);
711 rc_strlist_free (tmplist);
712 tmplist = NULL;
713 rc_strlist_free (services);
714 services = rc_get_depends (deptree, types, svclist,
715 softlevel, depoptions);
716 rc_strlist_reverse (services);
717 STRLIST_FOREACH (services, svc, i)
718 {
719 if (rc_service_state (svc, rc_service_started) ||
720 rc_service_state (svc, rc_service_inactive))
721 {
722 rc_wait_service (svc);
723 if (rc_service_state (svc, rc_service_started) ||
724 rc_service_state (svc, rc_service_inactive))
725 {
726 rc_stop_service (svc);
727 tmplist = rc_strlist_add (tmplist, svc);
728 }
729 }
730 }
731 rc_strlist_free (services);
732 services = NULL;
733
734 STRLIST_FOREACH (tmplist, svc, i)
735 {
736 if (rc_service_state (svc, rc_service_stopped))
737 continue;
738
739 /* We used to loop 3 times here - maybe re-do this if needed */
740 rc_wait_service (svc);
741 if (! rc_service_state (svc, rc_service_stopped))
742 {
743 if (rc_runlevel_stopping ())
744 rc_mark_service (svc, rc_service_failed);
745 eerrorx ("ERROR: cannot stop %s as %s is still up",
746 applet, svc);
747 }
748 }
749 rc_strlist_free (tmplist);
750 tmplist = NULL;
751
752 /* We now wait for other services that may use us and are stopping
753 This is important when a runlevel stops */
754 types = rc_strlist_add (types, "usesme");
755 types = rc_strlist_add (types, "ibefore");
756 services = rc_get_depends (deptree, types, svclist,
757 softlevel, depoptions);
758 STRLIST_FOREACH (services, svc, i)
759 {
760 if (rc_service_state (svc, rc_service_stopped))
761 continue;
762 rc_wait_service (svc);
763 }
764
765 rc_strlist_free (services);
766 services = NULL;
767 rc_strlist_free (types);
768 types = NULL;
769 }
770
771 if (ibsave)
772 setenv ("IN_BACKGROUND", ibsave, 1);
773 rc_plugin_run (rc_hook_service_stop_now, applet);
774 stopped = svc_exec (service, "stop", NULL);
775 if (ibsave)
776 unsetenv ("IN_BACKGROUND");
777
778 if (! in_control ())
779 {
780 rc_plugin_run (rc_hook_service_stop_done, applet);
781 ewarnx ("WARNING: %s not under our control, aborting", applet);
782 }
783
784 if (! stopped)
785 {
786 if (rc_service_state (service, rc_service_wasinactive))
787 rc_mark_service (service, rc_service_inactive);
788 else
789 rc_mark_service (service, rc_service_started);
790 rc_plugin_run (rc_hook_service_stop_done, applet);
791 eerrorx ("ERROR: %s failed to stop", applet);
792 }
793
794 if (in_background)
795 rc_mark_service (service, rc_service_inactive);
796 else
797 rc_mark_service (service, rc_service_stopped);
798
799 unlink_mtime_test ();
800 rc_plugin_run (rc_hook_service_stop_done, applet);
801 hook_out = 0;
802 rc_plugin_run (rc_hook_service_stop_out, applet);
803 }
804
805 static void svc_restart (const char *service, bool deps)
806 {
807 char *svc;
808 int i;
809 bool inactive = false;
810
811 /* This is hairly and a better way needs to be found I think!
812 The issue is this - openvpn need net and dns. net can restart
813 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
814 which in turn is waiting on net which in turn is waiting on dnsmasq.
815 The work around is for resolvconf to restart it's services with --nodeps
816 which means just that. The downside is that there is a small window when
817 our status is invalid.
818 One workaround would be to introduce a new status, or status locking. */
819 if (! deps)
820 {
821 if (rc_service_state (service, rc_service_started) ||
822 rc_service_state (service, rc_service_inactive))
823 svc_exec (service, "stop", "start");
824 else
825 svc_exec (service, "start", NULL);
826 return;
827 }
828
829 if (! rc_service_state (service, rc_service_stopped))
830 {
831 get_started_services ();
832 svc_stop (service, deps);
833
834 /* Flush our buffered output if any */
835 eflush ();
836 }
837
838 svc_start (service, deps);
839
840 inactive = rc_service_state (service, rc_service_inactive);
841 if (! inactive)
842 inactive = rc_service_state (service, rc_service_wasinactive);
843
844 if (inactive ||
845 rc_service_state (service, rc_service_starting) ||
846 rc_service_state (service, rc_service_started))
847 {
848 STRLIST_FOREACH (restart_services, svc, i)
849 {
850 if (rc_service_state (svc, rc_service_stopped))
851 {
852 if (inactive)
853 {
854 rc_schedule_start_service (service, svc);
855 ewarn ("WARNING: %s is scheduled to started when %s has started",
856 svc, basename (service));
857 }
858 else
859 rc_start_service (svc);
860 }
861 }
862 }
863 }
864
865 int main (int argc, char **argv)
866 {
867 const char *service = argv[1];
868 int i;
869 bool deps = true;
870 bool doneone = false;
871 char pid[16];
872 int retval;
873 bool ifstarted = false;
874
875 applet = strdup (basename (service));
876 atexit (cleanup);
877
878 /* Show help if insufficient args */
879 if (argc < 3)
880 {
881 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
882 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
883 applet, strerror (errno));
884 }
885
886 #ifdef __linux__
887 /* coldplug events can trigger init scripts, but we don't want to run them
888 until after rc sysinit has completed so we punt them to the boot runlevel */
889 if (rc_exists ("/dev/.rcsysinit"))
890 {
891 eerror ("%s: cannot run until sysvinit completes", applet);
892 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
893 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
894 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
895 symlink (service, tmp);
896 exit (EXIT_FAILURE);
897 }
898 #endif
899
900 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL)
901 {
902 /* Ensure our environment is pure
903 Also, add our configuration to it */
904 env = rc_filter_env ();
905 env = rc_config_env (env);
906
907 if (env)
908 {
909 char *p;
910
911 #ifdef __linux__
912 /* clearenv isn't portable, but there's no harm in using it
913 if we have it */
914 clearenv ();
915 #else
916 char *var;
917 /* No clearenv present here then.
918 We could manipulate environ directly ourselves, but it seems that
919 some kernels bitch about this according to the environ man pages
920 so we walk though environ and call unsetenv for each value. */
921 while (environ[0])
922 {
923 tmp = rc_xstrdup (environ[0]);
924 p = tmp;
925 var = strsep (&p, "=");
926 unsetenv (var);
927 free (tmp);
928 }
929 tmp = NULL;
930 #endif
931
932 STRLIST_FOREACH (env, p, i)
933 putenv (p);
934
935 /* We don't free our list as that would be null in environ */
936 }
937
938 softlevel = rc_get_runlevel ();
939
940 /* If not called from RC or another service then don't be parallel */
941 unsetenv ("RC_PARALLEL_STARTUP");
942 }
943
944 setenv ("RC_ELOG", service, 1);
945 setenv ("SVCNAME", applet, 1);
946
947 /* Set an env var so that we always know our pid regardless of any
948 subshells the init script may create so that our mark_service_*
949 functions can always instruct us of this change */
950 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
951 setenv ("RC_RUNSCRIPT_PID", pid, 1);
952
953 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
954 {
955 char ebname[PATH_MAX];
956 char *eb;
957
958 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
959 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
960 setenv ("RC_EBUFFER", eb, 1);
961 free (eb);
962 }
963
964 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
965 that is being called and not any dependents */
966 if (getenv ("IN_BACKGROUND"))
967 {
968 in_background = rc_is_env ("IN_BACKGROUND", "true");
969 ibsave = strdup (getenv ("IN_BACKGROUND"));
970 unsetenv ("IN_BACKGROUND");
971 }
972
973 #ifdef __linux__
974 /* Ok, we are ready to go, so setup selinux if applicable */
975 setup_selinux (argc, argv);
976 #endif
977
978 /* Right then, parse any options there may be */
979 for (i = 2; i < argc; i++)
980 {
981 if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-')
982 continue;
983
984 if (strcmp (argv[i], "--debug") == 0)
985 setenv ("RC_DEBUG", "yes", 1);
986 else if (strcmp (argv[i], "--help") == 0)
987 {
988 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
989 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
990 applet, strerror (errno));
991 }
992 else if (strcmp (argv[i],"--ifstarted") == 0)
993 ifstarted = true;
994 else if (strcmp (argv[i], "--nocolour") == 0 ||
995 strcmp (argv[i], "--nocolor") == 0)
996 setenv ("RC_NOCOLOR", "yes", 1);
997 else if (strcmp (argv[i], "--nodeps") == 0)
998 deps = false;
999 else if (strcmp (argv[i], "--quiet") == 0)
1000 setenv ("RC_QUIET", "yes", 1);
1001 else if (strcmp (argv[i], "--verbose") == 0)
1002 setenv ("RC_VERBOSE", "yes", 1);
1003 else if (strcmp (argv[i], "--version") == 0)
1004 printf ("version me\n");
1005 else
1006 eerror ("%s: unknown option `%s'", applet, argv[i]);
1007 }
1008
1009 if (ifstarted && ! rc_service_state (applet, rc_service_started))
1010 {
1011 if (! rc_is_env("RC_QUIET", "yes"))
1012 eerror ("ERROR: %s is not started", applet);
1013 exit (EXIT_FAILURE);
1014 }
1015
1016 if (rc_is_env ("IN_HOTPLUG", "1"))
1017 {
1018 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1019 eerrorx ("%s: not allowed to be hotplugged", applet);
1020 }
1021
1022 /* Setup a signal handler */
1023 signal (SIGHUP, handle_signal);
1024 signal (SIGINT, handle_signal);
1025 signal (SIGQUIT, handle_signal);
1026 signal (SIGTERM, handle_signal);
1027 signal (SIGCHLD, handle_signal);
1028
1029 /* Load our plugins */
1030 rc_plugin_load ();
1031
1032 /* Now run each option */
1033 retval = EXIT_SUCCESS;
1034 for (i = 2; i < argc; i++)
1035 {
1036 /* Abort on a sighup here */
1037 if (sighup)
1038 exit (EXIT_FAILURE);
1039
1040 if (strlen (argv[i]) < 2 ||
1041 (argv[i][0] == '-' && argv[i][1] == '-'))
1042 continue;
1043
1044 /* Export the command we're running.
1045 This is important as we stamp on the restart function now but
1046 some start/stop routines still need to behave differently if
1047 restarting. */
1048 unsetenv ("RC_CMD");
1049 setenv ("RC_CMD", argv[i], 1);
1050
1051 doneone = true;
1052 if (strcmp (argv[i], "conditionalrestart") == 0 ||
1053 strcmp (argv[i], "condrestart") == 0)
1054 {
1055 if (rc_service_state (service, rc_service_started))
1056 svc_restart (service, deps);
1057 }
1058 else if (strcmp (argv[i], "restart") == 0)
1059 svc_restart (service, deps);
1060 else if (strcmp (argv[i], "start") == 0)
1061 svc_start (service, deps);
1062 else if (strcmp (argv[i], "status") == 0)
1063 {
1064 rc_service_state_t r = svc_status (service);
1065 retval = (int) r;
1066 }
1067 else if (strcmp (argv[i], "stop") == 0)
1068 {
1069 if (in_background)
1070 get_started_services ();
1071
1072 svc_stop (service, deps);
1073
1074 if (! in_background &&
1075 ! rc_runlevel_stopping () &&
1076 rc_service_state (service, rc_service_stopped))
1077 uncoldplug (applet);
1078
1079 if (in_background &&
1080 rc_service_state (service, rc_service_inactive))
1081 {
1082 char *svc;
1083 int j;
1084 STRLIST_FOREACH (restart_services, svc, j)
1085 if (rc_service_state (svc, rc_service_stopped))
1086 rc_schedule_start_service (service, svc);
1087 }
1088 }
1089 else if (strcmp (argv[i], "zap") == 0)
1090 {
1091 einfo ("Manually resetting %s to stopped state", applet);
1092 rc_mark_service (applet, rc_service_stopped);
1093 uncoldplug (applet);
1094 }
1095 else if (strcmp (argv[i], "help") == 0)
1096 {
1097 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1098 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1099 applet, strerror (errno));
1100 }
1101 else
1102 svc_exec (service, argv[i], NULL);
1103
1104 /* Flush our buffered output if any */
1105 eflush ();
1106
1107 /* We should ensure this list is empty after an action is done */
1108 rc_strlist_free (restart_services);
1109 restart_services = NULL;
1110 }
1111
1112 if (! doneone)
1113 {
1114 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1115 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1116 applet, strerror (errno));
1117 }
1118
1119 return (retval);
1120 }

  ViewVC Help
Powered by ViewVC 1.1.20