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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20