📄 init.c
字号:
} 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); fflush(stdout); 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 BB_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; /* run everything to be run at "shutdown". This is done _prior_ * to killing everything, in case people wish to use scripts to * shut things down gracefully... */ run_actions(SHUTDOWN); /* 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); 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, strerror(errno)); sync(); sleep(2); init_reboot(RB_HALT_SYSTEM); loop_forever(); } }}static void halt_signal(int sig){ shutdown_system(); message(CONSOLE|LOG,#if #cpu(s390) /* Seems the s390 console is Wierd(tm). */ "\rThe system is halted. You may reboot now.\n"#else "\rThe system is halted. Press Reset or turn off power\n"#endif ); sync(); /* allow time for last message to reach serial console */ sleep(2); if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0)) init_reboot(RB_POWER_OFF); else init_reboot(RB_HALT_SYSTEM); loop_forever();}static void reboot_signal(int sig){ shutdown_system(); message(CONSOLE|LOG, "\rPlease stand by while rebooting the system.\n"); sync(); /* allow time for last message to reach serial console */ sleep(2); init_reboot(RB_AUTOBOOT); loop_forever();}static void ctrlaltdel_signal(int sig){ run_actions(CTRLALTDEL);}/* The SIGSTOP & SIGTSTP handler */static void stop_handler(int sig){ int saved_errno = errno; got_cont = 0; while(!got_cont) pause(); got_cont = 0; errno = saved_errno;}/* The SIGCONT handler */ static void cont_handler(int sig){ got_cont = 1;}#endif /* ! DEBUG_INIT */static void new_init_action(int action, char *command, char *cons){ struct init_action *new_action, *a; if (*cons == '\0') cons = console; /* do not run entries if console device is not available */ if (access(cons, R_OK|W_OK)) return; if (strcmp(cons, "/dev/null") == 0 && (action & ASKFIRST)) return; new_action = calloc((size_t) (1), sizeof(struct init_action)); if (!new_action) { message(LOG | CONSOLE, "\rMemory allocation failure\n"); loop_forever(); } /* Append to the end of the list */ for (a = init_action_list; a && a->next; a = a->next) ; if (a) { a->next = new_action; } else { init_action_list = new_action; } strcpy(new_action->command, command); new_action->action = action; strcpy(new_action->terminal, cons); new_action->pid = 0;// message(LOG|CONSOLE, "command='%s' action='%d' terminal='%s'\n",// new_action->command, new_action->action, new_action->terminal);}static void delete_init_action(struct init_action * action){ struct init_action *a, *b = NULL; for (a = init_action_list; a; b = a, a = a->next) { if (a == action) { if (b == NULL) { init_action_list = a->next; } else { b->next = a->next; } free(a); break; } }}/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default * actions(i.e., runs INIT_SCRIPT and then starts a pair * of "askfirst" shells). If BB_FEATURE_USE_INITTAB * _is_ defined, but /etc/inittab is missing, this * results in the same set of default behaviors. * */static void parse_inittab(void){#ifdef BB_FEATURE_USE_INITTAB FILE *file; char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE], tmpConsole[INIT_BUFFS_SIZE]; char *id, *runlev, *action, *command, *eol; const struct init_action_type *a = actions; int foundIt; file = fopen(INITTAB, "r"); if (file == NULL) { /* No inittab file -- set up some default behavior */#endif /* Reboot on Ctrl-Alt-Del */ new_init_action(CTRLALTDEL, "/sbin/reboot", console); /* Umount all filesystems on halt/reboot */ new_init_action(SHUTDOWN, "/bin/umount -a -r", console);#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) /* Swapoff on halt/reboot */ new_init_action(SHUTDOWN, "/sbin/swapoff -a", console);#endif /* Prepare to restart init when a HUP is received */ new_init_action(RESTART, "/sbin/init", console); /* Askfirst shell on tty1-4 */ new_init_action(ASKFIRST, LOGIN_SHELL, console); new_init_action(ASKFIRST, LOGIN_SHELL, VC_2); new_init_action(ASKFIRST, LOGIN_SHELL, VC_3); new_init_action(ASKFIRST, LOGIN_SHELL, VC_4); /* sysinit */ new_init_action(SYSINIT, INIT_SCRIPT, console); return;#ifdef BB_FEATURE_USE_INITTAB } while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { foundIt = FALSE; /* Skip leading spaces */ for (id = buf; *id == ' ' || *id == '\t'; id++); /* Skip the line if it's a comment */ if (*id == '#' || *id == '\n') continue; /* Trim the trailing \n */ eol = strrchr(id, '\n'); if (eol != NULL) *eol = '\0'; /* Keep a copy around for posterity's sake (and error msgs) */ strcpy(lineAsRead, buf); /* Separate the ID field from the runlevels */ runlev = strchr(id, ':'); if (runlev == NULL || *(runlev + 1) == '\0') { message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); continue; } else { *runlev = '\0'; ++runlev; } /* Separate the runlevels from the action */ action = strchr(runlev, ':'); if (action == NULL || *(action + 1) == '\0') { message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); continue; } else { *action = '\0'; ++action; } /* Separate the action from the command */ command = strchr(action, ':'); if (command == NULL || *(command + 1) == '\0') { message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); continue; } else { *command = '\0'; ++command; } /* Ok, now process it */ a = actions; while (a->name != 0) { if (strcmp(a->name, action) == 0) { if (*id != '\0') { strcpy(tmpConsole, "/dev/"); strncat(tmpConsole, id, INIT_BUFFS_SIZE-6); id = tmpConsole; } new_init_action(a->action, command, id); foundIt = TRUE; } a++; } if (foundIt == TRUE) continue; else { /* Choke on an unknown action */ message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); } } fclose(file); return;#endif /* BB_FEATURE_USE_INITTAB */}extern int init_main(int argc, char **argv){ struct init_action *a; pid_t wpid; int status; if (argc > 1 && !strcmp(argv[1], "-q")) { /* don't assume init's pid == 1 */ long *pid = find_pid_by_name("init"); if (!pid || *pid<=0) { pid = find_pid_by_name("linuxrc"); if (!pid || *pid<=0) error_msg_and_die("no process killed"); } kill(*pid, SIGHUP); exit(0); }#ifndef DEBUG_INIT /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1#ifdef BB_FEATURE_LINUXRC && strstr(applet_name, "linuxrc") == NULL#endif ) { show_usage(); } /* Set up sig handlers -- be sure to * clear all of these in run() */ signal(SIGHUP, exec_signal); signal(SIGUSR1, halt_signal); signal(SIGUSR2, halt_signal); signal(SIGINT, ctrlaltdel_signal); signal(SIGTERM, reboot_signal); signal(SIGCONT, cont_handler); signal(SIGSTOP, stop_handler); signal(SIGTSTP, stop_handler); /* Turn off rebooting via CTL-ALT-DEL -- we get a * SIGINT on CAD so we can shut things down gracefully... */ init_reboot(RB_DISABLE_CAD);#endif /* Figure out what kernel this is running */ kernelVersion = get_kernel_revision(); /* Figure out where the default console should be */ console_init(); /* Close whatever files are open, and reset the console. */ close(0); close(1); close(2); if(device_open(console, O_RDWR|O_NOCTTY)==0) { set_term(0); close(0); } chdir("/"); setsid(); /* Make sure PATH is set to something sane */ putenv("PATH="_PATH_STDPATH); /* Hello world */ message(MAYBE_CONSOLE|LOG, "\rinit started: %s\n", full_version); /* Make sure there is enough memory to do something useful. */ check_memory(); /* Check if we are supposed to be in single user mode */ if (argc > 1 && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { /* Ask first then start a shell on tty2-4 */ new_init_action(ASKFIRST, LOGIN_SHELL, VC_2); new_init_action(ASKFIRST, LOGIN_SHELL, VC_3); new_init_action(ASKFIRST, LOGIN_SHELL, VC_4); /* Start a shell on tty1 */ new_init_action(RESPAWN, LOGIN_SHELL, console); } else { /* Not in single user mode -- see what inittab says */ /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default * actions(i.e., runs INIT_SCRIPT and then starts a pair * of "askfirst" shells */ parse_inittab(); } /* Make the command line just say "init" -- thats all, nothing else */ fixup_argv(argc, argv, "init"); /* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); /* Next run anything that wants to block */ run_actions(WAIT); /* Next run anything to be run only once */ run_actions(ONCE); /* If there is nothing else to do, stop */ if (init_action_list == NULL) { message(LOG | CONSOLE, "\rNo more tasks for init -- sleeping forever.\n"); loop_forever(); } /* Now run the looping stuff for the rest of forever */ while (1) { /* run the respawn stuff */ run_actions(RESPAWN); /* run the askfirst stuff */ run_actions(ASKFIRST); /* Don't consume all CPU time -- sleep a bit */ sleep(1); /* Wait for a child process to exit */ wpid = wait(&status); while (wpid > 0) { /* Find out who died and clean up their corpse */ for (a = init_action_list; a; a = a->next) { if (a->pid == wpid) { /* Set the pid to 0 so that the process gets * restarted by run_actions() */ a->pid = 0; message(LOG, "Process '%s' (pid %d) exited. " "Scheduling it for restart.\n", a->command, wpid); } } /* see if anyone else is waiting to be reaped */ wpid = waitpid (-1, &status, WNOHANG); } }}/*Local Variables:c-file-style: "linux"c-basic-offset: 4tab-width: 4End:*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -