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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2547 - (hide annotations) (download) (as text)
Thu Apr 5 11:18:42 2007 UTC (7 years, 8 months ago) by uberlord
File MIME type: text/x-csrc
File size: 29258 byte(s)
    Rewrite the core parts in C. We now provide librc so other programs can
    query runlevels, services and state without using bash. We also provide
    libeinfo so other programs can easily use our informational functions.

    As such, we have dropped the requirement of using bash as the init script
    shell. We now use /bin/sh and have strived to make the scripts as portable
    as possible. Shells that work are bash and dash. busybox works provided
    you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you
    should disable find too.
    zsh and ksh do not work at this time.

    Networking support is currently being re-vamped also as it was heavily bash
    array based. As such, a new config format is available like so
    config_eth0="1.2.3.4/24 5.6.7.8/16"
    or like so
    config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'"

    We will still support the old bash array format provided that /bin/sh IS
    a link it bash.

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

  ViewVC Help
Powered by ViewVC 1.1.20