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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20