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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3035 - (show annotations) (download) (as text)
Thu Oct 11 23:17:53 2007 UTC (10 years, 9 months ago) by uberlord
File MIME type: text/x-csrc
File size: 36720 byte(s)
malloc data size, not pointer size
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 if (strcmp (applet, "mark_service_failed") == 0)
321 ok = rc_service_mark (argv[0], RC_SERVICE_FAILED);
322 else
323 eerrorx ("%s: unknown applet", applet);
324
325 /* If we're marking ourselves then we need to inform our parent runscript
326 process so they do not mark us based on our exit code */
327 if (ok && svcname && strcmp (svcname, argv[0]) == 0) {
328 char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
329 char *mtime;
330 pid_t pid = 0;
331 int l;
332
333 if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
334 if (kill (pid, SIGHUP) != 0)
335 eerror ("%s: failed to signal parent %d: %s",
336 applet, pid, strerror (errno));
337
338 /* Remove the exclusive time test. This ensures that it's not
339 in control as well */
340 l = strlen (RC_SVCDIR "exclusive") +
341 strlen (svcname) +
342 strlen (runscript_pid) +
343 4;
344 mtime = xmalloc (l);
345 snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
346 svcname, runscript_pid);
347 if (exists (mtime) && unlink (mtime) != 0)
348 eerror ("%s: unlink: %s", applet, strerror (errno));
349 free (mtime);
350 }
351
352 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
353 }
354
355 static int do_options (int argc, char **argv)
356 {
357 bool ok = false;
358 char *service = getenv ("SVCNAME");
359
360 if (! service)
361 eerrorx ("%s: no service specified", applet);
362
363 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
364 eerrorx ("%s: no option specified", applet);
365
366 if (strcmp (applet, "get_options") == 0) {
367 char *option = rc_service_value_get (service, argv[0]);
368 if (option) {
369 printf ("%s", option);
370 free (option);
371 ok = true;
372 }
373 } else if (strcmp (applet, "save_options") == 0)
374 ok = rc_service_value_set (service, argv[0], argv[1]);
375 else
376 eerrorx ("%s: unknown applet", applet);
377
378 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
379 }
380
381 #ifdef __linux__
382 static char *proc_getent (const char *ent)
383 {
384 FILE *fp;
385 char buffer[RC_LINEBUFFER];
386 char *p;
387 char *value = NULL;
388 int i;
389
390 if (! exists ("/proc/cmdline"))
391 return (NULL);
392
393 if (! (fp = fopen ("/proc/cmdline", "r"))) {
394 eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
395 return (NULL);
396 }
397
398 memset (buffer, 0, sizeof (buffer));
399 if (fgets (buffer, RC_LINEBUFFER, fp) &&
400 (p = strstr (buffer, ent)))
401 {
402 i = p - buffer;
403 if (i == '\0' || buffer[i - 1] == ' ') {
404 /* Trim the trailing carriage return if present */
405 i = strlen (buffer) - 1;
406 if (buffer[i] == '\n')
407 buffer[i] = 0;
408
409 p += strlen (ent);
410 if (*p == '=')
411 p++;
412 value = xstrdup (strsep (&p, " "));
413 }
414 } else
415 errno = ENOENT;
416 fclose (fp);
417
418 return (value);
419 }
420 #endif
421
422 static char read_key (bool block)
423 {
424 struct termios termios;
425 char c = 0;
426 int fd = fileno (stdin);
427
428 if (! isatty (fd))
429 return (false);
430
431 /* Now save our terminal settings. We need to restore them at exit as we
432 will be changing it for non-blocking reads for Interactive */
433 if (! termios_orig) {
434 termios_orig = xmalloc (sizeof (struct termios));
435 tcgetattr (fd, termios_orig);
436 }
437
438 tcgetattr (fd, &termios);
439 termios.c_lflag &= ~(ICANON | ECHO);
440 if (block)
441 termios.c_cc[VMIN] = 1;
442 else {
443 termios.c_cc[VMIN] = 0;
444 termios.c_cc[VTIME] = 0;
445 }
446 tcsetattr (fd, TCSANOW, &termios);
447
448 read (fd, &c, 1);
449
450 tcsetattr (fd, TCSANOW, termios_orig);
451
452 return (c);
453 }
454
455 static bool want_interactive (void)
456 {
457 char c;
458
459 if (PREVLEVEL &&
460 strcmp (PREVLEVEL, "N") != 0 &&
461 strcmp (PREVLEVEL, "S") != 0 &&
462 strcmp (PREVLEVEL, "1") != 0)
463 return (false);
464
465 if (! rc_env_bool ("RC_INTERACTIVE"))
466 return (false);
467
468 c = read_key (false);
469 return ((c == 'I' || c == 'i') ? true : false);
470 }
471
472 static void mark_interactive (void)
473 {
474 FILE *fp = fopen (INTERACTIVE, "w");
475 if (fp)
476 fclose (fp);
477 }
478
479 static void sulogin (bool cont)
480 {
481 #ifdef __linux__
482 char *e = getenv ("RC_SYS");
483
484 /* VPS systems cannot do an sulogin */
485 if (e && strcmp (e, "VPS") == 0) {
486 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
487 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
488 }
489 #endif
490
491 newenv = env_filter ();
492
493 if (cont) {
494 int status = 0;
495 #ifdef __linux__
496 char *tty = ttyname (fileno (stdout));
497 #endif
498
499 pid_t pid = vfork ();
500
501 if (pid == -1)
502 eerrorx ("%s: vfork: %s", applet, strerror (errno));
503 if (pid == 0) {
504 #ifdef __linux__
505 if (tty)
506 execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
507 else
508 execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
509
510 eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
511 strerror (errno));
512 #else
513 execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
514 eerror ("%s: unable to exec `/bin/sh': %s", applet,
515 strerror (errno));
516 #endif
517 _exit (EXIT_FAILURE);
518 }
519 waitpid (pid, &status, 0);
520 } else {
521 #ifdef __linux__
522 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
523 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
524 #else
525 exit (EXIT_SUCCESS);
526 #endif
527 }
528 }
529
530 static void single_user (void)
531 {
532 #ifdef __linux__
533 execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
534 eerrorx ("%s: unable to exec `/sbin/telinit': %s",
535 applet, strerror (errno));
536 #else
537 if (kill (1, SIGTERM) != 0)
538 eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
539 applet, strerror (errno));
540 exit (EXIT_SUCCESS);
541 #endif
542 }
543
544 static void set_ksoftlevel (const char *level)
545 {
546 FILE *fp;
547
548 if (! level ||
549 strcmp (level, getenv ("RC_BOOTLEVEL")) == 0 ||
550 strcmp (level, RC_LEVEL_SINGLE) == 0 ||
551 strcmp (level, RC_LEVEL_SYSINIT) == 0)
552 {
553 if (exists (RC_KSOFTLEVEL) &&
554 unlink (RC_KSOFTLEVEL) != 0)
555 eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
556 return;
557 }
558
559 if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
560 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
561 return;
562 }
563
564 fprintf (fp, "%s", level);
565 fclose (fp);
566 }
567
568 static int get_ksoftlevel (char *buffer, int buffer_len)
569 {
570 FILE *fp;
571 int i = 0;
572
573 if (! exists (RC_KSOFTLEVEL))
574 return (0);
575
576 if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
577 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
578 return (-1);
579 }
580
581 if (fgets (buffer, buffer_len, fp)) {
582 i = strlen (buffer) - 1;
583 if (buffer[i] == '\n')
584 buffer[i] = 0;
585 }
586
587 fclose (fp);
588 return (i);
589 }
590
591 static void wait_for_services ()
592 {
593 int status = 0;
594 while (wait (&status) != -1);
595 }
596
597 static void add_pid (pid_t pid)
598 {
599 pidlist_t *sp = service_pids;
600 if (sp) {
601 while (sp->next)
602 sp = sp->next;
603 sp->next = xmalloc (sizeof (pidlist_t));
604 sp = sp->next;
605 } else
606 sp = service_pids = xmalloc (sizeof (pidlist_t));
607 memset (sp, 0, sizeof (pidlist_t));
608 sp->pid = pid;
609 }
610
611 static void remove_pid (pid_t pid)
612 {
613 pidlist_t *last = NULL;
614 pidlist_t *pl;
615
616 for (pl = service_pids; pl; pl = pl->next) {
617 if (pl->pid == pid) {
618 if (last)
619 last->next = pl->next;
620 else
621 service_pids = pl->next;
622 free (pl);
623 break;
624 }
625 last = pl;
626 }
627 }
628
629 static int wait_pid (pid_t pid)
630 {
631 int status = 0;
632 pid_t savedpid = pid;
633 int retval = -1;
634
635 errno = 0;
636 while ((pid = waitpid (savedpid, &status, 0)) > 0) {
637 if (pid == savedpid)
638 retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
639 }
640
641 return (retval);
642 }
643
644 static void handle_signal (int sig)
645 {
646 int serrno = errno;
647 char signame[10] = { '\0' };
648 pidlist_t *pl;
649 pid_t pid;
650 int status = 0;
651
652 switch (sig) {
653 case SIGCHLD:
654 do {
655 pid = waitpid (-1, &status, WNOHANG);
656 if (pid < 0) {
657 if (errno != ECHILD)
658 eerror ("waitpid: %s", strerror (errno));
659 return;
660 }
661 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
662
663 /* Remove that pid from our list */
664 if (pid > 0)
665 remove_pid (pid);
666 break;
667
668 case SIGINT:
669 if (! signame[0])
670 snprintf (signame, sizeof (signame), "SIGINT");
671 case SIGTERM:
672 if (! signame[0])
673 snprintf (signame, sizeof (signame), "SIGTERM");
674 case SIGQUIT:
675 if (! signame[0])
676 snprintf (signame, sizeof (signame), "SIGQUIT");
677 eerrorx ("%s: caught %s, aborting", applet, signame);
678 case SIGUSR1:
679 eerror ("rc: Aborting!");
680 /* Kill any running services we have started */
681
682 signal (SIGCHLD, SIG_IGN);
683 for (pl = service_pids; pl; pl = pl->next)
684 kill (pl->pid, SIGTERM);
685
686 /* Notify plugins we are aborting */
687 rc_plugin_run (RC_HOOK_ABORT, NULL);
688
689 /* Only drop into single user mode if we're booting */
690 if ((PREVLEVEL &&
691 (strcmp (PREVLEVEL, "S") == 0 ||
692 strcmp (PREVLEVEL, "1") == 0)) ||
693 (RUNLEVEL &&
694 (strcmp (RUNLEVEL, "S") == 0 ||
695 strcmp (RUNLEVEL, "1") == 0)))
696 single_user ();
697
698 exit (EXIT_FAILURE);
699 break;
700
701 default:
702 eerror ("%s: caught unknown signal %d", applet, sig);
703 }
704
705 /* Restore errno */
706 errno = serrno;
707 }
708
709 static void run_script (const char *script) {
710 int status = 0;
711 pid_t pid = vfork ();
712
713 if (pid < 0)
714 eerrorx ("%s: vfork: %s", applet, strerror (errno));
715 else if (pid == 0) {
716 execl (script, script, (char *) NULL);
717 eerror ("%s: unable to exec `%s': %s",
718 script, applet, strerror (errno));
719 _exit (EXIT_FAILURE);
720 }
721
722 do {
723 pid_t wpid = waitpid (pid, &status, 0);
724 if (wpid < 1)
725 eerror ("waitpid: %s", strerror (errno));
726 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
727
728 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
729 eerrorx ("%s: failed to exec `%s'", applet, script);
730 }
731
732 #include "_usage.h"
733 #define getoptstring getoptstring_COMMON
734 static struct option longopts[] = {
735 longopts_COMMON
736 };
737 static const char * const longopts_help[] = {
738 longopts_help_COMMON
739 };
740 #include "_usage.c"
741
742 int main (int argc, char **argv)
743 {
744 const char *bootlevel = NULL;
745 char *newlevel = NULL;
746 char *service = NULL;
747 char **deporder = NULL;
748 char **tmplist;
749 int i = 0;
750 int j = 0;
751 bool going_down = false;
752 bool interactive = false;
753 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
754 char ksoftbuffer [PATH_MAX];
755 char pidstr[6];
756 int opt;
757 DIR *dp;
758 struct dirent *d;
759
760 atexit (cleanup);
761 if (argv[0])
762 applet = xstrdup (basename (argv[0]));
763
764 if (! applet)
765 eerrorx ("arguments required");
766
767 /* These used to be programs in their own right, so we shouldn't
768 * touch argc or argv for them */
769 if (strcmp (applet, "env-update") == 0)
770 exit (env_update (argc, argv));
771 else if (strcmp (applet, "fstabinfo") == 0)
772 exit (fstabinfo (argc, argv));
773 else if (strcmp (applet, "mountinfo") == 0)
774 exit (mountinfo (argc, argv));
775 else if (strcmp (applet, "rc-depend") == 0)
776 exit (rc_depend (argc, argv));
777 else if (strcmp (applet, "rc-status") == 0)
778 exit (rc_status (argc, argv));
779 else if (strcmp (applet, "rc-update") == 0 ||
780 strcmp (applet, "update-rc") == 0)
781 exit (rc_update (argc, argv));
782 else if (strcmp (applet, "runscript") == 0)
783 exit (runscript (argc, argv));
784 else if (strcmp (applet, "start-stop-daemon") == 0)
785 exit (start_stop_daemon (argc, argv));
786 else if (strcmp (applet, "checkown") == 0)
787 exit (checkown (argc, argv));
788
789 argc--;
790 argv++;
791
792 /* Handle multicall stuff */
793 if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
794 exit (do_e (argc, argv));
795
796 if (strncmp (applet, "service_", strlen ("service_")) == 0)
797 exit (do_service (argc, argv));
798
799 if (strcmp (applet, "get_options") == 0 ||
800 strcmp (applet, "save_options") == 0)
801 exit (do_options (argc, argv));
802
803 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
804 exit (do_mark_service (argc, argv));
805
806 if (strcmp (applet, "is_runlevel_start") == 0)
807 exit (rc_runlevel_starting () ? 0 : 1);
808 else if (strcmp (applet, "is_runlevel_stop") == 0)
809 exit (rc_runlevel_stopping () ? 0 : 1);
810
811 if (strcmp (applet, "rc-abort") == 0) {
812 char *p = getenv ("RC_PID");
813 pid_t pid = 0;
814
815 if (p && sscanf (p, "%d", &pid) == 1) {
816 if (kill (pid, SIGUSR1) != 0)
817 eerrorx ("rc-abort: failed to signal parent %d: %s",
818 pid, strerror (errno));
819 exit (EXIT_SUCCESS);
820 }
821 exit (EXIT_FAILURE);
822 }
823
824 if (strcmp (applet, "rc" ) != 0)
825 eerrorx ("%s: unknown applet", applet);
826
827 /* Change dir to / to ensure all scripts don't use stuff in pwd */
828 chdir ("/");
829
830 /* RUNLEVEL is set by sysvinit as is a magic number
831 RC_SOFTLEVEL is set by us and is the name for this magic number
832 even though all our userland documentation refers to runlevel */
833 RUNLEVEL = getenv ("RUNLEVEL");
834 PREVLEVEL = getenv ("PREVLEVEL");
835
836 /* Setup a signal handler */
837 signal (SIGINT, handle_signal);
838 signal (SIGQUIT, handle_signal);
839 signal (SIGTERM, handle_signal);
840 signal (SIGUSR1, handle_signal);
841
842 /* Ensure our environment is pure
843 Also, add our configuration to it */
844 env = env_filter ();
845 tmplist = env_config ();
846 rc_strlist_join (&env, tmplist);
847 rc_strlist_free (tmplist);
848
849 if (env) {
850 char *p;
851
852 #ifdef __linux__
853 /* clearenv isn't portable, but there's no harm in using it
854 if we have it */
855 clearenv ();
856 #else
857 char *var;
858 /* No clearenv present here then.
859 We could manipulate environ directly ourselves, but it seems that
860 some kernels bitch about this according to the environ man pages
861 so we walk though environ and call unsetenv for each value. */
862 while (environ[0]) {
863 tmp = xstrdup (environ[0]);
864 p = tmp;
865 var = strsep (&p, "=");
866 unsetenv (var);
867 free (tmp);
868 }
869 tmp = NULL;
870 #endif
871
872 STRLIST_FOREACH (env, p, i)
873 if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
874 putenv (p);
875
876 /* We don't free our list as that would be null in environ */
877 }
878
879 argc++;
880 argv--;
881 while ((opt = getopt_long (argc, argv, getoptstring,
882 longopts, (int *) 0)) != -1)
883 {
884 switch (opt) {
885 case_RC_COMMON_GETOPT
886 }
887 }
888
889 newlevel = argv[optind++];
890
891 /* OK, so we really are the main RC process
892 Only root should be able to run us */
893 if (geteuid () != 0)
894 eerrorx ("%s: root access required", applet);
895
896 /* Enable logging */
897 setenv ("RC_ELOG", "rc", 1);
898
899 /* Export our PID */
900 snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
901 setenv ("RC_PID", pidstr, 1);
902
903 interactive = exists (INTERACTIVE);
904 rc_plugin_load ();
905
906 /* Load current softlevel */
907 bootlevel = getenv ("RC_BOOTLEVEL");
908 runlevel = rc_runlevel_get ();
909
910 /* Check we're in the runlevel requested, ie from
911 rc single
912 rc shutdown
913 rc reboot
914 */
915 if (newlevel) {
916 if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
917 RUNLEVEL &&
918 (strcmp (RUNLEVEL, "S") == 0 ||
919 strcmp (RUNLEVEL, "1") == 0))
920 {
921 /* OK, we're either in runlevel 1 or single user mode */
922 struct utsname uts;
923 #ifdef __linux__
924 char *cmd;
925 #endif
926
927 /* exec init-early.sh if it exists
928 * This should just setup the console to use the correct
929 * font. Maybe it should setup the keyboard too? */
930 if (exists (INITEARLYSH))
931 run_script (INITEARLYSH);
932
933 uname (&uts);
934
935 printf ("\n");
936 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
937 "\n Copyright 1999-2007 Gentoo Foundation; "
938 "Distributed under the GPLv2\n\n",
939 ecolor (ECOLOR_GOOD), uts.sysname, ecolor (ECOLOR_BRACKET),
940 ecolor (ECOLOR_NORMAL));
941
942 if (rc_env_bool ("RC_INTERACTIVE"))
943 printf ("Press %sI%s to enter interactive boot mode\n\n",
944 ecolor (ECOLOR_GOOD), ecolor (ECOLOR_NORMAL));
945
946 setenv ("RC_SOFTLEVEL", newlevel, 1);
947 rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, newlevel);
948 run_script (INITSH);
949
950 #ifdef __linux__
951 /* If we requested a softlevel, save it now */
952 set_ksoftlevel (NULL);
953 if ((cmd = proc_getent ("softlevel"))) {
954 set_ksoftlevel (cmd);
955 free (cmd);
956 }
957
958 #endif
959 rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, newlevel);
960
961 if (want_interactive ())
962 mark_interactive ();
963
964 exit (EXIT_SUCCESS);
965 } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
966 if (! RUNLEVEL ||
967 (strcmp (RUNLEVEL, "S") != 0 &&
968 strcmp (RUNLEVEL, "1") != 0))
969 {
970 /* Remember the current runlevel for when we come back */
971 set_ksoftlevel (runlevel);
972 single_user ();
973 }
974 } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
975 if (! RUNLEVEL ||
976 strcmp (RUNLEVEL, "6") != 0)
977 {
978 execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
979 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
980 applet, strerror (errno));
981 }
982 } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
983 if (! RUNLEVEL ||
984 strcmp (RUNLEVEL, "0") != 0)
985 {
986 execl (SHUTDOWN, SHUTDOWN,
987 #ifdef __linux__
988 "-h",
989 #else
990 "-p",
991 #endif
992 "now", (char *) NULL);
993 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
994 applet, strerror (errno));
995 }
996 }
997 }
998
999 /* Now we start handling our children */
1000 signal (SIGCHLD, handle_signal);
1001
1002 /* We should only use ksoftlevel if we were in single user mode
1003 If not, we need to erase ksoftlevel now. */
1004 if (PREVLEVEL &&
1005 (strcmp (PREVLEVEL, "1") == 0 ||
1006 strcmp (PREVLEVEL, "S") == 0 ||
1007 strcmp (PREVLEVEL, "N") == 0))
1008 {
1009 /* Try not to join boot and ksoftlevels together */
1010 if (! newlevel ||
1011 strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
1012 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
1013 newlevel = ksoftbuffer;
1014 } else if (! RUNLEVEL ||
1015 (strcmp (RUNLEVEL, "1") != 0 &&
1016 strcmp (RUNLEVEL, "S") != 0 &&
1017 strcmp (RUNLEVEL, "N") != 0))
1018 {
1019 set_ksoftlevel (NULL);
1020 }
1021
1022 if (newlevel &&
1023 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
1024 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1025 strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
1026 {
1027 going_down = true;
1028 rc_runlevel_set (newlevel);
1029 setenv ("RC_SOFTLEVEL", newlevel, 1);
1030 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, newlevel);
1031 } else {
1032 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, runlevel);
1033 }
1034
1035 /* Check if runlevel is valid if we're changing */
1036 if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1037 if (! rc_runlevel_exists (newlevel))
1038 eerrorx ("%s: is not a valid runlevel", newlevel);
1039 }
1040
1041 /* Load our deptree now */
1042 if ((deptree = _rc_deptree_load ()) == NULL)
1043 eerrorx ("failed to load deptree");
1044
1045 /* Clean the failed services state dir now */
1046 if ((dp = opendir (RC_SVCDIR "/failed"))) {
1047 while ((d = readdir (dp))) {
1048 if (d->d_name[0] == '.' &&
1049 (d->d_name[1] == '\0' ||
1050 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
1051 continue;
1052
1053 asprintf (&tmp, RC_SVCDIR "/failed/%s", d->d_name);
1054 if (tmp) {
1055 if (unlink (tmp))
1056 eerror ("%s: unlink `%s': %s", applet, tmp,
1057 strerror (errno));
1058 free (tmp);
1059 }
1060 }
1061 closedir (dp);
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