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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20