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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2642 - (hide annotations) (download) (as text)
Fri Apr 20 19:03:56 2007 UTC (7 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 28504 byte(s)
Style fixes
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/stat.h>
13     #include <sys/wait.h>
14     #include <dlfcn.h>
15     #include <errno.h>
16 uberlord 2580 #include <getopt.h>
17 uberlord 2634 #include <libgen.h>
18 uberlord 2547 #include <limits.h>
19 uberlord 2641 #include <signal.h>
20 uberlord 2547 #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 uberlord 2641 static pid_t service_pid = 0;
53 uberlord 2547
54     extern char **environ;
55    
56     #ifdef __linux__
57     static void (*selinux_run_init_old) (void);
58     static void (*selinux_run_init_new) (int argc, char **argv);
59    
60     void setup_selinux (int argc, char **argv);
61     #endif
62    
63     #ifdef __linux__
64     void setup_selinux (int argc, char **argv)
65     {
66 uberlord 2577 void *lib_handle = NULL;
67 uberlord 2547
68 uberlord 2577 lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
69     if (lib_handle) {
70 uberlord 2638 /*
71     * FIXME: the below code generates the warning
72     * ISO C forbids assignment between function pointer and 'void *'
73     * which sucks ass
74     * http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html
75     */
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 uberlord 2641 if (pid == service_pid)
113     service_pid = 0;
114 uberlord 2577 break;
115 uberlord 2569
116 uberlord 2577 case SIGINT:
117     if (! signame[0])
118     snprintf (signame, sizeof (signame), "SIGINT");
119     case SIGTERM:
120     if (! signame[0])
121     snprintf (signame, sizeof (signame), "SIGTERM");
122     case SIGQUIT:
123     if (! signame[0])
124     snprintf (signame, sizeof (signame), "SIGQUIT");
125 uberlord 2641 /* Send the signal to our children too */
126     if (service_pid > 0)
127     kill (service_pid, sig);
128 uberlord 2577 eerrorx ("%s: caught %s, aborting", applet, signame);
129 uberlord 2547
130 uberlord 2577 default:
131     eerror ("%s: caught unknown signal %d", applet, sig);
132     }
133 uberlord 2547
134 uberlord 2577 /* Restore errno */
135     errno = serrno;
136 uberlord 2547 }
137    
138     static time_t get_mtime (const char *pathname, bool follow_link)
139     {
140 uberlord 2577 struct stat buf;
141     int retval;
142 uberlord 2547
143 uberlord 2577 if (! pathname)
144     return (0);
145 uberlord 2547
146 uberlord 2577 retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
147     if (! retval)
148     return (buf.st_mtime);
149 uberlord 2547
150 uberlord 2577 errno = 0;
151     return (0);
152 uberlord 2547 }
153    
154     static bool in_control ()
155     {
156 uberlord 2577 char *path;
157     time_t mtime;
158     const char *tests[] = { "starting", "started", "stopping",
159     "inactive", "wasinactive", NULL };
160     int i = 0;
161 uberlord 2547
162 uberlord 2577 if (sighup)
163     return (false);
164 uberlord 2547
165 uberlord 2577 if (! mtime_test || ! rc_exists (mtime_test))
166     return (false);
167 uberlord 2547
168 uberlord 2577 if (rc_service_state (applet, rc_service_stopped))
169     return (false);
170 uberlord 2547
171 uberlord 2577 if (! (mtime = get_mtime (mtime_test, false)))
172     return (false);
173 uberlord 2547
174 uberlord 2577 while (tests[i]) {
175     path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL);
176     if (rc_exists (path)) {
177     time_t m = get_mtime (path, false);
178     if (mtime < m && m != 0) {
179     free (path);
180     return (false);
181     }
182     }
183     free (path);
184     i++;
185     }
186 uberlord 2547
187 uberlord 2577 return (true);
188 uberlord 2547 }
189    
190     static void uncoldplug (char *service)
191     {
192 uberlord 2577 char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", basename (service),
193     (char *) NULL);
194     if (rc_exists (cold) && unlink (cold) != 0)
195     eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
196     free (cold);
197 uberlord 2547 }
198    
199     static void cleanup (void)
200     {
201 uberlord 2577 /* Flush our buffered output if any */
202     eflush ();
203 uberlord 2547
204 uberlord 2577 if (hook_out)
205     rc_plugin_run (hook_out, applet);
206     rc_plugin_unload ();
207 uberlord 2547
208 uberlord 2577 if (deptree)
209     rc_free_deptree (deptree);
210     if (services)
211     rc_strlist_free (services);
212     if (types)
213     rc_strlist_free (types);
214     if (svclist)
215     rc_strlist_free (svclist);
216     if (providelist)
217     rc_strlist_free (providelist);
218     if (restart_services)
219     rc_strlist_free (restart_services);
220     if (need_services)
221     rc_strlist_free (need_services);
222     if (tmplist)
223     rc_strlist_free (tmplist);
224     if (ibsave)
225     free (ibsave);
226 uberlord 2547
227 uberlord 2577 if (in_control ()) {
228     if (rc_service_state (applet, rc_service_stopping)) {
229     /* If the we're shutting down, do it cleanly */
230     if ((softlevel &&
231     rc_runlevel_stopping () &&
232     (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
233     strcmp (softlevel, RC_LEVEL_REBOOT) == 0)))
234     rc_mark_service (applet, rc_service_stopped);
235     else if (rc_service_state (applet, rc_service_wasinactive))
236     rc_mark_service (applet, rc_service_inactive);
237     else
238     rc_mark_service (applet, rc_service_started);
239     }
240     else if (rc_service_state (applet, rc_service_starting))
241     {
242     if (rc_service_state (applet, rc_service_wasinactive))
243     rc_mark_service (applet, rc_service_inactive);
244     else
245     rc_mark_service (applet, rc_service_stopped);
246     }
247     if (exclusive && rc_exists (exclusive))
248     unlink (exclusive);
249     }
250 uberlord 2547
251 uberlord 2577 if (env)
252     rc_strlist_free (env);
253 uberlord 2547
254 uberlord 2577 if (mtime_test)
255     {
256     unlink (mtime_test);
257     free (mtime_test);
258     }
259     if (exclusive)
260     free (exclusive);
261 uberlord 2547
262 uberlord 2577 if (applet)
263     free (applet);
264 uberlord 2547 }
265    
266     static bool svc_exec (const char *service, const char *arg1, const char *arg2)
267     {
268 uberlord 2641 bool retval;
269 uberlord 2547
270 uberlord 2577 /* We need to disable our child signal handler now so we block
271     until our script returns. */
272     signal (SIGCHLD, NULL);
273 uberlord 2569
274 uberlord 2641 service_pid = vfork();
275 uberlord 2547
276 uberlord 2641 if (service_pid == -1)
277 uberlord 2638 eerrorx ("%s: vfork: %s", service, strerror (errno));
278 uberlord 2641 if (service_pid == 0) {
279 uberlord 2577 if (rc_exists (RC_SVCDIR "runscript.sh")) {
280 uberlord 2638 execl (RC_SVCDIR "runscript.sh", service, service, arg1, arg2,
281 uberlord 2577 (char *) NULL);
282 uberlord 2638 eerror ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
283 uberlord 2642 service, strerror (errno));
284 uberlord 2638 _exit (EXIT_FAILURE);
285 uberlord 2577 } else {
286 uberlord 2638 execl (RC_LIBDIR "sh/runscript.sh", service, service, arg1, arg2,
287 uberlord 2577 (char *) NULL);
288 uberlord 2638 eerror ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
289 uberlord 2642 service, strerror (errno));
290 uberlord 2638 _exit (EXIT_FAILURE);
291 uberlord 2577 }
292     }
293 uberlord 2547
294 uberlord 2641 retval = rc_waitpid (service_pid) == 0 ? true : false;
295 uberlord 2547
296 uberlord 2641 service_pid = 0;
297 uberlord 2577 /* Done, so restore the signal handler */
298     signal (SIGCHLD, handle_signal);
299 uberlord 2547
300 uberlord 2641 return (retval);
301 uberlord 2547 }
302    
303     static rc_service_state_t svc_status (const char *service)
304     {
305 uberlord 2577 char status[10];
306     int (*e) (const char *fmt, ...) = &einfo;
307 uberlord 2547
308 uberlord 2577 rc_service_state_t retval = rc_service_stopped;
309 uberlord 2547
310 uberlord 2577 if (rc_service_state (service, rc_service_stopping)) {
311     snprintf (status, sizeof (status), "stopping");
312     e = &ewarn;
313     retval = rc_service_stopping;
314     } else if (rc_service_state (service, rc_service_starting)) {
315     snprintf (status, sizeof (status), "starting");
316     e = &ewarn;
317     retval = rc_service_starting;
318     } else if (rc_service_state (service, rc_service_inactive)) {
319     snprintf (status, sizeof (status), "inactive");
320     e = &ewarn;
321     retval = rc_service_inactive;
322     } else if (rc_service_state (service, rc_service_crashed)) {
323     snprintf (status, sizeof (status), "crashed");
324     e = &eerror;
325     retval = rc_service_crashed;
326     } else if (rc_service_state (service, rc_service_started)) {
327     snprintf (status, sizeof (status), "started");
328     retval = rc_service_started;
329     } else
330     snprintf (status, sizeof (status), "stopped");
331 uberlord 2547
332 uberlord 2577 e ("status: %s", status);
333     return (retval);
334 uberlord 2547 }
335    
336     static void make_exclusive (const char *service)
337     {
338 uberlord 2577 char *path;
339     int i;
340 uberlord 2547
341 uberlord 2577 /* We create a fifo so that other services can wait until we complete */
342     if (! exclusive)
343     exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
344 uberlord 2547
345 uberlord 2577 if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST &&
346     (errno != EACCES || geteuid () == 0))
347     eerrorx ("%s: unable to create fifo `%s': %s",
348     applet, exclusive, strerror (errno));
349 uberlord 2547
350 uberlord 2577 path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
351     i = strlen (path) + 16;
352     mtime_test = rc_xmalloc (sizeof (char *) * i);
353     snprintf (mtime_test, i, "%s.%d", path, getpid ());
354     free (path);
355 uberlord 2547
356 uberlord 2577 if (rc_exists (mtime_test) && unlink (mtime_test) != 0) {
357     eerror ("%s: unlink `%s': %s",
358     applet, mtime_test, strerror (errno));
359     free (mtime_test);
360     mtime_test = NULL;
361     return;
362     }
363 uberlord 2547
364 uberlord 2577 if (symlink (service, mtime_test) != 0) {
365     eerror ("%s: symlink `%s' to `%s': %s",
366     applet, service, mtime_test, strerror (errno));
367     free (mtime_test);
368     mtime_test = NULL;
369     }
370 uberlord 2547 }
371    
372     static void unlink_mtime_test ()
373     {
374 uberlord 2577 if (unlink (mtime_test) != 0)
375     eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno));
376     free (mtime_test);
377     mtime_test = NULL;
378 uberlord 2547 }
379    
380     static void get_started_services ()
381     {
382 uberlord 2577 char *service;
383     int i;
384 uberlord 2547
385 uberlord 2577 rc_strlist_free (tmplist);
386     tmplist = rc_services_in_state (rc_service_inactive);
387 uberlord 2547
388 uberlord 2577 rc_strlist_free (restart_services);
389     restart_services = rc_services_in_state (rc_service_started);
390 uberlord 2547
391 uberlord 2577 STRLIST_FOREACH (tmplist, service, i)
392     restart_services = rc_strlist_addsort (restart_services, service);
393 uberlord 2547
394 uberlord 2577 rc_strlist_free (tmplist);
395     tmplist = NULL;
396 uberlord 2547 }
397    
398     static void svc_start (const char *service, bool deps)
399     {
400 uberlord 2577 bool started;
401     bool background = false;
402     char *svc;
403     char *svc2;
404     int i;
405     int j;
406     int depoptions = RC_DEP_TRACE;
407 uberlord 2547
408 uberlord 2577 rc_plugin_run (rc_hook_service_start_in, applet);
409     hook_out = rc_hook_service_start_out;
410 uberlord 2573
411 uberlord 2577 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
412     depoptions |= RC_DEP_STRICT;
413 uberlord 2547
414 uberlord 2577 if (rc_is_env ("IN_HOTPLUG", "1") || in_background) {
415 uberlord 2578 if (! rc_service_state (service, rc_service_inactive) &&
416 uberlord 2582 ! rc_service_state (service, rc_service_stopped))
417 uberlord 2577 exit (EXIT_FAILURE);
418     background = true;
419     }
420 uberlord 2547
421 uberlord 2577 if (rc_service_state (service, rc_service_started))
422     ewarnx ("WARNING: %s has already been started", applet);
423     else if (rc_service_state (service, rc_service_starting))
424     ewarnx ("WARNING: %s is already starting", applet);
425     else if (rc_service_state (service, rc_service_stopping))
426     ewarnx ("WARNING: %s is stopping", applet);
427     else if (rc_service_state (service, rc_service_inactive) && ! background)
428     ewarnx ("WARNING: %s has already started, but is inactive", applet);
429 uberlord 2547
430 uberlord 2577 if (! rc_mark_service (service, rc_service_starting))
431     eerrorx ("ERROR: %s has been started by something else", applet);
432 uberlord 2547
433 uberlord 2577 make_exclusive (service);
434 uberlord 2547
435 uberlord 2577 if (deps) {
436     if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
437     eerrorx ("failed to load deptree");
438 uberlord 2547
439 uberlord 2577 rc_strlist_free (types);
440     types = rc_strlist_add (NULL, "broken");
441     rc_strlist_free (svclist);
442     svclist = rc_strlist_add (NULL, applet);
443     rc_strlist_free (services);
444     services = rc_get_depends (deptree, types, svclist, softlevel, 0);
445     if (services) {
446     eerrorn ("ERROR: `%s' needs ", applet);
447     STRLIST_FOREACH (services, svc, i) {
448     if (i > 0)
449     fprintf (stderr, ", ");
450     fprintf (stderr, "%s", svc);
451     }
452     exit (EXIT_FAILURE);
453     }
454     rc_strlist_free (services);
455     services = NULL;
456 uberlord 2547
457 uberlord 2577 rc_strlist_free (types);
458     types = rc_strlist_add (NULL, "ineed");
459     rc_strlist_free (need_services);
460     need_services = rc_get_depends (deptree, types, svclist,
461     softlevel, depoptions);
462     types = rc_strlist_add (types, "iuse");
463     if (! rc_runlevel_starting ()) {
464     services = rc_get_depends (deptree, types, svclist,
465     softlevel, depoptions);
466     STRLIST_FOREACH (services, svc, i)
467 uberlord 2641 if (rc_service_state (svc, rc_service_stopped)) {
468     pid_t pid = rc_start_service (svc);
469     if (! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
470     rc_waitpid (pid);
471     }
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 uberlord 2641 pid_t pid = rc_stop_service (svc);
673     if (! rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
674     rc_waitpid (pid);
675 uberlord 2577 tmplist = rc_strlist_add (tmplist, svc);
676     }
677     }
678     }
679     rc_strlist_free (services);
680     services = NULL;
681 uberlord 2547
682 uberlord 2577 STRLIST_FOREACH (tmplist, svc, i) {
683     if (rc_service_state (svc, rc_service_stopped))
684     continue;
685 uberlord 2547
686 uberlord 2577 /* We used to loop 3 times here - maybe re-do this if needed */
687     rc_wait_service (svc);
688     if (! rc_service_state (svc, rc_service_stopped)) {
689     if (rc_runlevel_stopping ())
690     rc_mark_service (svc, rc_service_failed);
691     eerrorx ("ERROR: cannot stop %s as %s is still up",
692     applet, svc);
693     }
694     }
695     rc_strlist_free (tmplist);
696     tmplist = NULL;
697 uberlord 2547
698 uberlord 2577 /* We now wait for other services that may use us and are stopping
699     This is important when a runlevel stops */
700     types = rc_strlist_add (types, "usesme");
701     types = rc_strlist_add (types, "ibefore");
702     services = rc_get_depends (deptree, types, svclist,
703     softlevel, depoptions);
704     STRLIST_FOREACH (services, svc, i) {
705     if (rc_service_state (svc, rc_service_stopped))
706     continue;
707     rc_wait_service (svc);
708     }
709 uberlord 2547
710 uberlord 2577 rc_strlist_free (services);
711     services = NULL;
712     rc_strlist_free (types);
713     types = NULL;
714     }
715 uberlord 2547
716 uberlord 2577 if (ibsave)
717     setenv ("IN_BACKGROUND", ibsave, 1);
718     rc_plugin_run (rc_hook_service_stop_now, applet);
719     stopped = svc_exec (service, "stop", NULL);
720     if (ibsave)
721     unsetenv ("IN_BACKGROUND");
722 uberlord 2547
723 uberlord 2577 if (! in_control ()) {
724     rc_plugin_run (rc_hook_service_stop_done, applet);
725     ewarnx ("WARNING: %s not under our control, aborting", applet);
726     }
727 uberlord 2547
728 uberlord 2577 if (! stopped) {
729     if (rc_service_state (service, rc_service_wasinactive))
730     rc_mark_service (service, rc_service_inactive);
731     else
732     rc_mark_service (service, rc_service_started);
733     rc_plugin_run (rc_hook_service_stop_done, applet);
734     eerrorx ("ERROR: %s failed to stop", applet);
735     }
736 uberlord 2547
737 uberlord 2577 if (in_background)
738     rc_mark_service (service, rc_service_inactive);
739     else
740     rc_mark_service (service, rc_service_stopped);
741 uberlord 2547
742 uberlord 2577 unlink_mtime_test ();
743     rc_plugin_run (rc_hook_service_stop_done, applet);
744     hook_out = 0;
745     rc_plugin_run (rc_hook_service_stop_out, applet);
746 uberlord 2547 }
747    
748     static void svc_restart (const char *service, bool deps)
749     {
750 uberlord 2577 char *svc;
751     int i;
752     bool inactive = false;
753 uberlord 2569
754 uberlord 2577 /* This is hairly and a better way needs to be found I think!
755     The issue is this - openvpn need net and dns. net can restart
756     dns via resolvconf, so you could have openvpn trying to restart dnsmasq
757     which in turn is waiting on net which in turn is waiting on dnsmasq.
758     The work around is for resolvconf to restart it's services with --nodeps
759     which means just that. The downside is that there is a small window when
760     our status is invalid.
761     One workaround would be to introduce a new status, or status locking. */
762     if (! deps) {
763     if (rc_service_state (service, rc_service_started) ||
764     rc_service_state (service, rc_service_inactive))
765     svc_exec (service, "stop", "start");
766     else
767     svc_exec (service, "start", NULL);
768     return;
769     }
770 uberlord 2547
771 uberlord 2577 if (! rc_service_state (service, rc_service_stopped)) {
772     get_started_services ();
773     svc_stop (service, deps);
774 uberlord 2547
775 uberlord 2577 /* Flush our buffered output if any */
776     eflush ();
777     }
778 uberlord 2547
779 uberlord 2577 svc_start (service, deps);
780 uberlord 2547
781 uberlord 2577 inactive = rc_service_state (service, rc_service_inactive);
782     if (! inactive)
783     inactive = rc_service_state (service, rc_service_wasinactive);
784 uberlord 2569
785 uberlord 2577 if (inactive ||
786     rc_service_state (service, rc_service_starting) ||
787     rc_service_state (service, rc_service_started))
788     {
789     STRLIST_FOREACH (restart_services, svc, i) {
790     if (rc_service_state (svc, rc_service_stopped)) {
791     if (inactive) {
792     rc_schedule_start_service (service, svc);
793     ewarn ("WARNING: %s is scheduled to started when %s has started",
794 uberlord 2634 svc, applet);
795 uberlord 2577 } else
796     rc_start_service (svc);
797     }
798     }
799     }
800 uberlord 2547 }
801    
802 vapier 2618 #define getoptstring "dCDNqvh"
803     static struct option longopts[] = {
804     { "debug", 0, NULL, 'd'},
805     { "nocolor", 0, NULL, 'C'},
806     { "nocolour", 0, NULL, 'C'},
807     { "nodeps", 0, NULL, 'D'},
808     { "quiet", 0, NULL, 'q'},
809     { "verbose", 0, NULL, 'v'},
810     { "help", 0, NULL, 'h'},
811     { NULL, 0, NULL, 0}
812     };
813 uberlord 2634 // #include "_usage.c"
814 vapier 2618
815 uberlord 2547 int main (int argc, char **argv)
816     {
817 uberlord 2634 char *service = argv[1];
818 uberlord 2577 int i;
819     bool deps = true;
820     bool doneone = false;
821     char pid[16];
822     int retval;
823 uberlord 2580 char c;
824 uberlord 2547
825 uberlord 2577 /* Show help if insufficient args */
826     if (argc < 3) {
827     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
828     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
829     applet, strerror (errno));
830     }
831 uberlord 2547
832 uberlord 2634 applet = rc_xstrdup (basename (service));
833 uberlord 2581 atexit (cleanup);
834    
835 uberlord 2547 #ifdef __linux__
836 uberlord 2577 /* coldplug events can trigger init scripts, but we don't want to run them
837     until after rc sysinit has completed so we punt them to the boot runlevel */
838     if (rc_exists ("/dev/.rcsysinit")) {
839     eerror ("%s: cannot run until sysvinit completes", applet);
840     if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
841     eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
842     tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
843     symlink (service, tmp);
844     exit (EXIT_FAILURE);
845     }
846 uberlord 2547 #endif
847    
848 uberlord 2577 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
849     /* Ensure our environment is pure
850     Also, add our configuration to it */
851     env = rc_filter_env ();
852     env = rc_config_env (env);
853 uberlord 2547
854 uberlord 2577 if (env) {
855     char *p;
856 uberlord 2547
857     #ifdef __linux__
858 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
859     if we have it */
860     clearenv ();
861 uberlord 2547 #else
862 uberlord 2577 char *var;
863     /* No clearenv present here then.
864     We could manipulate environ directly ourselves, but it seems that
865     some kernels bitch about this according to the environ man pages
866     so we walk though environ and call unsetenv for each value. */
867     while (environ[0]) {
868     tmp = rc_xstrdup (environ[0]);
869     p = tmp;
870     var = strsep (&p, "=");
871     unsetenv (var);
872     free (tmp);
873     }
874     tmp = NULL;
875 uberlord 2547 #endif
876    
877 uberlord 2577 STRLIST_FOREACH (env, p, i)
878     putenv (p);
879 uberlord 2547
880 uberlord 2577 /* We don't free our list as that would be null in environ */
881     }
882 uberlord 2547
883 uberlord 2577 softlevel = rc_get_runlevel ();
884 uberlord 2547
885 uberlord 2577 /* If not called from RC or another service then don't be parallel */
886     unsetenv ("RC_PARALLEL_STARTUP");
887     }
888 uberlord 2547
889 uberlord 2577 setenv ("RC_ELOG", service, 1);
890     setenv ("SVCNAME", applet, 1);
891 uberlord 2547
892 uberlord 2577 /* Set an env var so that we always know our pid regardless of any
893     subshells the init script may create so that our mark_service_*
894     functions can always instruct us of this change */
895     snprintf (pid, sizeof (pid), "%d", (int) getpid ());
896     setenv ("RC_RUNSCRIPT_PID", pid, 1);
897 uberlord 2547
898 uberlord 2577 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) {
899     char ebname[PATH_MAX];
900     char *eb;
901 uberlord 2547
902 uberlord 2577 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
903     eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
904     setenv ("RC_EBUFFER", eb, 1);
905     free (eb);
906     }
907 uberlord 2547
908     #ifdef __linux__
909 uberlord 2577 /* Ok, we are ready to go, so setup selinux if applicable */
910     setup_selinux (argc, argv);
911 uberlord 2547 #endif
912    
913 uberlord 2581 /* Punt the first arg as it's our service name */
914     argc--;
915     argv++;
916    
917 uberlord 2577 /* Right then, parse any options there may be */
918 vapier 2618 while ((c = getopt_long (argc, argv, getoptstring,
919 uberlord 2580 longopts, (int *) 0)) != -1)
920     switch (c) {
921     case 'd':
922     setenv ("RC_DEBUG", "yes", 1);
923     break;
924     case 'h':
925     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
926     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
927     applet, strerror (errno));
928     case 'C':
929     setenv ("RC_NOCOLOR", "yes", 1);
930     break;
931     case 'D':
932     deps = false;
933     break;
934     case 'q':
935     setenv ("RC_QUIET", "yes", 1);
936     break;
937     case 'v':
938     setenv ("RC_VERBOSE", "yes", 1);
939     break;
940     default:
941     exit (EXIT_FAILURE);
942     }
943 uberlord 2547
944 uberlord 2581 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
945     that is being called and not any dependents */
946     if (getenv ("IN_BACKGROUND")) {
947     in_background = rc_is_env ("IN_BACKGROUND", "true");
948 uberlord 2634 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
949 uberlord 2581 unsetenv ("IN_BACKGROUND");
950     }
951    
952 uberlord 2577 if (rc_is_env ("IN_HOTPLUG", "1")) {
953     if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
954     eerrorx ("%s: not allowed to be hotplugged", applet);
955     }
956 uberlord 2547
957 uberlord 2577 /* Setup a signal handler */
958     signal (SIGHUP, handle_signal);
959     signal (SIGINT, handle_signal);
960     signal (SIGQUIT, handle_signal);
961     signal (SIGTERM, handle_signal);
962     signal (SIGCHLD, handle_signal);
963 uberlord 2547
964 uberlord 2577 /* Load our plugins */
965     rc_plugin_load ();
966 uberlord 2547
967 uberlord 2577 /* Now run each option */
968     retval = EXIT_SUCCESS;
969 uberlord 2580 while (optind < argc) {
970     optarg = argv[optind++];
971    
972 uberlord 2577 /* Abort on a sighup here */
973     if (sighup)
974     exit (EXIT_FAILURE);
975 uberlord 2547
976 uberlord 2577 /* Export the command we're running.
977     This is important as we stamp on the restart function now but
978     some start/stop routines still need to behave differently if
979     restarting. */
980     unsetenv ("RC_CMD");
981 uberlord 2580 setenv ("RC_CMD", optarg, 1);
982 uberlord 2569
983 uberlord 2577 doneone = true;
984 uberlord 2580 if (strcmp (optarg, "conditionalrestart") == 0 ||
985     strcmp (optarg, "condrestart") == 0)
986 uberlord 2577 {
987     if (rc_service_state (service, rc_service_started))
988     svc_restart (service, deps);
989     }
990 uberlord 2580 else if (strcmp (optarg, "restart") == 0)
991 uberlord 2577 svc_restart (service, deps);
992 uberlord 2580 else if (strcmp (optarg, "start") == 0)
993 uberlord 2577 svc_start (service, deps);
994 uberlord 2580 else if (strcmp (optarg, "status") == 0) {
995 uberlord 2577 rc_service_state_t r = svc_status (service);
996     retval = (int) r;
997 uberlord 2580 } else if (strcmp (optarg, "stop") == 0) {
998 uberlord 2577 if (in_background)
999     get_started_services ();
1000 uberlord 2547
1001 uberlord 2577 svc_stop (service, deps);
1002 uberlord 2547
1003 uberlord 2577 if (! in_background &&
1004     ! rc_runlevel_stopping () &&
1005     rc_service_state (service, rc_service_stopped))
1006     uncoldplug (applet);
1007 uberlord 2560
1008 uberlord 2577 if (in_background &&
1009     rc_service_state (service, rc_service_inactive))
1010     {
1011     char *svc;
1012     int j;
1013     STRLIST_FOREACH (restart_services, svc, j)
1014     if (rc_service_state (svc, rc_service_stopped))
1015     rc_schedule_start_service (service, svc);
1016     }
1017 uberlord 2580 } else if (strcmp (optarg, "zap") == 0) {
1018 uberlord 2577 einfo ("Manually resetting %s to stopped state", applet);
1019     rc_mark_service (applet, rc_service_stopped);
1020     uncoldplug (applet);
1021 uberlord 2580 } else if (strcmp (optarg, "help") == 0) {
1022 uberlord 2577 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1023     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1024     applet, strerror (errno));
1025     }else
1026 uberlord 2580 svc_exec (service, optarg, NULL);
1027 uberlord 2547
1028 uberlord 2577 /* Flush our buffered output if any */
1029     eflush ();
1030 uberlord 2547
1031 uberlord 2577 /* We should ensure this list is empty after an action is done */
1032     rc_strlist_free (restart_services);
1033     restart_services = NULL;
1034     }
1035 uberlord 2547
1036 uberlord 2577 if (! doneone) {
1037     execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1038     eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1039     applet, strerror (errno));
1040     }
1041 uberlord 2547
1042 uberlord 2577 return (retval);
1043 uberlord 2547 }

  ViewVC Help
Powered by ViewVC 1.1.20