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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2573 - (hide annotations) (download) (as text)
Wed Apr 11 07:15:02 2007 UTC (7 years, 7 months ago) by uberlord
File MIME type: text/x-csrc
File size: 32615 byte(s)
Add new service hooks, remove pmake stuff from our Makefile and fix rc_services_in_state for scheduled.
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 uberlord 2571 time_t m = get_mtime (path, false);
179 uberlord 2569 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 uberlord 2573 rc_plugin_run (rc_hook_service_start_in, applet);
449     hook_out = rc_hook_service_start_out;
450    
451 uberlord 2547 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
452     depoptions |= RC_DEP_STRICT;
453    
454     if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
455     {
456     if (! rc_service_state (service, rc_service_inactive))
457 uberlord 2569 exit (EXIT_FAILURE);
458 uberlord 2547 background = true;
459     }
460    
461     if (rc_service_state (service, rc_service_started))
462     ewarnx ("WARNING: %s has already been started", applet);
463     else if (rc_service_state (service, rc_service_starting))
464     ewarnx ("WARNING: %s is already starting", applet);
465     else if (rc_service_state (service, rc_service_stopping))
466     ewarnx ("WARNING: %s is stopping", applet);
467     else if (rc_service_state (service, rc_service_inactive) && ! background)
468     ewarnx ("WARNING: %s has already started, but is inactive", applet);
469    
470     if (! rc_mark_service (service, rc_service_starting))
471     eerrorx ("ERROR: %s has been started by something else", applet);
472    
473     make_exclusive (service);
474    
475     if (deps)
476     {
477     if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
478 uberlord 2569 eerrorx ("failed to load deptree");
479 uberlord 2547
480     rc_strlist_free (types);
481     types = rc_strlist_add (NULL, "broken");
482     rc_strlist_free (svclist);
483     svclist = rc_strlist_add (NULL, applet);
484     rc_strlist_free (services);
485     services = rc_get_depends (deptree, types, svclist, softlevel, 0);
486     if (services)
487 uberlord 2569 {
488     eerrorn ("ERROR: `%s' needs ", applet);
489     STRLIST_FOREACH (services, svc, i)
490     {
491     if (i > 0)
492     fprintf (stderr, ", ");
493     fprintf (stderr, "%s", svc);
494     }
495     exit (EXIT_FAILURE);
496     }
497 uberlord 2547 rc_strlist_free (services);
498     services = NULL;
499    
500     rc_strlist_free (types);
501     types = rc_strlist_add (NULL, "ineed");
502     rc_strlist_free (need_services);
503     need_services = rc_get_depends (deptree, types, svclist,
504 uberlord 2569 softlevel, depoptions);
505 uberlord 2547 types = rc_strlist_add (types, "iuse");
506     if (! rc_runlevel_starting ())
507 uberlord 2569 {
508     services = rc_get_depends (deptree, types, svclist,
509     softlevel, depoptions);
510     STRLIST_FOREACH (services, svc, i)
511     if (rc_service_state (svc, rc_service_stopped))
512     rc_start_service (svc);
513 uberlord 2547
514 uberlord 2569 rc_strlist_free (services);
515     }
516 uberlord 2547
517     /* Now wait for them to start */
518     types = rc_strlist_add (types, "iafter");
519     services = rc_get_depends (deptree, types, svclist,
520 uberlord 2569 softlevel, depoptions);
521 uberlord 2547
522     /* We use tmplist to hold our scheduled by list */
523     rc_strlist_free (tmplist);
524     tmplist = NULL;
525    
526     STRLIST_FOREACH (services, svc, i)
527 uberlord 2569 {
528     if (rc_service_state (svc, rc_service_started))
529     continue;
530     if (! rc_wait_service (svc))
531     eerror ("%s: timed out waiting for %s", applet, svc);
532     if (rc_service_state (svc, rc_service_started))
533     continue;
534 uberlord 2547
535 uberlord 2569 STRLIST_FOREACH (need_services, svc2, j)
536     if (strcmp (svc, svc2) == 0)
537     {
538     if (rc_service_state (svc, rc_service_inactive) ||
539     rc_service_state (svc, rc_service_wasinactive))
540     tmplist = rc_strlist_add (tmplist, svc);
541     else
542     eerrorx ("ERROR: cannot start %s as %s would not start",
543     applet, svc);
544     }
545     }
546 uberlord 2547
547     if (tmplist)
548 uberlord 2569 {
549     int n = 0;
550     int len = 0;
551     char *p;
552 uberlord 2547
553 uberlord 2569 /* Set the state now, then unlink our exclusive so that
554     our scheduled list is preserved */
555     rc_mark_service (service, rc_service_stopped);
556     unlink_mtime_test ();
557 uberlord 2547
558 uberlord 2569 rc_strlist_free (types);
559     types = rc_strlist_add (NULL, "iprovide");
560     STRLIST_FOREACH (tmplist, svc, i)
561     {
562     rc_schedule_start_service (svc, service);
563 uberlord 2547
564 uberlord 2569 rc_strlist_free (svclist);
565     svclist = rc_strlist_add (NULL, svc);
566     rc_strlist_free (providelist);
567     providelist = rc_get_depends (deptree, types, svclist,
568     softlevel, depoptions);
569 uberlord 2573 STRLIST_FOREACH (providelist, svc2, j)
570 uberlord 2569 rc_schedule_start_service (svc2, service);
571 uberlord 2547
572 uberlord 2569 len += strlen (svc) + 2;
573     n++;
574     }
575 uberlord 2547
576 uberlord 2569 len += 5;
577     tmp = rc_xmalloc (sizeof (char *) * len);
578     p = tmp;
579     STRLIST_FOREACH (tmplist, svc, i)
580     {
581     if (i > 1)
582     {
583     if (i == n - 1)
584     p += snprintf (p, len, " or ");
585     else
586     p += snprintf (p, len, ", ");
587     }
588     p += snprintf (p, len, "%s", svc);
589     }
590     ewarnx ("WARNING: %s is scheduled to start when %s has started",
591     applet, tmp);
592     }
593 uberlord 2547
594     rc_strlist_free (services);
595     services = NULL;
596     rc_strlist_free (types);
597     types = NULL;
598     rc_strlist_free (svclist);
599     svclist = NULL;
600     }
601    
602     if (ibsave)
603     setenv ("IN_BACKGROUND", ibsave, 1);
604 uberlord 2573 rc_plugin_run (rc_hook_service_start_now, applet);
605 uberlord 2547 started = svc_exec (service, "start", NULL);
606     if (ibsave)
607     unsetenv ("IN_BACKGROUND");
608    
609     if (in_control ())
610     {
611     if (! started)
612 uberlord 2569 {
613     if (rc_service_state (service, rc_service_wasinactive))
614     rc_mark_service (service, rc_service_inactive);
615     else
616     {
617     rc_mark_service (service, rc_service_stopped);
618     if (rc_runlevel_starting ())
619     rc_mark_service (service, rc_service_failed);
620     }
621 uberlord 2573 rc_plugin_run (rc_hook_service_start_done, applet);
622 uberlord 2569 eerrorx ("ERROR: %s failed to start", applet);
623     }
624 uberlord 2547 rc_mark_service (service, rc_service_started);
625     unlink_mtime_test ();
626 uberlord 2573 rc_plugin_run (rc_hook_service_start_done, applet);
627 uberlord 2547 }
628     else
629     {
630 uberlord 2573 rc_plugin_run (rc_hook_service_start_done, applet);
631 uberlord 2547 if (rc_service_state (service, rc_service_inactive))
632 uberlord 2573 ewarnx ("WARNING: %s has started, but is inactive", applet);
633 uberlord 2547 else
634 uberlord 2573 ewarnx ("WARNING: %s not under our control, aborting", applet);
635 uberlord 2547 }
636    
637     /* Now start any scheduled services */
638     rc_strlist_free (services);
639     services = rc_services_scheduled (service);
640     STRLIST_FOREACH (services, svc, i)
641     if (rc_service_state (svc, rc_service_stopped))
642     rc_start_service (svc);
643     rc_strlist_free (services);
644     services = NULL;
645    
646     /* Do the same for any services we provide */
647     rc_strlist_free (types);
648     types = rc_strlist_add (NULL, "iprovide");
649     rc_strlist_free (svclist);
650     svclist = rc_strlist_add (NULL, applet);
651     rc_strlist_free (tmplist);
652     tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
653    
654     STRLIST_FOREACH (tmplist, svc2, j)
655     {
656     rc_strlist_free (services);
657     services = rc_services_scheduled (svc2);
658     STRLIST_FOREACH (services, svc, i)
659     if (rc_service_state (svc, rc_service_stopped))
660 uberlord 2569 rc_start_service (svc);
661 uberlord 2547 }
662 uberlord 2573
663     hook_out = 0;
664     rc_plugin_run (rc_hook_service_start_out, applet);
665 uberlord 2547 }
666    
667     static void svc_stop (const char *service, bool deps)
668     {
669     bool stopped;
670    
671 uberlord 2573 hook_out = rc_hook_service_stop_out;
672    
673 uberlord 2547 if (rc_runlevel_stopping () &&
674     rc_service_state (service, rc_service_failed))
675     exit (EXIT_FAILURE);
676    
677     if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
678     if (! rc_service_state (service, rc_service_started))
679     exit (EXIT_FAILURE);
680    
681     if (rc_service_state (service, rc_service_stopped))
682     ewarnx ("WARNING: %s is already stopped", applet);
683     else if (rc_service_state (service, rc_service_stopping))
684     ewarnx ("WARNING: %s is already stopping", applet);
685    
686     if (! rc_mark_service (service, rc_service_stopping))
687     eerrorx ("ERROR: %s has been stopped by something else", applet);
688    
689     make_exclusive (service);
690    
691     if (! rc_runlevel_stopping () &&
692 uberlord 2569 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
693     ewarn ("WARNING: you are stopping a boot service");
694 uberlord 2547
695     if (deps || ! rc_service_state (service, rc_service_wasinactive))
696     {
697     int depoptions = RC_DEP_TRACE;
698     char *svc;
699     int i;
700 uberlord 2569
701 uberlord 2547 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
702 uberlord 2569 depoptions |= RC_DEP_STRICT;
703 uberlord 2547
704     if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
705 uberlord 2569 eerrorx ("failed to load deptree");
706 uberlord 2547
707     rc_strlist_free (types);
708     types = rc_strlist_add (NULL, "needsme");
709     rc_strlist_free (svclist);
710     svclist = rc_strlist_add (NULL, applet);
711     rc_strlist_free (tmplist);
712     tmplist = NULL;
713     rc_strlist_free (services);
714     services = rc_get_depends (deptree, types, svclist,
715 uberlord 2569 softlevel, depoptions);
716 uberlord 2547 rc_strlist_reverse (services);
717     STRLIST_FOREACH (services, svc, i)
718 uberlord 2569 {
719     if (rc_service_state (svc, rc_service_started) ||
720     rc_service_state (svc, rc_service_inactive))
721     {
722     rc_wait_service (svc);
723     if (rc_service_state (svc, rc_service_started) ||
724     rc_service_state (svc, rc_service_inactive))
725     {
726     rc_stop_service (svc);
727     tmplist = rc_strlist_add (tmplist, svc);
728     }
729     }
730     }
731 uberlord 2547 rc_strlist_free (services);
732     services = NULL;
733    
734     STRLIST_FOREACH (tmplist, svc, i)
735 uberlord 2569 {
736     if (rc_service_state (svc, rc_service_stopped))
737     continue;
738 uberlord 2547
739 uberlord 2569 /* We used to loop 3 times here - maybe re-do this if needed */
740     rc_wait_service (svc);
741     if (! rc_service_state (svc, rc_service_stopped))
742     {
743     if (rc_runlevel_stopping ())
744     rc_mark_service (svc, rc_service_failed);
745     eerrorx ("ERROR: cannot stop %s as %s is still up",
746     applet, svc);
747     }
748     }
749 uberlord 2547 rc_strlist_free (tmplist);
750     tmplist = NULL;
751    
752     /* We now wait for other services that may use us and are stopping
753 uberlord 2569 This is important when a runlevel stops */
754 uberlord 2547 types = rc_strlist_add (types, "usesme");
755     types = rc_strlist_add (types, "ibefore");
756     services = rc_get_depends (deptree, types, svclist,
757 uberlord 2569 softlevel, depoptions);
758 uberlord 2547 STRLIST_FOREACH (services, svc, i)
759 uberlord 2569 {
760     if (rc_service_state (svc, rc_service_stopped))
761     continue;
762     rc_wait_service (svc);
763     }
764 uberlord 2547
765     rc_strlist_free (services);
766     services = NULL;
767     rc_strlist_free (types);
768     types = NULL;
769     }
770    
771     if (ibsave)
772     setenv ("IN_BACKGROUND", ibsave, 1);
773 uberlord 2573 rc_plugin_run (rc_hook_service_stop_now, applet);
774 uberlord 2547 stopped = svc_exec (service, "stop", NULL);
775     if (ibsave)
776     unsetenv ("IN_BACKGROUND");
777    
778     if (! in_control ())
779 uberlord 2573 {
780     rc_plugin_run (rc_hook_service_stop_done, applet);
781     ewarnx ("WARNING: %s not under our control, aborting", applet);
782     }
783 uberlord 2547
784     if (! stopped)
785     {
786     if (rc_service_state (service, rc_service_wasinactive))
787 uberlord 2569 rc_mark_service (service, rc_service_inactive);
788 uberlord 2547 else
789 uberlord 2569 rc_mark_service (service, rc_service_started);
790 uberlord 2573 rc_plugin_run (rc_hook_service_stop_done, applet);
791 uberlord 2547 eerrorx ("ERROR: %s failed to stop", applet);
792     }
793    
794     if (in_background)
795     rc_mark_service (service, rc_service_inactive);
796     else
797     rc_mark_service (service, rc_service_stopped);
798    
799     unlink_mtime_test ();
800 uberlord 2573 rc_plugin_run (rc_hook_service_stop_done, applet);
801 uberlord 2547 hook_out = 0;
802     rc_plugin_run (rc_hook_service_stop_out, applet);
803     }
804    
805     static void svc_restart (const char *service, bool deps)
806     {
807     char *svc;
808     int i;
809     bool inactive = false;
810 uberlord 2569
811 uberlord 2547 /* This is hairly and a better way needs to be found I think!
812     The issue is this - openvpn need net and dns. net can restart
813     dns via resolvconf, so you could have openvpn trying to restart dnsmasq
814     which in turn is waiting on net which in turn is waiting on dnsmasq.
815     The work around is for resolvconf to restart it's services with --nodeps
816     which means just that. The downside is that there is a small window when
817     our status is invalid.
818     One workaround would be to introduce a new status, or status locking. */
819     if (! deps)
820     {
821     if (rc_service_state (service, rc_service_started) ||
822 uberlord 2569 rc_service_state (service, rc_service_inactive))
823     svc_exec (service, "stop", "start");
824 uberlord 2547 else
825 uberlord 2569 svc_exec (service, "start", NULL);
826 uberlord 2547 return;
827     }
828    
829     if (! rc_service_state (service, rc_service_stopped))
830     {
831     get_started_services ();
832     svc_stop (service, deps);
833    
834     /* Flush our buffered output if any */
835     eflush ();
836     }
837    
838     svc_start (service, deps);
839    
840     inactive = rc_service_state (service, rc_service_inactive);
841     if (! inactive)
842     inactive = rc_service_state (service, rc_service_wasinactive);
843 uberlord 2569
844 uberlord 2547 if (inactive ||
845     rc_service_state (service, rc_service_starting) ||
846     rc_service_state (service, rc_service_started))
847     {
848     STRLIST_FOREACH (restart_services, svc, i)
849 uberlord 2569 {
850     if (rc_service_state (svc, rc_service_stopped))
851     {
852     if (inactive)
853     {
854     rc_schedule_start_service (service, svc);
855     ewarn ("WARNING: %s is scheduled to started when %s has started",
856     svc, basename (service));
857     }
858     else
859     rc_start_service (svc);
860     }
861     }
862 uberlord 2547 }
863     }
864    
865     int main (int argc, char **argv)
866     {
867     const char *service = argv[1];
868     int i;
869     bool deps = true;
870     bool doneone = false;
871     char pid[16];
872     int retval;
873     bool ifstarted = false;
874    
875     applet = strdup (basename (service));
876     atexit (cleanup);
877    
878     /* Show help if insufficient args */
879     if (argc < 3)
880     {
881 uberlord 2549 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
882 uberlord 2547 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
883 uberlord 2569 applet, strerror (errno));
884 uberlord 2547 }
885    
886     #ifdef __linux__
887     /* coldplug events can trigger init scripts, but we don't want to run them
888     until after rc sysinit has completed so we punt them to the boot runlevel */
889     if (rc_exists ("/dev/.rcsysinit"))
890     {
891     eerror ("%s: cannot run until sysvinit completes", applet);
892     if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
893 uberlord 2569 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
894 uberlord 2549 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
895 uberlord 2547 symlink (service, tmp);
896     exit (EXIT_FAILURE);
897     }
898     #endif
899    
900     if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL)
901     {
902     /* Ensure our environment is pure
903 uberlord 2569 Also, add our configuration to it */
904 uberlord 2547 env = rc_filter_env ();
905     env = rc_config_env (env);
906    
907     if (env)
908 uberlord 2569 {
909     char *p;
910 uberlord 2547
911     #ifdef __linux__
912 uberlord 2569 /* clearenv isn't portable, but there's no harm in using it
913     if we have it */
914     clearenv ();
915 uberlord 2547 #else
916 uberlord 2569 char *var;
917     /* No clearenv present here then.
918     We could manipulate environ directly ourselves, but it seems that
919     some kernels bitch about this according to the environ man pages
920     so we walk though environ and call unsetenv for each value. */
921     while (environ[0])
922     {
923     tmp = rc_xstrdup (environ[0]);
924     p = tmp;
925     var = strsep (&p, "=");
926     unsetenv (var);
927     free (tmp);
928     }
929     tmp = NULL;
930 uberlord 2547 #endif
931    
932 uberlord 2569 STRLIST_FOREACH (env, p, i)
933     putenv (p);
934 uberlord 2547
935 uberlord 2569 /* We don't free our list as that would be null in environ */
936     }
937 uberlord 2547
938     softlevel = rc_get_runlevel ();
939    
940     /* If not called from RC or another service then don't be parallel */
941     unsetenv ("RC_PARALLEL_STARTUP");
942     }
943    
944     setenv ("RC_ELOG", service, 1);
945     setenv ("SVCNAME", applet, 1);
946    
947     /* Set an env var so that we always know our pid regardless of any
948     subshells the init script may create so that our mark_service_*
949     functions can always instruct us of this change */
950     snprintf (pid, sizeof (pid), "%d", (int) getpid ());
951     setenv ("RC_RUNSCRIPT_PID", pid, 1);
952    
953     if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
954     {
955     char ebname[PATH_MAX];
956     char *eb;
957    
958     snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
959 uberlord 2549 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
960 uberlord 2547 setenv ("RC_EBUFFER", eb, 1);
961     free (eb);
962     }
963    
964     /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
965     that is being called and not any dependents */
966     if (getenv ("IN_BACKGROUND"))
967     {
968     in_background = rc_is_env ("IN_BACKGROUND", "true");
969     ibsave = strdup (getenv ("IN_BACKGROUND"));
970     unsetenv ("IN_BACKGROUND");
971     }
972    
973     #ifdef __linux__
974     /* Ok, we are ready to go, so setup selinux if applicable */
975     setup_selinux (argc, argv);
976     #endif
977    
978     /* Right then, parse any options there may be */
979     for (i = 2; i < argc; i++)
980     {
981     if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-')
982 uberlord 2569 continue;
983 uberlord 2547
984     if (strcmp (argv[i], "--debug") == 0)
985 uberlord 2569 setenv ("RC_DEBUG", "yes", 1);
986 uberlord 2547 else if (strcmp (argv[i], "--help") == 0)
987 uberlord 2569 {
988     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
989     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
990     applet, strerror (errno));
991     }
992 uberlord 2547 else if (strcmp (argv[i],"--ifstarted") == 0)
993 uberlord 2569 ifstarted = true;
994 uberlord 2547 else if (strcmp (argv[i], "--nocolour") == 0 ||
995 uberlord 2569 strcmp (argv[i], "--nocolor") == 0)
996     setenv ("RC_NOCOLOR", "yes", 1);
997 uberlord 2547 else if (strcmp (argv[i], "--nodeps") == 0)
998 uberlord 2569 deps = false;
999 uberlord 2547 else if (strcmp (argv[i], "--quiet") == 0)
1000 uberlord 2569 setenv ("RC_QUIET", "yes", 1);
1001 uberlord 2547 else if (strcmp (argv[i], "--verbose") == 0)
1002 uberlord 2569 setenv ("RC_VERBOSE", "yes", 1);
1003 uberlord 2547 else if (strcmp (argv[i], "--version") == 0)
1004 uberlord 2569 printf ("version me\n");
1005 uberlord 2547 else
1006 uberlord 2569 eerror ("%s: unknown option `%s'", applet, argv[i]);
1007 uberlord 2547 }
1008    
1009     if (ifstarted && ! rc_service_state (applet, rc_service_started))
1010     {
1011     if (! rc_is_env("RC_QUIET", "yes"))
1012 uberlord 2569 eerror ("ERROR: %s is not started", applet);
1013 uberlord 2547 exit (EXIT_FAILURE);
1014     }
1015    
1016     if (rc_is_env ("IN_HOTPLUG", "1"))
1017     {
1018     if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1019 uberlord 2569 eerrorx ("%s: not allowed to be hotplugged", applet);
1020 uberlord 2547 }
1021    
1022     /* Setup a signal handler */
1023     signal (SIGHUP, handle_signal);
1024     signal (SIGINT, handle_signal);
1025     signal (SIGQUIT, handle_signal);
1026     signal (SIGTERM, handle_signal);
1027     signal (SIGCHLD, handle_signal);
1028    
1029     /* Load our plugins */
1030     rc_plugin_load ();
1031    
1032     /* Now run each option */
1033     retval = EXIT_SUCCESS;
1034     for (i = 2; i < argc; i++)
1035     {
1036     /* Abort on a sighup here */
1037     if (sighup)
1038 uberlord 2569 exit (EXIT_FAILURE);
1039 uberlord 2547
1040     if (strlen (argv[i]) < 2 ||
1041 uberlord 2569 (argv[i][0] == '-' && argv[i][1] == '-'))
1042     continue;
1043 uberlord 2547
1044     /* Export the command we're running.
1045 uberlord 2569 This is important as we stamp on the restart function now but
1046     some start/stop routines still need to behave differently if
1047     restarting. */
1048 uberlord 2547 unsetenv ("RC_CMD");
1049     setenv ("RC_CMD", argv[i], 1);
1050 uberlord 2569
1051 uberlord 2547 doneone = true;
1052     if (strcmp (argv[i], "conditionalrestart") == 0 ||
1053 uberlord 2569 strcmp (argv[i], "condrestart") == 0)
1054     {
1055     if (rc_service_state (service, rc_service_started))
1056     svc_restart (service, deps);
1057     }
1058 uberlord 2547 else if (strcmp (argv[i], "restart") == 0)
1059 uberlord 2569 svc_restart (service, deps);
1060 uberlord 2547 else if (strcmp (argv[i], "start") == 0)
1061 uberlord 2569 svc_start (service, deps);
1062 uberlord 2547 else if (strcmp (argv[i], "status") == 0)
1063 uberlord 2569 {
1064     rc_service_state_t r = svc_status (service);
1065     retval = (int) r;
1066     }
1067 uberlord 2547 else if (strcmp (argv[i], "stop") == 0)
1068 uberlord 2569 {
1069     if (in_background)
1070     get_started_services ();
1071 uberlord 2547
1072 uberlord 2569 svc_stop (service, deps);
1073 uberlord 2547
1074 uberlord 2569 if (! in_background &&
1075     ! rc_runlevel_stopping () &&
1076     rc_service_state (service, rc_service_stopped))
1077     uncoldplug (applet);
1078 uberlord 2560
1079 uberlord 2569 if (in_background &&
1080     rc_service_state (service, rc_service_inactive))
1081     {
1082     char *svc;
1083     int j;
1084     STRLIST_FOREACH (restart_services, svc, j)
1085     if (rc_service_state (svc, rc_service_stopped))
1086     rc_schedule_start_service (service, svc);
1087     }
1088     }
1089 uberlord 2547 else if (strcmp (argv[i], "zap") == 0)
1090 uberlord 2569 {
1091     einfo ("Manually resetting %s to stopped state", applet);
1092     rc_mark_service (applet, rc_service_stopped);
1093     uncoldplug (applet);
1094     }
1095 uberlord 2547 else if (strcmp (argv[i], "help") == 0)
1096 uberlord 2569 {
1097     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1098     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1099     applet, strerror (errno));
1100     }
1101 uberlord 2547 else
1102 uberlord 2569 svc_exec (service, argv[i], NULL);
1103 uberlord 2547
1104     /* Flush our buffered output if any */
1105     eflush ();
1106    
1107     /* We should ensure this list is empty after an action is done */
1108     rc_strlist_free (restart_services);
1109     restart_services = NULL;
1110     }
1111    
1112     if (! doneone)
1113     {
1114 uberlord 2549 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1115 uberlord 2547 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1116 uberlord 2569 applet, strerror (errno));
1117 uberlord 2547 }
1118    
1119     return (retval);
1120     }

  ViewVC Help
Powered by ViewVC 1.1.20