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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20