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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20