/[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 2684
31#include "rc.h" 31#include "rc.h"
32#include "rc-misc.h" 32#include "rc-misc.h"
33#include "rc-plugin.h" 33#include "rc-plugin.h"
34#include "strlist.h" 34#include "strlist.h"
35 35
36#define INITSH RC_LIBDIR "sh/init.sh" 36#define INITSH RC_LIBDIR "sh/init.sh"
37#define HALTSH RC_INITDIR "halt.sh" 37#define INITEARLYSH RC_LIBDIR "sh/init-early.sh"
38#define HALTSH RC_INITDIR "halt.sh"
39#define SULOGIN "/sbin/sulogin"
38 40
39#define RC_SVCDIR_STARTING RC_SVCDIR "starting/" 41#define RC_SVCDIR_STARTING RC_SVCDIR "starting/"
40#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/" 42#define RC_SVCDIR_INACTIVE RC_SVCDIR "inactive/"
41#define RC_SVCDIR_STARTED RC_SVCDIR "started/" 43#define RC_SVCDIR_STARTED RC_SVCDIR "started/"
42#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/" 44#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "coldplugged/"
43 45
44#define INTERACTIVE RC_SVCDIR "interactive" 46#define INTERACTIVE RC_SVCDIR "interactive"
45 47
46#define DEVBOOT "/dev/.rcboot" 48#define DEVBOOT "/dev/.rcboot"
47 49
48/* Cleanup anything in main */ 50/* Cleanup anything in main */
49#define CHAR_FREE(_item) if (_item) { \ 51#define CHAR_FREE(_item) if (_item) { \
63static char **types = NULL; 65static char **types = NULL;
64static char *tmp = NULL; 66static char *tmp = NULL;
65 67
66struct termios *termios_orig = NULL; 68struct termios *termios_orig = NULL;
67 69
70typedef struct pidlist
71{
72 pid_t pid;
73 struct pidlist *next;
74} pidlist_t;
75static pidlist_t *service_pids = NULL;
76
68static void cleanup (void) 77static void cleanup (void)
69{ 78{
79 pidlist_t *pl = service_pids;
80
70 rc_plugin_unload (); 81 rc_plugin_unload ();
71 82
72 if (termios_orig) { 83 if (termios_orig) {
73 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); 84 tcsetattr (STDIN_FILENO, TCSANOW, termios_orig);
74 free (termios_orig); 85 free (termios_orig);
86 }
87
88 while (pl) {
89 pidlist_t *p = pl->next;
90 free (pl);
91 pl = p;
75 } 92 }
76 93
77 rc_strlist_free (env); 94 rc_strlist_free (env);
78 rc_strlist_free (newenv); 95 rc_strlist_free (newenv);
79 rc_strlist_free (coldplugged_services); 96 rc_strlist_free (coldplugged_services);
318 335
319static char read_key (bool block) 336static char read_key (bool block)
320{ 337{
321 struct termios termios; 338 struct termios termios;
322 char c = 0; 339 char c = 0;
323 340
324 if (! isatty (STDIN_FILENO)) 341 if (! isatty (STDIN_FILENO))
325 return (false); 342 return (false);
326 343
327 /* Now save our terminal settings. We need to restore them at exit as we 344 /* 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 */ 345 will be changing it for non-blocking reads for Interactive */
369 /* VPS systems cannot do an sulogin */ 386 /* VPS systems cannot do an sulogin */
370 if (e && strcmp (e, "VPS") == 0) { 387 if (e && strcmp (e, "VPS") == 0) {
371 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL); 388 execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
372 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno)); 389 eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
373 } 390 }
391#endif
392
393 newenv = rc_filter_env ();
374 394
375 if (cont) { 395 if (cont) {
376 int status = 0; 396 int status = 0;
397#ifdef __linux__
398 char *tty = ttyname (fileno (stdout));
399#endif
400
377 pid_t pid = vfork(); 401 pid_t pid = vfork ();
378 402
379 if (pid == -1) 403 if (pid == -1)
380 eerrorx ("%s: vfork: %s", applet, strerror (errno)); 404 eerrorx ("%s: vfork: %s", applet, strerror (errno));
381 if (pid == 0) { 405 if (pid == 0) {
382 newenv = rc_filter_env (); 406#ifdef __linux__
383 execl ("/sbin/sulogin", "/sbin/sulogin", 407 if (tty)
384 getenv ("CONSOLE"), (char *) NULL, newenv); 408 execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
409 else
410 execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
411
385 eerror ("%s: unable to exec `/sbin/sulogin': %s", applet, 412 eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
386 strerror (errno)); 413 strerror (errno));
414#else
415 execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
416 eerror ("%s: unable to exec `/bin/sh': %s", applet,
417 strerror (errno));
418#endif
387 _exit (EXIT_FAILURE); 419 _exit (EXIT_FAILURE);
388 } 420 }
389 waitpid (pid, &status, 0); 421 waitpid (pid, &status, 0);
390 } else { 422 } else {
391 newenv = rc_filter_env (); 423#ifdef __linux
392 execl ("/sbin/sulogin", "/sbin/sulogin", 424 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)); 425 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
395 }
396#else 426#else
397 exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); 427 exit (EXIT_SUCCESS);
398#endif 428#endif
429 }
399} 430}
400 431
401static void single_user (void) 432static void single_user (void)
402{ 433{
403#ifdef __linux__ 434#ifdef __linux__
437} 468}
438 469
439static void wait_for_services () 470static void wait_for_services ()
440{ 471{
441 int status = 0; 472 int status = 0;
442 struct timeval tv;
443 while (wait (&status) != -1); 473 while (wait (&status) != -1);
474}
444 475
445 /* Wait for a little bit to flush our ebuffer */ 476static void add_pid (pid_t pid)
446 tv.tv_usec = 50000; 477{
447 tv.tv_sec = 0; 478 pidlist_t *sp = service_pids;
448 select (0, NULL, NULL, NULL, &tv); 479 if (sp) {
480 while (sp->next)
481 sp = sp->next;
482 sp->next = rc_xmalloc (sizeof (pidlist_t));
483 sp = sp->next;
484 } else
485 sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
486 memset (sp, 0, sizeof (pidlist_t));
487 sp->pid = pid;
488}
489
490static void remove_pid (pid_t pid)
491{
492 pidlist_t *last = NULL;
493 pidlist_t *pl;
494
495 for (pl = service_pids; pl; pl = pl->next) {
496 if (pl->pid == pid) {
497 if (last)
498 last->next = pl->next;
499 else
500 service_pids = pl->next;
501 free (pl);
502 break;
503 }
504 last = pl;
505 }
449} 506}
450 507
451static void handle_signal (int sig) 508static void handle_signal (int sig)
452{ 509{
453 int serrno = errno; 510 int serrno = errno;
454 char signame[10] = { '\0' }; 511 char signame[10] = { '\0' };
455 char *run; 512 char *run;
456 char *prev; 513 char *prev;
514 pidlist_t *pl;
515 pid_t pid;
516 int status = 0;
457 517
458 switch (sig) { 518 switch (sig) {
519 case SIGCHLD:
520 do {
521 pid = waitpid (-1, &status, WNOHANG);
522 if (pid < 0) {
523 if (errno != ECHILD)
524 eerror ("waitpid: %s", strerror (errno));
525 return;
526 }
527 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
528
529 /* Remove that pid from our list */
530 if (pid > 0)
531 remove_pid (pid);
532 break;
533
459 case SIGINT: 534 case SIGINT:
460 if (! signame[0]) 535 if (! signame[0])
461 snprintf (signame, sizeof (signame), "SIGINT"); 536 snprintf (signame, sizeof (signame), "SIGINT");
462 case SIGTERM: 537 case SIGTERM:
463 if (! signame[0]) 538 if (! signame[0])
467 snprintf (signame, sizeof (signame), "SIGQUIT"); 542 snprintf (signame, sizeof (signame), "SIGQUIT");
468 eerrorx ("%s: caught %s, aborting", applet, signame); 543 eerrorx ("%s: caught %s, aborting", applet, signame);
469 case SIGUSR1: 544 case SIGUSR1:
470 eerror ("rc: Aborting!"); 545 eerror ("rc: Aborting!");
471 /* Kill any running services we have started */ 546 /* Kill any running services we have started */
547
472 signal (SIGTERM, SIG_IGN); 548 signal (SIGCHLD, SIG_IGN);
473 killpg (getpgrp (), SIGTERM); 549 for (pl = service_pids; pl; pl = pl->next)
550 kill (pl->pid, SIGTERM);
474 551
475 /* Notify plugins we are aborting */ 552 /* Notify plugins we are aborting */
476 rc_plugin_run (rc_hook_abort, "rc"); 553 rc_plugin_run (rc_hook_abort, NULL);
477 554
555 /* Only drop into single user mode if we're booting */
478 run = getenv ("RUNLEVEL"); 556 run = getenv ("RUNLEVEL");
479 prev = getenv ("PREVLEVEL"); 557 prev = getenv ("PREVLEVEL");
480 /* Only drop into single user mode if we're booting */ 558 if ((prev &&
481 if ((prev && strcmp (prev, "S") == 0) || 559 (strcmp (prev, "S") == 0 ||
560 strcmp (prev, "1") == 0)) ||
561 (run &&
562 (strcmp (run, "S") == 0 ||
482 (run && strcmp (run, "S") == 0)) 563 strcmp (run, "1") == 0)))
483 single_user (); 564 single_user ();
484 565
485 exit (EXIT_FAILURE); 566 exit (EXIT_FAILURE);
486 break; 567 break;
487 568
627 pid_t wpid; 708 pid_t wpid;
628 int status = 0; 709 int status = 0;
629#ifdef __linux__ 710#ifdef __linux__
630 FILE *fp; 711 FILE *fp;
631#endif 712#endif
713
714 /* exec init-early.sh if it exists
715 * This should just setup the console to use the correct
716 * font. Maybe it should setup the keyboard too? */
717 if (rc_exists (INITEARLYSH)) {
718 if ((pid = vfork ()) == -1)
719 eerrorx ("%s: vfork: %s", applet, strerror (errno));
720
721 if (pid == 0) {
722 execl (INITEARLYSH, INITEARLYSH, (char *) NULL);
723 eerror ("%s: unable to exec `" INITEARLYSH "': %s",
724 applet, strerror (errno));
725 _exit (EXIT_FAILURE);
726 }
727
728 do {
729 wpid = waitpid (pid, &status, 0);
730 if (wpid < 1)
731 eerror ("waitpid: %s", strerror (errno));
732 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
733 }
632 734
633 uname (&uts); 735 uname (&uts);
634 736
635 printf ("\n"); 737 printf ("\n");
636 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s" 738 printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
791 } 893 }
792 894
793 /* Export our current softlevel */ 895 /* Export our current softlevel */
794 runlevel = rc_get_runlevel (); 896 runlevel = rc_get_runlevel ();
795 897
898 /* Now we start handling our children */
899 signal (SIGCHLD, handle_signal);
900
796 /* If we're in the default runlevel and ksoftlevel exists, we should use 901 /* If we're in the default runlevel and ksoftlevel exists, we should use
797 that instead */ 902 that instead */
798 if (newlevel && 903 if (newlevel &&
799 rc_exists (RC_SVCDIR "ksoftlevel") && 904 rc_exists (RC_SVCDIR "ksoftlevel") &&
800 strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) 905 strcmp (newlevel, RC_LEVEL_DEFAULT) == 0)
994 if (rc_service_state (service, rc_service_stopped)) 1099 if (rc_service_state (service, rc_service_stopped))
995 continue; 1100 continue;
996 1101
997 /* We always stop the service when in these runlevels */ 1102 /* We always stop the service when in these runlevels */
998 if (going_down) { 1103 if (going_down) {
999 rc_stop_service (service); 1104 pid_t pid = rc_stop_service (service);
1105 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1106 rc_waitpid (pid);
1000 continue; 1107 continue;
1001 } 1108 }
1002 1109
1003 /* If we're in the start list then don't bother stopping us */ 1110 /* If we're in the start list then don't bother stopping us */
1004 STRLIST_FOREACH (start_services, svc1, j) 1111 STRLIST_FOREACH (start_services, svc1, j)
1056 } 1163 }
1057 rc_strlist_free (deporder); 1164 rc_strlist_free (deporder);
1058 deporder = NULL; 1165 deporder = NULL;
1059 1166
1060 /* After all that we can finally stop the blighter! */ 1167 /* After all that we can finally stop the blighter! */
1061 if (! found) 1168 if (! found) {
1062 rc_stop_service (service); 1169 pid_t pid = rc_stop_service (service);
1170 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1171 rc_waitpid (pid);
1172 }
1063 } 1173 }
1064 rc_strlist_free (types); 1174 rc_strlist_free (types);
1065 types = NULL; 1175 types = NULL;
1066 1176
1067 /* Wait for our services to finish */ 1177 /* Wait for our services to finish */
1068 if (rc_is_env ("RC_PARALLEL_STARTUP", "yes"))
1069 wait_for_services (); 1178 wait_for_services ();
1070 1179
1071 /* Notify the plugins we have finished */ 1180 /* Notify the plugins we have finished */
1072 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); 1181 rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1073 1182
1074 rmdir (RC_SVCDIR "/softscripts.new"); 1183 rmdir (RC_SVCDIR "/softscripts.new");
1115 start_services = deporder; 1224 start_services = deporder;
1116 deporder = NULL; 1225 deporder = NULL;
1117 1226
1118 STRLIST_FOREACH (start_services, service, i) { 1227 STRLIST_FOREACH (start_services, service, i) {
1119 if (rc_service_state (service, rc_service_stopped)) { 1228 if (rc_service_state (service, rc_service_stopped)) {
1229 pid_t pid;
1230
1120 if (! interactive) 1231 if (! interactive)
1121 interactive = want_interactive (); 1232 interactive = want_interactive ();
1122 1233
1123 if (interactive) { 1234 if (interactive) {
1124interactive_retry: 1235interactive_retry:
1135 case '3': interactive = false; break; 1246 case '3': interactive = false; break;
1136 case '4': sulogin (true); goto interactive_retry; 1247 case '4': sulogin (true); goto interactive_retry;
1137 default: goto interactive_option; 1248 default: goto interactive_option;
1138 } 1249 }
1139 } 1250 }
1251
1252 /* Remember the pid if we're running in parallel */
1140 rc_start_service (service); 1253 if ((pid = rc_start_service (service)))
1254 add_pid (pid);
1255
1256 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1257 rc_waitpid (pid);
1258 remove_pid (pid);
1259 }
1141 } 1260 }
1142 } 1261 }
1143 1262
1144 /* Wait for our services to finish */ 1263 /* Wait for our services to finish */
1145 wait_for_services (); 1264 wait_for_services ();

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

  ViewVC Help
Powered by ViewVC 1.1.20