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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20