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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20