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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20