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

Diff of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 2640 Revision 2834
8 Gentoo einfo family of informational functions. 8 Gentoo einfo family of informational functions.
9 9
10 Copyright 2007 Gentoo Foundation 10 Copyright 2007 Gentoo Foundation
11 Released under the GPLv2 11 Released under the GPLv2
12 */ 12 */
13
14#define APPLET "rc"
15
16#define SYSLOG_NAMES
13 17
14#include <sys/types.h> 18#include <sys/types.h>
15#include <sys/stat.h> 19#include <sys/stat.h>
16#include <sys/utsname.h> 20#include <sys/utsname.h>
17#include <sys/wait.h> 21#include <sys/wait.h>
18#include <errno.h> 22#include <errno.h>
19#include <ctype.h> 23#include <ctype.h>
24#include <getopt.h>
20#include <libgen.h> 25#include <libgen.h>
21#include <limits.h> 26#include <limits.h>
22#include <stdbool.h> 27#include <stdbool.h>
23#include <stdio.h> 28#include <stdio.h>
24#include <stdlib.h> 29#include <stdlib.h>
25#include <signal.h> 30#include <signal.h>
26#include <string.h> 31#include <string.h>
32#include <syslog.h>
27#include <termios.h> 33#include <termios.h>
28#include <unistd.h> 34#include <unistd.h>
29 35
36#include "builtins.h"
30#include "einfo.h" 37#include "einfo.h"
31#include "rc.h" 38#include "rc.h"
32#include "rc-misc.h" 39#include "rc-misc.h"
33#include "rc-plugin.h" 40#include "rc-plugin.h"
34#include "strlist.h" 41#include "strlist.h"
35 42
36#define INITSH RC_LIBDIR "sh/init.sh" 43#define INITSH RC_LIBDIR "/sh/init.sh"
37#define HALTSH RC_INITDIR "halt.sh" 44#define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
45#define HALTSH RC_INITDIR "/halt.sh"
46#define SULOGIN "/sbin/sulogin"
38 47
39#define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
40#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
41#define RC_SVCDIR_STARTED RC_SVCDIR "started/"
42#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
43
44#define INTERACTIVE RC_SVCDIR "interactive" 48#define INTERACTIVE RC_SVCDIR "/interactive"
45 49
46#define DEVBOOT "/dev/.rcboot" 50#define DEVBOOT "/dev/.rcboot"
47 51
48/* Cleanup anything in main */ 52/* Cleanup anything in main */
49#define CHAR_FREE(_item) if (_item) { \ 53#define CHAR_FREE(_item) if (_item) { \
50 free (_item); \ 54 free (_item); \
51 _item = NULL; \ 55 _item = NULL; \
52} 56}
53 57
54extern char **environ; 58extern char **environ;
59
60static char *RUNLEVEL = NULL;
61static char *PREVLEVEL = NULL;
55 62
56static char *applet = NULL; 63static char *applet = NULL;
57static char **env = NULL; 64static char **env = NULL;
58static char **newenv = NULL; 65static char **newenv = NULL;
59static char **coldplugged_services = NULL; 66static char **coldplugged_services = NULL;
63static char **types = NULL; 70static char **types = NULL;
64static char *tmp = NULL; 71static char *tmp = NULL;
65 72
66struct termios *termios_orig = NULL; 73struct termios *termios_orig = NULL;
67 74
75typedef struct pidlist
76{
77 pid_t pid;
78 struct pidlist *next;
79} pidlist_t;
80static pidlist_t *service_pids = NULL;
81
68static void cleanup (void) 82static void cleanup (void)
69{ 83{
84 if (applet && strcmp (applet, "rc") == 0) {
85 pidlist_t *pl = service_pids;
86
70 rc_plugin_unload (); 87 rc_plugin_unload ();
71 88
72 if (termios_orig) { 89 if (! rc_in_plugin && termios_orig) {
73 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); 90 tcsetattr (fileno (stdin), TCSANOW, termios_orig);
74 free (termios_orig); 91 free (termios_orig);
75 } 92 }
76 93
94 while (pl) {
95 pidlist_t *p = pl->next;
96 free (pl);
97 pl = p;
98 }
99
77 rc_strlist_free (env); 100 rc_strlist_free (env);
78 rc_strlist_free (newenv); 101 rc_strlist_free (newenv);
79 rc_strlist_free (coldplugged_services); 102 rc_strlist_free (coldplugged_services);
80 rc_strlist_free (stop_services); 103 rc_strlist_free (stop_services);
81 rc_strlist_free (start_services); 104 rc_strlist_free (start_services);
82 rc_free_deptree (deptree); 105 rc_free_deptree (deptree);
83 rc_strlist_free (types); 106 rc_strlist_free (types);
84 107
85 /* Clean runlevel start, stop markers */ 108 /* Clean runlevel start, stop markers */
109 if (! rc_in_plugin) {
86 if (rc_is_dir (RC_SVCDIR "softscripts.new")) 110 if (rc_is_dir (RC_SVCDIR "softscripts.new"))
87 rc_rm_dir (RC_SVCDIR "softscripts.new", true); 111 rc_rm_dir (RC_SVCDIR "softscripts.new", true);
88 if (rc_is_dir (RC_SVCDIR "softscripts.old")) 112 if (rc_is_dir (RC_SVCDIR "softscripts.old"))
89 rc_rm_dir (RC_SVCDIR "softscripts.old", true); 113 rc_rm_dir (RC_SVCDIR "softscripts.old", true);
114 }
115 }
90 116
91 free (applet); 117 free (applet);
118}
119
120static int syslog_decode (char *name, CODE *codetab)
121{
122 CODE *c;
123
124 if (isdigit (*name))
125 return (atoi (name));
126
127 for (c = codetab; c->c_name; c++)
128 if (! strcasecmp (name, c->c_name))
129 return (c->c_val);
130
131 return (-1);
92} 132}
93 133
94static int do_e (int argc, char **argv) 134static int do_e (int argc, char **argv)
95{ 135{
96 int retval = EXIT_SUCCESS; 136 int retval = EXIT_SUCCESS;
97 int i; 137 int i;
98 int l = 0; 138 int l = 0;
99 char *message = NULL; 139 char *message = NULL;
100 char *p; 140 char *p;
101 char *fmt = NULL; 141 char *fmt = NULL;
142 int level = 0;
102 143
103 if (strcmp (applet, "eval_ecolors") == 0) { 144 if (strcmp (applet, "eval_ecolors") == 0) {
104 printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n", 145 printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
105 ecolor (ecolor_good), 146 ecolor (ecolor_good),
106 ecolor (ecolor_warn), 147 ecolor (ecolor_warn),
109 ecolor (ecolor_bracket), 150 ecolor (ecolor_bracket),
110 ecolor (ecolor_normal)); 151 ecolor (ecolor_normal));
111 exit (EXIT_SUCCESS); 152 exit (EXIT_SUCCESS);
112 } 153 }
113 154
155 if (argc > 0) {
156
114 if (strcmp (applet, "eend") == 0 || 157 if (strcmp (applet, "eend") == 0 ||
115 strcmp (applet, "ewend") == 0 || 158 strcmp (applet, "ewend") == 0 ||
116 strcmp (applet, "veend") == 0 || 159 strcmp (applet, "veend") == 0 ||
117 strcmp (applet, "vweend") == 0) 160 strcmp (applet, "vweend") == 0)
118 { 161 {
119 if (argc > 0) {
120 errno = 0; 162 errno = 0;
121 retval = strtol (argv[0], NULL, 0); 163 retval = strtol (argv[0], NULL, 0);
122 if (errno != 0) 164 if (errno != 0)
123 retval = EXIT_FAILURE; 165 retval = EXIT_FAILURE;
124 else { 166 else {
125 argc--; 167 argc--;
126 argv++; 168 argv++;
127 } 169 }
128 } 170 } else if (strcmp (applet, "esyslog") == 0 ||
129 else 171 strcmp (applet, "elog") == 0) {
130 retval = EXIT_FAILURE; 172 char *dot = strchr (argv[0], '.');
173 if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
174 eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
175 argc--;
176 argv++;
131 } 177 }
178 }
179
132 180
133 if (argc > 0) { 181 if (argc > 0) {
134 for (i = 0; i < argc; i++) 182 for (i = 0; i < argc; i++)
135 l += strlen (argv[i]) + 1; 183 l += strlen (argv[i]) + 1;
136 184
167 ebegin (fmt, message); 215 ebegin (fmt, message);
168 else if (strcmp (applet, "eend") == 0) 216 else if (strcmp (applet, "eend") == 0)
169 eend (retval, fmt, message); 217 eend (retval, fmt, message);
170 else if (strcmp (applet, "ewend") == 0) 218 else if (strcmp (applet, "ewend") == 0)
171 ewend (retval, fmt, message); 219 ewend (retval, fmt, message);
220 else if (strcmp (applet, "esyslog") == 0)
221 elog (level, fmt, message);
172 else if (strcmp (applet, "veinfo") == 0) 222 else if (strcmp (applet, "veinfo") == 0)
173 einfov (fmt, message); 223 einfov (fmt, message);
174 else if (strcmp (applet, "veinfon") == 0) 224 else if (strcmp (applet, "veinfon") == 0)
175 einfovn (fmt, message); 225 einfovn (fmt, message);
176 else if (strcmp (applet, "vewarn") == 0) 226 else if (strcmp (applet, "vewarn") == 0)
189 eoutdent (); 239 eoutdent ();
190 else if (strcmp (applet, "veindent") == 0) 240 else if (strcmp (applet, "veindent") == 0)
191 eindentv (); 241 eindentv ();
192 else if (strcmp (applet, "veoutdent") == 0) 242 else if (strcmp (applet, "veoutdent") == 0)
193 eoutdentv (); 243 eoutdentv ();
194 else if (strcmp (applet, "eflush") == 0)
195 eflush ();
196 else { 244 else {
197 eerror ("%s: unknown applet", applet); 245 eerror ("%s: unknown applet", applet);
198 retval = EXIT_FAILURE; 246 retval = EXIT_FAILURE;
199 } 247 }
200 248
314 eerrorx ("%s: unknown applet", applet); 362 eerrorx ("%s: unknown applet", applet);
315 363
316 return (ok ? EXIT_SUCCESS : EXIT_FAILURE); 364 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
317} 365}
318 366
367#ifdef __linux__
368static char *proc_getent (const char *ent)
369{
370 FILE *fp;
371 char buffer[RC_LINEBUFFER];
372 char *p;
373 char *value = NULL;
374 int i;
375
376 if (! (fp = fopen ("/proc/cmdline", "r"))) {
377 eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
378 return (NULL);
379 }
380
381 memset (buffer, 0, sizeof (buffer));
382 if (fgets (buffer, RC_LINEBUFFER, fp) &&
383 (p = strstr (buffer, ent)))
384 {
385 i = p - buffer;
386 if (i == '\0' || buffer[i - 1] == ' ') {
387 /* Trim the trailing carriage return if present */
388 i = strlen (buffer) - 1;
389 if (buffer[i] == '\n')
390 buffer[i] = 0;
391
392 p += strlen (ent);
393 if (*p == '=')
394 p++;
395 value = strdup (strsep (&p, " "));
396 }
397 } else
398 errno = ENOENT;
399 fclose (fp);
400
401 return (value);
402}
403#endif
404
319static char read_key (bool block) 405static char read_key (bool block)
320{ 406{
321 struct termios termios; 407 struct termios termios;
322 char c = 0; 408 char c = 0;
409 int fd = fileno (stdin);
323 410
324 if (! isatty (STDIN_FILENO)) 411 if (! isatty (fd))
325 return (false); 412 return (false);
326 413
327 /* Now save our terminal settings. We need to restore them at exit as we 414 /* Now save our terminal settings. We need to restore them at exit as we
328 will be changing it for non-blocking reads for Interactive */ 415 will be changing it for non-blocking reads for Interactive */
329 if (! termios_orig) { 416 if (! termios_orig) {
330 termios_orig = rc_xmalloc (sizeof (struct termios)); 417 termios_orig = rc_xmalloc (sizeof (struct termios));
331 tcgetattr (STDIN_FILENO, termios_orig); 418 tcgetattr (fd, termios_orig);
332 } 419 }
333 420
334 tcgetattr (STDIN_FILENO, &termios); 421 tcgetattr (fd, &termios);
335 termios.c_lflag &= ~(ICANON | ECHO); 422 termios.c_lflag &= ~(ICANON | ECHO);
336 if (block) 423 if (block)
337 termios.c_cc[VMIN] = 1; 424 termios.c_cc[VMIN] = 1;
338 else { 425 else {
339 termios.c_cc[VMIN] = 0; 426 termios.c_cc[VMIN] = 0;
340 termios.c_cc[VTIME] = 0; 427 termios.c_cc[VTIME] = 0;
341 } 428 }
342 tcsetattr (STDIN_FILENO, TCSANOW, &termios); 429 tcsetattr (fd, TCSANOW, &termios);
343 430
344 read (STDIN_FILENO, &c, 1); 431 read (fd, &c, 1);
345 432
346 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); 433 tcsetattr (fd, TCSANOW, termios_orig);
347 434
348 return (c); 435 return (c);
349} 436}
350 437
351static bool want_interactive (void) 438static bool want_interactive (void)
352{ 439{
440 char c;
441
442 if (PREVLEVEL &&
443 strcmp (PREVLEVEL, "N") != 0 &&
444 strcmp (PREVLEVEL, "S") != 0 &&
445 strcmp (PREVLEVEL, "1") != 0)
446 return (false);
447
448 if (! rc_is_env ("RC_INTERACTIVE", "yes"))
449 return (false);
450
353 char c = read_key (false); 451 c = read_key (false);
354 return ((c == 'I' || c == 'i') ? true : false); 452 return ((c == 'I' || c == 'i') ? true : false);
355} 453}
356 454
357static void mark_interactive (void) 455static void mark_interactive (void)
358{ 456{
369 /* VPS systems cannot do an sulogin */ 467 /* VPS systems cannot do an sulogin */
370 if (e && strcmp (e, "VPS") == 0) { 468 if (e && strcmp (e, "VPS") == 0) {
371 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL); 469 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
372 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno)); 470 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
373 } 471 }
472#endif
473
474 newenv = rc_filter_env ();
374 475
375 if (cont) { 476 if (cont) {
376 int status = 0; 477 int status = 0;
478#ifdef __linux__
479 char *tty = ttyname (fileno (stdout));
480#endif
481
377 pid_t pid = vfork(); 482 pid_t pid = vfork ();
378 483
379 if (pid == -1) 484 if (pid == -1)
380 eerrorx ("%s: vfork: %s", applet, strerror (errno)); 485 eerrorx ("%s: vfork: %s", applet, strerror (errno));
381 if (pid == 0) { 486 if (pid == 0) {
382 newenv = rc_filter_env (); 487#ifdef __linux__
383 execl ("/sbin/sulogin", "/sbin/sulogin", 488 if (tty)
384 getenv ("CONSOLE"), (char *) NULL, newenv); 489 execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
490 else
491 execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
492
385 eerror ("%s: unable to exec `/sbin/sulogin': %s", applet, 493 eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
386 strerror (errno)); 494 strerror (errno));
495#else
496 execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
497 eerror ("%s: unable to exec `/bin/sh': %s", applet,
498 strerror (errno));
499#endif
387 _exit (EXIT_FAILURE); 500 _exit (EXIT_FAILURE);
388 } 501 }
389 waitpid (pid, &status, 0); 502 waitpid (pid, &status, 0);
390 } else { 503 } else {
391 newenv = rc_filter_env (); 504#ifdef __linux
392 execl ("/sbin/sulogin", "/sbin/sulogin", 505 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
393 getenv ("CONSOLE"), (char *) NULL, newenv);
394 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); 506 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
395 }
396#else 507#else
397 exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); 508 exit (EXIT_SUCCESS);
398#endif 509#endif
510 }
399} 511}
400 512
401static void single_user (void) 513static void single_user (void)
402{ 514{
403#ifdef __linux__ 515#ifdef __linux__
415static void set_ksoftlevel (const char *runlevel) 527static void set_ksoftlevel (const char *runlevel)
416{ 528{
417 FILE *fp; 529 FILE *fp;
418 530
419 if (! runlevel || 531 if (! runlevel ||
420 strcmp (runlevel, RC_LEVEL_BOOT) == 0 || 532 strcmp (runlevel, getenv ("RC_BOOTLEVEL")) == 0 ||
421 strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || 533 strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
422 strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) 534 strcmp (runlevel, RC_LEVEL_SYSINIT) == 0)
423 { 535 {
424 if (rc_exists (RC_SVCDIR "ksoftlevel") && 536 if (rc_exists (RC_SVCDIR "ksoftlevel") &&
425 unlink (RC_SVCDIR "ksoftlevel") != 0) 537 unlink (RC_SVCDIR "ksoftlevel") != 0)
434 546
435 fprintf (fp, "%s", runlevel); 547 fprintf (fp, "%s", runlevel);
436 fclose (fp); 548 fclose (fp);
437} 549}
438 550
551static int get_ksoftlevel (char *buffer, int buffer_len)
552{
553 FILE *fp;
554 int i = 0;
555
556 if (! rc_exists (RC_SVCDIR "ksoftlevel"))
557 return 0;
558
559 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) {
560 eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
561 strerror (errno));
562 return -1;
563 }
564
565 if (fgets (buffer, buffer_len, fp)) {
566 i = strlen (buffer) - 1;
567 if (buffer[i] == '\n')
568 buffer[i] = 0;
569 }
570
571 fclose (fp);
572 return i;
573}
574
439static void wait_for_services () 575static void wait_for_services ()
440{ 576{
441 int status = 0; 577 int status = 0;
442 struct timeval tv;
443 while (wait (&status) != -1); 578 while (wait (&status) != -1);
579}
444 580
445 /* Wait for a little bit to flush our ebuffer */ 581static void add_pid (pid_t pid)
446 tv.tv_usec = 50000; 582{
447 tv.tv_sec = 0; 583 pidlist_t *sp = service_pids;
448 select (0, NULL, NULL, NULL, &tv); 584 if (sp) {
585 while (sp->next)
586 sp = sp->next;
587 sp->next = rc_xmalloc (sizeof (pidlist_t));
588 sp = sp->next;
589 } else
590 sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
591 memset (sp, 0, sizeof (pidlist_t));
592 sp->pid = pid;
593}
594
595static void remove_pid (pid_t pid)
596{
597 pidlist_t *last = NULL;
598 pidlist_t *pl;
599
600 for (pl = service_pids; pl; pl = pl->next) {
601 if (pl->pid == pid) {
602 if (last)
603 last->next = pl->next;
604 else
605 service_pids = pl->next;
606 free (pl);
607 break;
608 }
609 last = pl;
610 }
449} 611}
450 612
451static void handle_signal (int sig) 613static void handle_signal (int sig)
452{ 614{
453 int serrno = errno; 615 int serrno = errno;
454 char signame[10] = { '\0' }; 616 char signame[10] = { '\0' };
455 char *run; 617 pidlist_t *pl;
456 char *prev; 618 pid_t pid;
619 int status = 0;
457 620
458 switch (sig) { 621 switch (sig) {
622 case SIGCHLD:
623 do {
624 pid = waitpid (-1, &status, WNOHANG);
625 if (pid < 0) {
626 if (errno != ECHILD)
627 eerror ("waitpid: %s", strerror (errno));
628 return;
629 }
630 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
631
632 /* Remove that pid from our list */
633 if (pid > 0)
634 remove_pid (pid);
635 break;
636
459 case SIGINT: 637 case SIGINT:
460 if (! signame[0]) 638 if (! signame[0])
461 snprintf (signame, sizeof (signame), "SIGINT"); 639 snprintf (signame, sizeof (signame), "SIGINT");
462 case SIGTERM: 640 case SIGTERM:
463 if (! signame[0]) 641 if (! signame[0])
467 snprintf (signame, sizeof (signame), "SIGQUIT"); 645 snprintf (signame, sizeof (signame), "SIGQUIT");
468 eerrorx ("%s: caught %s, aborting", applet, signame); 646 eerrorx ("%s: caught %s, aborting", applet, signame);
469 case SIGUSR1: 647 case SIGUSR1:
470 eerror ("rc: Aborting!"); 648 eerror ("rc: Aborting!");
471 /* Kill any running services we have started */ 649 /* Kill any running services we have started */
650
472 signal (SIGTERM, SIG_IGN); 651 signal (SIGCHLD, SIG_IGN);
473 killpg (getpgrp (), SIGTERM); 652 for (pl = service_pids; pl; pl = pl->next)
653 kill (pl->pid, SIGTERM);
474 654
475 /* Notify plugins we are aborting */ 655 /* Notify plugins we are aborting */
476 rc_plugin_run (rc_hook_abort, "rc"); 656 rc_plugin_run (rc_hook_abort, NULL);
477 657
478 run = getenv ("RUNLEVEL");
479 prev = getenv ("PREVLEVEL");
480 /* Only drop into single user mode if we're booting */ 658 /* Only drop into single user mode if we're booting */
481 if ((prev && strcmp (prev, "S") == 0) || 659 if ((PREVLEVEL &&
482 (run && strcmp (run, "S") == 0)) 660 (strcmp (PREVLEVEL, "S") == 0 ||
661 strcmp (PREVLEVEL, "1") == 0)) ||
662 (RUNLEVEL &&
663 (strcmp (RUNLEVEL, "S") == 0 ||
664 strcmp (RUNLEVEL, "1") == 0)))
483 single_user (); 665 single_user ();
484 666
485 exit (EXIT_FAILURE); 667 exit (EXIT_FAILURE);
486 break; 668 break;
487 669
491 673
492 /* Restore errno */ 674 /* Restore errno */
493 errno = serrno; 675 errno = serrno;
494} 676}
495 677
678static void run_script (const char *script) {
679 int status = 0;
680 pid_t pid = vfork ();
681
682 if (pid < 0)
683 eerrorx ("%s: vfork: %s", applet, strerror (errno));
684 else if (pid == 0) {
685 execl (script, script, (char *) NULL);
686 eerror ("%s: unable to exec `%s': %s",
687 script, applet, strerror (errno));
688 _exit (EXIT_FAILURE);
689 }
690
691 do {
692 pid_t wpid = waitpid (pid, &status, 0);
693 if (wpid < 1)
694 eerror ("waitpid: %s", strerror (errno));
695 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
696
697 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
698 eerrorx ("%s: failed to exec `%s'", applet, script);
699}
700
701#include "_usage.h"
702#define getoptstring getoptstring_COMMON
703static struct option longopts[] = {
704 longopts_COMMON
705 { NULL, 0, NULL, 0}
706};
707#include "_usage.c"
708
496int main (int argc, char **argv) 709int main (int argc, char **argv)
497{ 710{
498 char *RUNLEVEL = NULL;
499 char *PREVLEVEL = NULL;
500 char *runlevel = NULL; 711 char *runlevel = NULL;
712 const char *bootlevel = NULL;
501 char *newlevel = NULL; 713 char *newlevel = NULL;
502 char *service = NULL; 714 char *service = NULL;
503 char **deporder = NULL; 715 char **deporder = NULL;
504 int i = 0; 716 int i = 0;
505 int j = 0; 717 int j = 0;
506 bool going_down = false; 718 bool going_down = false;
507 bool interactive = false; 719 bool interactive = false;
508 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; 720 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
509 char ksoftbuffer [PATH_MAX]; 721 char ksoftbuffer [PATH_MAX];
510 char pidstr[6]; 722 char pidstr[6];
723 int opt;
511 724
725 atexit (cleanup);
512 if (argv[0]) 726 if (argv[0])
513 applet = rc_xstrdup (basename (argv[0])); 727 applet = rc_xstrdup (basename (argv[0]));
514 728
515 if (! applet) 729 if (! applet)
516 eerrorx ("arguments required"); 730 eerrorx ("arguments required");
731
732 /* These used to be programs in their own right, so we shouldn't
733 * touch argc or argv for them */
734 if (strcmp (applet, "env-update") == 0)
735 exit (env_update (argc, argv));
736 else if (strcmp (applet, "fstabinfo") == 0)
737 exit (fstabinfo (argc, argv));
738 else if (strcmp (applet, "mountinfo") == 0)
739 exit (mountinfo (argc, argv));
740 else if (strcmp (applet, "rc-depend") == 0)
741 exit (rc_depend (argc, argv));
742 else if (strcmp (applet, "rc-status") == 0)
743 exit (rc_status (argc, argv));
744 else if (strcmp (applet, "rc-update") == 0 ||
745 strcmp (applet, "update-rc") == 0)
746 exit (rc_update (argc, argv));
747 else if (strcmp (applet, "runscript") == 0)
748 exit (runscript (argc, argv));
749 else if (strcmp (applet, "start-stop-daemon") == 0)
750 exit (start_stop_daemon (argc, argv));
517 751
518 argc--; 752 argc--;
519 argv++; 753 argv++;
520 754
521 /* Handle multicall stuff */ 755 /* Handle multicall stuff */
551 } 785 }
552 786
553 if (strcmp (applet, "rc" ) != 0) 787 if (strcmp (applet, "rc" ) != 0)
554 eerrorx ("%s: unknown applet", applet); 788 eerrorx ("%s: unknown applet", applet);
555 789
556 /* OK, so we really are the main RC process 790 /* Change dir to / to ensure all scripts don't use stuff in pwd */
557 Only root should be able to run us */ 791 chdir ("/");
558 if (geteuid () != 0)
559 eerrorx ("%s: root access required", applet);
560 792
561 atexit (cleanup); 793 /* RUNLEVEL is set by sysvinit as is a magic number
562 newlevel = argv[0]; 794 RC_SOFTLEVEL is set by us and is the name for this magic number
795 even though all our userland documentation refers to runlevel */
796 RUNLEVEL = getenv ("RUNLEVEL");
797 PREVLEVEL = getenv ("PREVLEVEL");
563 798
564 /* Setup a signal handler */ 799 /* Setup a signal handler */
565 signal (SIGINT, handle_signal); 800 signal (SIGINT, handle_signal);
566 signal (SIGQUIT, handle_signal); 801 signal (SIGQUIT, handle_signal);
567 signal (SIGTERM, handle_signal); 802 signal (SIGTERM, handle_signal);
600 putenv (p); 835 putenv (p);
601 836
602 /* We don't free our list as that would be null in environ */ 837 /* We don't free our list as that would be null in environ */
603 } 838 }
604 839
840 argc++;
841 argv--;
842 while ((opt = getopt_long (argc, argv, getoptstring,
843 longopts, (int *) 0)) != -1)
844 {
845 switch (opt) {
846 case_RC_COMMON_GETOPT
847 }
848 }
849
850 newlevel = argv[optind++];
851
852 /* OK, so we really are the main RC process
853 Only root should be able to run us */
854 if (geteuid () != 0)
855 eerrorx ("%s: root access required", applet);
856
605 /* Enable logging */ 857 /* Enable logging */
606 setenv ("RC_ELOG", "rc", 1); 858 setenv ("RC_ELOG", "rc", 1);
607 859
608 /* Export our PID */ 860 /* Export our PID */
609 snprintf (pidstr, sizeof (pidstr), "%d", getpid ()); 861 snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
610 setenv ("RC_PID", pidstr, 1); 862 setenv ("RC_PID", pidstr, 1);
611 863
612 interactive = rc_exists (INTERACTIVE); 864 interactive = rc_exists (INTERACTIVE);
613 rc_plugin_load (); 865 rc_plugin_load ();
614 866
615 /* RUNLEVEL is set by sysvinit as is a magic number 867 /* Load current softlevel */
616 RC_SOFTLEVEL is set by us and is the name for this magic number 868 bootlevel = getenv ("RC_BOOTLEVEL");
617 even though all our userland documentation refers to runlevel */ 869 runlevel = rc_get_runlevel ();
618 RUNLEVEL = getenv ("RUNLEVEL");
619 PREVLEVEL = getenv ("PREVLEVEL");
620
621 if (RUNLEVEL && newlevel) {
622 if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) {
623 /* OK, we're either in runlevel 1 or single user mode */
624 if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) {
625 struct utsname uts;
626 pid_t pid;
627 pid_t wpid;
628 int status = 0;
629#ifdef __linux__
630 FILE *fp;
631#endif
632
633 uname (&uts);
634
635 printf ("\n");
636 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
637 "\n Copyright 1999-2007 Gentoo Foundation; "
638 "Distributed under the GPLv2\n\n",
639 ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
640 ecolor (ecolor_normal));
641
642 printf ("Press %sI%s to enter interactive boot mode\n\n",
643 ecolor (ecolor_good), ecolor (ecolor_normal));
644
645 setenv ("RC_SOFTLEVEL", newlevel, 1);
646 rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
647
648 if ((pid = vfork ()) == -1)
649 eerrorx ("%s: vfork: %s", applet, strerror (errno));
650
651 if (pid == 0) {
652 execl (INITSH, INITSH, (char *) NULL);
653 eerror ("%s: unable to exec `" INITSH "': %s",
654 applet, strerror (errno));
655 _exit (EXIT_FAILURE);
656 }
657
658 do {
659 wpid = waitpid (pid, &status, 0);
660 if (wpid < 1)
661 eerror ("waitpid: %s", strerror (errno));
662 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
663
664 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
665 exit (EXIT_FAILURE);
666
667 /* If we requested a softlevel, save it now */
668#ifdef __linux__
669 set_ksoftlevel (NULL);
670
671 if ((fp = fopen ("/proc/cmdline", "r"))) {
672 char buffer[RC_LINEBUFFER];
673 char *soft;
674
675 memset (buffer, 0, sizeof (buffer));
676 if (fgets (buffer, RC_LINEBUFFER, fp) &&
677 (soft = strstr (buffer, "softlevel=")))
678 {
679 i = soft - buffer;
680 if (i == 0 || buffer[i - 1] == ' ') {
681 char *level;
682
683 /* Trim the trailing carriage return if present */
684 i = strlen (buffer) - 1;
685 if (buffer[i] == '\n')
686 buffer[i] = 0;
687
688 soft += strlen ("softlevel=");
689 level = strsep (&soft, " ");
690 set_ksoftlevel (level);
691 }
692 }
693 fclose (fp);
694 }
695#endif
696 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
697
698 if (want_interactive ())
699 mark_interactive ();
700
701 exit (EXIT_SUCCESS);
702 }
703
704#ifdef __linux__
705 /* Parse the inittab file so we can work out the level to telinit */
706 if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 &&
707 strcmp (newlevel, RC_LEVEL_SINGLE) != 0)
708 {
709 char **inittab = rc_get_list (NULL, "/etc/inittab");
710 char *line;
711 char *p;
712 char *token;
713 char lvl[2] = {0, 0};
714
715 STRLIST_FOREACH (inittab, line, i) {
716 p = line;
717 token = strsep (&p, ":");
718 if (! token || token[0] != 'l')
719 continue;
720
721 if ((token = strsep (&p, ":")) == NULL)
722 continue;
723
724 /* Snag the level */
725 lvl[0] = token[0];
726
727 /* The name is spaced after this */
728 if ((token = strsep (&p, " ")) == NULL)
729 continue;
730
731 if ((token = strsep (&p, " ")) == NULL)
732 continue;
733
734 if (strcmp (token, newlevel) == 0)
735 break;
736 }
737 rc_strlist_free (inittab);
738
739 /* We have a level, so telinit into it */
740 if (lvl[0] == 0) {
741 eerrorx ("%s: couldn't find a runlevel called `%s'",
742 applet, newlevel);
743 } else {
744 execl ("/sbin/telinit", "/sbin/telinit", lvl, (char *) NULL);
745 eerrorx ("%s: unable to exec `/sbin/telinit': %s",
746 applet, strerror (errno));
747 }
748 }
749#endif
750 }
751 }
752 870
753 /* Check we're in the runlevel requested, ie from 871 /* Check we're in the runlevel requested, ie from
754 rc single 872 rc single
755 rc shutdown 873 rc shutdown
756 rc reboot 874 rc reboot
757 */ 875 */
758 if (newlevel) { 876 if (newlevel) {
877 if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
878 RUNLEVEL &&
879 (strcmp (RUNLEVEL, "S") == 0 ||
880 strcmp (RUNLEVEL, "1") == 0))
881 {
882 /* OK, we're either in runlevel 1 or single user mode */
883 struct utsname uts;
884#ifdef __linux__
885 char *cmd;
886#endif
887
888 /* exec init-early.sh if it exists
889 * This should just setup the console to use the correct
890 * font. Maybe it should setup the keyboard too? */
891 if (rc_exists (INITEARLYSH))
892 run_script (INITEARLYSH);
893
894 uname (&uts);
895
896 printf ("\n");
897 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
898 "\n Copyright 1999-2007 Gentoo Foundation; "
899 "Distributed under the GPLv2\n\n",
900 ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
901 ecolor (ecolor_normal));
902
903 if (rc_is_env ("RC_INTERACTIVE", "yes"))
904 printf ("Press %sI%s to enter interactive boot mode\n\n",
905 ecolor (ecolor_good), ecolor (ecolor_normal));
906
907 setenv ("RC_SOFTLEVEL", newlevel, 1);
908 rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
909 run_script (INITSH);
910
911#ifdef __linux__
912 /* If we requested a softlevel, save it now */
913 set_ksoftlevel (NULL);
914 if ((cmd = proc_getent ("softlevel"))) {
915 set_ksoftlevel (cmd);
916 free (cmd);
917 }
918
919#endif
920 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
921
922 if (want_interactive ())
923 mark_interactive ();
924
925 exit (EXIT_SUCCESS);
759 if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) { 926 } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
760 if (! RUNLEVEL || 927 if (! RUNLEVEL ||
761 (strcmp (RUNLEVEL, "S") != 0 && 928 (strcmp (RUNLEVEL, "S") != 0 &&
762 strcmp (RUNLEVEL, "1") != 0)) 929 strcmp (RUNLEVEL, "1") != 0))
763 { 930 {
764 /* Remember the current runlevel for when we come back */ 931 /* Remember the current runlevel for when we come back */
788 applet, strerror (errno)); 955 applet, strerror (errno));
789 } 956 }
790 } 957 }
791 } 958 }
792 959
793 /* Export our current softlevel */ 960 /* Now we start handling our children */
794 runlevel = rc_get_runlevel (); 961 signal (SIGCHLD, handle_signal);
795 962
796 /* If we're in the default runlevel and ksoftlevel exists, we should use 963 /* We should only use ksoftlevel if we were in single user mode
797 that instead */ 964 If not, we need to erase ksoftlevel now. */
798 if (newlevel && 965 if (PREVLEVEL &&
799 rc_exists (RC_SVCDIR "ksoftlevel") && 966 (strcmp (PREVLEVEL, "1") == 0 ||
800 strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) 967 strcmp (PREVLEVEL, "S") == 0 ||
968 strcmp (PREVLEVEL, "N") == 0))
801 { 969 {
802 /* We should only use ksoftlevel if we were in single user mode
803 If not, we need to erase ksoftlevel now. */
804 if (PREVLEVEL &&
805 (strcmp (PREVLEVEL, "1") == 0 ||
806 strcmp (PREVLEVEL, "S") == 0 ||
807 strcmp (PREVLEVEL, "N") == 0))
808 {
809 FILE *fp;
810
811 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
812 eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
813 strerror (errno));
814 else {
815 if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) { 970 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
816 i = strlen (ksoftbuffer) - 1;
817 if (ksoftbuffer[i] == '\n')
818 ksoftbuffer[i] = 0;
819 newlevel = ksoftbuffer; 971 newlevel = ksoftbuffer;
820 } 972 } else if (! RUNLEVEL ||
821 fclose (fp); 973 (strcmp (RUNLEVEL, "1") != 0 &&
822 } 974 strcmp (RUNLEVEL, "S") != 0 &&
823 } else 975 strcmp (RUNLEVEL, "N") != 0))
976 {
824 set_ksoftlevel (NULL); 977 set_ksoftlevel (NULL);
825 } 978 }
826 979
827 if (newlevel && 980 if (newlevel &&
828 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || 981 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
829 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || 982 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
876#else 1029#else
877 /* BSD's on the other hand populate /dev automagically and use devd. 1030 /* BSD's on the other hand populate /dev automagically and use devd.
878 The only downside of this approach and ours is that we have to hard code 1031 The only downside of this approach and ours is that we have to hard code
879 the device node to the init script to simulate the coldplug into 1032 the device node to the init script to simulate the coldplug into
880 runlevel for our dependency tree to work. */ 1033 runlevel for our dependency tree to work. */
881 if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 && 1034 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
882 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || 1035 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
883 strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) && 1036 strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
884 rc_is_env ("RC_COLDPLUG", "yes")) 1037 rc_is_env ("RC_COLDPLUG", "yes"))
885 { 1038 {
1039#if defined(__DragonFly__) || defined(__FreeBSD__)
886 /* The net interfaces are easy - they're all in net /dev/net :) */ 1040 /* The net interfaces are easy - they're all in net /dev/net :) */
887 start_services = rc_ls_dir (NULL, "/dev/net", 0); 1041 start_services = rc_ls_dir (NULL, "/dev/net", 0);
888 STRLIST_FOREACH (start_services, service, i) { 1042 STRLIST_FOREACH (start_services, service, i) {
889 j = (strlen ("net.") + strlen (service) + 1); 1043 j = (strlen ("net.") + strlen (service) + 1);
890 tmp = rc_xmalloc (sizeof (char *) * j); 1044 tmp = rc_xmalloc (sizeof (char *) * j);
892 if (rc_service_exists (tmp) && rc_allow_plug (tmp)) 1046 if (rc_service_exists (tmp) && rc_allow_plug (tmp))
893 rc_mark_service (tmp, rc_service_coldplugged); 1047 rc_mark_service (tmp, rc_service_coldplugged);
894 CHAR_FREE (tmp); 1048 CHAR_FREE (tmp);
895 } 1049 }
896 rc_strlist_free (start_services); 1050 rc_strlist_free (start_services);
1051#endif
897 1052
898 /* The mice are a little more tricky. 1053 /* The mice are a little more tricky.
899 If we coldplug anything else, we'll probably do it here. */ 1054 If we coldplug anything else, we'll probably do it here. */
900 start_services = rc_ls_dir (NULL, "/dev", 0); 1055 start_services = rc_ls_dir (NULL, "/dev", 0);
901 STRLIST_FOREACH (start_services, service, i) { 1056 STRLIST_FOREACH (start_services, service, i) {
926 1081
927 types = rc_strlist_add (NULL, "ineed"); 1082 types = rc_strlist_add (NULL, "ineed");
928 types = rc_strlist_add (types, "iuse"); 1083 types = rc_strlist_add (types, "iuse");
929 types = rc_strlist_add (types, "iafter"); 1084 types = rc_strlist_add (types, "iafter");
930 deporder = rc_get_depends (deptree, types, stop_services, 1085 deporder = rc_get_depends (deptree, types, stop_services,
931 runlevel, depoptions); 1086 runlevel, depoptions | RC_DEP_STOP);
932 rc_strlist_free (stop_services); 1087 rc_strlist_free (stop_services);
933 rc_strlist_free (types); 1088 rc_strlist_free (types);
934 stop_services = deporder; 1089 stop_services = deporder;
935 deporder = NULL; 1090 deporder = NULL;
936 types = NULL; 1091 types = NULL;
940 coldplugged_services = rc_ls_dir (coldplugged_services, 1095 coldplugged_services = rc_ls_dir (coldplugged_services,
941 RC_SVCDIR_COLDPLUGGED, RC_LS_INITD); 1096 RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
942 1097
943 /* Load our start services now. 1098 /* Load our start services now.
944 We have different rules dependent on runlevel. */ 1099 We have different rules dependent on runlevel. */
945 if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) { 1100 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
946 if (coldplugged_services) { 1101 if (coldplugged_services) {
947 einfon ("Device initiated services:"); 1102 einfon ("Device initiated services:");
948 STRLIST_FOREACH (coldplugged_services, service, i) { 1103 STRLIST_FOREACH (coldplugged_services, service, i) {
949 printf (" %s", service); 1104 printf (" %s", service);
950 start_services = rc_strlist_add (start_services, service); 1105 start_services = rc_strlist_add (start_services, service);
962 if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 && 1117 if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
963 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && 1118 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
964 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) 1119 strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
965 { 1120 {
966 /* We need to include the boot runlevel services if we're not in it */ 1121 /* We need to include the boot runlevel services if we're not in it */
967 start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT, 1122 char **services = rc_services_in_runlevel (bootlevel);
968 RC_LS_INITD); 1123
1124 start_services = rc_strlist_join (start_services, services);
1125 services = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1126 start_services = rc_strlist_join (start_services, services);
1127 services = NULL;
1128
969 STRLIST_FOREACH (coldplugged_services, service, i) 1129 STRLIST_FOREACH (coldplugged_services, service, i)
970 start_services = rc_strlist_add (start_services, service); 1130 start_services = rc_strlist_add (start_services, service);
971 1131
972 tmp = rc_strcatpaths (RC_RUNLEVELDIR,
973 newlevel ? newlevel : runlevel, (char *) NULL);
974 start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
975 CHAR_FREE (tmp);
976 } 1132 }
977 } 1133 }
978 1134
979 /* Save out softlevel now */ 1135 /* Save out softlevel now */
980 if (going_down) 1136 if (going_down)
994 if (rc_service_state (service, rc_service_stopped)) 1150 if (rc_service_state (service, rc_service_stopped))
995 continue; 1151 continue;
996 1152
997 /* We always stop the service when in these runlevels */ 1153 /* We always stop the service when in these runlevels */
998 if (going_down) { 1154 if (going_down) {
999 rc_stop_service (service); 1155 pid_t pid = rc_stop_service (service);
1156 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1157 rc_waitpid (pid);
1000 continue; 1158 continue;
1001 } 1159 }
1002 1160
1003 /* If we're in the start list then don't bother stopping us */ 1161 /* If we're in the start list then don't bother stopping us */
1004 STRLIST_FOREACH (start_services, svc1, j) 1162 STRLIST_FOREACH (start_services, svc1, j)
1056 } 1214 }
1057 rc_strlist_free (deporder); 1215 rc_strlist_free (deporder);
1058 deporder = NULL; 1216 deporder = NULL;
1059 1217
1060 /* After all that we can finally stop the blighter! */ 1218 /* After all that we can finally stop the blighter! */
1061 if (! found) 1219 if (! found) {
1062 rc_stop_service (service); 1220 pid_t pid = rc_stop_service (service);
1221 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1222 rc_waitpid (pid);
1223 }
1063 } 1224 }
1064 rc_strlist_free (types); 1225 rc_strlist_free (types);
1065 types = NULL; 1226 types = NULL;
1066 1227
1067 /* Wait for our services to finish */ 1228 /* Wait for our services to finish */
1068 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
1069 wait_for_services (); 1229 wait_for_services ();
1070 1230
1071 /* Notify the plugins we have finished */ 1231 /* Notify the plugins we have finished */
1072 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); 1232 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1073 1233
1074 rmdir (RC_SVCDIR "/softscripts.new"); 1234 rmdir (RC_SVCDIR "/softscripts.new");
1106 /* Order the services to start */ 1266 /* Order the services to start */
1107 types = rc_strlist_add (NULL, "ineed"); 1267 types = rc_strlist_add (NULL, "ineed");
1108 types = rc_strlist_add (types, "iuse"); 1268 types = rc_strlist_add (types, "iuse");
1109 types = rc_strlist_add (types, "iafter"); 1269 types = rc_strlist_add (types, "iafter");
1110 deporder = rc_get_depends (deptree, types, start_services, 1270 deporder = rc_get_depends (deptree, types, start_services,
1111 runlevel, depoptions); 1271 runlevel, depoptions | RC_DEP_START);
1112 rc_strlist_free (types); 1272 rc_strlist_free (types);
1113 types = NULL; 1273 types = NULL;
1114 rc_strlist_free (start_services); 1274 rc_strlist_free (start_services);
1115 start_services = deporder; 1275 start_services = deporder;
1116 deporder = NULL; 1276 deporder = NULL;
1117 1277
1278#ifdef __linux__
1279 /* mark any services skipped as started */
1280 if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1281 if ((service = proc_getent ("noinitd"))) {
1282 char *p = service;
1283 char *token;
1284
1285 while ((token = strsep (&p, ",")))
1286 rc_mark_service (token, rc_service_started);
1287 free (service);
1288 }
1289 }
1290#endif
1291
1292
1118 STRLIST_FOREACH (start_services, service, i) { 1293 STRLIST_FOREACH (start_services, service, i) {
1119 if (rc_service_state (service, rc_service_stopped)) { 1294 if (rc_service_state (service, rc_service_stopped)) {
1295 pid_t pid;
1296
1120 if (! interactive) 1297 if (! interactive)
1121 interactive = want_interactive (); 1298 interactive = want_interactive ();
1122 1299
1123 if (interactive) { 1300 if (interactive) {
1124interactive_retry: 1301interactive_retry:
1135 case '3': interactive = false; break; 1312 case '3': interactive = false; break;
1136 case '4': sulogin (true); goto interactive_retry; 1313 case '4': sulogin (true); goto interactive_retry;
1137 default: goto interactive_option; 1314 default: goto interactive_option;
1138 } 1315 }
1139 } 1316 }
1317
1318 /* Remember the pid if we're running in parallel */
1140 rc_start_service (service); 1319 if ((pid = rc_start_service (service)))
1320 add_pid (pid);
1321
1322 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1323 rc_waitpid (pid);
1324 remove_pid (pid);
1325 }
1141 } 1326 }
1142 } 1327 }
1143 1328
1144 /* Wait for our services to finish */ 1329 /* Wait for our services to finish */
1145 wait_for_services (); 1330 wait_for_services ();
1146 1331
1147 rc_plugin_run (rc_hook_runlevel_start_out, runlevel); 1332 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1148 1333
1334#ifdef __linux__
1335 /* mark any services skipped as stopped */
1336 if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1337 if ((service = proc_getent ("noinitd"))) {
1338 char *p = service;
1339 char *token;
1340
1341 while ((token = strsep (&p, ",")))
1342 rc_mark_service (token, rc_service_stopped);
1343 free (service);
1344 }
1345 }
1346#endif
1347
1149 /* Store our interactive status for boot */ 1348 /* Store our interactive status for boot */
1150 if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0) 1349 if (interactive && strcmp (runlevel, bootlevel) == 0)
1151 mark_interactive (); 1350 mark_interactive ();
1152 else { 1351 else {
1153 if (rc_exists (INTERACTIVE)) 1352 if (rc_exists (INTERACTIVE))
1154 unlink (INTERACTIVE); 1353 unlink (INTERACTIVE);
1155 } 1354 }

Legend:
Removed from v.2640  
changed lines
  Added in v.2834

  ViewVC Help
Powered by ViewVC 1.1.20