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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20