int main(int argc, char *argv[]) { int i; struct sigaction sa; /* * setup all the signal handlers here */ memset(&sa, 0, sizeof(sa)); /* sa.sa_flags = SA_RESETHAND we want to keep the handlers armed */ sa.sa_handler = tstp_handler; sigaction(SIGTSTP, &sa, NULL); sa.sa_handler = cont_handler; sigaction(SIGCONT, &sa, NULL); sa.sa_handler = int_handler; sigaction(SIGINT, &sa, NULL); sa.sa_handler = respawn_children; sigaction(SIGALRM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); #if defined(CONSOLE_BAUD_RATE) && LINUX_VERSION_CODE < 0x020100 set_console_baud(CONSOLE_BAUD_RATE); #endif /* * start up in single user mode if /etc/singleboot exists or if * argv[1] is "single". */ if(boot_single(0, argc, argv)) enter_single(); #ifdef CONFIG_RTL865X for(i = 1; i < argc; i++) { if(argv[i] && !strcmp(argv[i], "uart1")) boot_uart1=1;; } #endif #ifdef RUN_RC /* Register console if defined by boot */ #if LINUX_VERSION_CODE < 0x020100 if ((console_device = getenv("CONSOLE"))) { char *sp; unsetenv("CONSOLE"); if ((sp = strchr(console_device, ','))) { *sp++ = 0; set_console_baud(atoi(sp)); } } make_ascii_tty(); #else { struct stat st; if (isatty(1)) { have_console = 1; make_ascii_tty(); } else if (fstat(1, &st) == -1 && errno == EBADF) { close(0); close(1); close(2); open("/dev/null", O_RDWR); dup(0); dup(0); } } #endif /*If we get a SIGTSTP before multi-user mode, do nothing*/ while(stopped) pause(); if(do_rc() != 0 && boot_single(1, argc, argv) && !stopped) enter_single(); while(stopped) /*Also if /etc/rc fails & we get SIGTSTP*/ pause(); #endif write_wtmp(); /* write boottime record */ read_inittab(); #ifdef DEBUGGING for(i = 0; i < numcmd; i++) { char **p; p = inittab[i].toks; printf("toks= %s %s %s %s\n",p[0], p[1], p[2], p[3]); printf("tty= %s\n", inittab[i].tty); printf("termcap= %s\n", inittab[i].termcap); } /*exit(0);*/ #endif #if LINUX_VERSION_CODE < 0x020100 for(i = 0; i < getdtablesize(); i++) close(i); #else i = 0; if (have_console) i = 3; for(; i < getdtablesize(); i++) close(i); #endif for (;;) { pid_t pid; int vec; if (run_sigint_processing) { run_sigint_processing = 0; sigint_processing(); } respawn_children(); if (reload) { reload = 0; reload_inittab(); continue; /* process all reloads before waiting */ } pid = wait(&vec); alarm(0); /* clear utmp entry, and append to wtmp if possible */ #if 0 /* DAVIDM */ { struct utmp *ut; int ut_fd; utmpname(_PATH_UTMP); setutent(); while((ut = getutent())) { if(ut->ut_pid == pid) { time(&ut->ut_time); bzero(&ut->ut_user, UT_NAMESIZE); bzero(&ut->ut_host, sizeof(ut->ut_host)); ut->ut_type = DEAD_PROCESS; ut->ut_pid = 0; ut->ut_addr = 0; endutent(); pututline(ut); if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { flock(ut_fd, LOCK_EX|LOCK_NB); write(ut_fd, (const void *)ut, sizeof(struct utmp)); flock(ut_fd, LOCK_UN|LOCK_NB); close(ut_fd); } break; } } endutent(); } #endif for(i = 0; i < numcmd; i++) { if(pid == inittab[i].pid) { inittab[i].pid = -1; } } } }
int halt_main(int argc UNUSED_PARAM, char **argv) { static const int magic[] = { RB_HALT_SYSTEM, RB_POWER_OFF, RB_AUTOBOOT }; static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM }; int delay = 0; int which, flags, rc; /* Figure out which applet we're running */ for (which = 0; "hpr"[which] != applet_name[0]; which++) continue; /* Parse and handle arguments */ opt_complementary = "d+"; /* -d N */ /* We support -w even if !ENABLE_FEATURE_WTMP, * in order to not break scripts. * -i (shut down network interfaces) is ignored. */ flags = getopt32(argv, "d:nfwi", &delay); sleep(delay); write_wtmp(); if (flags & 8) /* -w */ return EXIT_SUCCESS; if (!(flags & 2)) /* no -n */ sync(); /* Perform action. */ rc = 1; if (!(flags & 4)) { /* no -f */ //TODO: I tend to think that signalling linuxrc is wrong // pity original author didn't comment on it... if (ENABLE_FEATURE_INITRD) { /* talk to linuxrc */ /* bbox init/linuxrc assumed */ pid_t *pidlist = find_pid_by_name("linuxrc"); if (pidlist[0] > 0) rc = kill(pidlist[0], signals[which]); if (ENABLE_FEATURE_CLEAN_UP) free(pidlist); } if (rc) { /* talk to init */ if (!ENABLE_FEATURE_CALL_TELINIT) { /* bbox init assumed */ rc = kill(1, signals[which]); } else { /* SysV style init assumed */ /* runlevels: * 0 == shutdown * 6 == reboot */ rc = execlp(CONFIG_TELINIT_PATH, CONFIG_TELINIT_PATH, which == 2 ? "6" : "0", (char *)NULL ); } } } else { rc = reboot(magic[which]); } if (rc) bb_perror_nomsg_and_die(); return rc; }
int main(int argc, char *argv[]) { int c, i, fd; char *ptr; i = getdtablesize (); for (fd = 3; fd < i; fd++) close (fd); if (getpid () == 1) { for (fd = 0; fd < 3; fd++) close (fd); while (1) wait (NULL); /* Grim reaper never stops */ } sigsetmask (0); /* simpleinit(8) blocks all signals: undo for ALRM */ for (i = 1; i < NSIG; i++) signal (i, SIG_DFL); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #ifndef DEBUGGING if(setreuid (0, 0)) { fprintf(stderr, _("%s: Only root can shut a system down.\n"), argv[0]); exit(1); } #endif if(*argv[0] == '-') argv[0]++; /* allow shutdown as login shell */ prog = argv[0]; if((ptr = strrchr(argv[0], '/'))) prog = ++ptr; /* All names (halt, reboot, fasthalt, fastboot, shutdown) refer to the same program with the same options, only the defaults differ. */ if(!strcmp("halt", prog)) { opt_reboot = 0; opt_quiet = 1; opt_fast = 0; timeout = 0; } else if(!strcmp("fasthalt", prog)) { opt_reboot = 0; opt_quiet = 1; opt_fast = 1; timeout = 0; } else if(!strcmp("reboot", prog)) { opt_reboot = 1; opt_quiet = 1; opt_fast = 0; timeout = 0; } else if(!strcmp("fastboot", prog)) { opt_reboot = 1; opt_quiet = 1; opt_fast = 1; timeout = 0; } else { /* defaults */ opt_reboot = 0; opt_quiet = 0; opt_fast = 0; timeout = 2*60; } c = 0; while(++c < argc) { if(argv[c][0] == '-') { for(i = 1; argv[c][i]; i++) { switch(argv[c][i]) { case 'C': opt_use_config_file = 1; break; case 'h': opt_reboot = 0; break; case 'r': opt_reboot = 1; break; case 'f': opt_fast = 1; break; case 'q': opt_quiet = 1; break; case 's': opt_single = 1; break; default: usage(); } } } else if(!strcmp("now", argv[c])) { timeout = 0; } else if(argv[c][0] == '+') { timeout = 60 * atoi(&argv[c][1]); } else if (isdigit(argv[c][0])) { char *colon; int hour = 0; int minute = 0; time_t tics; struct tm *tt; int now, then; if((colon = strchr(argv[c], ':'))) { *colon = '\0'; hour = atoi(argv[c]); minute = atoi(++colon); } else usage(); (void) time(&tics); tt = localtime(&tics); now = 3600 * tt->tm_hour + 60 * tt->tm_min; then = 3600 * hour + 60 * minute; timeout = then - now; if(timeout < 0) { fprintf(stderr, _("That must be tomorrow, " "can't you wait till then?\n")); exit(1); } } else { xstrncpy(message, argv[c], sizeof(message)); opt_msgset = 1; } } halt_action[0] = 0; /* No doubt we shall want to extend this some day and register a series of commands to be executed at various points during the shutdown sequence, and to define the number of milliseconds to sleep, etc. */ if (opt_use_config_file) { char line[256], *p; FILE *fp; /* Read and parse the config file */ halt_action[0] = '\0'; if ((fp = fopen (_PATH_SHUTDOWN_CONF, "r")) != NULL) { if (fgets (line, sizeof(line), fp) != NULL && strncasecmp (line, "HALT_ACTION", 11) == 0 && iswhitespace(line[11])) { p = index(line, '\n'); if (p) *p = 0; /* strip final '\n' */ p = line+11; while(iswhitespace(*p)) p++; strcpy(halt_action, p); } fclose (fp); } } if(!opt_quiet && !opt_msgset) { /* now ask for message, gets() is insecure */ int cnt = sizeof(message)-1; char *ptr; printf("Why? "); fflush(stdout); ptr = message; while(--cnt >= 0 && (*ptr = getchar()) && *ptr != '\n') { ptr++; } *ptr = '\0'; } else if (!opt_msgset) { strcpy(message, _("for maintenance; bounce, bounce")); } #ifdef DEBUGGING printf(_("timeout = %d, quiet = %d, reboot = %d\n"), timeout, opt_quiet, opt_reboot); #endif /* so much for option-processing, now begin termination... */ if(!(whom = getlogin()) || !*whom) whom = "ghost"; if(strlen(whom) > 40) whom[40] = 0; /* see write_user() */ setpriority(PRIO_PROCESS, 0, PRIO_MIN); signal(SIGINT, int_handler); signal(SIGHUP, int_handler); signal(SIGQUIT, int_handler); signal(SIGTERM, int_handler); chdir("/"); if(timeout > 5*60) { sleep(timeout - 5*60); timeout = 5*60; } if((fd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT, 0644)) >= 0) { /* keep xgettext happy and leave \r\n outside strings */ WRCRLF; WR(_("The system is being shut down within 5 minutes")); WRCRLF; write(fd, message, strlen(message)); WRCRLF; WR(_("Login is therefore prohibited.")); WRCRLF; close(fd); } signal(SIGPIPE, SIG_IGN); if(timeout > 0) { wall(); sleep(timeout); } timeout = 0; wall(); sleep(3); /* now there's no turning back... */ signal(SIGINT, SIG_IGN); /* do syslog message... */ openlog(prog, LOG_CONS, LOG_AUTH); if (opt_reboot) syslog(LOG_NOTICE, _("rebooted by %s: %s"), whom, message); else syslog(LOG_NOTICE, _("halted by %s: %s"), whom, message); closelog(); if(opt_fast) if((fd = open("/fastboot", O_WRONLY|O_CREAT, 0644)) >= 0) close(fd); kill(1, SIGTSTP); /* tell init not to spawn more getty's */ write_wtmp(); if(opt_single) if((fd = open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644)) >= 0) close(fd); sync(); signal(SIGTERM, SIG_IGN); if(fork() > 0) sleep(1000); /* the parent will die soon... */ setpgrp(); /* so the shell wont kill us in the fall */ #ifndef DEBUGGING /* a gentle kill of all other processes except init */ kill_mortals (SIGTERM); for (fd = 0; fd < 3; fd++) close (fd); stop_finalprog (); sleep (1); /* Time for saves to start */ kill (1, SIGTERM); /* Tell init to kill spawned gettys */ usleep (100000); /* Wait for gettys to die */ my_puts (""); /* Get past the login prompt */ system ("/sbin/initctl -r"); /* Roll back services */ syncwait (1); my_puts ("Sending SIGTERM to all remaining processes..."); kill (-1, SIGTERM); sleep (2); /* Default 2, some people need 5 */ kill (-1, SIGKILL); /* Now use brute force... */ /* turn off accounting */ acct(NULL); #endif /* RedHat and SuSE like to remove /etc/nologin. Perhaps the usual sequence is touch nologin; shutdown -h; fiddle with hardware; boot; fiddle with software; rm nologin and removing it here will be counterproductive. Let us see whether people complain. */ unlink(_PATH_NOLOGIN); /* Tell init(8) to exec so that the old inode may be freed cleanly if required. Need to sleep before remounting root read-only */ kill (1, SIGQUIT); sleep (1); /* Time for processes to die and close files */ syncwait (2); /* remove swap files and partitions using swapoff */ swap_off(); /* unmount disks... */ unmount_disks(); syncwait (1); if(opt_reboot) { my_reboot(LINUX_REBOOT_CMD_RESTART); /* RB_AUTOBOOT */ my_puts(_("\nWhy am I still alive after reboot?")); } else { my_puts(_("\nNow you can turn off the power...")); /* allow C-A-D now, [email protected], re-fixed 8-Jul-96 */ my_reboot(LINUX_REBOOT_CMD_CAD_ON); /* RB_ENABLE_CAD */ sleep (1); /* Wait for devices to finish writing to media */ do_halt(halt_action); } /* NOTREACHED */ exit(0); /* to quiet gcc */ }