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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2634 - (hide annotations) (download) (as text)
Thu Apr 19 14:54:35 2007 UTC (7 years, 5 months ago) by uberlord
File MIME type: text/x-csrc
File size: 28539 byte(s)
strdup -> rc_xstrdup
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 2634 #include <libgen.h>
19 uberlord 2547 #include <limits.h>
20     #include <stdio.h>
21     #include <stdlib.h>
22     #include <string.h>
23     #include <unistd.h>
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 uberlord 2582 #define RCSCRIPT_HELP RC_LIBDIR "/sh/rc-help.sh"
32     #define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
33 uberlord 2547
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 uberlord 2582 ! 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 uberlord 2582 ! 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 uberlord 2634 svc, applet);
803 uberlord 2577 } else
804     rc_start_service (svc);
805     }
806     }
807     }
808 uberlord 2547 }
809    
810 vapier 2618 #define getoptstring "dCDNqvh"
811     static struct option longopts[] = {
812     { "debug", 0, NULL, 'd'},
813     { "nocolor", 0, NULL, 'C'},
814     { "nocolour", 0, NULL, 'C'},
815     { "nodeps", 0, NULL, 'D'},
816     { "quiet", 0, NULL, 'q'},
817     { "verbose", 0, NULL, 'v'},
818     { "help", 0, NULL, 'h'},
819     { NULL, 0, NULL, 0}
820     };
821 uberlord 2634 // #include "_usage.c"
822 vapier 2618
823 uberlord 2547 int main (int argc, char **argv)
824     {
825 uberlord 2634 char *service = argv[1];
826 uberlord 2577 int i;
827     bool deps = true;
828     bool doneone = false;
829     char pid[16];
830     int retval;
831 uberlord 2580 char c;
832 uberlord 2547
833 uberlord 2577 /* Show help if insufficient args */
834     if (argc < 3) {
835     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
836     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
837     applet, strerror (errno));
838     }
839 uberlord 2547
840 uberlord 2634 applet = rc_xstrdup (basename (service));
841 uberlord 2581 atexit (cleanup);
842    
843 uberlord 2547 #ifdef __linux__
844 uberlord 2577 /* coldplug events can trigger init scripts, but we don't want to run them
845     until after rc sysinit has completed so we punt them to the boot runlevel */
846     if (rc_exists ("/dev/.rcsysinit")) {
847     eerror ("%s: cannot run until sysvinit completes", applet);
848     if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
849     eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
850     tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
851     symlink (service, tmp);
852     exit (EXIT_FAILURE);
853     }
854 uberlord 2547 #endif
855    
856 uberlord 2577 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
857     /* Ensure our environment is pure
858     Also, add our configuration to it */
859     env = rc_filter_env ();
860     env = rc_config_env (env);
861 uberlord 2547
862 uberlord 2577 if (env) {
863     char *p;
864 uberlord 2547
865     #ifdef __linux__
866 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
867     if we have it */
868     clearenv ();
869 uberlord 2547 #else
870 uberlord 2577 char *var;
871     /* No clearenv present here then.
872     We could manipulate environ directly ourselves, but it seems that
873     some kernels bitch about this according to the environ man pages
874     so we walk though environ and call unsetenv for each value. */
875     while (environ[0]) {
876     tmp = rc_xstrdup (environ[0]);
877     p = tmp;
878     var = strsep (&p, "=");
879     unsetenv (var);
880     free (tmp);
881     }
882     tmp = NULL;
883 uberlord 2547 #endif
884    
885 uberlord 2577 STRLIST_FOREACH (env, p, i)
886     putenv (p);
887 uberlord 2547
888 uberlord 2577 /* We don't free our list as that would be null in environ */
889     }
890 uberlord 2547
891 uberlord 2577 softlevel = rc_get_runlevel ();
892 uberlord 2547
893 uberlord 2577 /* If not called from RC or another service then don't be parallel */
894     unsetenv ("RC_PARALLEL_STARTUP");
895     }
896 uberlord 2547
897 uberlord 2577 setenv ("RC_ELOG", service, 1);
898     setenv ("SVCNAME", applet, 1);
899 uberlord 2547
900 uberlord 2577 /* Set an env var so that we always know our pid regardless of any
901     subshells the init script may create so that our mark_service_*
902     functions can always instruct us of this change */
903     snprintf (pid, sizeof (pid), "%d", (int) getpid ());
904     setenv ("RC_RUNSCRIPT_PID", pid, 1);
905 uberlord 2547
906 uberlord 2577 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) {
907     char ebname[PATH_MAX];
908     char *eb;
909 uberlord 2547
910 uberlord 2577 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
911     eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
912     setenv ("RC_EBUFFER", eb, 1);
913     free (eb);
914     }
915 uberlord 2547
916     #ifdef __linux__
917 uberlord 2577 /* Ok, we are ready to go, so setup selinux if applicable */
918     setup_selinux (argc, argv);
919 uberlord 2547 #endif
920    
921 uberlord 2581 /* Punt the first arg as it's our service name */
922     argc--;
923     argv++;
924    
925 uberlord 2577 /* Right then, parse any options there may be */
926 vapier 2618 while ((c = getopt_long (argc, argv, getoptstring,
927 uberlord 2580 longopts, (int *) 0)) != -1)
928     switch (c) {
929     case 'd':
930     setenv ("RC_DEBUG", "yes", 1);
931     break;
932     case 'h':
933     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
934     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
935     applet, strerror (errno));
936     case 'C':
937     setenv ("RC_NOCOLOR", "yes", 1);
938     break;
939     case 'D':
940     deps = false;
941     break;
942     case 'q':
943     setenv ("RC_QUIET", "yes", 1);
944     break;
945     case 'v':
946     setenv ("RC_VERBOSE", "yes", 1);
947     break;
948     default:
949     exit (EXIT_FAILURE);
950     }
951 uberlord 2547
952 uberlord 2581 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
953     that is being called and not any dependents */
954     if (getenv ("IN_BACKGROUND")) {
955     in_background = rc_is_env ("IN_BACKGROUND", "true");
956 uberlord 2634 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
957 uberlord 2581 unsetenv ("IN_BACKGROUND");
958     }
959    
960 uberlord 2577 if (rc_is_env ("IN_HOTPLUG", "1")) {
961     if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
962     eerrorx ("%s: not allowed to be hotplugged", applet);
963     }
964 uberlord 2547
965 uberlord 2577 /* Setup a signal handler */
966     signal (SIGHUP, handle_signal);
967     signal (SIGINT, handle_signal);
968     signal (SIGQUIT, handle_signal);
969     signal (SIGTERM, handle_signal);
970     signal (SIGCHLD, handle_signal);
971 uberlord 2547
972 uberlord 2577 /* Load our plugins */
973     rc_plugin_load ();
974 uberlord 2547
975 uberlord 2577 /* Now run each option */
976     retval = EXIT_SUCCESS;
977 uberlord 2580 while (optind < argc) {
978     optarg = argv[optind++];
979    
980 uberlord 2577 /* Abort on a sighup here */
981     if (sighup)
982     exit (EXIT_FAILURE);
983 uberlord 2547
984 uberlord 2577 /* Export the command we're running.
985     This is important as we stamp on the restart function now but
986     some start/stop routines still need to behave differently if
987     restarting. */
988     unsetenv ("RC_CMD");
989 uberlord 2580 setenv ("RC_CMD", optarg, 1);
990 uberlord 2569
991 uberlord 2577 doneone = true;
992 uberlord 2580 if (strcmp (optarg, "conditionalrestart") == 0 ||
993     strcmp (optarg, "condrestart") == 0)
994 uberlord 2577 {
995     if (rc_service_state (service, rc_service_started))
996     svc_restart (service, deps);
997     }
998 uberlord 2580 else if (strcmp (optarg, "restart") == 0)
999 uberlord 2577 svc_restart (service, deps);
1000 uberlord 2580 else if (strcmp (optarg, "start") == 0)
1001 uberlord 2577 svc_start (service, deps);
1002 uberlord 2580 else if (strcmp (optarg, "status") == 0) {
1003 uberlord 2577 rc_service_state_t r = svc_status (service);
1004     retval = (int) r;
1005 uberlord 2580 } else if (strcmp (optarg, "stop") == 0) {
1006 uberlord 2577 if (in_background)
1007     get_started_services ();
1008 uberlord 2547
1009 uberlord 2577 svc_stop (service, deps);
1010 uberlord 2547
1011 uberlord 2577 if (! in_background &&
1012     ! rc_runlevel_stopping () &&
1013     rc_service_state (service, rc_service_stopped))
1014     uncoldplug (applet);
1015 uberlord 2560
1016 uberlord 2577 if (in_background &&
1017     rc_service_state (service, rc_service_inactive))
1018     {
1019     char *svc;
1020     int j;
1021     STRLIST_FOREACH (restart_services, svc, j)
1022     if (rc_service_state (svc, rc_service_stopped))
1023     rc_schedule_start_service (service, svc);
1024     }
1025 uberlord 2580 } else if (strcmp (optarg, "zap") == 0) {
1026 uberlord 2577 einfo ("Manually resetting %s to stopped state", applet);
1027     rc_mark_service (applet, rc_service_stopped);
1028     uncoldplug (applet);
1029 uberlord 2580 } else if (strcmp (optarg, "help") == 0) {
1030 uberlord 2577 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1031     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1032     applet, strerror (errno));
1033     }else
1034 uberlord 2580 svc_exec (service, optarg, NULL);
1035 uberlord 2547
1036 uberlord 2577 /* Flush our buffered output if any */
1037     eflush ();
1038 uberlord 2547
1039 uberlord 2577 /* We should ensure this list is empty after an action is done */
1040     rc_strlist_free (restart_services);
1041     restart_services = NULL;
1042     }
1043 uberlord 2547
1044 uberlord 2577 if (! doneone) {
1045     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1046     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1047     applet, strerror (errno));
1048     }
1049 uberlord 2547
1050 uberlord 2577 return (retval);
1051 uberlord 2547 }

  ViewVC Help
Powered by ViewVC 1.1.20