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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20