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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20