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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20