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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20