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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20