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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20