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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2550 - (hide annotations) (download) (as text)
Fri Apr 6 01:04:07 2007 UTC (7 years, 8 months ago) by uberlord
File MIME type: text/x-csrc
File size: 29385 byte(s)
Misc fixes, plugged a memory leak in runscript.c and use va_copy to avoid nasty segfaults
1 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     /* Don't hang around */
954     if (in_background)
955     setenv ("RC_PARALLEL_STARTUP", "yes", 1);
956     }
957    
958     #ifdef __linux__
959     /* Ok, we are ready to go, so setup selinux if applicable */
960     setup_selinux (argc, argv);
961     #endif
962    
963     /* Right then, parse any options there may be */
964     for (i = 2; i < argc; i++)
965     {
966     if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-')
967     continue;
968    
969     if (strcmp (argv[i], "--debug") == 0)
970     setenv ("RC_DEBUG", "yes", 1);
971     else if (strcmp (argv[i], "--help") == 0)
972     {
973 uberlord 2549 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
974 uberlord 2547 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
975     applet, strerror (errno));
976     }
977     else if (strcmp (argv[i],"--ifstarted") == 0)
978     ifstarted = true;
979     else if (strcmp (argv[i], "--nocolour") == 0 ||
980     strcmp (argv[i], "--nocolor") == 0)
981     setenv ("RC_NOCOLOR", "yes", 1);
982     else if (strcmp (argv[i], "--nodeps") == 0)
983     deps = false;
984     else if (strcmp (argv[i], "--quiet") == 0)
985     setenv ("RC_QUIET", "yes", 1);
986     else if (strcmp (argv[i], "--verbose") == 0)
987     setenv ("RC_VERBOSE", "yes", 1);
988     else if (strcmp (argv[i], "--version") == 0)
989     printf ("version me\n");
990     else
991     eerror ("%s: unknown option `%s'", applet, argv[i]);
992     }
993    
994     if (ifstarted && ! rc_service_state (applet, rc_service_started))
995     {
996     if (! rc_is_env("RC_QUIET", "yes"))
997     eerror ("ERROR: %s is not started", applet);
998     exit (EXIT_FAILURE);
999     }
1000    
1001     if (rc_is_env ("IN_HOTPLUG", "1"))
1002     {
1003     if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1004     eerrorx ("%s: not allowed to be hotplugged", applet);
1005     }
1006    
1007     /* Setup a signal handler */
1008     signal (SIGHUP, handle_signal);
1009     signal (SIGINT, handle_signal);
1010     signal (SIGQUIT, handle_signal);
1011     signal (SIGTERM, handle_signal);
1012     signal (SIGCHLD, handle_signal);
1013    
1014     /* Load our plugins */
1015     rc_plugin_load ();
1016    
1017     /* Now run each option */
1018     retval = EXIT_SUCCESS;
1019     for (i = 2; i < argc; i++)
1020     {
1021     /* Abort on a sighup here */
1022     if (sighup)
1023     exit (EXIT_FAILURE);
1024    
1025     if (strlen (argv[i]) < 2 ||
1026     (argv[i][0] == '-' && argv[i][1] == '-'))
1027     continue;
1028    
1029     /* Export the command we're running.
1030     This is important as we stamp on the restart function now but
1031     some start/stop routines still need to behave differently if
1032     restarting. */
1033     unsetenv ("RC_CMD");
1034     setenv ("RC_CMD", argv[i], 1);
1035    
1036     doneone = true;
1037     if (strcmp (argv[i], "conditionalrestart") == 0 ||
1038     strcmp (argv[i], "condrestart") == 0)
1039     {
1040     if (rc_service_state (service, rc_service_started))
1041     svc_restart (service, deps);
1042     }
1043     else if (strcmp (argv[i], "restart") == 0)
1044     svc_restart (service, deps);
1045     else if (strcmp (argv[i], "start") == 0)
1046     svc_start (service, deps);
1047     else if (strcmp (argv[i], "status") == 0)
1048     {
1049     rc_service_state_t r = svc_status (service);
1050     retval = (int) r;
1051     }
1052     else if (strcmp (argv[i], "stop") == 0)
1053     {
1054     if (in_background)
1055     get_started_services ();
1056     else if (! rc_runlevel_stopping ())
1057     uncoldplug (applet);
1058    
1059     svc_stop (service, deps);
1060    
1061     if (in_background &&
1062     rc_service_state (service, rc_service_inactive))
1063     {
1064     char *svc;
1065     int j;
1066     STRLIST_FOREACH (restart_services, svc, j)
1067     if (rc_service_state (svc, rc_service_stopped))
1068     rc_schedule_start_service (service, svc);
1069     }
1070     }
1071     else if (strcmp (argv[i], "zap") == 0)
1072     {
1073     einfo ("Manually resetting %s to stopped state", applet);
1074     rc_mark_service (applet, rc_service_stopped);
1075     uncoldplug (applet);
1076     }
1077     else if (strcmp (argv[i], "help") == 0)
1078     {
1079 uberlord 2549 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1080 uberlord 2547 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1081     applet, strerror (errno));
1082     }
1083     else
1084     svc_exec (service, argv[i], NULL);
1085    
1086     /* Flush our buffered output if any */
1087     eflush ();
1088    
1089     /* We should ensure this list is empty after an action is done */
1090     rc_strlist_free (restart_services);
1091     restart_services = NULL;
1092     }
1093    
1094     if (! doneone)
1095     {
1096 uberlord 2549 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1097 uberlord 2547 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1098     applet, strerror (errno));
1099     }
1100    
1101     return (retval);
1102     }

  ViewVC Help
Powered by ViewVC 1.1.20