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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2786 - (hide annotations) (download) (as text)
Sat Jul 21 12:49:51 2007 UTC (10 years, 11 months ago) by uberlord
File MIME type: text/x-csrc
File size: 33554 byte(s)
    RC_DEPEND_STRICT now controls dependency strictness.
    If yes then we only use services in the boot and default runlevels,
    regradless of service state.
    If no then we take into account coldplugged services and the state
    of currently running services.
    Fixes #185640.
1 uberlord 2547 /*
2     rc.c
3     rc - manager for init scripts which control the startup, shutdown
4     and the running of daemons on a Gentoo system.
5    
6     Also a multicall binary for various commands that can be used in shell
7     scripts to query service state, mark service state and provide the
8     Gentoo einfo family of informational functions.
9 uberlord 2569
10 uberlord 2547 Copyright 2007 Gentoo Foundation
11     Released under the GPLv2
12     */
13    
14 uberlord 2734 #define APPLET "rc"
15    
16 uberlord 2547 #include <sys/types.h>
17     #include <sys/stat.h>
18     #include <sys/utsname.h>
19     #include <sys/wait.h>
20     #include <errno.h>
21     #include <ctype.h>
22 uberlord 2734 #include <getopt.h>
23 uberlord 2547 #include <libgen.h>
24     #include <limits.h>
25     #include <stdbool.h>
26     #include <stdio.h>
27     #include <stdlib.h>
28     #include <signal.h>
29     #include <string.h>
30     #include <termios.h>
31     #include <unistd.h>
32    
33     #include "einfo.h"
34     #include "rc.h"
35     #include "rc-misc.h"
36     #include "rc-plugin.h"
37     #include "strlist.h"
38    
39 uberlord 2659 #define INITSH RC_LIBDIR "sh/init.sh"
40     #define INITEARLYSH RC_LIBDIR "sh/init-early.sh"
41     #define HALTSH RC_INITDIR "halt.sh"
42 uberlord 2684 #define SULOGIN "/sbin/sulogin"
43 uberlord 2547
44 uberlord 2659 #define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
45     #define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
46     #define RC_SVCDIR_STARTED RC_SVCDIR "started/"
47     #define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
48 uberlord 2547
49 uberlord 2659 #define INTERACTIVE RC_SVCDIR "interactive"
50 uberlord 2547
51 uberlord 2615 #define DEVBOOT "/dev/.rcboot"
52 uberlord 2547
53     /* Cleanup anything in main */
54 uberlord 2577 #define CHAR_FREE(_item) if (_item) { \
55     free (_item); \
56     _item = NULL; \
57 uberlord 2547 }
58    
59     extern char **environ;
60    
61 uberlord 2769 static char *RUNLEVEL = NULL;
62     static char *PREVLEVEL = NULL;
63    
64 uberlord 2563 static char *applet = NULL;
65 uberlord 2547 static char **env = NULL;
66     static char **newenv = NULL;
67 uberlord 2638 static char **coldplugged_services = NULL;
68 uberlord 2547 static char **stop_services = NULL;
69     static char **start_services = NULL;
70     static rc_depinfo_t *deptree = NULL;
71     static char **types = NULL;
72     static char *tmp = NULL;
73    
74 uberlord 2638 struct termios *termios_orig = NULL;
75 uberlord 2547
76 uberlord 2641 typedef struct pidlist
77     {
78     pid_t pid;
79     struct pidlist *next;
80     } pidlist_t;
81     static pidlist_t *service_pids = NULL;
82    
83 uberlord 2547 static void cleanup (void)
84     {
85 uberlord 2641 pidlist_t *pl = service_pids;
86    
87 uberlord 2577 rc_plugin_unload ();
88 uberlord 2547
89 uberlord 2744 if (! rc_in_plugin && termios_orig) {
90 uberlord 2769 tcsetattr (fileno (stdin), TCSANOW, termios_orig);
91 uberlord 2577 free (termios_orig);
92     }
93 uberlord 2547
94 uberlord 2641 while (pl) {
95     pidlist_t *p = pl->next;
96     free (pl);
97     pl = p;
98     }
99    
100 uberlord 2638 rc_strlist_free (env);
101     rc_strlist_free (newenv);
102     rc_strlist_free (coldplugged_services);
103     rc_strlist_free (stop_services);
104     rc_strlist_free (start_services);
105     rc_free_deptree (deptree);
106     rc_strlist_free (types);
107 uberlord 2547
108 uberlord 2577 /* Clean runlevel start, stop markers */
109 uberlord 2744 if (! rc_in_plugin) {
110     if (rc_is_dir (RC_SVCDIR "softscripts.new"))
111     rc_rm_dir (RC_SVCDIR "softscripts.new", true);
112     if (rc_is_dir (RC_SVCDIR "softscripts.old"))
113     rc_rm_dir (RC_SVCDIR "softscripts.old", true);
114     }
115 uberlord 2563
116 uberlord 2638 free (applet);
117 uberlord 2547 }
118    
119     static int do_e (int argc, char **argv)
120     {
121 uberlord 2577 int retval = EXIT_SUCCESS;
122     int i;
123     int l = 0;
124     char *message = NULL;
125     char *p;
126     char *fmt = NULL;
127 uberlord 2547
128 uberlord 2615 if (strcmp (applet, "eval_ecolors") == 0) {
129     printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
130     ecolor (ecolor_good),
131     ecolor (ecolor_warn),
132     ecolor (ecolor_bad),
133     ecolor (ecolor_hilite),
134     ecolor (ecolor_bracket),
135     ecolor (ecolor_normal));
136     exit (EXIT_SUCCESS);
137     }
138    
139 uberlord 2577 if (strcmp (applet, "eend") == 0 ||
140     strcmp (applet, "ewend") == 0 ||
141     strcmp (applet, "veend") == 0 ||
142     strcmp (applet, "vweend") == 0)
143     {
144     if (argc > 0) {
145     errno = 0;
146     retval = strtol (argv[0], NULL, 0);
147     if (errno != 0)
148     retval = EXIT_FAILURE;
149     else {
150     argc--;
151     argv++;
152     }
153     }
154     }
155 uberlord 2547
156 uberlord 2577 if (argc > 0) {
157     for (i = 0; i < argc; i++)
158     l += strlen (argv[i]) + 1;
159 uberlord 2547
160 uberlord 2577 message = rc_xmalloc (l);
161     p = message;
162 uberlord 2547
163 uberlord 2577 for (i = 0; i < argc; i++) {
164     if (i > 0)
165     *p++ = ' ';
166     memcpy (p, argv[i], strlen (argv[i]));
167     p += strlen (argv[i]);
168     }
169     *p = 0;
170     }
171 uberlord 2547
172 uberlord 2577 if (message)
173 uberlord 2634 fmt = rc_xstrdup ("%s");
174 uberlord 2547
175 uberlord 2577 if (strcmp (applet, "einfo") == 0)
176     einfo (fmt, message);
177     else if (strcmp (applet, "einfon") == 0)
178     einfon (fmt, message);
179     else if (strcmp (applet, "ewarn") == 0)
180     ewarn (fmt, message);
181     else if (strcmp (applet, "ewarnn") == 0)
182     ewarnn (fmt, message);
183     else if (strcmp (applet, "eerror") == 0) {
184     eerror (fmt, message);
185     retval = 1;
186     } else if (strcmp (applet, "eerrorn") == 0) {
187     eerrorn (fmt, message);
188     retval = 1;
189     } else if (strcmp (applet, "ebegin") == 0)
190     ebegin (fmt, message);
191     else if (strcmp (applet, "eend") == 0)
192     eend (retval, fmt, message);
193     else if (strcmp (applet, "ewend") == 0)
194     ewend (retval, fmt, message);
195     else if (strcmp (applet, "veinfo") == 0)
196     einfov (fmt, message);
197     else if (strcmp (applet, "veinfon") == 0)
198     einfovn (fmt, message);
199     else if (strcmp (applet, "vewarn") == 0)
200     ewarnv (fmt, message);
201     else if (strcmp (applet, "vewarnn") == 0)
202     ewarnvn (fmt, message);
203     else if (strcmp (applet, "vebegin") == 0)
204     ebeginv (fmt, message);
205     else if (strcmp (applet, "veend") == 0)
206     eendv (retval, fmt, message);
207     else if (strcmp (applet, "vewend") == 0)
208     ewendv (retval, fmt, message);
209     else if (strcmp (applet, "eindent") == 0)
210     eindent ();
211     else if (strcmp (applet, "eoutdent") == 0)
212     eoutdent ();
213     else if (strcmp (applet, "veindent") == 0)
214     eindentv ();
215     else if (strcmp (applet, "veoutdent") == 0)
216     eoutdentv ();
217     else {
218     eerror ("%s: unknown applet", applet);
219     retval = EXIT_FAILURE;
220     }
221 uberlord 2547
222 uberlord 2577 if (fmt)
223     free (fmt);
224     if (message)
225     free (message);
226     return (retval);
227 uberlord 2547 }
228    
229     static int do_service (int argc, char **argv)
230     {
231 uberlord 2577 bool ok = false;
232 uberlord 2547
233 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
234     eerrorx ("%s: no service specified", applet);
235 uberlord 2547
236 uberlord 2577 if (strcmp (applet, "service_started") == 0)
237     ok = rc_service_state (argv[0], rc_service_started);
238     else if (strcmp (applet, "service_stopped") == 0)
239     ok = rc_service_state (argv[0], rc_service_stopped);
240     else if (strcmp (applet, "service_inactive") == 0)
241     ok = rc_service_state (argv[0], rc_service_inactive);
242     else if (strcmp (applet, "service_starting") == 0)
243     ok = rc_service_state (argv[0], rc_service_starting);
244     else if (strcmp (applet, "service_stopping") == 0)
245     ok = rc_service_state (argv[0], rc_service_stopping);
246     else if (strcmp (applet, "service_coldplugged") == 0)
247     ok = rc_service_state (argv[0], rc_service_coldplugged);
248     else if (strcmp (applet, "service_wasinactive") == 0)
249     ok = rc_service_state (argv[0], rc_service_wasinactive);
250     else if (strcmp (applet, "service_started_daemon") == 0) {
251     int idx = 0;
252     if (argc > 2)
253     sscanf (argv[2], "%d", &idx);
254     exit (rc_service_started_daemon (argv[0], argv[1], idx)
255     ? 0 : 1);
256     } else
257     eerrorx ("%s: unknown applet", applet);
258 uberlord 2547
259 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
260 uberlord 2547 }
261    
262     static int do_mark_service (int argc, char **argv)
263     {
264 uberlord 2577 bool ok = false;
265     char *svcname = getenv ("SVCNAME");
266 uberlord 2547
267 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
268     eerrorx ("%s: no service specified", applet);
269 uberlord 2547
270 uberlord 2577 if (strcmp (applet, "mark_service_started") == 0)
271     ok = rc_mark_service (argv[0], rc_service_started);
272     else if (strcmp (applet, "mark_service_stopped") == 0)
273     ok = rc_mark_service (argv[0], rc_service_stopped);
274     else if (strcmp (applet, "mark_service_inactive") == 0)
275     ok = rc_mark_service (argv[0], rc_service_inactive);
276     else if (strcmp (applet, "mark_service_starting") == 0)
277     ok = rc_mark_service (argv[0], rc_service_starting);
278     else if (strcmp (applet, "mark_service_stopping") == 0)
279     ok = rc_mark_service (argv[0], rc_service_stopping);
280     else if (strcmp (applet, "mark_service_coldplugged") == 0)
281     ok = rc_mark_service (argv[0], rc_service_coldplugged);
282     else
283     eerrorx ("%s: unknown applet", applet);
284 uberlord 2547
285 uberlord 2577 /* If we're marking ourselves then we need to inform our parent runscript
286     process so they do not mark us based on our exit code */
287     if (ok && svcname && strcmp (svcname, argv[0]) == 0) {
288     char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
289     char *mtime;
290     pid_t pid = 0;
291     int l;
292 uberlord 2547
293 uberlord 2577 if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
294     if (kill (pid, SIGHUP) != 0)
295     eerror ("%s: failed to signal parent %d: %s",
296     applet, pid, strerror (errno));
297 uberlord 2547
298 uberlord 2577 /* Remove the exclsive time test. This ensures that it's not
299     in control as well */
300     l = strlen (RC_SVCDIR "exclusive") +
301     strlen (svcname) +
302     strlen (runscript_pid) +
303     4;
304     mtime = rc_xmalloc (l);
305     snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
306     svcname, runscript_pid);
307     if (rc_exists (mtime) && unlink (mtime) != 0)
308     eerror ("%s: unlink: %s", applet, strerror (errno));
309     free (mtime);
310     }
311 uberlord 2547
312 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
313 uberlord 2547 }
314    
315     static int do_options (int argc, char **argv)
316     {
317 uberlord 2577 bool ok = false;
318     char *service = getenv ("SVCNAME");
319 uberlord 2547
320 uberlord 2577 if (! service)
321     eerrorx ("%s: no service specified", applet);
322 uberlord 2547
323 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
324     eerrorx ("%s: no option specified", applet);
325 uberlord 2547
326 uberlord 2577 if (strcmp (applet, "get_options") == 0) {
327     char buffer[1024];
328     memset (buffer, 0, 1024);
329     ok = rc_get_service_option (service, argv[0], buffer);
330     if (ok)
331     printf ("%s", buffer);
332     } else if (strcmp (applet, "save_options") == 0)
333     ok = rc_set_service_option (service, argv[0], argv[1]);
334     else
335     eerrorx ("%s: unknown applet", applet);
336 uberlord 2547
337 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
338 uberlord 2547 }
339    
340     static char read_key (bool block)
341     {
342 uberlord 2577 struct termios termios;
343     char c = 0;
344 uberlord 2769 int fd = fileno (stdin);
345    
346     if (! isatty (fd))
347 uberlord 2577 return (false);
348 uberlord 2547
349 uberlord 2577 /* Now save our terminal settings. We need to restore them at exit as we
350     will be changing it for non-blocking reads for Interactive */
351     if (! termios_orig) {
352     termios_orig = rc_xmalloc (sizeof (struct termios));
353 uberlord 2769 tcgetattr (fd, termios_orig);
354 uberlord 2577 }
355 uberlord 2547
356 uberlord 2769 tcgetattr (fd, &termios);
357 uberlord 2577 termios.c_lflag &= ~(ICANON | ECHO);
358     if (block)
359     termios.c_cc[VMIN] = 1;
360     else {
361     termios.c_cc[VMIN] = 0;
362     termios.c_cc[VTIME] = 0;
363     }
364 uberlord 2769 tcsetattr (fd, TCSANOW, &termios);
365 uberlord 2547
366 uberlord 2769 read (fd, &c, 1);
367 uberlord 2547
368 uberlord 2769 tcsetattr (fd, TCSANOW, termios_orig);
369 uberlord 2547
370 uberlord 2577 return (c);
371 uberlord 2547 }
372    
373     static bool want_interactive (void)
374     {
375 uberlord 2700 char c;
376    
377 uberlord 2769 if (PREVLEVEL &&
378     strcmp (PREVLEVEL, "N") != 0 &&
379     strcmp (PREVLEVEL, "S") != 0 &&
380     strcmp (PREVLEVEL, "1") != 0)
381     return (false);
382    
383 uberlord 2700 if (! rc_is_env ("RC_INTERACTIVE", "yes"))
384     return (false);
385    
386     c = read_key (false);
387 uberlord 2577 return ((c == 'I' || c == 'i') ? true : false);
388 uberlord 2547 }
389    
390     static void mark_interactive (void)
391     {
392 uberlord 2577 FILE *fp = fopen (INTERACTIVE, "w");
393     if (fp)
394     fclose (fp);
395 uberlord 2547 }
396    
397     static void sulogin (bool cont)
398     {
399     #ifdef __linux__
400 uberlord 2638 char *e = getenv ("RC_SYS");
401    
402     /* VPS systems cannot do an sulogin */
403     if (e && strcmp (e, "VPS") == 0) {
404     execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
405     eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
406     }
407 uberlord 2641 #endif
408 uberlord 2638
409 uberlord 2652 newenv = rc_filter_env ();
410    
411 uberlord 2577 if (cont) {
412     int status = 0;
413 uberlord 2684 #ifdef __linux__
414     char *tty = ttyname (fileno (stdout));
415     #endif
416    
417 uberlord 2652 pid_t pid = vfork ();
418 uberlord 2547
419 uberlord 2577 if (pid == -1)
420 uberlord 2638 eerrorx ("%s: vfork: %s", applet, strerror (errno));
421 uberlord 2577 if (pid == 0) {
422 uberlord 2641 #ifdef __linux__
423 uberlord 2684 if (tty)
424     execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
425     else
426     execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
427    
428     eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
429 uberlord 2638 strerror (errno));
430 uberlord 2641 #else
431     execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
432     eerror ("%s: unable to exec `/bin/sh': %s", applet,
433     strerror (errno));
434     #endif
435 uberlord 2638 _exit (EXIT_FAILURE);
436 uberlord 2577 }
437     waitpid (pid, &status, 0);
438     } else {
439 uberlord 2641 #ifdef __linux
440 uberlord 2656 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
441 uberlord 2577 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
442 uberlord 2547 #else
443 uberlord 2641 exit (EXIT_SUCCESS);
444 uberlord 2547 #endif
445 uberlord 2641 }
446 uberlord 2547 }
447    
448 uberlord 2638 static void single_user (void)
449     {
450     #ifdef __linux__
451     execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
452     eerrorx ("%s: unable to exec `/sbin/telinit': %s",
453     applet, strerror (errno));
454     #else
455     if (kill (1, SIGTERM) != 0)
456     eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
457     applet, strerror (errno));
458     exit (EXIT_SUCCESS);
459     #endif
460     }
461    
462 uberlord 2547 static void set_ksoftlevel (const char *runlevel)
463     {
464 uberlord 2577 FILE *fp;
465 uberlord 2547
466 uberlord 2577 if (! runlevel ||
467 uberlord 2786 strcmp (runlevel, getenv ("RC_BOOTLEVEL")) == 0 ||
468 uberlord 2577 strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
469     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0)
470     {
471     if (rc_exists (RC_SVCDIR "ksoftlevel") &&
472     unlink (RC_SVCDIR "ksoftlevel") != 0)
473     eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
474     return;
475     }
476 uberlord 2547
477 uberlord 2577 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) {
478     eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
479     return;
480     }
481 uberlord 2569
482 uberlord 2577 fprintf (fp, "%s", runlevel);
483     fclose (fp);
484 uberlord 2547 }
485    
486 uberlord 2759 static int get_ksoftlevel (char *buffer, int buffer_len)
487     {
488     FILE *fp;
489     int i = 0;
490    
491     if (! rc_exists (RC_SVCDIR "ksoftlevel"))
492     return 0;
493    
494     if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) {
495     eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
496     strerror (errno));
497     return -1;
498     }
499    
500     if (fgets (buffer, buffer_len, fp)) {
501     i = strlen (buffer) - 1;
502     if (buffer[i] == '\n')
503     buffer[i] = 0;
504     }
505    
506     fclose (fp);
507     return i;
508     }
509    
510 uberlord 2547 static void wait_for_services ()
511     {
512 uberlord 2577 int status = 0;
513     while (wait (&status) != -1);
514 uberlord 2547 }
515    
516 uberlord 2641 static void add_pid (pid_t pid)
517     {
518     pidlist_t *sp = service_pids;
519     if (sp) {
520     while (sp->next)
521     sp = sp->next;
522     sp->next = rc_xmalloc (sizeof (pidlist_t));
523     sp = sp->next;
524     } else
525     sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
526     memset (sp, 0, sizeof (pidlist_t));
527     sp->pid = pid;
528     }
529    
530     static void remove_pid (pid_t pid)
531     {
532     pidlist_t *last = NULL;
533     pidlist_t *pl;
534    
535     for (pl = service_pids; pl; pl = pl->next) {
536     if (pl->pid == pid) {
537     if (last)
538     last->next = pl->next;
539     else
540     service_pids = pl->next;
541     free (pl);
542     break;
543     }
544     last = pl;
545     }
546     }
547    
548 uberlord 2563 static void handle_signal (int sig)
549     {
550 uberlord 2577 int serrno = errno;
551     char signame[10] = { '\0' };
552 uberlord 2641 pidlist_t *pl;
553     pid_t pid;
554     int status = 0;
555 uberlord 2563
556 uberlord 2577 switch (sig) {
557 uberlord 2641 case SIGCHLD:
558     do {
559     pid = waitpid (-1, &status, WNOHANG);
560     if (pid < 0) {
561     if (errno != ECHILD)
562     eerror ("waitpid: %s", strerror (errno));
563     return;
564     }
565     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
566    
567     /* Remove that pid from our list */
568     if (pid > 0)
569     remove_pid (pid);
570     break;
571 uberlord 2642
572 uberlord 2577 case SIGINT:
573     if (! signame[0])
574     snprintf (signame, sizeof (signame), "SIGINT");
575     case SIGTERM:
576     if (! signame[0])
577     snprintf (signame, sizeof (signame), "SIGTERM");
578     case SIGQUIT:
579     if (! signame[0])
580     snprintf (signame, sizeof (signame), "SIGQUIT");
581     eerrorx ("%s: caught %s, aborting", applet, signame);
582 uberlord 2638 case SIGUSR1:
583     eerror ("rc: Aborting!");
584     /* Kill any running services we have started */
585 uberlord 2642
586 uberlord 2641 signal (SIGCHLD, SIG_IGN);
587     for (pl = service_pids; pl; pl = pl->next)
588     kill (pl->pid, SIGTERM);
589 uberlord 2642
590 uberlord 2640 /* Notify plugins we are aborting */
591 uberlord 2652 rc_plugin_run (rc_hook_abort, NULL);
592 uberlord 2642
593 uberlord 2641 /* Only drop into single user mode if we're booting */
594 uberlord 2769 if ((PREVLEVEL &&
595     (strcmp (PREVLEVEL, "S") == 0 ||
596     strcmp (PREVLEVEL, "1") == 0)) ||
597     (RUNLEVEL &&
598     (strcmp (RUNLEVEL, "S") == 0 ||
599     strcmp (RUNLEVEL, "1") == 0)))
600 uberlord 2638 single_user ();
601    
602     exit (EXIT_FAILURE);
603     break;
604    
605 uberlord 2577 default:
606     eerror ("%s: caught unknown signal %d", applet, sig);
607     }
608 uberlord 2563
609 uberlord 2577 /* Restore errno */
610     errno = serrno;
611 uberlord 2563 }
612    
613 uberlord 2713 static void run_script (const char *script) {
614     int status = 0;
615     pid_t pid = vfork ();
616 uberlord 2759
617 uberlord 2713 if (pid < 0)
618     eerrorx ("%s: vfork: %s", applet, strerror (errno));
619     else if (pid == 0) {
620     execl (script, script, (char *) NULL);
621     eerror ("%s: unable to exec `%s': %s",
622     script, applet, strerror (errno));
623     _exit (EXIT_FAILURE);
624     }
625    
626     do {
627     pid_t wpid = waitpid (pid, &status, 0);
628     if (wpid < 1)
629     eerror ("waitpid: %s", strerror (errno));
630     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
631    
632     if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
633     exit (EXIT_FAILURE);
634     }
635    
636 uberlord 2734 #include "_usage.h"
637     #define getoptstring getoptstring_COMMON
638     static struct option longopts[] = {
639     longopts_COMMON
640     { NULL, 0, NULL, 0}
641     };
642     #include "_usage.c"
643    
644 uberlord 2547 int main (int argc, char **argv)
645     {
646 uberlord 2577 char *runlevel = NULL;
647 uberlord 2786 const char *bootlevel = NULL;
648 uberlord 2577 char *newlevel = NULL;
649     char *service = NULL;
650     char **deporder = NULL;
651     int i = 0;
652     int j = 0;
653     bool going_down = false;
654     bool interactive = false;
655     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
656     char ksoftbuffer [PATH_MAX];
657 uberlord 2638 char pidstr[6];
658 uberlord 2734 int opt;
659 uberlord 2547
660 uberlord 2577 if (argv[0])
661 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
662 uberlord 2547
663 uberlord 2577 if (! applet)
664     eerrorx ("arguments required");
665 uberlord 2547
666 uberlord 2577 argc--;
667     argv++;
668 uberlord 2547
669 uberlord 2577 /* Handle multicall stuff */
670     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
671     exit (do_e (argc, argv));
672 uberlord 2547
673 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
674     exit (do_service (argc, argv));
675 uberlord 2547
676 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
677     strcmp (applet, "save_options") == 0)
678     exit (do_options (argc, argv));
679 uberlord 2547
680 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
681     exit (do_mark_service (argc, argv));
682 uberlord 2547
683 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
684     exit (rc_runlevel_starting () ? 0 : 1);
685     else if (strcmp (applet, "is_runlevel_stop") == 0)
686     exit (rc_runlevel_stopping () ? 0 : 1);
687 uberlord 2547
688 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
689     char *p = getenv ("RC_PID");
690     pid_t pid = 0;
691    
692     if (p && sscanf (p, "%d", &pid) == 1) {
693     if (kill (pid, SIGUSR1) != 0)
694     eerrorx ("rc-abort: failed to signal parent %d: %s",
695     pid, strerror (errno));
696     exit (EXIT_SUCCESS);
697     }
698     exit (EXIT_FAILURE);
699     }
700    
701 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
702     eerrorx ("%s: unknown applet", applet);
703 uberlord 2547
704 uberlord 2577 atexit (cleanup);
705 uberlord 2547
706 uberlord 2732 /* Change dir to / to ensure all scripts don't use stuff in pwd */
707     chdir ("/");
708    
709 uberlord 2769 /* RUNLEVEL is set by sysvinit as is a magic number
710     RC_SOFTLEVEL is set by us and is the name for this magic number
711     even though all our userland documentation refers to runlevel */
712     RUNLEVEL = getenv ("RUNLEVEL");
713     PREVLEVEL = getenv ("PREVLEVEL");
714    
715 uberlord 2577 /* Setup a signal handler */
716     signal (SIGINT, handle_signal);
717     signal (SIGQUIT, handle_signal);
718     signal (SIGTERM, handle_signal);
719 uberlord 2638 signal (SIGUSR1, handle_signal);
720 uberlord 2563
721 uberlord 2577 /* Ensure our environment is pure
722     Also, add our configuration to it */
723     env = rc_filter_env ();
724     env = rc_config_env (env);
725 uberlord 2547
726 uberlord 2577 if (env) {
727     char *p;
728 uberlord 2547
729     #ifdef __linux__
730 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
731     if we have it */
732     clearenv ();
733 uberlord 2547 #else
734 uberlord 2577 char *var;
735     /* No clearenv present here then.
736     We could manipulate environ directly ourselves, but it seems that
737     some kernels bitch about this according to the environ man pages
738     so we walk though environ and call unsetenv for each value. */
739     while (environ[0]) {
740     tmp = rc_xstrdup (environ[0]);
741     p = tmp;
742     var = strsep (&p, "=");
743     unsetenv (var);
744     free (tmp);
745     }
746     tmp = NULL;
747 uberlord 2547 #endif
748    
749 uberlord 2577 STRLIST_FOREACH (env, p, i)
750     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
751     putenv (p);
752 uberlord 2547
753 uberlord 2577 /* We don't free our list as that would be null in environ */
754     }
755 uberlord 2547
756 uberlord 2734 argc++;
757     argv--;
758     while ((opt = getopt_long (argc, argv, getoptstring,
759     longopts, (int *) 0)) != -1)
760     {
761     switch (opt) {
762     case_RC_COMMON_GETOPT
763     }
764     }
765    
766     newlevel = argv[optind++];
767 uberlord 2759
768 uberlord 2734 /* OK, so we really are the main RC process
769     Only root should be able to run us */
770     if (geteuid () != 0)
771     eerrorx ("%s: root access required", applet);
772    
773 uberlord 2577 /* Enable logging */
774     setenv ("RC_ELOG", "rc", 1);
775 uberlord 2547
776 uberlord 2638 /* Export our PID */
777     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
778     setenv ("RC_PID", pidstr, 1);
779    
780 uberlord 2577 interactive = rc_exists (INTERACTIVE);
781     rc_plugin_load ();
782 uberlord 2547
783 uberlord 2759 /* Load current softlevel */
784 uberlord 2786 bootlevel = getenv ("RC_BOOTLEVEL");
785 uberlord 2759 runlevel = rc_get_runlevel ();
786    
787     /* Check we're in the runlevel requested, ie from
788     rc single
789     rc shutdown
790     rc reboot
791     */
792     if (newlevel) {
793     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
794     RUNLEVEL &&
795     (strcmp (RUNLEVEL, "S") == 0 ||
796     strcmp (RUNLEVEL, "1") == 0))
797     {
798 uberlord 2577 /* OK, we're either in runlevel 1 or single user mode */
799 uberlord 2759 struct utsname uts;
800 uberlord 2547 #ifdef __linux__
801 uberlord 2759 FILE *fp;
802 uberlord 2547 #endif
803    
804 uberlord 2759 /* exec init-early.sh if it exists
805     * This should just setup the console to use the correct
806     * font. Maybe it should setup the keyboard too? */
807     if (rc_exists (INITEARLYSH))
808     run_script (INITEARLYSH);
809 uberlord 2659
810 uberlord 2759 uname (&uts);
811 uberlord 2547
812 uberlord 2759 printf ("\n");
813     printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
814     "\n Copyright 1999-2007 Gentoo Foundation; "
815     "Distributed under the GPLv2\n\n",
816     ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
817     ecolor (ecolor_normal));
818 uberlord 2547
819 uberlord 2759 if (rc_is_env ("RC_INTERACTIVE", "yes"))
820     printf ("Press %sI%s to enter interactive boot mode\n\n",
821     ecolor (ecolor_good), ecolor (ecolor_normal));
822 uberlord 2547
823 uberlord 2759 setenv ("RC_SOFTLEVEL", newlevel, 1);
824     rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
825     run_script (INITSH);
826 uberlord 2547
827 uberlord 2759 /* If we requested a softlevel, save it now */
828 uberlord 2547 #ifdef __linux__
829 uberlord 2759 set_ksoftlevel (NULL);
830 uberlord 2547
831 uberlord 2759 if ((fp = fopen ("/proc/cmdline", "r"))) {
832     char buffer[RC_LINEBUFFER];
833     char *soft;
834 uberlord 2547
835 uberlord 2759 memset (buffer, 0, sizeof (buffer));
836     if (fgets (buffer, RC_LINEBUFFER, fp) &&
837     (soft = strstr (buffer, "softlevel=")))
838     {
839     i = soft - buffer;
840     if (i == 0 || buffer[i - 1] == ' ') {
841     char *level;
842 uberlord 2547
843 uberlord 2759 /* Trim the trailing carriage return if present */
844     i = strlen (buffer) - 1;
845     if (buffer[i] == '\n')
846     buffer[i] = 0;
847 uberlord 2547
848 uberlord 2759 soft += strlen ("softlevel=");
849     level = strsep (&soft, " ");
850     set_ksoftlevel (level);
851 uberlord 2577 }
852     }
853 uberlord 2759 fclose (fp);
854     }
855 uberlord 2547 #endif
856 uberlord 2759 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
857 uberlord 2547
858 uberlord 2759 if (want_interactive ())
859     mark_interactive ();
860 uberlord 2547
861 uberlord 2759 exit (EXIT_SUCCESS);
862     } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
863 uberlord 2577 if (! RUNLEVEL ||
864     (strcmp (RUNLEVEL, "S") != 0 &&
865     strcmp (RUNLEVEL, "1") != 0))
866     {
867     /* Remember the current runlevel for when we come back */
868     set_ksoftlevel (runlevel);
869 uberlord 2638 single_user ();
870 uberlord 2577 }
871     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
872     if (! RUNLEVEL ||
873     strcmp (RUNLEVEL, "6") != 0)
874     {
875 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown", "-r", "now", (char *) NULL);
876     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
877     applet, strerror (errno));
878 uberlord 2577 }
879     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
880     if (! RUNLEVEL ||
881     strcmp (RUNLEVEL, "0") != 0)
882     {
883 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown",
884     #ifdef __linux
885     "-h",
886 uberlord 2547 #else
887 uberlord 2638 "-p",
888 uberlord 2547 #endif
889 uberlord 2638 "now", (char *) NULL);
890     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
891     applet, strerror (errno));
892 uberlord 2577 }
893     }
894     }
895 uberlord 2547
896 uberlord 2641 /* Now we start handling our children */
897     signal (SIGCHLD, handle_signal);
898    
899 uberlord 2759 /* We should only use ksoftlevel if we were in single user mode
900     If not, we need to erase ksoftlevel now. */
901     if (PREVLEVEL &&
902     (strcmp (PREVLEVEL, "1") == 0 ||
903     strcmp (PREVLEVEL, "S") == 0 ||
904     strcmp (PREVLEVEL, "N") == 0))
905 uberlord 2577 {
906 uberlord 2759 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
907     newlevel = ksoftbuffer;
908     } else if (! RUNLEVEL ||
909     (strcmp (RUNLEVEL, "1") != 0 &&
910     strcmp (RUNLEVEL, "S") != 0 &&
911     strcmp (RUNLEVEL, "N") != 0))
912     {
913     set_ksoftlevel (NULL);
914 uberlord 2577 }
915 uberlord 2547
916 uberlord 2577 if (newlevel &&
917     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
918     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
919     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
920     {
921     going_down = true;
922     rc_set_runlevel (newlevel);
923     setenv ("RC_SOFTLEVEL", newlevel, 1);
924     rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
925     } else {
926     rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
927     }
928 uberlord 2547
929 uberlord 2577 /* Check if runlevel is valid if we're changing */
930     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
931     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL);
932     if (! rc_is_dir (tmp))
933     eerrorx ("%s: is not a valid runlevel", newlevel);
934     CHAR_FREE (tmp);
935     }
936 uberlord 2547
937 uberlord 2577 /* Load our deptree now */
938     if ((deptree = rc_load_deptree ()) == NULL)
939     eerrorx ("failed to load deptree");
940 uberlord 2547
941 uberlord 2577 /* Clean the failed services state dir now */
942     if (rc_is_dir (RC_SVCDIR "failed"))
943     rc_rm_dir (RC_SVCDIR "failed", false);
944 uberlord 2547
945 uberlord 2577 mkdir (RC_SVCDIR "/softscripts.new", 0755);
946 uberlord 2547
947     #ifdef __linux__
948 uberlord 2577 /* udev likes to start services before we're ready when it does
949     its coldplugging thing. runscript knows when we're not ready so it
950     stores a list of coldplugged services in DEVBOOT for us to pick up
951     here when we are ready for them */
952     if (rc_is_dir (DEVBOOT)) {
953     start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD);
954     rc_rm_dir (DEVBOOT, true);
955 uberlord 2547
956 uberlord 2577 STRLIST_FOREACH (start_services, service, i)
957     if (rc_allow_plug (service))
958     rc_mark_service (service, rc_service_coldplugged);
959     /* We need to dump this list now.
960     This may seem redunant, but only Linux needs this and saves on
961     code bloat. */
962     rc_strlist_free (start_services);
963     start_services = NULL;
964     }
965 uberlord 2547 #else
966 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
967     The only downside of this approach and ours is that we have to hard code
968     the device node to the init script to simulate the coldplug into
969     runlevel for our dependency tree to work. */
970 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
971 uberlord 2577 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
972     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
973     rc_is_env ("RC_COLDPLUG", "yes"))
974     {
975     /* The net interfaces are easy - they're all in net /dev/net :) */
976     start_services = rc_ls_dir (NULL, "/dev/net", 0);
977     STRLIST_FOREACH (start_services, service, i) {
978     j = (strlen ("net.") + strlen (service) + 1);
979     tmp = rc_xmalloc (sizeof (char *) * j);
980     snprintf (tmp, j, "net.%s", service);
981     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
982     rc_mark_service (tmp, rc_service_coldplugged);
983     CHAR_FREE (tmp);
984     }
985     rc_strlist_free (start_services);
986 uberlord 2547
987 uberlord 2577 /* The mice are a little more tricky.
988     If we coldplug anything else, we'll probably do it here. */
989     start_services = rc_ls_dir (NULL, "/dev", 0);
990     STRLIST_FOREACH (start_services, service, i) {
991     if (strncmp (service, "psm", 3) == 0 ||
992     strncmp (service, "ums", 3) == 0)
993     {
994     char *p = service + 3;
995     if (p && isdigit (*p)) {
996     j = (strlen ("moused.") + strlen (service) + 1);
997     tmp = rc_xmalloc (sizeof (char *) * j);
998     snprintf (tmp, j, "moused.%s", service);
999     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1000     rc_mark_service (tmp, rc_service_coldplugged);
1001     CHAR_FREE (tmp);
1002     }
1003     }
1004     }
1005     rc_strlist_free (start_services);
1006     start_services = NULL;
1007     }
1008 uberlord 2547 #endif
1009    
1010 uberlord 2577 /* Build a list of all services to stop and then work out the
1011     correct order for stopping them */
1012     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD);
1013     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD);
1014     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD);
1015 uberlord 2547
1016 uberlord 2577 types = rc_strlist_add (NULL, "ineed");
1017     types = rc_strlist_add (types, "iuse");
1018     types = rc_strlist_add (types, "iafter");
1019     deporder = rc_get_depends (deptree, types, stop_services,
1020 uberlord 2786 runlevel, depoptions | RC_DEP_STOP);
1021 uberlord 2577 rc_strlist_free (stop_services);
1022     rc_strlist_free (types);
1023     stop_services = deporder;
1024     deporder = NULL;
1025     types = NULL;
1026     rc_strlist_reverse (stop_services);
1027 uberlord 2547
1028 uberlord 2577 /* Load our list of coldplugged services */
1029     coldplugged_services = rc_ls_dir (coldplugged_services,
1030     RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
1031 uberlord 2547
1032 uberlord 2577 /* Load our start services now.
1033     We have different rules dependent on runlevel. */
1034 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1035 uberlord 2577 if (coldplugged_services) {
1036     einfon ("Device initiated services:");
1037     STRLIST_FOREACH (coldplugged_services, service, i) {
1038     printf (" %s", service);
1039     start_services = rc_strlist_add (start_services, service);
1040     }
1041     printf ("\n");
1042     }
1043     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel,
1044     (char *) NULL);
1045     start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
1046     CHAR_FREE (tmp);
1047     } else {
1048     /* Store our list of coldplugged services */
1049     coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED,
1050     RC_LS_INITD);
1051     if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1052     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1053     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1054     {
1055     /* We need to include the boot runlevel services if we're not in it */
1056 uberlord 2786 char **services = rc_services_in_runlevel (bootlevel);
1057    
1058     start_services = rc_strlist_join (start_services, services);
1059     services = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1060     start_services = rc_strlist_join (start_services, services);
1061     services = NULL;
1062    
1063 uberlord 2577 STRLIST_FOREACH (coldplugged_services, service, i)
1064     start_services = rc_strlist_add (start_services, service);
1065 uberlord 2547
1066 uberlord 2577 }
1067     }
1068 uberlord 2547
1069 uberlord 2577 /* Save out softlevel now */
1070     if (going_down)
1071     rc_set_runlevel (newlevel);
1072 uberlord 2547
1073 uberlord 2577 types = rc_strlist_add (NULL, "needsme");
1074     types = rc_strlist_add (types, "usesme");
1075     /* Now stop the services that shouldn't be running */
1076     STRLIST_FOREACH (stop_services, service, i) {
1077     bool found = false;
1078     char *conf = NULL;
1079     char **stopdeps = NULL;
1080     char *svc1 = NULL;
1081     char *svc2 = NULL;
1082     int k;
1083 uberlord 2547
1084 uberlord 2577 if (rc_service_state (service, rc_service_stopped))
1085     continue;
1086 uberlord 2547
1087 uberlord 2577 /* We always stop the service when in these runlevels */
1088     if (going_down) {
1089 uberlord 2641 pid_t pid = rc_stop_service (service);
1090 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1091 uberlord 2641 rc_waitpid (pid);
1092 uberlord 2659 continue;
1093 uberlord 2577 }
1094 uberlord 2547
1095 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1096     STRLIST_FOREACH (start_services, svc1, j)
1097     if (strcmp (svc1, service) == 0) {
1098     found = true;
1099     break;
1100     }
1101 uberlord 2547
1102 uberlord 2577 /* Unless we would use a different config file */
1103     if (found) {
1104     int len;
1105     if (! newlevel)
1106     continue;
1107 uberlord 2550
1108 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1109     tmp = rc_xmalloc (sizeof (char *) * len);
1110     snprintf (tmp, len, "%s.%s", service, runlevel);
1111     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1112     found = rc_exists (conf);
1113     CHAR_FREE (conf);
1114     CHAR_FREE (tmp);
1115     if (! found) {
1116     len = strlen (service) + strlen (newlevel) + 2;
1117     tmp = rc_xmalloc (sizeof (char *) * len);
1118     snprintf (tmp, len, "%s.%s", service, newlevel);
1119     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1120     found = rc_exists (conf);
1121     CHAR_FREE (conf);
1122     CHAR_FREE (tmp);
1123     if (!found)
1124     continue;
1125     }
1126     } else {
1127     /* Allow coldplugged services not to be in the runlevels list */
1128     if (rc_service_state (service, rc_service_coldplugged))
1129     continue;
1130     }
1131 uberlord 2547
1132 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1133     going to be started depends on us */
1134     stopdeps = rc_strlist_add (stopdeps, service);
1135     deporder = rc_get_depends (deptree, types, stopdeps,
1136     runlevel, RC_DEP_STRICT);
1137     rc_strlist_free (stopdeps);
1138     stopdeps = NULL;
1139     found = false;
1140     STRLIST_FOREACH (deporder, svc1, j) {
1141     STRLIST_FOREACH (start_services, svc2, k)
1142     if (strcmp (svc1, svc2) == 0) {
1143     found = true;
1144     break;
1145     }
1146     if (found)
1147     break;
1148     }
1149     rc_strlist_free (deporder);
1150     deporder = NULL;
1151 uberlord 2547
1152 uberlord 2577 /* After all that we can finally stop the blighter! */
1153 uberlord 2641 if (! found) {
1154     pid_t pid = rc_stop_service (service);
1155 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1156 uberlord 2641 rc_waitpid (pid);
1157     }
1158 uberlord 2577 }
1159     rc_strlist_free (types);
1160     types = NULL;
1161 uberlord 2547
1162 uberlord 2577 /* Wait for our services to finish */
1163 uberlord 2641 wait_for_services ();
1164 uberlord 2547
1165 uberlord 2577 /* Notify the plugins we have finished */
1166     rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1167 uberlord 2547
1168 uberlord 2577 rmdir (RC_SVCDIR "/softscripts.new");
1169 uberlord 2547
1170 uberlord 2577 /* Store the new runlevel */
1171     if (newlevel) {
1172     rc_set_runlevel (newlevel);
1173     runlevel = newlevel;
1174     setenv ("RC_SOFTLEVEL", runlevel, 1);
1175     }
1176 uberlord 2547
1177 uberlord 2577 /* Run the halt script if needed */
1178     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1179     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1180     {
1181 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1182 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1183     applet, HALTSH, strerror (errno));
1184     }
1185 uberlord 2547
1186 uberlord 2577 /* Single user is done now */
1187     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1188     if (rc_exists (INTERACTIVE))
1189     unlink (INTERACTIVE);
1190     sulogin (false);
1191     }
1192 uberlord 2547
1193 uberlord 2577 mkdir (RC_SVCDIR "softscripts.old", 0755);
1194     rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
1195 uberlord 2547
1196 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1197     STRLIST_FOREACH (coldplugged_services, service, i)
1198     rc_mark_service (service, rc_service_coldplugged);
1199 uberlord 2547
1200 uberlord 2577 /* Order the services to start */
1201     types = rc_strlist_add (NULL, "ineed");
1202     types = rc_strlist_add (types, "iuse");
1203     types = rc_strlist_add (types, "iafter");
1204     deporder = rc_get_depends (deptree, types, start_services,
1205 uberlord 2786 runlevel, depoptions | RC_DEP_START);
1206 uberlord 2577 rc_strlist_free (types);
1207     types = NULL;
1208     rc_strlist_free (start_services);
1209     start_services = deporder;
1210     deporder = NULL;
1211 uberlord 2547
1212 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1213     if (rc_service_state (service, rc_service_stopped)) {
1214 uberlord 2641 pid_t pid;
1215    
1216 uberlord 2577 if (! interactive)
1217     interactive = want_interactive ();
1218 uberlord 2547
1219 uberlord 2577 if (interactive) {
1220 uberlord 2547 interactive_retry:
1221 uberlord 2577 printf ("\n");
1222     einfo ("About to start the service %s", service);
1223     eindent ();
1224     einfo ("1) Start the service\t\t2) Skip the service");
1225     einfo ("3) Continue boot process\t\t4) Exit to shell");
1226     eoutdent ();
1227 uberlord 2547 interactive_option:
1228 uberlord 2577 switch (read_key (true)) {
1229     case '1': break;
1230     case '2': continue;
1231     case '3': interactive = false; break;
1232     case '4': sulogin (true); goto interactive_retry;
1233     default: goto interactive_option;
1234     }
1235     }
1236 uberlord 2641
1237     /* Remember the pid if we're running in parallel */
1238     if ((pid = rc_start_service (service)))
1239     add_pid (pid);
1240    
1241 uberlord 2650 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1242 uberlord 2641 rc_waitpid (pid);
1243     remove_pid (pid);
1244     }
1245 uberlord 2577 }
1246     }
1247 uberlord 2547
1248 uberlord 2577 /* Wait for our services to finish */
1249 uberlord 2636 wait_for_services ();
1250 uberlord 2547
1251 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1252 uberlord 2547
1253 uberlord 2577 /* Store our interactive status for boot */
1254 uberlord 2786 if (interactive && strcmp (runlevel, bootlevel) == 0)
1255 uberlord 2577 mark_interactive ();
1256     else {
1257     if (rc_exists (INTERACTIVE))
1258     unlink (INTERACTIVE);
1259     }
1260 uberlord 2547
1261 uberlord 2577 return (EXIT_SUCCESS);
1262 uberlord 2547 }
1263    

  ViewVC Help
Powered by ViewVC 1.1.20