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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20