/[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 2760
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"
13 15
14#include <sys/types.h> 16#include <sys/types.h>
15#include <sys/stat.h> 17#include <sys/stat.h>
16#include <sys/utsname.h> 18#include <sys/utsname.h>
17#include <sys/wait.h> 19#include <sys/wait.h>
18#include <errno.h> 20#include <errno.h>
19#include <ctype.h> 21#include <ctype.h>
22#include <getopt.h>
20#include <libgen.h> 23#include <libgen.h>
21#include <limits.h> 24#include <limits.h>
22#include <stdbool.h> 25#include <stdbool.h>
23#include <stdio.h> 26#include <stdio.h>
24#include <stdlib.h> 27#include <stdlib.h>
31#include "rc.h" 34#include "rc.h"
32#include "rc-misc.h" 35#include "rc-misc.h"
33#include "rc-plugin.h" 36#include "rc-plugin.h"
34#include "strlist.h" 37#include "strlist.h"
35 38
36#define INITSH RC_LIBDIR "sh/init.sh" 39#define INITSH RC_LIBDIR "sh/init.sh"
37#define HALTSH RC_INITDIR "halt.sh" 40#define INITEARLYSH RC_LIBDIR "sh/init-early.sh"
41#define HALTSH RC_INITDIR "halt.sh"
42#define SULOGIN "/sbin/sulogin"
38 43
39#define RC_SVCDIR_STARTING RC_SVCDIR "starting/" 44#define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
40#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/" 45#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
41#define RC_SVCDIR_STARTED RC_SVCDIR "started/" 46#define RC_SVCDIR_STARTED RC_SVCDIR "started/"
42#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/" 47#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
43 48
44#define INTERACTIVE RC_SVCDIR "interactive" 49#define INTERACTIVE RC_SVCDIR "interactive"
45 50
46#define DEVBOOT "/dev/.rcboot" 51#define DEVBOOT "/dev/.rcboot"
47 52
48/* Cleanup anything in main */ 53/* Cleanup anything in main */
49#define CHAR_FREE(_item) if (_item) { \ 54#define CHAR_FREE(_item) if (_item) { \
63static char **types = NULL; 68static char **types = NULL;
64static char *tmp = NULL; 69static char *tmp = NULL;
65 70
66struct termios *termios_orig = NULL; 71struct termios *termios_orig = NULL;
67 72
73typedef struct pidlist
74{
75 pid_t pid;
76 struct pidlist *next;
77} pidlist_t;
78static pidlist_t *service_pids = NULL;
79
68static void cleanup (void) 80static void cleanup (void)
69{ 81{
82 pidlist_t *pl = service_pids;
83
70 rc_plugin_unload (); 84 rc_plugin_unload ();
71 85
72 if (termios_orig) { 86 if (! rc_in_plugin && termios_orig) {
73 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); 87 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig);
74 free (termios_orig); 88 free (termios_orig);
89 }
90
91 while (pl) {
92 pidlist_t *p = pl->next;
93 free (pl);
94 pl = p;
75 } 95 }
76 96
77 rc_strlist_free (env); 97 rc_strlist_free (env);
78 rc_strlist_free (newenv); 98 rc_strlist_free (newenv);
79 rc_strlist_free (coldplugged_services); 99 rc_strlist_free (coldplugged_services);
81 rc_strlist_free (start_services); 101 rc_strlist_free (start_services);
82 rc_free_deptree (deptree); 102 rc_free_deptree (deptree);
83 rc_strlist_free (types); 103 rc_strlist_free (types);
84 104
85 /* Clean runlevel start, stop markers */ 105 /* Clean runlevel start, stop markers */
106 if (! rc_in_plugin) {
86 if (rc_is_dir (RC_SVCDIR "softscripts.new")) 107 if (rc_is_dir (RC_SVCDIR "softscripts.new"))
87 rc_rm_dir (RC_SVCDIR "softscripts.new", true); 108 rc_rm_dir (RC_SVCDIR "softscripts.new", true);
88 if (rc_is_dir (RC_SVCDIR "softscripts.old")) 109 if (rc_is_dir (RC_SVCDIR "softscripts.old"))
89 rc_rm_dir (RC_SVCDIR "softscripts.old", true); 110 rc_rm_dir (RC_SVCDIR "softscripts.old", true);
111 }
90 112
91 free (applet); 113 free (applet);
92} 114}
93 115
94static int do_e (int argc, char **argv) 116static int do_e (int argc, char **argv)
124 else { 146 else {
125 argc--; 147 argc--;
126 argv++; 148 argv++;
127 } 149 }
128 } 150 }
129 else
130 retval = EXIT_FAILURE;
131 } 151 }
132 152
133 if (argc > 0) { 153 if (argc > 0) {
134 for (i = 0; i < argc; i++) 154 for (i = 0; i < argc; i++)
135 l += strlen (argv[i]) + 1; 155 l += strlen (argv[i]) + 1;
318 338
319static char read_key (bool block) 339static char read_key (bool block)
320{ 340{
321 struct termios termios; 341 struct termios termios;
322 char c = 0; 342 char c = 0;
323 343
324 if (! isatty (STDIN_FILENO)) 344 if (! isatty (STDIN_FILENO))
325 return (false); 345 return (false);
326 346
327 /* Now save our terminal settings. We need to restore them at exit as we 347 /* 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 */ 348 will be changing it for non-blocking reads for Interactive */
348 return (c); 368 return (c);
349} 369}
350 370
351static bool want_interactive (void) 371static bool want_interactive (void)
352{ 372{
373 char c;
374
375 if (! rc_is_env ("RC_INTERACTIVE", "yes"))
376 return (false);
377
353 char c = read_key (false); 378 c = read_key (false);
354 return ((c == 'I' || c == 'i') ? true : false); 379 return ((c == 'I' || c == 'i') ? true : false);
355} 380}
356 381
357static void mark_interactive (void) 382static void mark_interactive (void)
358{ 383{
369 /* VPS systems cannot do an sulogin */ 394 /* VPS systems cannot do an sulogin */
370 if (e && strcmp (e, "VPS") == 0) { 395 if (e && strcmp (e, "VPS") == 0) {
371 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL); 396 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
372 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno)); 397 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
373 } 398 }
399#endif
400
401 newenv = rc_filter_env ();
374 402
375 if (cont) { 403 if (cont) {
376 int status = 0; 404 int status = 0;
405#ifdef __linux__
406 char *tty = ttyname (fileno (stdout));
407#endif
408
377 pid_t pid = vfork(); 409 pid_t pid = vfork ();
378 410
379 if (pid == -1) 411 if (pid == -1)
380 eerrorx ("%s: vfork: %s", applet, strerror (errno)); 412 eerrorx ("%s: vfork: %s", applet, strerror (errno));
381 if (pid == 0) { 413 if (pid == 0) {
382 newenv = rc_filter_env (); 414#ifdef __linux__
383 execl ("/sbin/sulogin", "/sbin/sulogin", 415 if (tty)
384 getenv ("CONSOLE"), (char *) NULL, newenv); 416 execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
417 else
418 execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
419
385 eerror ("%s: unable to exec `/sbin/sulogin': %s", applet, 420 eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
386 strerror (errno)); 421 strerror (errno));
422#else
423 execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
424 eerror ("%s: unable to exec `/bin/sh': %s", applet,
425 strerror (errno));
426#endif
387 _exit (EXIT_FAILURE); 427 _exit (EXIT_FAILURE);
388 } 428 }
389 waitpid (pid, &status, 0); 429 waitpid (pid, &status, 0);
390 } else { 430 } else {
391 newenv = rc_filter_env (); 431#ifdef __linux
392 execl ("/sbin/sulogin", "/sbin/sulogin", 432 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)); 433 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
395 }
396#else 434#else
397 exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); 435 exit (EXIT_SUCCESS);
398#endif 436#endif
437 }
399} 438}
400 439
401static void single_user (void) 440static void single_user (void)
402{ 441{
403#ifdef __linux__ 442#ifdef __linux__
434 473
435 fprintf (fp, "%s", runlevel); 474 fprintf (fp, "%s", runlevel);
436 fclose (fp); 475 fclose (fp);
437} 476}
438 477
478static int get_ksoftlevel (char *buffer, int buffer_len)
479{
480 FILE *fp;
481 int i = 0;
482
483 if (! rc_exists (RC_SVCDIR "ksoftlevel"))
484 return 0;
485
486 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) {
487 eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
488 strerror (errno));
489 return -1;
490 }
491
492 if (fgets (buffer, buffer_len, fp)) {
493 i = strlen (buffer) - 1;
494 if (buffer[i] == '\n')
495 buffer[i] = 0;
496 }
497
498 fclose (fp);
499 return i;
500}
501
439static void wait_for_services () 502static void wait_for_services ()
440{ 503{
441 int status = 0; 504 int status = 0;
442 struct timeval tv;
443 while (wait (&status) != -1); 505 while (wait (&status) != -1);
506}
444 507
445 /* Wait for a little bit to flush our ebuffer */ 508static void add_pid (pid_t pid)
446 tv.tv_usec = 50000; 509{
447 tv.tv_sec = 0; 510 pidlist_t *sp = service_pids;
448 select (0, NULL, NULL, NULL, &tv); 511 if (sp) {
512 while (sp->next)
513 sp = sp->next;
514 sp->next = rc_xmalloc (sizeof (pidlist_t));
515 sp = sp->next;
516 } else
517 sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
518 memset (sp, 0, sizeof (pidlist_t));
519 sp->pid = pid;
520}
521
522static void remove_pid (pid_t pid)
523{
524 pidlist_t *last = NULL;
525 pidlist_t *pl;
526
527 for (pl = service_pids; pl; pl = pl->next) {
528 if (pl->pid == pid) {
529 if (last)
530 last->next = pl->next;
531 else
532 service_pids = pl->next;
533 free (pl);
534 break;
535 }
536 last = pl;
537 }
449} 538}
450 539
451static void handle_signal (int sig) 540static void handle_signal (int sig)
452{ 541{
453 int serrno = errno; 542 int serrno = errno;
454 char signame[10] = { '\0' }; 543 char signame[10] = { '\0' };
455 char *run; 544 char *run;
456 char *prev; 545 char *prev;
546 pidlist_t *pl;
547 pid_t pid;
548 int status = 0;
457 549
458 switch (sig) { 550 switch (sig) {
551 case SIGCHLD:
552 do {
553 pid = waitpid (-1, &status, WNOHANG);
554 if (pid < 0) {
555 if (errno != ECHILD)
556 eerror ("waitpid: %s", strerror (errno));
557 return;
558 }
559 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
560
561 /* Remove that pid from our list */
562 if (pid > 0)
563 remove_pid (pid);
564 break;
565
459 case SIGINT: 566 case SIGINT:
460 if (! signame[0]) 567 if (! signame[0])
461 snprintf (signame, sizeof (signame), "SIGINT"); 568 snprintf (signame, sizeof (signame), "SIGINT");
462 case SIGTERM: 569 case SIGTERM:
463 if (! signame[0]) 570 if (! signame[0])
467 snprintf (signame, sizeof (signame), "SIGQUIT"); 574 snprintf (signame, sizeof (signame), "SIGQUIT");
468 eerrorx ("%s: caught %s, aborting", applet, signame); 575 eerrorx ("%s: caught %s, aborting", applet, signame);
469 case SIGUSR1: 576 case SIGUSR1:
470 eerror ("rc: Aborting!"); 577 eerror ("rc: Aborting!");
471 /* Kill any running services we have started */ 578 /* Kill any running services we have started */
579
472 signal (SIGTERM, SIG_IGN); 580 signal (SIGCHLD, SIG_IGN);
473 killpg (getpgrp (), SIGTERM); 581 for (pl = service_pids; pl; pl = pl->next)
582 kill (pl->pid, SIGTERM);
474 583
475 /* Notify plugins we are aborting */ 584 /* Notify plugins we are aborting */
476 rc_plugin_run (rc_hook_abort, "rc"); 585 rc_plugin_run (rc_hook_abort, NULL);
477 586
587 /* Only drop into single user mode if we're booting */
478 run = getenv ("RUNLEVEL"); 588 run = getenv ("RUNLEVEL");
479 prev = getenv ("PREVLEVEL"); 589 prev = getenv ("PREVLEVEL");
480 /* Only drop into single user mode if we're booting */ 590 if ((prev &&
481 if ((prev && strcmp (prev, "S") == 0) || 591 (strcmp (prev, "S") == 0 ||
592 strcmp (prev, "1") == 0)) ||
593 (run &&
594 (strcmp (run, "S") == 0 ||
482 (run && strcmp (run, "S") == 0)) 595 strcmp (run, "1") == 0)))
483 single_user (); 596 single_user ();
484 597
485 exit (EXIT_FAILURE); 598 exit (EXIT_FAILURE);
486 break; 599 break;
487 600
490 } 603 }
491 604
492 /* Restore errno */ 605 /* Restore errno */
493 errno = serrno; 606 errno = serrno;
494} 607}
608
609static void run_script (const char *script) {
610 int status = 0;
611 pid_t pid = vfork ();
612
613 if (pid < 0)
614 eerrorx ("%s: vfork: %s", applet, strerror (errno));
615 else if (pid == 0) {
616 execl (script, script, (char *) NULL);
617 eerror ("%s: unable to exec `%s': %s",
618 script, applet, strerror (errno));
619 _exit (EXIT_FAILURE);
620 }
621
622 do {
623 pid_t wpid = waitpid (pid, &status, 0);
624 if (wpid < 1)
625 eerror ("waitpid: %s", strerror (errno));
626 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
627
628 if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
629 exit (EXIT_FAILURE);
630}
631
632#include "_usage.h"
633#define getoptstring getoptstring_COMMON
634static struct option longopts[] = {
635 longopts_COMMON
636 { NULL, 0, NULL, 0}
637};
638#include "_usage.c"
495 639
496int main (int argc, char **argv) 640int main (int argc, char **argv)
497{ 641{
498 char *RUNLEVEL = NULL; 642 char *RUNLEVEL = NULL;
499 char *PREVLEVEL = NULL; 643 char *PREVLEVEL = NULL;
506 bool going_down = false; 650 bool going_down = false;
507 bool interactive = false; 651 bool interactive = false;
508 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; 652 int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
509 char ksoftbuffer [PATH_MAX]; 653 char ksoftbuffer [PATH_MAX];
510 char pidstr[6]; 654 char pidstr[6];
655 int opt;
511 656
512 if (argv[0]) 657 if (argv[0])
513 applet = rc_xstrdup (basename (argv[0])); 658 applet = rc_xstrdup (basename (argv[0]));
514 659
515 if (! applet) 660 if (! applet)
551 } 696 }
552 697
553 if (strcmp (applet, "rc" ) != 0) 698 if (strcmp (applet, "rc" ) != 0)
554 eerrorx ("%s: unknown applet", applet); 699 eerrorx ("%s: unknown applet", applet);
555 700
556 /* OK, so we really are the main RC process
557 Only root should be able to run us */
558 if (geteuid () != 0)
559 eerrorx ("%s: root access required", applet);
560
561 atexit (cleanup); 701 atexit (cleanup);
562 newlevel = argv[0]; 702
703 /* Change dir to / to ensure all scripts don't use stuff in pwd */
704 chdir ("/");
563 705
564 /* Setup a signal handler */ 706 /* Setup a signal handler */
565 signal (SIGINT, handle_signal); 707 signal (SIGINT, handle_signal);
566 signal (SIGQUIT, handle_signal); 708 signal (SIGQUIT, handle_signal);
567 signal (SIGTERM, handle_signal); 709 signal (SIGTERM, handle_signal);
600 putenv (p); 742 putenv (p);
601 743
602 /* We don't free our list as that would be null in environ */ 744 /* We don't free our list as that would be null in environ */
603 } 745 }
604 746
747 argc++;
748 argv--;
749 while ((opt = getopt_long (argc, argv, getoptstring,
750 longopts, (int *) 0)) != -1)
751 {
752 switch (opt) {
753 case_RC_COMMON_GETOPT
754 }
755 }
756
757 newlevel = argv[optind++];
758
759 /* OK, so we really are the main RC process
760 Only root should be able to run us */
761 if (geteuid () != 0)
762 eerrorx ("%s: root access required", applet);
763
605 /* Enable logging */ 764 /* Enable logging */
606 setenv ("RC_ELOG", "rc", 1); 765 setenv ("RC_ELOG", "rc", 1);
607 766
608 /* Export our PID */ 767 /* Export our PID */
609 snprintf (pidstr, sizeof (pidstr), "%d", getpid ()); 768 snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
616 RC_SOFTLEVEL is set by us and is the name for this magic number 775 RC_SOFTLEVEL is set by us and is the name for this magic number
617 even though all our userland documentation refers to runlevel */ 776 even though all our userland documentation refers to runlevel */
618 RUNLEVEL = getenv ("RUNLEVEL"); 777 RUNLEVEL = getenv ("RUNLEVEL");
619 PREVLEVEL = getenv ("PREVLEVEL"); 778 PREVLEVEL = getenv ("PREVLEVEL");
620 779
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 780
633 uname (&uts); 781 /* Load current softlevel */
634 782 runlevel = rc_get_runlevel ();
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 783
753 /* Check we're in the runlevel requested, ie from 784 /* Check we're in the runlevel requested, ie from
754 rc single 785 rc single
755 rc shutdown 786 rc shutdown
756 rc reboot 787 rc reboot
757 */ 788 */
758 if (newlevel) { 789 if (newlevel) {
790 if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
791 RUNLEVEL &&
792 (strcmp (RUNLEVEL, "S") == 0 ||
793 strcmp (RUNLEVEL, "1") == 0))
794 {
795 /* OK, we're either in runlevel 1 or single user mode */
796 struct utsname uts;
797#ifdef __linux__
798 FILE *fp;
799#endif
800
801 /* exec init-early.sh if it exists
802 * This should just setup the console to use the correct
803 * font. Maybe it should setup the keyboard too? */
804 if (rc_exists (INITEARLYSH))
805 run_script (INITEARLYSH);
806
807 uname (&uts);
808
809 printf ("\n");
810 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
811 "\n Copyright 1999-2007 Gentoo Foundation; "
812 "Distributed under the GPLv2\n\n",
813 ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
814 ecolor (ecolor_normal));
815
816 if (rc_is_env ("RC_INTERACTIVE", "yes"))
817 printf ("Press %sI%s to enter interactive boot mode\n\n",
818 ecolor (ecolor_good), ecolor (ecolor_normal));
819
820 setenv ("RC_SOFTLEVEL", newlevel, 1);
821 rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
822 run_script (INITSH);
823
824 /* If we requested a softlevel, save it now */
825#ifdef __linux__
826 set_ksoftlevel (NULL);
827
828 if ((fp = fopen ("/proc/cmdline", "r"))) {
829 char buffer[RC_LINEBUFFER];
830 char *soft;
831
832 memset (buffer, 0, sizeof (buffer));
833 if (fgets (buffer, RC_LINEBUFFER, fp) &&
834 (soft = strstr (buffer, "softlevel=")))
835 {
836 i = soft - buffer;
837 if (i == 0 || buffer[i - 1] == ' ') {
838 char *level;
839
840 /* Trim the trailing carriage return if present */
841 i = strlen (buffer) - 1;
842 if (buffer[i] == '\n')
843 buffer[i] = 0;
844
845 soft += strlen ("softlevel=");
846 level = strsep (&soft, " ");
847 set_ksoftlevel (level);
848 }
849 }
850 fclose (fp);
851 }
852#endif
853 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
854
855 if (want_interactive ())
856 mark_interactive ();
857
858 exit (EXIT_SUCCESS);
759 if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) { 859 } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
760 if (! RUNLEVEL || 860 if (! RUNLEVEL ||
761 (strcmp (RUNLEVEL, "S") != 0 && 861 (strcmp (RUNLEVEL, "S") != 0 &&
762 strcmp (RUNLEVEL, "1") != 0)) 862 strcmp (RUNLEVEL, "1") != 0))
763 { 863 {
764 /* Remember the current runlevel for when we come back */ 864 /* Remember the current runlevel for when we come back */
788 applet, strerror (errno)); 888 applet, strerror (errno));
789 } 889 }
790 } 890 }
791 } 891 }
792 892
793 /* Export our current softlevel */ 893 /* Now we start handling our children */
794 runlevel = rc_get_runlevel (); 894 signal (SIGCHLD, handle_signal);
795 895
796 /* If we're in the default runlevel and ksoftlevel exists, we should use 896 /* We should only use ksoftlevel if we were in single user mode
797 that instead */ 897 If not, we need to erase ksoftlevel now. */
798 if (newlevel && 898 if (PREVLEVEL &&
799 rc_exists (RC_SVCDIR "ksoftlevel") && 899 (strcmp (PREVLEVEL, "1") == 0 ||
800 strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) 900 strcmp (PREVLEVEL, "S") == 0 ||
901 strcmp (PREVLEVEL, "N") == 0))
801 { 902 {
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)) { 903 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
816 i = strlen (ksoftbuffer) - 1;
817 if (ksoftbuffer[i] == '\n')
818 ksoftbuffer[i] = 0;
819 newlevel = ksoftbuffer; 904 newlevel = ksoftbuffer;
820 } 905 } else if (! RUNLEVEL ||
821 fclose (fp); 906 (strcmp (RUNLEVEL, "1") != 0 &&
822 } 907 strcmp (RUNLEVEL, "S") != 0 &&
823 } else 908 strcmp (RUNLEVEL, "N") != 0))
909 {
824 set_ksoftlevel (NULL); 910 set_ksoftlevel (NULL);
825 } 911 }
826 912
827 if (newlevel && 913 if (newlevel &&
828 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || 914 (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
829 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || 915 strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
994 if (rc_service_state (service, rc_service_stopped)) 1080 if (rc_service_state (service, rc_service_stopped))
995 continue; 1081 continue;
996 1082
997 /* We always stop the service when in these runlevels */ 1083 /* We always stop the service when in these runlevels */
998 if (going_down) { 1084 if (going_down) {
999 rc_stop_service (service); 1085 pid_t pid = rc_stop_service (service);
1086 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1087 rc_waitpid (pid);
1000 continue; 1088 continue;
1001 } 1089 }
1002 1090
1003 /* If we're in the start list then don't bother stopping us */ 1091 /* If we're in the start list then don't bother stopping us */
1004 STRLIST_FOREACH (start_services, svc1, j) 1092 STRLIST_FOREACH (start_services, svc1, j)
1056 } 1144 }
1057 rc_strlist_free (deporder); 1145 rc_strlist_free (deporder);
1058 deporder = NULL; 1146 deporder = NULL;
1059 1147
1060 /* After all that we can finally stop the blighter! */ 1148 /* After all that we can finally stop the blighter! */
1061 if (! found) 1149 if (! found) {
1062 rc_stop_service (service); 1150 pid_t pid = rc_stop_service (service);
1151 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1152 rc_waitpid (pid);
1153 }
1063 } 1154 }
1064 rc_strlist_free (types); 1155 rc_strlist_free (types);
1065 types = NULL; 1156 types = NULL;
1066 1157
1067 /* Wait for our services to finish */ 1158 /* Wait for our services to finish */
1068 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
1069 wait_for_services (); 1159 wait_for_services ();
1070 1160
1071 /* Notify the plugins we have finished */ 1161 /* Notify the plugins we have finished */
1072 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); 1162 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1073 1163
1074 rmdir (RC_SVCDIR "/softscripts.new"); 1164 rmdir (RC_SVCDIR "/softscripts.new");
1115 start_services = deporder; 1205 start_services = deporder;
1116 deporder = NULL; 1206 deporder = NULL;
1117 1207
1118 STRLIST_FOREACH (start_services, service, i) { 1208 STRLIST_FOREACH (start_services, service, i) {
1119 if (rc_service_state (service, rc_service_stopped)) { 1209 if (rc_service_state (service, rc_service_stopped)) {
1210 pid_t pid;
1211
1120 if (! interactive) 1212 if (! interactive)
1121 interactive = want_interactive (); 1213 interactive = want_interactive ();
1122 1214
1123 if (interactive) { 1215 if (interactive) {
1124interactive_retry: 1216interactive_retry:
1135 case '3': interactive = false; break; 1227 case '3': interactive = false; break;
1136 case '4': sulogin (true); goto interactive_retry; 1228 case '4': sulogin (true); goto interactive_retry;
1137 default: goto interactive_option; 1229 default: goto interactive_option;
1138 } 1230 }
1139 } 1231 }
1232
1233 /* Remember the pid if we're running in parallel */
1140 rc_start_service (service); 1234 if ((pid = rc_start_service (service)))
1235 add_pid (pid);
1236
1237 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1238 rc_waitpid (pid);
1239 remove_pid (pid);
1240 }
1141 } 1241 }
1142 } 1242 }
1143 1243
1144 /* Wait for our services to finish */ 1244 /* Wait for our services to finish */
1145 wait_for_services (); 1245 wait_for_services ();

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

  ViewVC Help
Powered by ViewVC 1.1.20