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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20