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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20