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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2569 - (hide annotations) (download) (as text)
Tue Apr 10 11:24:58 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 32203 byte(s)
Fix indentation
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 uberlord 2569 ISO C forbids assignment between function pointer and 'void *'
75     which sucks ass
76     http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html */
77 uberlord 2547 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 uberlord 2569 selinux_run_init_new (argc, argv);
83 uberlord 2547 else if (selinux_run_init_old)
84 uberlord 2569 selinux_run_init_old ();
85 uberlord 2547 else
86 uberlord 2569 /* This shouldnt happen... probably corrupt lib */
87     eerrorx ("run_init is missing from runscript_selinux.so!");
88 uberlord 2547 }
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 uberlord 2569 {
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 uberlord 2547 break;
117 uberlord 2569
118 uberlord 2547 case SIGINT:
119 uberlord 2563 if (! signame[0])
120 uberlord 2569 snprintf (signame, sizeof (signame), "SIGINT");
121 uberlord 2547 case SIGTERM:
122 uberlord 2563 if (! signame[0])
123 uberlord 2569 snprintf (signame, sizeof (signame), "SIGTERM");
124 uberlord 2547 case SIGQUIT:
125 uberlord 2563 if (! signame[0])
126 uberlord 2569 snprintf (signame, sizeof (signame), "SIGQUIT");
127 uberlord 2563 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 uberlord 2569 {
178     int m = get_mtime (path, false);
179     if (mtime < m && m != 0)
180     {
181     free (path);
182     return (false);
183     }
184     }
185 uberlord 2547 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 uberlord 2569 (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 uberlord 2567 if (rc_service_state (applet, rc_service_stopping))
238 uberlord 2569 {
239     /* If the we're shutting down, do it cleanly */
240     if ((softlevel &&
241     rc_runlevel_stopping () &&
242     (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
243     strcmp (softlevel, RC_LEVEL_REBOOT) == 0)))
244     rc_mark_service (applet, rc_service_stopped);
245     else if (rc_service_state (applet, rc_service_wasinactive))
246     rc_mark_service (applet, rc_service_inactive);
247     else
248     rc_mark_service (applet, rc_service_started);
249     }
250 uberlord 2567 else if (rc_service_state (applet, rc_service_starting))
251 uberlord 2569 {
252     if (rc_service_state (applet, rc_service_wasinactive))
253     rc_mark_service (applet, rc_service_inactive);
254     else
255     rc_mark_service (applet, rc_service_stopped);
256     }
257 uberlord 2547 if (exclusive && rc_exists (exclusive))
258 uberlord 2569 unlink (exclusive);
259 uberlord 2547 }
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 uberlord 2569
285 uberlord 2547 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 uberlord 2569 myarg2 = rc_xstrdup (arg2);
295 uberlord 2547
296     if (rc_exists (RC_SVCDIR "runscript.sh"))
297 uberlord 2569 {
298     execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2,
299     (char *) NULL);
300     eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
301     service, strerror (errno));
302     }
303 uberlord 2547 else
304 uberlord 2569 {
305     execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2,
306     (char *) NULL);
307     eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
308     service, strerror (errno));
309     }
310 uberlord 2547 }
311    
312     do
313     {
314     if (waitpid (pid, &status, 0) < 0)
315 uberlord 2569 {
316     if (errno != ECHILD)
317     eerror ("waitpid: %s", strerror (errno));
318     break;
319     }
320 uberlord 2547 } 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 uberlord 2569 applet, exclusive, strerror (errno));
387 uberlord 2547
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 uberlord 2569 applet, mtime_test, strerror (errno));
398 uberlord 2547 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 uberlord 2569 applet, service, mtime_test, strerror (errno));
407 uberlord 2547 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 uberlord 2569 exit (EXIT_FAILURE);
455 uberlord 2547 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 uberlord 2569 eerrorx ("failed to load deptree");
476 uberlord 2547
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 uberlord 2569 {
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 uberlord 2547 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 uberlord 2569 softlevel, depoptions);
502 uberlord 2547 types = rc_strlist_add (types, "iuse");
503     if (! rc_runlevel_starting ())
504 uberlord 2569 {
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 uberlord 2547
511 uberlord 2569 rc_strlist_free (services);
512     }
513 uberlord 2547
514     /* Now wait for them to start */
515     types = rc_strlist_add (types, "iafter");
516     services = rc_get_depends (deptree, types, svclist,
517 uberlord 2569 softlevel, depoptions);
518 uberlord 2547
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 uberlord 2569 {
525     if (rc_service_state (svc, rc_service_started))
526     continue;
527     if (! rc_wait_service (svc))
528     eerror ("%s: timed out waiting for %s", applet, svc);
529     if (rc_service_state (svc, rc_service_started))
530     continue;
531 uberlord 2547
532 uberlord 2569 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 uberlord 2547
544     if (tmplist)
545 uberlord 2569 {
546     int n = 0;
547     int len = 0;
548     char *p;
549 uberlord 2547
550 uberlord 2569 /* 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 uberlord 2547
555 uberlord 2569 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 uberlord 2547
561 uberlord 2569 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 uberlord 2547
569 uberlord 2569 len += strlen (svc) + 2;
570     n++;
571     }
572 uberlord 2547
573 uberlord 2569 len += 5;
574     tmp = rc_xmalloc (sizeof (char *) * len);
575     p = tmp;
576     STRLIST_FOREACH (tmplist, svc, i)
577     {
578     if (i > 1)
579     {
580     if (i == n - 1)
581     p += snprintf (p, len, " or ");
582     else
583     p += snprintf (p, len, ", ");
584     }
585     p += snprintf (p, len, "%s", svc);
586     }
587     ewarnx ("WARNING: %s is scheduled to start when %s has started",
588     applet, tmp);
589     }
590 uberlord 2547
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 uberlord 2569 {
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 uberlord 2547
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 uberlord 2569 ewarn ("WARNING: %s has started, but is inactive", applet);
632 uberlord 2547 else
633 uberlord 2569 ewarn ("WARNING: %s not under our control, aborting", applet);
634 uberlord 2547 }
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 uberlord 2569 rc_start_service (svc);
660 uberlord 2547 }
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 uberlord 2569 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
687     ewarn ("WARNING: you are stopping a boot service");
688 uberlord 2547
689     if (deps || ! rc_service_state (service, rc_service_wasinactive))
690     {
691     int depoptions = RC_DEP_TRACE;
692     char *svc;
693     int i;
694 uberlord 2569
695 uberlord 2547 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
696 uberlord 2569 depoptions |= RC_DEP_STRICT;
697 uberlord 2547
698     if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
699 uberlord 2569 eerrorx ("failed to load deptree");
700 uberlord 2547
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 uberlord 2569 softlevel, depoptions);
710 uberlord 2547 rc_strlist_reverse (services);
711     STRLIST_FOREACH (services, svc, i)
712 uberlord 2569 {
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 uberlord 2547 rc_strlist_free (services);
726     services = NULL;
727    
728     STRLIST_FOREACH (tmplist, svc, i)
729 uberlord 2569 {
730     if (rc_service_state (svc, rc_service_stopped))
731     continue;
732 uberlord 2547
733 uberlord 2569 /* 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 uberlord 2547 rc_strlist_free (tmplist);
744     tmplist = NULL;
745    
746     /* We now wait for other services that may use us and are stopping
747 uberlord 2569 This is important when a runlevel stops */
748 uberlord 2547 types = rc_strlist_add (types, "usesme");
749     types = rc_strlist_add (types, "ibefore");
750     services = rc_get_depends (deptree, types, svclist,
751 uberlord 2569 softlevel, depoptions);
752 uberlord 2547 STRLIST_FOREACH (services, svc, i)
753 uberlord 2569 {
754     if (rc_service_state (svc, rc_service_stopped))
755     continue;
756     rc_wait_service (svc);
757     }
758 uberlord 2547
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 uberlord 2569 rc_mark_service (service, rc_service_inactive);
780 uberlord 2547 else
781 uberlord 2569 rc_mark_service (service, rc_service_started);
782 uberlord 2547 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 uberlord 2569
801 uberlord 2547 /* 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 uberlord 2569 rc_service_state (service, rc_service_inactive))
813     svc_exec (service, "stop", "start");
814 uberlord 2547 else
815 uberlord 2569 svc_exec (service, "start", NULL);
816 uberlord 2547 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 uberlord 2569
834 uberlord 2547 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 uberlord 2569 {
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 uberlord 2547 }
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 uberlord 2569 applet, strerror (errno));
874 uberlord 2547 }
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 uberlord 2569 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 uberlord 2569 Also, add our configuration to it */
894 uberlord 2547 env = rc_filter_env ();
895     env = rc_config_env (env);
896    
897     if (env)
898 uberlord 2569 {
899     char *p;
900 uberlord 2547
901     #ifdef __linux__
902 uberlord 2569 /* clearenv isn't portable, but there's no harm in using it
903     if we have it */
904     clearenv ();
905 uberlord 2547 #else
906 uberlord 2569 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 uberlord 2547 #endif
921    
922 uberlord 2569 STRLIST_FOREACH (env, p, i)
923     putenv (p);
924 uberlord 2547
925 uberlord 2569 /* We don't free our list as that would be null in environ */
926     }
927 uberlord 2547
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 uberlord 2569 continue;
973 uberlord 2547
974     if (strcmp (argv[i], "--debug") == 0)
975 uberlord 2569 setenv ("RC_DEBUG", "yes", 1);
976 uberlord 2547 else if (strcmp (argv[i], "--help") == 0)
977 uberlord 2569 {
978     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
979     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
980     applet, strerror (errno));
981     }
982 uberlord 2547 else if (strcmp (argv[i],"--ifstarted") == 0)
983 uberlord 2569 ifstarted = true;
984 uberlord 2547 else if (strcmp (argv[i], "--nocolour") == 0 ||
985 uberlord 2569 strcmp (argv[i], "--nocolor") == 0)
986     setenv ("RC_NOCOLOR", "yes", 1);
987 uberlord 2547 else if (strcmp (argv[i], "--nodeps") == 0)
988 uberlord 2569 deps = false;
989 uberlord 2547 else if (strcmp (argv[i], "--quiet") == 0)
990 uberlord 2569 setenv ("RC_QUIET", "yes", 1);
991 uberlord 2547 else if (strcmp (argv[i], "--verbose") == 0)
992 uberlord 2569 setenv ("RC_VERBOSE", "yes", 1);
993 uberlord 2547 else if (strcmp (argv[i], "--version") == 0)
994 uberlord 2569 printf ("version me\n");
995 uberlord 2547 else
996 uberlord 2569 eerror ("%s: unknown option `%s'", applet, argv[i]);
997 uberlord 2547 }
998    
999     if (ifstarted && ! rc_service_state (applet, rc_service_started))
1000     {
1001     if (! rc_is_env("RC_QUIET", "yes"))
1002 uberlord 2569 eerror ("ERROR: %s is not started", applet);
1003 uberlord 2547 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 uberlord 2569 eerrorx ("%s: not allowed to be hotplugged", applet);
1010 uberlord 2547 }
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 uberlord 2569 exit (EXIT_FAILURE);
1029 uberlord 2547
1030     if (strlen (argv[i]) < 2 ||
1031 uberlord 2569 (argv[i][0] == '-' && argv[i][1] == '-'))
1032     continue;
1033 uberlord 2547
1034     /* Export the command we're running.
1035 uberlord 2569 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 uberlord 2547 unsetenv ("RC_CMD");
1039     setenv ("RC_CMD", argv[i], 1);
1040 uberlord 2569
1041 uberlord 2547 doneone = true;
1042     if (strcmp (argv[i], "conditionalrestart") == 0 ||
1043 uberlord 2569 strcmp (argv[i], "condrestart") == 0)
1044     {
1045     if (rc_service_state (service, rc_service_started))
1046     svc_restart (service, deps);
1047     }
1048 uberlord 2547 else if (strcmp (argv[i], "restart") == 0)
1049 uberlord 2569 svc_restart (service, deps);
1050 uberlord 2547 else if (strcmp (argv[i], "start") == 0)
1051 uberlord 2569 svc_start (service, deps);
1052 uberlord 2547 else if (strcmp (argv[i], "status") == 0)
1053 uberlord 2569 {
1054     rc_service_state_t r = svc_status (service);
1055     retval = (int) r;
1056     }
1057 uberlord 2547 else if (strcmp (argv[i], "stop") == 0)
1058 uberlord 2569 {
1059     if (in_background)
1060     get_started_services ();
1061 uberlord 2547
1062 uberlord 2569 svc_stop (service, deps);
1063 uberlord 2547
1064 uberlord 2569 if (! in_background &&
1065     ! rc_runlevel_stopping () &&
1066     rc_service_state (service, rc_service_stopped))
1067     uncoldplug (applet);
1068 uberlord 2560
1069 uberlord 2569 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 uberlord 2547 else if (strcmp (argv[i], "zap") == 0)
1080 uberlord 2569 {
1081     einfo ("Manually resetting %s to stopped state", applet);
1082     rc_mark_service (applet, rc_service_stopped);
1083     uncoldplug (applet);
1084     }
1085 uberlord 2547 else if (strcmp (argv[i], "help") == 0)
1086 uberlord 2569 {
1087     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1088     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1089     applet, strerror (errno));
1090     }
1091 uberlord 2547 else
1092 uberlord 2569 svc_exec (service, argv[i], NULL);
1093 uberlord 2547
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 uberlord 2569 applet, strerror (errno));
1107 uberlord 2547 }
1108    
1109     return (retval);
1110     }

  ViewVC Help
Powered by ViewVC 1.1.20