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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20