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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20