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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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