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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20