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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3040 - (show annotations) (download) (as text)
Mon Oct 15 14:40:53 2007 UTC (7 years, 1 month ago) by uberlord
File MIME type: text/x-csrc
File size: 36530 byte(s)
const correctness
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 int wait_pid (pid_t pid)
633 {
634 int status = 0;
635 pid_t savedpid = pid;
636 int retval = -1;
637
638 errno = 0;
639 while ((pid = waitpid (savedpid, &status, 0)) > 0) {
640 if (pid == savedpid)
641 retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
642 }
643
644 return (retval);
645 }
646
647 static void handle_signal (int sig)
648 {
649 int serrno = errno;
650 char signame[10] = { '\0' };
651 pidlist_t *pl;
652 pid_t pid;
653 int status = 0;
654
655 switch (sig) {
656 case SIGCHLD:
657 do {
658 pid = waitpid (-1, &status, WNOHANG);
659 if (pid < 0) {
660 if (errno != ECHILD)
661 eerror ("waitpid: %s", strerror (errno));
662 return;
663 }
664 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
665
666 /* Remove that pid from our list */
667 if (pid > 0)
668 remove_pid (pid);
669 break;
670
671 case SIGINT:
672 if (! signame[0])
673 snprintf (signame, sizeof (signame), "SIGINT");
674 case SIGTERM:
675 if (! signame[0])
676 snprintf (signame, sizeof (signame), "SIGTERM");
677 case SIGQUIT:
678 if (! signame[0])
679 snprintf (signame, sizeof (signame), "SIGQUIT");
680 eerrorx ("%s: caught %s, aborting", applet, signame);
681 case SIGUSR1:
682 eerror ("rc: Aborting!");
683 /* Kill any running services we have started */
684
685 signal (SIGCHLD, SIG_IGN);
686 for (pl = service_pids; pl; pl = pl->next)
687 kill (pl->pid, SIGTERM);
688
689 /* Notify plugins we are aborting */
690 rc_plugin_run (RC_HOOK_ABORT, NULL);
691
692 /* Only drop into single user mode if we're booting */
693 if ((PREVLEVEL &&
694 (strcmp (PREVLEVEL, "S") == 0 ||
695 strcmp (PREVLEVEL, "1") == 0)) ||
696 (RUNLEVEL &&
697 (strcmp (RUNLEVEL, "S") == 0 ||
698 strcmp (RUNLEVEL, "1") == 0)))
699 single_user ();
700
701 exit (EXIT_FAILURE);
702 break;
703
704 default:
705 eerror ("%s: caught unknown signal %d", applet, sig);
706 }
707
708 /* Restore errno */
709 errno = serrno;
710 }
711
712 static void run_script (const char *script) {
713 int status = 0;
714 pid_t pid = vfork ();
715
716 if (pid < 0)
717 eerrorx ("%s: vfork: %s", applet, strerror (errno));
718 else if (pid == 0) {
719 execl (script, script, (char *) NULL);
720 eerror ("%s: unable to exec `%s': %s",
721 script, applet, strerror (errno));
722 _exit (EXIT_FAILURE);
723 }
724
725 do {
726 pid_t wpid = waitpid (pid, &status, 0);
727 if (wpid < 1)
728 eerror ("waitpid: %s", strerror (errno));
729 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
730
731 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
732 eerrorx ("%s: failed to exec `%s'", applet, script);
733 }
734
735 #include "_usage.h"
736 #define getoptstring getoptstring_COMMON
737 static struct option longopts[] = {
738 longopts_COMMON
739 };
740 static const char * const longopts_help[] = {
741 longopts_help_COMMON
742 };
743 #include "_usage.c"
744
745 int main (int argc, char **argv)
746 {
747 const char *bootlevel = NULL;
748 char *newlevel = NULL;
749 char *service = NULL;
750 char **deporder = NULL;
751 char **tmplist;
752 int i = 0;
753 int j = 0;
754 bool going_down = false;
755 bool interactive = false;
756 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
757 char ksoftbuffer [PATH_MAX];
758 char pidstr[6];
759 int opt;
760 DIR *dp;
761 struct dirent *d;
762
763 atexit (cleanup);
764 if (argv[0])
765 applet = xstrdup (basename (argv[0]));
766
767 if (! applet)
768 eerrorx ("arguments required");
769
770 /* These used to be programs in their own right, so we shouldn't
771 * touch argc or argv for them */
772 if (strcmp (applet, "env-update") == 0)
773 exit (env_update (argc, argv));
774 else if (strcmp (applet, "fstabinfo") == 0)
775 exit (fstabinfo (argc, argv));
776 else if (strcmp (applet, "mountinfo") == 0)
777 exit (mountinfo (argc, argv));
778 else if (strcmp (applet, "rc-depend") == 0)
779 exit (rc_depend (argc, argv));
780 else if (strcmp (applet, "rc-status") == 0)
781 exit (rc_status (argc, argv));
782 else if (strcmp (applet, "rc-update") == 0 ||
783 strcmp (applet, "update-rc") == 0)
784 exit (rc_update (argc, argv));
785 else if (strcmp (applet, "runscript") == 0)
786 exit (runscript (argc, argv));
787 else if (strcmp (applet, "start-stop-daemon") == 0)
788 exit (start_stop_daemon (argc, argv));
789 else if (strcmp (applet, "checkown") == 0)
790 exit (checkown (argc, argv));
791
792 argc--;
793 argv++;
794
795 /* Handle multicall stuff */
796 if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
797 exit (do_e (argc, argv));
798
799 if (strncmp (applet, "service_", strlen ("service_")) == 0)
800 exit (do_service (argc, argv));
801
802 if (strcmp (applet, "get_options") == 0 ||
803 strcmp (applet, "save_options") == 0)
804 exit (do_options (argc, argv));
805
806 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
807 exit (do_mark_service (argc, argv));
808
809 if (strcmp (applet, "is_runlevel_start") == 0)
810 exit (rc_runlevel_starting () ? 0 : 1);
811 else if (strcmp (applet, "is_runlevel_stop") == 0)
812 exit (rc_runlevel_stopping () ? 0 : 1);
813
814 if (strcmp (applet, "rc-abort") == 0) {
815 char *p = getenv ("RC_PID");
816 pid_t pid = 0;
817
818 if (p && sscanf (p, "%d", &pid) == 1) {
819 if (kill (pid, SIGUSR1) != 0)
820 eerrorx ("rc-abort: failed to signal parent %d: %s",
821 pid, strerror (errno));
822 exit (EXIT_SUCCESS);
823 }
824 exit (EXIT_FAILURE);
825 }
826
827 if (strcmp (applet, "rc" ) != 0)
828 eerrorx ("%s: unknown applet", applet);
829
830 /* Change dir to / to ensure all scripts don't use stuff in pwd */
831 chdir ("/");
832
833 /* RUNLEVEL is set by sysvinit as is a magic number
834 RC_SOFTLEVEL is set by us and is the name for this magic number
835 even though all our userland documentation refers to runlevel */
836 RUNLEVEL = getenv ("RUNLEVEL");
837 PREVLEVEL = getenv ("PREVLEVEL");
838
839 /* Setup a signal handler */
840 signal (SIGINT, handle_signal);
841 signal (SIGQUIT, handle_signal);
842 signal (SIGTERM, handle_signal);
843 signal (SIGUSR1, handle_signal);
844
845 /* Ensure our environment is pure
846 Also, add our configuration to it */
847 env = env_filter ();
848 tmplist = env_config ();
849 rc_strlist_join (&env, tmplist);
850 rc_strlist_free (tmplist);
851
852 if (env) {
853 char *p;
854
855 #ifdef __linux__
856 /* clearenv isn't portable, but there's no harm in using it
857 if we have it */
858 clearenv ();
859 #else
860 char *var;
861 /* No clearenv present here then.
862 We could manipulate environ directly ourselves, but it seems that
863 some kernels bitch about this according to the environ man pages
864 so we walk though environ and call unsetenv for each value. */
865 while (environ[0]) {
866 tmp = xstrdup (environ[0]);
867 p = tmp;
868 var = strsep (&p, "=");
869 unsetenv (var);
870 free (tmp);
871 }
872 tmp = NULL;
873 #endif
874
875 STRLIST_FOREACH (env, p, i)
876 if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
877 putenv (p);
878
879 /* We don't free our list as that would be null in environ */
880 }
881
882 argc++;
883 argv--;
884 while ((opt = getopt_long (argc, argv, getoptstring,
885 longopts, (int *) 0)) != -1)
886 {
887 switch (opt) {
888 case_RC_COMMON_GETOPT
889 }
890 }
891
892 newlevel = argv[optind++];
893
894 /* OK, so we really are the main RC process
895 Only root should be able to run us */
896 if (geteuid () != 0)
897 eerrorx ("%s: root access required", applet);
898
899 /* Enable logging */
900 setenv ("RC_ELOG", "rc", 1);
901
902 /* Export our PID */
903 snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
904 setenv ("RC_PID", pidstr, 1);
905
906 interactive = exists (INTERACTIVE);
907 rc_plugin_load ();
908
909 /* Load current softlevel */
910 bootlevel = getenv ("RC_BOOTLEVEL");
911 runlevel = rc_runlevel_get ();
912
913 /* Check we're in the runlevel requested, ie from
914 rc single
915 rc shutdown
916 rc reboot
917 */
918 if (newlevel) {
919 if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
920 RUNLEVEL &&
921 (strcmp (RUNLEVEL, "S") == 0 ||
922 strcmp (RUNLEVEL, "1") == 0))
923 {
924 /* OK, we're either in runlevel 1 or single user mode */
925 struct utsname uts;
926 #ifdef __linux__
927 char *cmd;
928 #endif
929
930 /* exec init-early.sh if it exists
931 * This should just setup the console to use the correct
932 * font. Maybe it should setup the keyboard too? */
933 if (exists (INITEARLYSH))
934 run_script (INITEARLYSH);
935
936 uname (&uts);
937
938 printf ("\n");
939 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
940 "\n Copyright 1999-2007 Gentoo Foundation; "
941 "Distributed under the GPLv2\n\n",
942 ecolor (ECOLOR_GOOD), uts.sysname, ecolor (ECOLOR_BRACKET),
943 ecolor (ECOLOR_NORMAL));
944
945 if (rc_env_bool ("RC_INTERACTIVE"))
946 printf ("Press %sI%s to enter interactive boot mode\n\n",
947 ecolor (ECOLOR_GOOD), ecolor (ECOLOR_NORMAL));
948
949 setenv ("RC_SOFTLEVEL", newlevel, 1);
950 rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, newlevel);
951 run_script (INITSH);
952
953 #ifdef __linux__
954 /* If we requested a softlevel, save it now */
955 set_ksoftlevel (NULL);
956 if ((cmd = proc_getent ("softlevel"))) {
957 set_ksoftlevel (cmd);
958 free (cmd);
959 }
960
961 #endif
962 rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, newlevel);
963
964 if (want_interactive ())
965 mark_interactive ();
966
967 exit (EXIT_SUCCESS);
968 } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
969 if (! RUNLEVEL ||
970 (strcmp (RUNLEVEL, "S") != 0 &&
971 strcmp (RUNLEVEL, "1") != 0))
972 {
973 /* Remember the current runlevel for when we come back */
974 set_ksoftlevel (runlevel);
975 single_user ();
976 }
977 } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
978 if (! RUNLEVEL ||
979 strcmp (RUNLEVEL, "6") != 0)
980 {
981 execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
982 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
983 applet, strerror (errno));
984 }
985 } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
986 if (! RUNLEVEL ||
987 strcmp (RUNLEVEL, "0") != 0)
988 {
989 execl (SHUTDOWN, SHUTDOWN,
990 #ifdef __linux__
991 "-h",
992 #else
993 "-p",
994 #endif
995 "now", (char *) NULL);
996 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
997 applet, strerror (errno));
998 }
999 }
1000 }
1001
1002 /* Now we start handling our children */
1003 signal (SIGCHLD, handle_signal);
1004
1005 /* We should only use ksoftlevel if we were in single user mode
1006 If not, we need to erase ksoftlevel now. */
1007 if (PREVLEVEL &&
1008 (strcmp (PREVLEVEL, "1") == 0 ||
1009 strcmp (PREVLEVEL, "S") == 0 ||
1010 strcmp (PREVLEVEL, "N") == 0))
1011 {
1012 /* Try not to join boot and ksoftlevels together */
1013 if (! newlevel ||
1014 strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
1015 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
1016 newlevel = ksoftbuffer;
1017 } else if (! RUNLEVEL ||
1018 (strcmp (RUNLEVEL, "1") != 0 &&
1019 strcmp (RUNLEVEL, "S") != 0 &&
1020 strcmp (RUNLEVEL, "N") != 0))
1021 {
1022 set_ksoftlevel (NULL);
1023 }
1024
1025 if (newlevel &&
1026 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
1027 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1028 strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
1029 {
1030 going_down = true;
1031 rc_runlevel_set (newlevel);
1032 setenv ("RC_SOFTLEVEL", newlevel, 1);
1033 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, newlevel);
1034 } else {
1035 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, runlevel);
1036 }
1037
1038 /* Check if runlevel is valid if we're changing */
1039 if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1040 if (! rc_runlevel_exists (newlevel))
1041 eerrorx ("%s: is not a valid runlevel", newlevel);
1042 }
1043
1044 /* Load our deptree now */
1045 if ((deptree = _rc_deptree_load ()) == NULL)
1046 eerrorx ("failed to load deptree");
1047
1048 /* Clean the failed services state dir now */
1049 if ((dp = opendir (RC_SVCDIR "/failed"))) {
1050 while ((d = readdir (dp))) {
1051 if (d->d_name[0] == '.' &&
1052 (d->d_name[1] == '\0' ||
1053 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
1054 continue;
1055
1056 asprintf (&tmp, RC_SVCDIR "/failed/%s", d->d_name);
1057 if (tmp) {
1058 if (unlink (tmp))
1059 eerror ("%s: unlink `%s': %s", applet, tmp,
1060 strerror (errno));
1061 free (tmp);
1062 }
1063 }
1064 closedir (dp);
1065 }
1066
1067 mkdir (RC_STOPPING, 0755);
1068
1069 #ifdef __linux__
1070 /* udev likes to start services before we're ready when it does
1071 its coldplugging thing. runscript knows when we're not ready so it
1072 stores a list of coldplugged services in DEVBOOT for us to pick up
1073 here when we are ready for them */
1074 if ((dp = opendir (DEVBOOT))) {
1075 while ((d = readdir (dp))) {
1076 if (d->d_name[0] == '.' &&
1077 (d->d_name[1] == '\0' ||
1078 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
1079 continue;
1080
1081 if (rc_service_exists (d->d_name) &&
1082 rc_service_plugable (d->d_name))
1083 rc_service_mark (d->d_name, RC_SERVICE_COLDPLUGGED);
1084
1085 asprintf (&tmp, DEVBOOT "/%s", d->d_name);
1086 if (tmp) {
1087 if (unlink (tmp))
1088 eerror ("%s: unlink `%s': %s", applet, tmp,
1089 strerror (errno));
1090 free (tmp);
1091 }
1092 }
1093 closedir (dp);
1094 rmdir (DEVBOOT);
1095 }
1096 #else
1097 /* BSD's on the other hand populate /dev automagically and use devd.
1098 The only downside of this approach and ours is that we have to hard code
1099 the device node to the init script to simulate the coldplug into
1100 runlevel for our dependency tree to work. */
1101 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
1102 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
1103 strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
1104 rc_env_bool ("RC_COLDPLUG"))
1105 {
1106 #if defined(__DragonFly__) || defined(__FreeBSD__)
1107 /* The net interfaces are easy - they're all in net /dev/net :) */
1108 if ((dp = opendir ("/dev/net"))) {
1109 while ((d = readdir (dp))) {
1110 i = (strlen ("net.") + strlen (d->d_name) + 1);
1111 tmp = xmalloc (sizeof (char) * i);
1112 snprintf (tmp, i, "net.%s", d->d_name);
1113 if (rc_service_exists (tmp) &&
1114 rc_service_plugable (tmp))
1115 rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
1116 CHAR_FREE (tmp);
1117 }
1118 closedir (dp);
1119 }
1120 #endif
1121
1122 /* The mice are a little more tricky.
1123 If we coldplug anything else, we'll probably do it here. */
1124 if ((dp == opendir ("/dev"))) {
1125 while ((d = readdir (dp))) {
1126 if (strncmp (d->d_name, "psm", 3) == 0 ||
1127 strncmp (d->d_name, "ums", 3) == 0)
1128 {
1129 char *p = d->d_name + 3;
1130 if (p && isdigit (*p)) {
1131 i = (strlen ("moused.") + strlen (d->d_name) + 1);
1132 tmp = xmalloc (sizeof (char) * i);
1133 snprintf (tmp, i, "moused.%s", d->d_name);
1134 if (rc_service_exists (tmp) && rc_service_plugable (tmp))
1135 rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
1136 CHAR_FREE (tmp);
1137 }
1138 }
1139 }
1140 closedir (dp);
1141 }
1142 }
1143 #endif
1144
1145 /* Build a list of all services to stop and then work out the
1146 correct order for stopping them */
1147 stop_services = rc_services_in_state (RC_SERVICE_STARTING);
1148
1149 tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
1150 rc_strlist_join (&stop_services, tmplist);
1151 rc_strlist_free (tmplist);
1152
1153 tmplist = rc_services_in_state (RC_SERVICE_STARTED);
1154 rc_strlist_join (&stop_services, tmplist);
1155 rc_strlist_free (tmplist);
1156
1157 deporder = rc_deptree_depends (deptree, types_nua,
1158 (const char **) stop_services,
1159 runlevel, depoptions | RC_DEP_STOP);
1160
1161 rc_strlist_free (stop_services);
1162 stop_services = deporder;
1163 deporder = NULL;
1164 rc_strlist_reverse (stop_services);
1165
1166 /* Load our list of coldplugged services */
1167 coldplugged_services = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
1168
1169 /* Load our start services now.
1170 We have different rules dependent on runlevel. */
1171 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1172 if (coldplugged_services) {
1173 einfon ("Device initiated services:");
1174 STRLIST_FOREACH (coldplugged_services, service, i) {
1175 printf (" %s", service);
1176 rc_strlist_add (&start_services, service);
1177 }
1178 printf ("\n");
1179 }
1180 tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1181 rc_strlist_join (&start_services, tmplist);
1182 rc_strlist_free (tmplist);
1183 } else {
1184 /* Store our list of coldplugged services */
1185 tmplist = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
1186 rc_strlist_join (&coldplugged_services, tmplist);
1187 rc_strlist_free (tmplist);
1188 if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1189 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1190 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1191 {
1192 /* We need to include the boot runlevel services if we're not in it */
1193 tmplist = rc_services_in_runlevel (bootlevel);
1194 rc_strlist_join (&start_services, tmplist);
1195 rc_strlist_free (tmplist);
1196 tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1197 rc_strlist_join (&start_services, tmplist);
1198 rc_strlist_free (tmplist);
1199
1200 STRLIST_FOREACH (coldplugged_services, service, i)
1201 rc_strlist_add (&start_services, service);
1202
1203 }
1204 }
1205
1206 /* Save out softlevel now */
1207 if (going_down)
1208 rc_runlevel_set (newlevel);
1209
1210 /* Now stop the services that shouldn't be running */
1211 STRLIST_FOREACH (stop_services, service, i) {
1212 bool found = false;
1213 char *conf = NULL;
1214 char **stopdeps = NULL;
1215 char *svc1 = NULL;
1216 char *svc2 = NULL;
1217 int k;
1218
1219 if (rc_service_state (service) & RC_SERVICE_STOPPED)
1220 continue;
1221
1222 /* We always stop the service when in these runlevels */
1223 if (going_down) {
1224 pid_t pid = rc_service_stop (service);
1225 if (pid > 0 && ! rc_env_bool ("RC_PARALLEL"))
1226 wait_pid (pid);
1227 continue;
1228 }
1229
1230 /* If we're in the start list then don't bother stopping us */
1231 STRLIST_FOREACH (start_services, svc1, j)
1232 if (strcmp (svc1, service) == 0) {
1233 found = true;
1234 break;
1235 }
1236
1237 /* Unless we would use a different config file */
1238 if (found) {
1239 int len;
1240 if (! newlevel)
1241 continue;
1242
1243 len = strlen (service) + strlen (runlevel) + 2;
1244 tmp = xmalloc (sizeof (char) * len);
1245 snprintf (tmp, len, "%s.%s", service, runlevel);
1246 conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1247 found = exists (conf);
1248 CHAR_FREE (conf);
1249 CHAR_FREE (tmp);
1250 if (! found) {
1251 len = strlen (service) + strlen (newlevel) + 2;
1252 tmp = xmalloc (sizeof (char) * len);
1253 snprintf (tmp, len, "%s.%s", service, newlevel);
1254 conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1255 found = exists (conf);
1256 CHAR_FREE (conf);
1257 CHAR_FREE (tmp);
1258 if (!found)
1259 continue;
1260 }
1261 } else {
1262 /* Allow coldplugged services not to be in the runlevels list */
1263 if (rc_service_state (service) & RC_SERVICE_COLDPLUGGED)
1264 continue;
1265 }
1266
1267 /* We got this far! Or last check is to see if any any service that
1268 going to be started depends on us */
1269 rc_strlist_add (&stopdeps, service);
1270 deporder = rc_deptree_depends (deptree, types_n,
1271 (const char **) stopdeps,
1272 runlevel, RC_DEP_STRICT);
1273 rc_strlist_free (stopdeps);
1274 stopdeps = NULL;
1275 found = false;
1276 STRLIST_FOREACH (deporder, svc1, j) {
1277 STRLIST_FOREACH (start_services, svc2, k)
1278 if (strcmp (svc1, svc2) == 0) {
1279 found = true;
1280 break;
1281 }
1282 if (found)
1283 break;
1284 }
1285 rc_strlist_free (deporder);
1286 deporder = NULL;
1287
1288 /* After all that we can finally stop the blighter! */
1289 if (! found) {
1290 pid_t pid = rc_service_stop (service);
1291 if (pid > 0 && ! rc_env_bool ("RC_PARALLEL"))
1292 wait_pid (pid);
1293 }
1294 }
1295
1296 /* Wait for our services to finish */
1297 wait_for_services ();
1298
1299 /* Notify the plugins we have finished */
1300 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_OUT, runlevel);
1301
1302 rmdir (RC_STOPPING);
1303
1304 /* Store the new runlevel */
1305 if (newlevel) {
1306 rc_runlevel_set (newlevel);
1307 free (runlevel);
1308 runlevel = xstrdup (newlevel);
1309 setenv ("RC_SOFTLEVEL", runlevel, 1);
1310 }
1311
1312 /* Run the halt script if needed */
1313 if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1314 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1315 {
1316 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1317 eerrorx ("%s: unable to exec `%s': %s",
1318 applet, HALTSH, strerror (errno));
1319 }
1320
1321 /* Single user is done now */
1322 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1323 if (exists (INTERACTIVE))
1324 unlink (INTERACTIVE);
1325 sulogin (false);
1326 }
1327
1328 mkdir (RC_STARTING, 0755);
1329 rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, runlevel);
1330
1331 /* Re-add our coldplugged services if they stopped */
1332 STRLIST_FOREACH (coldplugged_services, service, i)
1333 rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
1334
1335 /* Order the services to start */
1336 deporder = rc_deptree_depends (deptree, types_nua,
1337 (const char **) start_services,
1338 runlevel, depoptions | RC_DEP_START);
1339 rc_strlist_free (start_services);
1340 start_services = deporder;
1341 deporder = NULL;
1342
1343 #ifdef __linux__
1344 /* mark any services skipped as started */
1345 if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1346 if ((service = proc_getent ("noinitd"))) {
1347 char *p = service;
1348 char *token;
1349
1350 while ((token = strsep (&p, ",")))
1351 rc_service_mark (token, RC_SERVICE_STARTED);
1352 free (service);
1353 }
1354 }
1355 #endif
1356
1357
1358 STRLIST_FOREACH (start_services, service, i) {
1359 if (rc_service_state (service) & RC_SERVICE_STOPPED) {
1360 pid_t pid;
1361
1362 if (! interactive)
1363 interactive = want_interactive ();
1364
1365 if (interactive) {
1366 interactive_retry:
1367 printf ("\n");
1368 einfo ("About to start the service %s", service);
1369 eindent ();
1370 einfo ("1) Start the service\t\t2) Skip the service");
1371 einfo ("3) Continue boot process\t\t4) Exit to shell");
1372 eoutdent ();
1373 interactive_option:
1374 switch (read_key (true)) {
1375 case '1': break;
1376 case '2': continue;
1377 case '3': interactive = false; break;
1378 case '4': sulogin (true); goto interactive_retry;
1379 default: goto interactive_option;
1380 }
1381 }
1382
1383 /* Remember the pid if we're running in parallel */
1384 if ((pid = rc_service_start (service)))
1385 add_pid (pid);
1386
1387 if (! rc_env_bool ("RC_PARALLEL")) {
1388 wait_pid (pid);
1389 remove_pid (pid);
1390 }
1391 }
1392 }
1393
1394 /* Wait for our services to finish */
1395 wait_for_services ();
1396
1397 rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, runlevel);
1398
1399 #ifdef __linux__
1400 /* mark any services skipped as stopped */
1401 if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1402 if ((service = proc_getent ("noinitd"))) {
1403 char *p = service;
1404 char *token;
1405
1406 while ((token = strsep (&p, ",")))
1407 rc_service_mark (token, RC_SERVICE_STOPPED);
1408 free (service);
1409 }
1410 }
1411 #endif
1412
1413 /* Store our interactive status for boot */
1414 if (interactive && strcmp (runlevel, bootlevel) == 0)
1415 mark_interactive ();
1416 else {
1417 if (exists (INTERACTIVE))
1418 unlink (INTERACTIVE);
1419 }
1420
1421 return (EXIT_SUCCESS);
1422 }

  ViewVC Help
Powered by ViewVC 1.1.20