📄 init.c
字号:
close(fd); } message(LOG, "console=%s\n", console);} static void fixup_argv(int argc, char **argv, char *new_argv0){ int len; /* Fix up argv[0] to be certain we claim to be init */ len = strlen(argv[0]); memset(argv[0], 0, len); safe_strncpy(argv[0], new_argv0, len + 1); /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ len = 1; while (argc > len) { memset(argv[len], 0, strlen(argv[len])); len++; }}/* Make sure there is enough memory to do something useful. * * Calls "swapon -a" if needed so be sure /etc/fstab is present... */static void check_memory(void){ struct stat statBuf; if (check_free_memory() > 1000) return;#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) if (stat("/etc/fstab", &statBuf) == 0) { /* swapon -a requires /proc typically */ system("/bin/mount -t proc proc /proc"); /* Try to turn on swap */ system("/sbin/swapon -a"); if (check_free_memory() < 1000) goto goodnight; } else goto goodnight; return;#endif goodnight: message(CONSOLE, "\rSorry, your computer does not have enough memory.\n"); loop_forever();}static pid_t run(struct init_action *a){ struct stat sb; int i, j, junk; pid_t pid, pgrp, tmp_pid; char *s, *tmpCmd, *cmd[INIT_BUFFS_SIZE], *cmdpath; char buf[INIT_BUFFS_SIZE+6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */ sigset_t nmask, omask; char *environment[MAXENV+1] = { termType, "HOME=/", "PATH=" _PATH_STDPATH, "SHELL=" SHELL, "USER=root", NULL }; static const char press_enter[] =#ifdef CUSTOMIZED_BANNER#include CUSTOMIZED_BANNER#endif "\nPlease press Enter to activate this console. "; /* inherit environment to the child, merging our values -andy */ for (i=0; environ[i]; i++) { for (j=0; environment[j]; j++) { s = strchr(environment[j], '='); if (!strncmp(environ[i], environment[j], s - environment[j])) break; } if (!environment[j]) { environment[j++] = environ[i]; environment[j] = NULL; } } /* Block sigchild while forking. */ sigemptyset(&nmask); sigaddset(&nmask, SIGCHLD); sigprocmask(SIG_BLOCK, &nmask, &omask); if ((pid = fork()) == 0) { /* Clean up */ close(0); close(1); close(2); sigprocmask(SIG_SETMASK, &omask, NULL); /* Reset signal handlers that were set by the parent process */ signal(SIGUSR1, SIG_DFL); signal(SIGUSR2, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGCONT, SIG_DFL); signal(SIGSTOP, SIG_DFL); signal(SIGTSTP, SIG_DFL); /* Create a new session and make ourself the process * group leader for non-interactive jobs */ if ((a->action & (RESPAWN))==0) setsid(); /* Open the new terminal device */ if ((device_open(a->terminal, O_RDWR|O_NOCTTY)) < 0) { if (stat(a->terminal, &sb) != 0) { message(LOG | CONSOLE, "\rdevice '%s' does not exist.\n", a->terminal); _exit(1); } message(LOG | CONSOLE, "\rBummer, can't open %s\n", a->terminal); _exit(1); } /* Non-interactive jobs should not get a controling tty */ if ((a->action & (RESPAWN))==0) (void)ioctl(0, TIOCSCTTY, 0); /* Make sure the terminal will act fairly normal for us */ set_term(0); /* Setup stdout, stderr for the new process so * they point to the supplied terminal */ dup(0); dup(0); /* For interactive jobs, create a new session * and become the process group leader */ if ((a->action & (RESPAWN))) setsid(); /* If the init Action requires us to wait, then force the * supplied terminal to be the controlling tty. */ if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) { /* Now fork off another process to just hang around */ if ((pid = fork()) < 0) { message(LOG | CONSOLE, "Can't fork!\n"); _exit(1); } if (pid > 0) { /* We are the parent -- wait till the child is done */ signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGCHLD, SIG_DFL); /* Wait for child to exit */ while ((tmp_pid = waitpid(pid, &junk, 0)) != pid) ; /* See if stealing the controlling tty back is necessary */ pgrp = tcgetpgrp(0); if (pgrp != getpid()) _exit(0); /* Use a temporary process to steal the controlling tty. */ if ((pid = fork()) < 0) { message(LOG | CONSOLE, "\rCan't fork!\n"); _exit(1); } if (pid == 0) { setsid(); ioctl(0, TIOCSCTTY, 1); _exit(0); } while((tmp_pid = waitpid(pid, &junk, 0)) != pid) { if (tmp_pid < 0 && errno == ECHILD) break; } _exit(0); } /* Now fall though to actually execute things */ } /* See if any special /bin/sh requiring characters are present */ if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { cmd[0] = SHELL; cmd[1] = "-c"; strcat(strcpy(buf, "exec "), a->command); cmd[2] = buf; cmd[3] = NULL; } else { /* Convert command (char*) into cmd (char**, one word per string) */ strcpy(buf, a->command); s = buf; for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) { if (*tmpCmd != '\0') { cmd[i] = tmpCmd; i++; } } cmd[i] = NULL; } cmdpath = cmd[0]; /* Interactive shells want to see a dash in argv[0]. This typically is handled by login, argv will be setup this way if a dash appears at the front of the command path (like "-/bin/sh"). */ if (*cmdpath == '-') { /* skip over the dash */ ++cmdpath; /* find the last component in the command pathname */ s = get_last_path_component(cmdpath); /* make a new argv[0] */ if ((cmd[0] = malloc(strlen(s)+2)) == NULL) { message(LOG | CONSOLE, "malloc failed"); cmd[0] = cmdpath; } else { cmd[0][0] = '-'; strcpy(cmd[0]+1, s); } } if (a->action & ASKFIRST) { /* * Save memory by not exec-ing anything large (like a shell) * before the user wants it. This is critical if swap is not * enabled and the system has low memory. Generally this will * be run on the second virtual console, and the first will * be allowed to start a shell or whatever an init script * specifies. */ messageND(LOG, "Waiting for enter to start '%s' (pid %d, terminal %s)\n", cmdpath, getpid(), a->terminal); write(fileno(stdout), press_enter, sizeof(press_enter) - 1); getc(stdin); } /* Log the process name and args */ messageND(LOG, "Starting pid %d, console %s: '%s'\n", getpid(), a->terminal, cmdpath);#if defined CONFIG_FEATURE_INIT_COREDUMPS if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) { struct rlimit limit; limit.rlim_cur = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &limit); }#endif /* Now run it. The new program will take over this PID, * so nothing further in init.c should be run. */ execve(cmdpath, cmd, environment); /* We're still here? Some error happened. */ message(LOG | CONSOLE, "\rBummer, could not run '%s': %s\n", cmdpath, strerror(errno)); _exit(-1); } sigprocmask(SIG_SETMASK, &omask, NULL); return pid;}static int waitfor(struct init_action *a){ int pid; int status, wpid; pid = run(a); while (1) { wpid = wait(&status); if (wpid > 0 && wpid != pid) { continue; } if (wpid == pid) break; } return wpid;}/* Run all commands of a particular type */static void run_actions(int action){ struct init_action *a, *tmp; for (a = init_action_list; a; a = tmp) { tmp = a->next; if (a->action == action) { if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) { waitfor(a); delete_init_action(a); } else if (a->action & ONCE) { run(a); delete_init_action(a); } else if (a->action & (RESPAWN|ASKFIRST)) { /* Only run stuff with pid==0. If they have * a pid, that means it is still running */ if (a->pid == 0) { a->pid = run(a); } } } }}#ifndef DEBUG_INITstatic void shutdown_system(void){ sigset_t block_signals; /* first disable all our signals */ sigemptyset(&block_signals); sigaddset(&block_signals, SIGHUP); sigaddset(&block_signals, SIGCHLD); sigaddset(&block_signals, SIGUSR1); sigaddset(&block_signals, SIGUSR2); sigaddset(&block_signals, SIGINT); sigaddset(&block_signals, SIGTERM); sigaddset(&block_signals, SIGCONT); sigaddset(&block_signals, SIGSTOP); sigaddset(&block_signals, SIGTSTP); sigprocmask(SIG_BLOCK, &block_signals, NULL); /* Allow Ctrl-Alt-Del to reboot system. */ init_reboot(RB_ENABLE_CAD); message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n"); sync(); /* Send signals to every process _except_ pid 1 */ message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n"); kill(-1, SIGTERM); sleep(1); sync(); message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n"); kill(-1, SIGKILL); sleep(1); /* run everything to be run at "shutdown" */ run_actions(SHUTDOWN); sync(); if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) { /* bdflush, kupdate not needed for kernels >2.2.11 */ bdflush(1, 0); sync(); }}static void exec_signal(int sig){ struct init_action *a, *tmp; sigset_t unblock_signals; for (a = init_action_list; a; a = tmp) { tmp = a->next; if (a->action & RESTART) { shutdown_system(); /* unblock all signals, blocked in shutdown_system() */ sigemptyset(&unblock_signals); sigaddset(&unblock_signals, SIGHUP); sigaddset(&unblock_signals, SIGCHLD); sigaddset(&unblock_signals, SIGUSR1); sigaddset(&unblock_signals, SIGUSR2); sigaddset(&unblock_signals, SIGINT); sigaddset(&unblock_signals, SIGTERM); sigaddset(&unblock_signals, SIGCONT); sigaddset(&unblock_signals, SIGSTOP); sigaddset(&unblock_signals, SIGTSTP); sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL); message(CONSOLE|LOG, "\rTrying to re-exec %s\n", a->command); execl(a->command, a->command, NULL); message(CONSOLE|LOG, "\rexec of '%s' failed: %s\n", a->command, sys_errlist[errno]); sync(); sleep(2); init_reboot(RB_HALT_SYSTEM); loop_forever(); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -