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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20