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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20