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

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

  ViewVC Help
Powered by ViewVC 1.1.20