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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2659 - (hide annotations) (download) (as text)
Thu Apr 26 11:24:07 2007 UTC (11 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 34538 byte(s)
Set fonts in init-early.sh, don't stop services twice when shutting down and lock prefixed output.
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     if ((prev && strcmp (prev, "S") == 0) ||
550 uberlord 2642 (run &&
551     (strcmp (run, "S") == 0 ||
552     strcmp (run, "1") == 0)))
553 uberlord 2638 single_user ();
554    
555     exit (EXIT_FAILURE);
556     break;
557    
558 uberlord 2577 default:
559     eerror ("%s: caught unknown signal %d", applet, sig);
560     }
561 uberlord 2563
562 uberlord 2577 /* Restore errno */
563     errno = serrno;
564 uberlord 2563 }
565    
566 uberlord 2547 int main (int argc, char **argv)
567     {
568 uberlord 2577 char *RUNLEVEL = NULL;
569     char *PREVLEVEL = NULL;
570     char *runlevel = NULL;
571     char *newlevel = NULL;
572     char *service = NULL;
573     char **deporder = NULL;
574     int i = 0;
575     int j = 0;
576     bool going_down = false;
577     bool interactive = false;
578     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
579     char ksoftbuffer [PATH_MAX];
580 uberlord 2638 char pidstr[6];
581 uberlord 2547
582 uberlord 2577 if (argv[0])
583 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
584 uberlord 2547
585 uberlord 2577 if (! applet)
586     eerrorx ("arguments required");
587 uberlord 2547
588 uberlord 2577 argc--;
589     argv++;
590 uberlord 2547
591 uberlord 2577 /* Handle multicall stuff */
592     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
593     exit (do_e (argc, argv));
594 uberlord 2547
595 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
596     exit (do_service (argc, argv));
597 uberlord 2547
598 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
599     strcmp (applet, "save_options") == 0)
600     exit (do_options (argc, argv));
601 uberlord 2547
602 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
603     exit (do_mark_service (argc, argv));
604 uberlord 2547
605 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
606     exit (rc_runlevel_starting () ? 0 : 1);
607     else if (strcmp (applet, "is_runlevel_stop") == 0)
608     exit (rc_runlevel_stopping () ? 0 : 1);
609 uberlord 2547
610 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
611     char *p = getenv ("RC_PID");
612     pid_t pid = 0;
613    
614     if (p && sscanf (p, "%d", &pid) == 1) {
615     if (kill (pid, SIGUSR1) != 0)
616     eerrorx ("rc-abort: failed to signal parent %d: %s",
617     pid, strerror (errno));
618     exit (EXIT_SUCCESS);
619     }
620     exit (EXIT_FAILURE);
621     }
622    
623 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
624     eerrorx ("%s: unknown applet", applet);
625 uberlord 2547
626 uberlord 2577 /* OK, so we really are the main RC process
627     Only root should be able to run us */
628     if (geteuid () != 0)
629     eerrorx ("%s: root access required", applet);
630 uberlord 2547
631 uberlord 2577 atexit (cleanup);
632     newlevel = argv[0];
633 uberlord 2547
634 uberlord 2577 /* Setup a signal handler */
635     signal (SIGINT, handle_signal);
636     signal (SIGQUIT, handle_signal);
637     signal (SIGTERM, handle_signal);
638 uberlord 2638 signal (SIGUSR1, handle_signal);
639 uberlord 2563
640 uberlord 2577 /* Ensure our environment is pure
641     Also, add our configuration to it */
642     env = rc_filter_env ();
643     env = rc_config_env (env);
644 uberlord 2547
645 uberlord 2577 if (env) {
646     char *p;
647 uberlord 2547
648     #ifdef __linux__
649 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
650     if we have it */
651     clearenv ();
652 uberlord 2547 #else
653 uberlord 2577 char *var;
654     /* No clearenv present here then.
655     We could manipulate environ directly ourselves, but it seems that
656     some kernels bitch about this according to the environ man pages
657     so we walk though environ and call unsetenv for each value. */
658     while (environ[0]) {
659     tmp = rc_xstrdup (environ[0]);
660     p = tmp;
661     var = strsep (&p, "=");
662     unsetenv (var);
663     free (tmp);
664     }
665     tmp = NULL;
666 uberlord 2547 #endif
667    
668 uberlord 2577 STRLIST_FOREACH (env, p, i)
669     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
670     putenv (p);
671 uberlord 2547
672 uberlord 2577 /* We don't free our list as that would be null in environ */
673     }
674 uberlord 2547
675 uberlord 2577 /* Enable logging */
676     setenv ("RC_ELOG", "rc", 1);
677 uberlord 2547
678 uberlord 2638 /* Export our PID */
679     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
680     setenv ("RC_PID", pidstr, 1);
681    
682 uberlord 2577 interactive = rc_exists (INTERACTIVE);
683     rc_plugin_load ();
684 uberlord 2547
685 uberlord 2577 /* RUNLEVEL is set by sysvinit as is a magic number
686     RC_SOFTLEVEL is set by us and is the name for this magic number
687     even though all our userland documentation refers to runlevel */
688     RUNLEVEL = getenv ("RUNLEVEL");
689     PREVLEVEL = getenv ("PREVLEVEL");
690 uberlord 2547
691 uberlord 2577 if (RUNLEVEL && newlevel) {
692     if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) {
693     /* OK, we're either in runlevel 1 or single user mode */
694     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) {
695     struct utsname uts;
696     pid_t pid;
697     pid_t wpid;
698     int status = 0;
699 uberlord 2547 #ifdef __linux__
700 uberlord 2577 FILE *fp;
701 uberlord 2547 #endif
702    
703 uberlord 2659 /* exec init-early.sh if it exists
704     * This should just setup the console to use the correct
705     * font. Maybe it should setup the keyboard too? */
706     if (rc_exists (INITEARLYSH)) {
707     if ((pid = vfork ()) == -1)
708     eerrorx ("%s: vfork: %s", applet, strerror (errno));
709    
710     if (pid == 0) {
711     execl (INITEARLYSH, INITEARLYSH, (char *) NULL);
712     eerror ("%s: unable to exec `" INITEARLYSH "': %s",
713     applet, strerror (errno));
714     _exit (EXIT_FAILURE);
715     }
716    
717     do {
718     wpid = waitpid (pid, &status, 0);
719     if (wpid < 1)
720     eerror ("waitpid: %s", strerror (errno));
721     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
722     }
723    
724 uberlord 2577 uname (&uts);
725 uberlord 2547
726 uberlord 2577 printf ("\n");
727 uberlord 2615 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
728     "\n Copyright 1999-2007 Gentoo Foundation; "
729     "Distributed under the GPLv2\n\n",
730     ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
731     ecolor (ecolor_normal));
732 uberlord 2547
733 uberlord 2615 printf ("Press %sI%s to enter interactive boot mode\n\n",
734     ecolor (ecolor_good), ecolor (ecolor_normal));
735 uberlord 2547
736 uberlord 2577 setenv ("RC_SOFTLEVEL", newlevel, 1);
737     rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
738 uberlord 2547
739 uberlord 2638 if ((pid = vfork ()) == -1)
740     eerrorx ("%s: vfork: %s", applet, strerror (errno));
741 uberlord 2547
742 uberlord 2577 if (pid == 0) {
743 uberlord 2638 execl (INITSH, INITSH, (char *) NULL);
744     eerror ("%s: unable to exec `" INITSH "': %s",
745     applet, strerror (errno));
746     _exit (EXIT_FAILURE);
747 uberlord 2577 }
748 uberlord 2547
749 uberlord 2577 do {
750     wpid = waitpid (pid, &status, 0);
751     if (wpid < 1)
752     eerror ("waitpid: %s", strerror (errno));
753     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
754 uberlord 2547
755 uberlord 2577 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
756     exit (EXIT_FAILURE);
757 uberlord 2547
758 uberlord 2577 /* If we requested a softlevel, save it now */
759 uberlord 2547 #ifdef __linux__
760 uberlord 2577 set_ksoftlevel (NULL);
761 uberlord 2547
762 uberlord 2577 if ((fp = fopen ("/proc/cmdline", "r"))) {
763     char buffer[RC_LINEBUFFER];
764     char *soft;
765 uberlord 2547
766 uberlord 2577 memset (buffer, 0, sizeof (buffer));
767     if (fgets (buffer, RC_LINEBUFFER, fp) &&
768     (soft = strstr (buffer, "softlevel=")))
769     {
770     i = soft - buffer;
771     if (i == 0 || buffer[i - 1] == ' ') {
772     char *level;
773 uberlord 2547
774 uberlord 2577 /* Trim the trailing carriage return if present */
775     i = strlen (buffer) - 1;
776     if (buffer[i] == '\n')
777     buffer[i] = 0;
778 uberlord 2547
779 uberlord 2577 soft += strlen ("softlevel=");
780     level = strsep (&soft, " ");
781     set_ksoftlevel (level);
782     }
783     }
784     fclose (fp);
785     }
786 uberlord 2547 #endif
787 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
788 uberlord 2547
789 uberlord 2577 if (want_interactive ())
790     mark_interactive ();
791 uberlord 2547
792 uberlord 2577 exit (EXIT_SUCCESS);
793     }
794 uberlord 2547
795     #ifdef __linux__
796 uberlord 2577 /* Parse the inittab file so we can work out the level to telinit */
797     if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 &&
798     strcmp (newlevel, RC_LEVEL_SINGLE) != 0)
799     {
800     char **inittab = rc_get_list (NULL, "/etc/inittab");
801     char *line;
802     char *p;
803     char *token;
804     char lvl[2] = {0, 0};
805 uberlord 2547
806 uberlord 2577 STRLIST_FOREACH (inittab, line, i) {
807     p = line;
808     token = strsep (&p, ":");
809     if (! token || token[0] != 'l')
810     continue;
811 uberlord 2547
812 uberlord 2577 if ((token = strsep (&p, ":")) == NULL)
813     continue;
814 uberlord 2547
815 uberlord 2577 /* Snag the level */
816     lvl[0] = token[0];
817 uberlord 2547
818 uberlord 2577 /* The name is spaced after this */
819     if ((token = strsep (&p, " ")) == NULL)
820     continue;
821 uberlord 2547
822 uberlord 2577 if ((token = strsep (&p, " ")) == NULL)
823     continue;
824 uberlord 2569
825 uberlord 2577 if (strcmp (token, newlevel) == 0)
826     break;
827     }
828     rc_strlist_free (inittab);
829 uberlord 2569
830 uberlord 2577 /* We have a level, so telinit into it */
831     if (lvl[0] == 0) {
832     eerrorx ("%s: couldn't find a runlevel called `%s'",
833     applet, newlevel);
834     } else {
835 uberlord 2638 execl ("/sbin/telinit", "/sbin/telinit", lvl, (char *) NULL);
836 uberlord 2577 eerrorx ("%s: unable to exec `/sbin/telinit': %s",
837     applet, strerror (errno));
838     }
839     }
840 uberlord 2547 #endif
841 uberlord 2577 }
842     }
843 uberlord 2547
844 uberlord 2577 /* Check we're in the runlevel requested, ie from
845     rc single
846     rc shutdown
847     rc reboot
848     */
849     if (newlevel) {
850     if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
851     if (! RUNLEVEL ||
852     (strcmp (RUNLEVEL, "S") != 0 &&
853     strcmp (RUNLEVEL, "1") != 0))
854     {
855     /* Remember the current runlevel for when we come back */
856     set_ksoftlevel (runlevel);
857 uberlord 2638 single_user ();
858 uberlord 2577 }
859     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
860     if (! RUNLEVEL ||
861     strcmp (RUNLEVEL, "6") != 0)
862     {
863 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown", "-r", "now", (char *) NULL);
864     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
865     applet, strerror (errno));
866 uberlord 2577 }
867     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
868     if (! RUNLEVEL ||
869     strcmp (RUNLEVEL, "0") != 0)
870     {
871 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown",
872     #ifdef __linux
873     "-h",
874 uberlord 2547 #else
875 uberlord 2638 "-p",
876 uberlord 2547 #endif
877 uberlord 2638 "now", (char *) NULL);
878     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
879     applet, strerror (errno));
880 uberlord 2577 }
881     }
882     }
883 uberlord 2547
884 uberlord 2577 /* Export our current softlevel */
885     runlevel = rc_get_runlevel ();
886 uberlord 2547
887 uberlord 2641 /* Now we start handling our children */
888     signal (SIGCHLD, handle_signal);
889    
890 uberlord 2577 /* If we're in the default runlevel and ksoftlevel exists, we should use
891     that instead */
892     if (newlevel &&
893     rc_exists (RC_SVCDIR "ksoftlevel") &&
894     strcmp (newlevel, RC_LEVEL_DEFAULT) == 0)
895     {
896     /* We should only use ksoftlevel if we were in single user mode
897     If not, we need to erase ksoftlevel now. */
898     if (PREVLEVEL &&
899     (strcmp (PREVLEVEL, "1") == 0 ||
900     strcmp (PREVLEVEL, "S") == 0 ||
901     strcmp (PREVLEVEL, "N") == 0))
902     {
903     FILE *fp;
904 uberlord 2547
905 uberlord 2577 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
906     eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
907     strerror (errno));
908     else {
909     if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) {
910     i = strlen (ksoftbuffer) - 1;
911     if (ksoftbuffer[i] == '\n')
912     ksoftbuffer[i] = 0;
913     newlevel = ksoftbuffer;
914     }
915     fclose (fp);
916     }
917     } else
918     set_ksoftlevel (NULL);
919     }
920 uberlord 2547
921 uberlord 2577 if (newlevel &&
922     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
923     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
924     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
925     {
926     going_down = true;
927     rc_set_runlevel (newlevel);
928     setenv ("RC_SOFTLEVEL", newlevel, 1);
929     rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
930     } else {
931     rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
932     }
933 uberlord 2547
934 uberlord 2577 /* Check if runlevel is valid if we're changing */
935     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
936     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL);
937     if (! rc_is_dir (tmp))
938     eerrorx ("%s: is not a valid runlevel", newlevel);
939     CHAR_FREE (tmp);
940     }
941 uberlord 2547
942 uberlord 2577 /* Load our deptree now */
943     if ((deptree = rc_load_deptree ()) == NULL)
944     eerrorx ("failed to load deptree");
945 uberlord 2547
946 uberlord 2577 /* Clean the failed services state dir now */
947     if (rc_is_dir (RC_SVCDIR "failed"))
948     rc_rm_dir (RC_SVCDIR "failed", false);
949 uberlord 2547
950 uberlord 2577 mkdir (RC_SVCDIR "/softscripts.new", 0755);
951 uberlord 2547
952     #ifdef __linux__
953 uberlord 2577 /* udev likes to start services before we're ready when it does
954     its coldplugging thing. runscript knows when we're not ready so it
955     stores a list of coldplugged services in DEVBOOT for us to pick up
956     here when we are ready for them */
957     if (rc_is_dir (DEVBOOT)) {
958     start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD);
959     rc_rm_dir (DEVBOOT, true);
960 uberlord 2547
961 uberlord 2577 STRLIST_FOREACH (start_services, service, i)
962     if (rc_allow_plug (service))
963     rc_mark_service (service, rc_service_coldplugged);
964     /* We need to dump this list now.
965     This may seem redunant, but only Linux needs this and saves on
966     code bloat. */
967     rc_strlist_free (start_services);
968     start_services = NULL;
969     }
970 uberlord 2547 #else
971 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
972     The only downside of this approach and ours is that we have to hard code
973     the device node to the init script to simulate the coldplug into
974     runlevel for our dependency tree to work. */
975     if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 &&
976     (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
977     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
978     rc_is_env ("RC_COLDPLUG", "yes"))
979     {
980     /* The net interfaces are easy - they're all in net /dev/net :) */
981     start_services = rc_ls_dir (NULL, "/dev/net", 0);
982     STRLIST_FOREACH (start_services, service, i) {
983     j = (strlen ("net.") + strlen (service) + 1);
984     tmp = rc_xmalloc (sizeof (char *) * j);
985     snprintf (tmp, j, "net.%s", service);
986     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
987     rc_mark_service (tmp, rc_service_coldplugged);
988     CHAR_FREE (tmp);
989     }
990     rc_strlist_free (start_services);
991 uberlord 2547
992 uberlord 2577 /* The mice are a little more tricky.
993     If we coldplug anything else, we'll probably do it here. */
994     start_services = rc_ls_dir (NULL, "/dev", 0);
995     STRLIST_FOREACH (start_services, service, i) {
996     if (strncmp (service, "psm", 3) == 0 ||
997     strncmp (service, "ums", 3) == 0)
998     {
999     char *p = service + 3;
1000     if (p && isdigit (*p)) {
1001     j = (strlen ("moused.") + strlen (service) + 1);
1002     tmp = rc_xmalloc (sizeof (char *) * j);
1003     snprintf (tmp, j, "moused.%s", service);
1004     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1005     rc_mark_service (tmp, rc_service_coldplugged);
1006     CHAR_FREE (tmp);
1007     }
1008     }
1009     }
1010     rc_strlist_free (start_services);
1011     start_services = NULL;
1012     }
1013 uberlord 2547 #endif
1014    
1015 uberlord 2577 /* Build a list of all services to stop and then work out the
1016     correct order for stopping them */
1017     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD);
1018     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD);
1019     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD);
1020 uberlord 2547
1021 uberlord 2577 types = rc_strlist_add (NULL, "ineed");
1022     types = rc_strlist_add (types, "iuse");
1023     types = rc_strlist_add (types, "iafter");
1024     deporder = rc_get_depends (deptree, types, stop_services,
1025     runlevel, depoptions);
1026     rc_strlist_free (stop_services);
1027     rc_strlist_free (types);
1028     stop_services = deporder;
1029     deporder = NULL;
1030     types = NULL;
1031     rc_strlist_reverse (stop_services);
1032 uberlord 2547
1033 uberlord 2577 /* Load our list of coldplugged services */
1034     coldplugged_services = rc_ls_dir (coldplugged_services,
1035     RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
1036 uberlord 2547
1037 uberlord 2577 /* Load our start services now.
1038     We have different rules dependent on runlevel. */
1039     if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) {
1040     if (coldplugged_services) {
1041     einfon ("Device initiated services:");
1042     STRLIST_FOREACH (coldplugged_services, service, i) {
1043     printf (" %s", service);
1044     start_services = rc_strlist_add (start_services, service);
1045     }
1046     printf ("\n");
1047     }
1048     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel,
1049     (char *) NULL);
1050     start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
1051     CHAR_FREE (tmp);
1052     } else {
1053     /* Store our list of coldplugged services */
1054     coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED,
1055     RC_LS_INITD);
1056     if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1057     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1058     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1059     {
1060     /* We need to include the boot runlevel services if we're not in it */
1061     start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT,
1062     RC_LS_INITD);
1063     STRLIST_FOREACH (coldplugged_services, service, i)
1064     start_services = rc_strlist_add (start_services, service);
1065 uberlord 2547
1066 uberlord 2577 tmp = rc_strcatpaths (RC_RUNLEVELDIR,
1067     newlevel ? newlevel : runlevel, (char *) NULL);
1068     start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
1069     CHAR_FREE (tmp);
1070     }
1071     }
1072 uberlord 2547
1073 uberlord 2577 /* Save out softlevel now */
1074     if (going_down)
1075     rc_set_runlevel (newlevel);
1076 uberlord 2547
1077 uberlord 2577 types = rc_strlist_add (NULL, "needsme");
1078     types = rc_strlist_add (types, "usesme");
1079     /* Now stop the services that shouldn't be running */
1080     STRLIST_FOREACH (stop_services, service, i) {
1081     bool found = false;
1082     char *conf = NULL;
1083     char **stopdeps = NULL;
1084     char *svc1 = NULL;
1085     char *svc2 = NULL;
1086     int k;
1087 uberlord 2547
1088 uberlord 2577 if (rc_service_state (service, rc_service_stopped))
1089     continue;
1090 uberlord 2547
1091 uberlord 2577 /* We always stop the service when in these runlevels */
1092     if (going_down) {
1093 uberlord 2641 pid_t pid = rc_stop_service (service);
1094 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1095 uberlord 2641 rc_waitpid (pid);
1096 uberlord 2659 continue;
1097 uberlord 2577 }
1098 uberlord 2547
1099 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1100     STRLIST_FOREACH (start_services, svc1, j)
1101     if (strcmp (svc1, service) == 0) {
1102     found = true;
1103     break;
1104     }
1105 uberlord 2547
1106 uberlord 2577 /* Unless we would use a different config file */
1107     if (found) {
1108     int len;
1109     if (! newlevel)
1110     continue;
1111 uberlord 2550
1112 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1113     tmp = rc_xmalloc (sizeof (char *) * len);
1114     snprintf (tmp, len, "%s.%s", service, runlevel);
1115     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1116     found = rc_exists (conf);
1117     CHAR_FREE (conf);
1118     CHAR_FREE (tmp);
1119     if (! found) {
1120     len = strlen (service) + strlen (newlevel) + 2;
1121     tmp = rc_xmalloc (sizeof (char *) * len);
1122     snprintf (tmp, len, "%s.%s", service, newlevel);
1123     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1124     found = rc_exists (conf);
1125     CHAR_FREE (conf);
1126     CHAR_FREE (tmp);
1127     if (!found)
1128     continue;
1129     }
1130     } else {
1131     /* Allow coldplugged services not to be in the runlevels list */
1132     if (rc_service_state (service, rc_service_coldplugged))
1133     continue;
1134     }
1135 uberlord 2547
1136 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1137     going to be started depends on us */
1138     stopdeps = rc_strlist_add (stopdeps, service);
1139     deporder = rc_get_depends (deptree, types, stopdeps,
1140     runlevel, RC_DEP_STRICT);
1141     rc_strlist_free (stopdeps);
1142     stopdeps = NULL;
1143     found = false;
1144     STRLIST_FOREACH (deporder, svc1, j) {
1145     STRLIST_FOREACH (start_services, svc2, k)
1146     if (strcmp (svc1, svc2) == 0) {
1147     found = true;
1148     break;
1149     }
1150     if (found)
1151     break;
1152     }
1153     rc_strlist_free (deporder);
1154     deporder = NULL;
1155 uberlord 2547
1156 uberlord 2577 /* After all that we can finally stop the blighter! */
1157 uberlord 2641 if (! found) {
1158     pid_t pid = rc_stop_service (service);
1159 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1160 uberlord 2641 rc_waitpid (pid);
1161     }
1162 uberlord 2577 }
1163     rc_strlist_free (types);
1164     types = NULL;
1165 uberlord 2547
1166 uberlord 2577 /* Wait for our services to finish */
1167 uberlord 2641 wait_for_services ();
1168 uberlord 2547
1169 uberlord 2577 /* Notify the plugins we have finished */
1170     rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1171 uberlord 2547
1172 uberlord 2577 rmdir (RC_SVCDIR "/softscripts.new");
1173 uberlord 2547
1174 uberlord 2577 /* Store the new runlevel */
1175     if (newlevel) {
1176     rc_set_runlevel (newlevel);
1177     runlevel = newlevel;
1178     setenv ("RC_SOFTLEVEL", runlevel, 1);
1179     }
1180 uberlord 2547
1181 uberlord 2577 /* Run the halt script if needed */
1182     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1183     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1184     {
1185 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1186 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1187     applet, HALTSH, strerror (errno));
1188     }
1189 uberlord 2547
1190 uberlord 2577 /* Single user is done now */
1191     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1192     if (rc_exists (INTERACTIVE))
1193     unlink (INTERACTIVE);
1194     sulogin (false);
1195     }
1196 uberlord 2547
1197 uberlord 2577 mkdir (RC_SVCDIR "softscripts.old", 0755);
1198     rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
1199 uberlord 2547
1200 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1201     STRLIST_FOREACH (coldplugged_services, service, i)
1202     rc_mark_service (service, rc_service_coldplugged);
1203 uberlord 2547
1204 uberlord 2577 /* Order the services to start */
1205     types = rc_strlist_add (NULL, "ineed");
1206     types = rc_strlist_add (types, "iuse");
1207     types = rc_strlist_add (types, "iafter");
1208     deporder = rc_get_depends (deptree, types, start_services,
1209     runlevel, depoptions);
1210     rc_strlist_free (types);
1211     types = NULL;
1212     rc_strlist_free (start_services);
1213     start_services = deporder;
1214     deporder = NULL;
1215 uberlord 2547
1216 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1217     if (rc_service_state (service, rc_service_stopped)) {
1218 uberlord 2641 pid_t pid;
1219    
1220 uberlord 2577 if (! interactive)
1221     interactive = want_interactive ();
1222 uberlord 2547
1223 uberlord 2577 if (interactive) {
1224 uberlord 2547 interactive_retry:
1225 uberlord 2577 printf ("\n");
1226     einfo ("About to start the service %s", service);
1227     eindent ();
1228     einfo ("1) Start the service\t\t2) Skip the service");
1229     einfo ("3) Continue boot process\t\t4) Exit to shell");
1230     eoutdent ();
1231 uberlord 2547 interactive_option:
1232 uberlord 2577 switch (read_key (true)) {
1233     case '1': break;
1234     case '2': continue;
1235     case '3': interactive = false; break;
1236     case '4': sulogin (true); goto interactive_retry;
1237     default: goto interactive_option;
1238     }
1239     }
1240 uberlord 2641
1241     /* Remember the pid if we're running in parallel */
1242     if ((pid = rc_start_service (service)))
1243     add_pid (pid);
1244    
1245 uberlord 2650 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1246 uberlord 2641 rc_waitpid (pid);
1247     remove_pid (pid);
1248     }
1249 uberlord 2577 }
1250     }
1251 uberlord 2547
1252 uberlord 2577 /* Wait for our services to finish */
1253 uberlord 2636 wait_for_services ();
1254 uberlord 2547
1255 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1256 uberlord 2547
1257 uberlord 2577 /* Store our interactive status for boot */
1258     if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0)
1259     mark_interactive ();
1260     else {
1261     if (rc_exists (INTERACTIVE))
1262     unlink (INTERACTIVE);
1263     }
1264 uberlord 2547
1265 uberlord 2577 return (EXIT_SUCCESS);
1266 uberlord 2547 }
1267    

  ViewVC Help
Powered by ViewVC 1.1.20