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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20