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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3007 - (show annotations) (download) (as text)
Mon Oct 8 11:07:39 2007 UTC (7 years, 9 months ago) by uberlord
File MIME type: text/x-csrc
File size: 36731 byte(s)
Move rc_env_filter and rc_env_config out of librc and into rc
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 <syslog.h>
34 #include <termios.h>
35 #include <unistd.h>
36
37 #include "builtins.h"
38 #include "einfo.h"
39 #include "rc.h"
40 #include "rc-misc.h"
41 #include "rc-plugin.h"
42 #include "strlist.h"
43
44 #define INITSH RC_LIBDIR "/sh/init.sh"
45 #define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
46 #define HALTSH RC_INITDIR "/halt.sh"
47
48 #define SHUTDOWN "/sbin/shutdown"
49 #define SULOGIN "/sbin/sulogin"
50
51 #define INTERACTIVE RC_SVCDIR "/interactive"
52
53 #define DEVBOOT "/dev/.rcboot"
54
55 /* Cleanup anything in main */
56 #define CHAR_FREE(_item) if (_item) { \
57 free (_item); \
58 _item = NULL; \
59 }
60
61 extern char **environ;
62
63 static char *RUNLEVEL = NULL;
64 static char *PREVLEVEL = NULL;
65
66 static char *applet = NULL;
67 static char *runlevel = NULL;
68 static char **env = NULL;
69 static char **newenv = NULL;
70 static char **coldplugged_services = NULL;
71 static char **stop_services = NULL;
72 static char **start_services = NULL;
73 static rc_depinfo_t *deptree = NULL;
74 static char **types = NULL;
75 static char *tmp = NULL;
76
77 struct termios *termios_orig = NULL;
78
79 typedef struct pidlist
80 {
81 pid_t pid;
82 struct pidlist *next;
83 } pidlist_t;
84 static pidlist_t *service_pids = NULL;
85
86 static void cleanup (void)
87 {
88 if (applet && strcmp (applet, "rc") == 0) {
89 pidlist_t *pl = service_pids;
90
91 rc_plugin_unload ();
92
93 if (! rc_in_plugin && termios_orig) {
94 tcsetattr (fileno (stdin), TCSANOW, termios_orig);
95 free (termios_orig);
96 }
97
98 while (pl) {
99 pidlist_t *p = pl->next;
100 free (pl);
101 pl = p;
102 }
103
104 rc_strlist_free (env);
105 rc_strlist_free (newenv);
106 rc_strlist_free (coldplugged_services);
107 rc_strlist_free (stop_services);
108 rc_strlist_free (start_services);
109 rc_deptree_free (deptree);
110 rc_strlist_free (types);
111
112 /* Clean runlevel start, stop markers */
113 if (! rc_in_plugin) {
114 rmdir (RC_STARTING);
115 rmdir (RC_STOPPING);
116 }
117
118 free (runlevel);
119 }
120
121 free (applet);
122 }
123
124 static int syslog_decode (char *name, CODE *codetab)
125 {
126 CODE *c;
127
128 if (isdigit (*name))
129 return (atoi (name));
130
131 for (c = codetab; c->c_name; c++)
132 if (! strcasecmp (name, c->c_name))
133 return (c->c_val);
134
135 return (-1);
136 }
137
138 static int do_e (int argc, char **argv)
139 {
140 int retval = EXIT_SUCCESS;
141 int i;
142 int l = 0;
143 char *message = NULL;
144 char *p;
145 char *fmt = NULL;
146 int level = 0;
147
148 if (strcmp (applet, "eval_ecolors") == 0) {
149 printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
150 ecolor (ECOLOR_GOOD),
151 ecolor (ECOLOR_WARN),
152 ecolor (ECOLOR_BAD),
153 ecolor (ECOLOR_HILITE),
154 ecolor (ECOLOR_BRACKET),
155 ecolor (ECOLOR_NORMAL));
156 exit (EXIT_SUCCESS);
157 }
158
159 if (argc > 0) {
160
161 if (strcmp (applet, "eend") == 0 ||
162 strcmp (applet, "ewend") == 0 ||
163 strcmp (applet, "veend") == 0 ||
164 strcmp (applet, "vweend") == 0)
165 {
166 errno = 0;
167 retval = strtol (argv[0], NULL, 0);
168 if (errno != 0)
169 retval = EXIT_FAILURE;
170 else {
171 argc--;
172 argv++;
173 }
174 } else if (strcmp (applet, "esyslog") == 0 ||
175 strcmp (applet, "elog") == 0) {
176 char *dot = strchr (argv[0], '.');
177 if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
178 eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
179
180 if (argc < 3)
181 eerrorx ("%s: not enough arguments", applet);
182
183 unsetenv ("RC_ELOG");
184 setenv ("RC_ELOG", argv[1], 1);
185
186 argc -= 2;
187 argv += 2;
188 }
189 }
190
191 if (argc > 0) {
192 for (i = 0; i < argc; i++)
193 l += strlen (argv[i]) + 1;
194
195 message = rc_xmalloc (l);
196 p = message;
197
198 for (i = 0; i < argc; i++) {
199 if (i > 0)
200 *p++ = ' ';
201 memcpy (p, argv[i], strlen (argv[i]));
202 p += strlen (argv[i]);
203 }
204 *p = 0;
205 }
206
207 if (message)
208 fmt = rc_xstrdup ("%s");
209
210 if (strcmp (applet, "einfo") == 0)
211 einfo (fmt, message);
212 else if (strcmp (applet, "einfon") == 0)
213 einfon (fmt, message);
214 else if (strcmp (applet, "ewarn") == 0)
215 ewarn (fmt, message);
216 else if (strcmp (applet, "ewarnn") == 0)
217 ewarnn (fmt, message);
218 else if (strcmp (applet, "eerror") == 0) {
219 eerror (fmt, message);
220 retval = 1;
221 } else if (strcmp (applet, "eerrorn") == 0) {
222 eerrorn (fmt, message);
223 retval = 1;
224 } else if (strcmp (applet, "ebegin") == 0)
225 ebegin (fmt, message);
226 else if (strcmp (applet, "eend") == 0)
227 eend (retval, fmt, message);
228 else if (strcmp (applet, "ewend") == 0)
229 ewend (retval, fmt, message);
230 else if (strcmp (applet, "esyslog") == 0)
231 elog (level, fmt, message);
232 else if (strcmp (applet, "veinfo") == 0)
233 einfov (fmt, message);
234 else if (strcmp (applet, "veinfon") == 0)
235 einfovn (fmt, message);
236 else if (strcmp (applet, "vewarn") == 0)
237 ewarnv (fmt, message);
238 else if (strcmp (applet, "vewarnn") == 0)
239 ewarnvn (fmt, message);
240 else if (strcmp (applet, "vebegin") == 0)
241 ebeginv (fmt, message);
242 else if (strcmp (applet, "veend") == 0)
243 eendv (retval, fmt, message);
244 else if (strcmp (applet, "vewend") == 0)
245 ewendv (retval, fmt, message);
246 else if (strcmp (applet, "eindent") == 0)
247 eindent ();
248 else if (strcmp (applet, "eoutdent") == 0)
249 eoutdent ();
250 else if (strcmp (applet, "veindent") == 0)
251 eindentv ();
252 else if (strcmp (applet, "veoutdent") == 0)
253 eoutdentv ();
254 else {
255 eerror ("%s: unknown applet", applet);
256 retval = EXIT_FAILURE;
257 }
258
259 if (fmt)
260 free (fmt);
261 if (message)
262 free (message);
263 return (retval);
264 }
265
266 static int do_service (int argc, char **argv)
267 {
268 bool ok = false;
269
270 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
271 eerrorx ("%s: no service specified", applet);
272
273 if (strcmp (applet, "service_started") == 0)
274 ok = (rc_service_state (argv[0]) & RC_SERVICE_STARTED);
275 else if (strcmp (applet, "service_stopped") == 0)
276 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPED);
277 else if (strcmp (applet, "service_inactive") == 0)
278 ok = (rc_service_state (argv[0]) & RC_SERVICE_INACTIVE);
279 else if (strcmp (applet, "service_starting") == 0)
280 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPING);
281 else if (strcmp (applet, "service_stopping") == 0)
282 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPING);
283 else if (strcmp (applet, "service_coldplugged") == 0)
284 ok = (rc_service_state (argv[0]) & RC_SERVICE_COLDPLUGGED);
285 else if (strcmp (applet, "service_wasinactive") == 0)
286 ok = (rc_service_state (argv[0]) & RC_SERVICE_WASINACTIVE);
287 else if (strcmp (applet, "service_started_daemon") == 0) {
288 int idx = 0;
289 if (argc > 2)
290 sscanf (argv[2], "%d", &idx);
291 exit (rc_service_started_daemon (argv[0], argv[1], idx)
292 ? 0 : 1);
293 } else
294 eerrorx ("%s: unknown applet", applet);
295
296 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
297 }
298
299 static int do_mark_service (int argc, char **argv)
300 {
301 bool ok = false;
302 char *svcname = getenv ("SVCNAME");
303
304 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
305 eerrorx ("%s: no service specified", applet);
306
307 if (strcmp (applet, "mark_service_started") == 0)
308 ok = rc_service_mark (argv[0], RC_SERVICE_STARTED);
309 else if (strcmp (applet, "mark_service_stopped") == 0)
310 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPED);
311 else if (strcmp (applet, "mark_service_inactive") == 0)
312 ok = rc_service_mark (argv[0], RC_SERVICE_INACTIVE);
313 else if (strcmp (applet, "mark_service_starting") == 0)
314 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPING);
315 else if (strcmp (applet, "mark_service_stopping") == 0)
316 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPING);
317 else if (strcmp (applet, "mark_service_coldplugged") == 0)
318 ok = rc_service_mark (argv[0], RC_SERVICE_COLDPLUGGED);
319 else
320 eerrorx ("%s: unknown applet", applet);
321
322 /* If we're marking ourselves then we need to inform our parent runscript
323 process so they do not mark us based on our exit code */
324 if (ok && svcname && strcmp (svcname, argv[0]) == 0) {
325 char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
326 char *mtime;
327 pid_t pid = 0;
328 int l;
329
330 if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
331 if (kill (pid, SIGHUP) != 0)
332 eerror ("%s: failed to signal parent %d: %s",
333 applet, pid, strerror (errno));
334
335 /* Remove the exclusive time test. This ensures that it's not
336 in control as well */
337 l = strlen (RC_SVCDIR "exclusive") +
338 strlen (svcname) +
339 strlen (runscript_pid) +
340 4;
341 mtime = rc_xmalloc (l);
342 snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
343 svcname, runscript_pid);
344 if (rc_exists (mtime) && unlink (mtime) != 0)
345 eerror ("%s: unlink: %s", applet, strerror (errno));
346 free (mtime);
347 }
348
349 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
350 }
351
352 static int do_options (int argc, char **argv)
353 {
354 bool ok = false;
355 char *service = getenv ("SVCNAME");
356
357 if (! service)
358 eerrorx ("%s: no service specified", applet);
359
360 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
361 eerrorx ("%s: no option specified", applet);
362
363 if (strcmp (applet, "get_options") == 0) {
364 char *option = rc_service_value_get (service, argv[0]);
365 if (option) {
366 printf ("%s", option);
367 free (option);
368 ok = true;
369 }
370 } else if (strcmp (applet, "save_options") == 0)
371 ok = rc_service_value_set (service, argv[0], argv[1]);
372 else
373 eerrorx ("%s: unknown applet", applet);
374
375 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
376 }
377
378 #ifdef __linux__
379 static char *proc_getent (const char *ent)
380 {
381 FILE *fp;
382 char buffer[RC_LINEBUFFER];
383 char *p;
384 char *value = NULL;
385 int i;
386
387 if (! rc_exists ("/proc/cmdline"))
388 return (NULL);
389
390 if (! (fp = fopen ("/proc/cmdline", "r"))) {
391 eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
392 return (NULL);
393 }
394
395 memset (buffer, 0, sizeof (buffer));
396 if (fgets (buffer, RC_LINEBUFFER, fp) &&
397 (p = strstr (buffer, ent)))
398 {
399 i = p - buffer;
400 if (i == '\0' || buffer[i - 1] == ' ') {
401 /* Trim the trailing carriage return if present */
402 i = strlen (buffer) - 1;
403 if (buffer[i] == '\n')
404 buffer[i] = 0;
405
406 p += strlen (ent);
407 if (*p == '=')
408 p++;
409 value = strdup (strsep (&p, " "));
410 }
411 } else
412 errno = ENOENT;
413 fclose (fp);
414
415 return (value);
416 }
417 #endif
418
419 static char read_key (bool block)
420 {
421 struct termios termios;
422 char c = 0;
423 int fd = fileno (stdin);
424
425 if (! isatty (fd))
426 return (false);
427
428 /* Now save our terminal settings. We need to restore them at exit as we
429 will be changing it for non-blocking reads for Interactive */
430 if (! termios_orig) {
431 termios_orig = rc_xmalloc (sizeof (struct termios));
432 tcgetattr (fd, termios_orig);
433 }
434
435 tcgetattr (fd, &termios);
436 termios.c_lflag &= ~(ICANON | ECHO);
437 if (block)
438 termios.c_cc[VMIN] = 1;
439 else {
440 termios.c_cc[VMIN] = 0;
441 termios.c_cc[VTIME] = 0;
442 }
443 tcsetattr (fd, TCSANOW, &termios);
444
445 read (fd, &c, 1);
446
447 tcsetattr (fd, TCSANOW, termios_orig);
448
449 return (c);
450 }
451
452 static bool want_interactive (void)
453 {
454 char c;
455
456 if (PREVLEVEL &&
457 strcmp (PREVLEVEL, "N") != 0 &&
458 strcmp (PREVLEVEL, "S") != 0 &&
459 strcmp (PREVLEVEL, "1") != 0)
460 return (false);
461
462 if (! rc_env_bool ("RC_INTERACTIVE"))
463 return (false);
464
465 c = read_key (false);
466 return ((c == 'I' || c == 'i') ? true : false);
467 }
468
469 static void mark_interactive (void)
470 {
471 FILE *fp = fopen (INTERACTIVE, "w");
472 if (fp)
473 fclose (fp);
474 }
475
476 static void sulogin (bool cont)
477 {
478 #ifdef __linux__
479 char *e = getenv ("RC_SYS");
480
481 /* VPS systems cannot do an sulogin */
482 if (e && strcmp (e, "VPS") == 0) {
483 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
484 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
485 }
486 #endif
487
488 newenv = env_filter ();
489
490 if (cont) {
491 int status = 0;
492 #ifdef __linux__
493 char *tty = ttyname (fileno (stdout));
494 #endif
495
496 pid_t pid = vfork ();
497
498 if (pid == -1)
499 eerrorx ("%s: vfork: %s", applet, strerror (errno));
500 if (pid == 0) {
501 #ifdef __linux__
502 if (tty)
503 execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
504 else
505 execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
506
507 eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
508 strerror (errno));
509 #else
510 execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
511 eerror ("%s: unable to exec `/bin/sh': %s", applet,
512 strerror (errno));
513 #endif
514 _exit (EXIT_FAILURE);
515 }
516 waitpid (pid, &status, 0);
517 } else {
518 #ifdef __linux__
519 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
520 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
521 #else
522 exit (EXIT_SUCCESS);
523 #endif
524 }
525 }
526
527 static void single_user (void)
528 {
529 #ifdef __linux__
530 execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
531 eerrorx ("%s: unable to exec `/sbin/telinit': %s",
532 applet, strerror (errno));
533 #else
534 if (kill (1, SIGTERM) != 0)
535 eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
536 applet, strerror (errno));
537 exit (EXIT_SUCCESS);
538 #endif
539 }
540
541 static void set_ksoftlevel (const char *level)
542 {
543 FILE *fp;
544
545 if (! level ||
546 strcmp (level, getenv ("RC_BOOTLEVEL")) == 0 ||
547 strcmp (level, RC_LEVEL_SINGLE) == 0 ||
548 strcmp (level, RC_LEVEL_SYSINIT) == 0)
549 {
550 if (rc_exists (RC_KSOFTLEVEL) &&
551 unlink (RC_KSOFTLEVEL) != 0)
552 eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
553 return;
554 }
555
556 if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
557 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
558 return;
559 }
560
561 fprintf (fp, "%s", level);
562 fclose (fp);
563 }
564
565 static int get_ksoftlevel (char *buffer, int buffer_len)
566 {
567 FILE *fp;
568 int i = 0;
569
570 if (! rc_exists (RC_KSOFTLEVEL))
571 return (0);
572
573 if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
574 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
575 return (-1);
576 }
577
578 if (fgets (buffer, buffer_len, fp)) {
579 i = strlen (buffer) - 1;
580 if (buffer[i] == '\n')
581 buffer[i] = 0;
582 }
583
584 fclose (fp);
585 return (i);
586 }
587
588 static void wait_for_services ()
589 {
590 int status = 0;
591 while (wait (&status) != -1);
592 }
593
594 static void add_pid (pid_t pid)
595 {
596 pidlist_t *sp = service_pids;
597 if (sp) {
598 while (sp->next)
599 sp = sp->next;
600 sp->next = rc_xmalloc (sizeof (pidlist_t));
601 sp = sp->next;
602 } else
603 sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
604 memset (sp, 0, sizeof (pidlist_t));
605 sp->pid = pid;
606 }
607
608 static void remove_pid (pid_t pid)
609 {
610 pidlist_t *last = NULL;
611 pidlist_t *pl;
612
613 for (pl = service_pids; pl; pl = pl->next) {
614 if (pl->pid == pid) {
615 if (last)
616 last->next = pl->next;
617 else
618 service_pids = pl->next;
619 free (pl);
620 break;
621 }
622 last = pl;
623 }
624 }
625
626 static int wait_pid (pid_t pid)
627 {
628 int status = 0;
629 pid_t savedpid = pid;
630 int retval = -1;
631
632 errno = 0;
633 while ((pid = waitpid (savedpid, &status, 0)) > 0) {
634 if (pid == savedpid)
635 retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
636 }
637
638 return (retval);
639 }
640
641 static void handle_signal (int sig)
642 {
643 int serrno = errno;
644 char signame[10] = { '\0' };
645 pidlist_t *pl;
646 pid_t pid;
647 int status = 0;
648
649 switch (sig) {
650 case SIGCHLD:
651 do {
652 pid = waitpid (-1, &status, WNOHANG);
653 if (pid < 0) {
654 if (errno != ECHILD)
655 eerror ("waitpid: %s", strerror (errno));
656 return;
657 }
658 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
659
660 /* Remove that pid from our list */
661 if (pid > 0)
662 remove_pid (pid);
663 break;
664
665 case SIGINT:
666 if (! signame[0])
667 snprintf (signame, sizeof (signame), "SIGINT");
668 case SIGTERM:
669 if (! signame[0])
670 snprintf (signame, sizeof (signame), "SIGTERM");
671 case SIGQUIT:
672 if (! signame[0])
673 snprintf (signame, sizeof (signame), "SIGQUIT");
674 eerrorx ("%s: caught %s, aborting", applet, signame);
675 case SIGUSR1:
676 eerror ("rc: Aborting!");
677 /* Kill any running services we have started */
678
679 signal (SIGCHLD, SIG_IGN);
680 for (pl = service_pids; pl; pl = pl->next)
681 kill (pl->pid, SIGTERM);
682
683 /* Notify plugins we are aborting */
684 rc_plugin_run (RC_HOOK_ABORT, NULL);
685
686 /* Only drop into single user mode if we're booting */
687 if ((PREVLEVEL &&
688 (strcmp (PREVLEVEL, "S") == 0 ||
689 strcmp (PREVLEVEL, "1") == 0)) ||
690 (RUNLEVEL &&
691 (strcmp (RUNLEVEL, "S") == 0 ||
692 strcmp (RUNLEVEL, "1") == 0)))
693 single_user ();
694
695 exit (EXIT_FAILURE);
696 break;
697
698 default:
699 eerror ("%s: caught unknown signal %d", applet, sig);
700 }
701
702 /* Restore errno */
703 errno = serrno;
704 }
705
706 static void run_script (const char *script) {
707 int status = 0;
708 pid_t pid = vfork ();
709
710 if (pid < 0)
711 eerrorx ("%s: vfork: %s", applet, strerror (errno));
712 else if (pid == 0) {
713 execl (script, script, (char *) NULL);
714 eerror ("%s: unable to exec `%s': %s",
715 script, applet, strerror (errno));
716 _exit (EXIT_FAILURE);
717 }
718
719 do {
720 pid_t wpid = waitpid (pid, &status, 0);
721 if (wpid < 1)
722 eerror ("waitpid: %s", strerror (errno));
723 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
724
725 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
726 eerrorx ("%s: failed to exec `%s'", applet, script);
727 }
728
729 #include "_usage.h"
730 #define getoptstring getoptstring_COMMON
731 static struct option longopts[] = {
732 longopts_COMMON
733 { NULL, 0, NULL, 0}
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 = rc_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 = rc_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 = rc_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 (rc_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 = rc_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 = rc_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 = rc_xmalloc (sizeof (char *) * len);
1249 snprintf (tmp, len, "%s.%s", service, runlevel);
1250 conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1251 found = rc_exists (conf);
1252 CHAR_FREE (conf);
1253 CHAR_FREE (tmp);
1254 if (! found) {
1255 len = strlen (service) + strlen (newlevel) + 2;
1256 tmp = rc_xmalloc (sizeof (char *) * len);
1257 snprintf (tmp, len, "%s.%s", service, newlevel);
1258 conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1259 found = rc_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 = rc_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 (rc_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 (rc_exists (INTERACTIVE))
1427 unlink (INTERACTIVE);
1428 }
1429
1430 return (EXIT_SUCCESS);
1431 }

  ViewVC Help
Powered by ViewVC 1.1.20