📄 init.c
字号:
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 (get_enter == TRUE) { /* * 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, console %s)\n", cmd[0], getpid(), 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(), terminal, command);#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, "Bummer, could not run '%s': %s\n", cmdpath, strerror(errno)); exit(-1); } return pid;}static int waitfor(char *command, char *terminal, int get_enter){ int status, wpid; int pid = run(command, terminal, get_enter); while (1) { wpid = wait(&status); if (wpid > 0 && wpid != pid) { continue; } if (wpid == pid) break; } return wpid;}/* 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(){ 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 */ waitfor("mount proc /proc -t proc", console, FALSE); /* Try to turn on swap */ waitfor("swapon -a", console, FALSE); if (check_free_memory() < 1000) goto goodnight; } else goto goodnight; return;#endif goodnight: message(CONSOLE, "Sorry, your computer does not have enough memory.\n"); loop_forever();}/* Run all commands to be run right before halt/reboot */static void run_actions(initActionEnum action){ initAction *a, *tmp; for (a = initActionList; a; a = tmp) { tmp = a->nextPtr; if (a->action == action) { waitfor(a->process, a->console, FALSE); delete_initAction(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); sigprocmask(SIG_BLOCK, &block_signals, NULL); /* Allow Ctrl-Alt-Del to reboot system. */ init_reboot(RB_ENABLE_CAD); message(CONSOLE|LOG, "\nThe system is going down NOW !!\n"); sync(); /* Send signals to every process _except_ pid 1 */ message(CONSOLE|LOG, "Sending SIGTERM to all processes.\n"); kill(-1, SIGTERM); sleep(1); sync(); message(CONSOLE|LOG, "Sending 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 halt_signal(int sig){ shutdown_system(); message(CONSOLE|LOG,#if #cpu(s390) /* Seems the s390 console is Wierd(tm). */ "The system is halted. You may reboot now.\n",#else /* secondConsole is NULL for a serial console */ "The system is halted. Press %s or turn off power\n", (secondConsole == NULL)? "Reset" : "CTRL-ALT-DEL"#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, "Please 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);}#endif /* ! DEBUG_INIT */static void new_initAction(initActionEnum action, char *process, char *cons){ initAction *newAction; if (*cons == '\0') cons = console; /* If BusyBox detects that a serial console is in use, * then entries not refering to the console or null devices will _not_ be run. * The exception to this rule is the null device. */ if (secondConsole == NULL && strcmp(cons, console) && strcmp(cons, "/dev/null")) return; if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST) return; newAction = calloc((size_t) (1), sizeof(initAction)); if (!newAction) { message(LOG | CONSOLE, "Memory allocation failure\n"); loop_forever(); } newAction->nextPtr = initActionList; initActionList = newAction; safe_strncpy(newAction->process, process, 255); newAction->action = action; safe_strncpy(newAction->console, cons, 255); newAction->pid = 0;// message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",// newAction->process, newAction->action, newAction->console);}static void delete_initAction(initAction * action){ initAction *a, *b = NULL; for (a = initActionList; a; b = a, a = a->nextPtr) { if (a == action) { if (b == NULL) { initActionList = a->nextPtr; } else { b->nextPtr = a->nextPtr; } 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[256], lineAsRead[256], tmpConsole[256]; char *id, *runlev, *action, *process, *eol; const struct initActionType *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_initAction(CTRLALTDEL, "/sbin/reboot", console);#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) /* Swapoff on halt/reboot */ new_initAction(SHUTDOWN, "/sbin/swapoff -a", console);#endif /* Umount all filesystems on halt/reboot */ new_initAction(SHUTDOWN, "/bin/umount -a -r", console); /* Askfirst shell on tty1 */ new_initAction(ASKFIRST, LOGIN_SHELL, console); /* Askfirst shell on tty2 */ if (secondConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); /* Askfirst shell on tty3 */ if (thirdConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); /* Askfirst shell on tty4 */ if (fourthConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); /* sysinit */ new_initAction(SYSINIT, INIT_SCRIPT, console); return;#ifdef BB_FEATURE_USE_INITTAB } while (fgets(buf, 255, 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, "Bad 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, "Bad inittab entry: %s\n", lineAsRead); continue; } else { *action = '\0'; ++action; } /* Separate the action from the process */ process = strchr(action, ':'); if (process == NULL || *(process + 1) == '\0') { message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); continue; } else { *process = '\0'; ++process; } /* 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, 200); id = tmpConsole; } new_initAction(a->action, process, id); foundIt = TRUE; } a++; } if (foundIt == TRUE) continue; else { /* Choke on an unknown action */ message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); } } return;#endif /* BB_FEATURE_USE_INITTAB */}extern int init_main(int argc, char **argv){ initAction *a, *tmp; pid_t wpid; int status;#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(SIGUSR1, halt_signal); signal(SIGUSR2, halt_signal); signal(SIGINT, ctrlaltdel_signal); signal(SIGTERM, reboot_signal); /* 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(); /* Close whatever files are open, and reset the console. */ close(0); close(1); close(2); /* Figure out where the default console should be */ console_init(); set_term(0); chdir("/"); setsid(); /* Make sure PATH is set to something sane */ putenv("PATH="_PATH_STDPATH); /* Hello world */ message(MAYBE_CONSOLE|LOG, "init 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 */ if (secondConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); if (thirdConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); if (fourthConsole != NULL) new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); /* Start a shell on tty1 */ new_initAction(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 */ for (a = initActionList; a; a = tmp) { tmp = a->nextPtr; if (a->action == ONCE) { run(a->process, a->console, FALSE); /* Now remove the "once" entry from the list */ delete_initAction(a); } } /* If there is nothing else to do, stop */ if (initActionList == NULL) { message(LOG | CONSOLE, "No more tasks for init -- sleeping forever.\n"); loop_forever(); } /* Now run the looping stuff for the rest of forever */ while (1) { for (a = initActionList; a; a = a->nextPtr) { /* Only run stuff with pid==0. If they have * a pid, that means they are still running */ if (a->pid == 0) { switch (a->action) { case RESPAWN: /* run the respawn stuff */ a->pid = run(a->process, a->console, FALSE); break; case ASKFIRST: /* run the askfirst stuff */ a->pid = run(a->process, a->console, TRUE); break; /* silence the compiler's incessant whining */ default: break; } } } /* Wait for a child process to exit */ wpid = wait(&status); if (wpid > 0) { /* Find out who died and clean up their corpse */ for (a = initActionList; a; a = a->nextPtr) { if (a->pid == wpid) { a->pid = 0; message(LOG, "Process '%s' (pid %d) exited. Scheduling it for restart.\n", a->process, wpid); } } } sleep(1); }}/*Local Variables:c-file-style: "linux"c-basic-offset: 4tab-width: 4End:*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -