一、busybox:ls,cp等命令的组合
执行:ls "/sbin/init 会发现/sbin/init-->../bin/busybox
所以"/sbin/init"也是在busybox进程中,所以要分析这些,需要进入busybox中分析
二、uboot启动内核,内核启动应用程序
内核----->../sbit/init/----->应用程序
int程序:1、配置文件---->2、解析配置文件---->3、执行应用程序
配置文件:指定程序-->指定执行时间
三、阅读源码
解压缩:busybox-1.7.0.tar.bz2
1、 init.c (位于busybox-1.7.0\init)
busybox--->init_main,
init_main--->parse_inittab();
#define INITTAB "/etc/inittab"
parse_inittab--->file = fopen(INITTAB, "r");//打开配置文件/etc/inittab
new_init_action
run_actions(SYSINIT);
run_actions(WAIT);
run_actions(ONCE);
while (1) {
run_actions(RESPAWN);
run_actions(ASKFIRST);
sleep(1);
}
inittab格式:
<id>:<runlevels>:<action>:<process>
inittab文件下部分说明(busybox-1.7.0\examples)
# <id>:The contents of this field are appended to "/dev/" and used as-is.
id=>/dev/id.用作终端:stdin、stdout、stderr 、printf、scanf、err
# <runlevels>: The runlevels field is completely ignored.
runlevels完全可以忽略掉
# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once, restart, ctrlaltdel, and shutdown.
action指定何时执行
# <process>: Specifies the process to be executed and it's command line.
process:应用程序或者脚本
如果没有配置文件,将执行默认的配置,即if下面的代码
if (file == NULL) {/* No inittab file -- set up some default behavior */#endif/* Reboot on Ctrl-Alt-Del */new_init_action(CTRLALTDEL, "reboot", "");/* Umount all filesystems on halt/reboot */new_init_action(SHUTDOWN, "umount -a -r", "");/* Swapoff on halt/reboot */if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");/* Prepare to restart init when a HUP is received */new_init_action(RESTART, "init", "");/* Askfirst shell on tty1-4 */new_init_action(ASKFIRST, bb_default_login_shell, "");new_init_action(ASKFIRST, bb_default_login_shell, VC_2);new_init_action(ASKFIRST, bb_default_login_shell, VC_3);new_init_action(ASKFIRST, bb_default_login_shell, VC_4);/* sysinit */new_init_action(SYSINIT, INIT_SCRIPT, "");return;#if ENABLE_FEATURE_USE_INITTAB}
如果有的话将执行下面的方法,对配置文件解析
while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {/* Skip leading spaces */for (id = buf; *id == ' ' || *id == '\t'; id++);/* Skip the line if it's a comment */if (*id == '#' || *id == '\n') //如果是#或者\n就忽略掉continue;/* Trim the trailing \n *///XXX: chomp() ?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(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);continue;} else {*runlev = '\0';++runlev;}/* Separate the runlevels from the action */action = strchr(runlev, ':');if (action == NULL || *(action + 1) == '\0') {message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);continue;} else {*action = '\0';++action;}/* Separate the action from the command */command = strchr(action, ':');if (command == NULL || *(command + 1) == '\0') {message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);continue;} else {*command = '\0';++command;}/* Ok, now process it */for (a = actions; a->name != 0; a++) {if (strcmp(a->name, action) == 0) {if (*id != '\0') {if (strncmp(id, "/dev/", 5) == 0) //将id加上/dev/前缀id += 5;strcpy(tmpConsole, "/dev/");safe_strncpy(tmpConsole + 5, id,sizeof(tmpConsole) - 5);id = tmpConsole;}new_init_action(a->action, command, id); //解析完后执行new_init_actionbreak;}}if (a->name == 0) {/* Choke on an unknown action */message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);}}
分析 new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);# define VC_2 "/dev/tty2"#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"new_init_action(ASKFIRST, "-/bin/sh","/dev/tty2");static void new_init_action(int action, const char *command, const char *cons){struct init_action *new_action, *a, *last;if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))return;/* Append to the end of the list */for (a = last = init_action_list; a; a = a->next) {/* don't enter action if it's already in the list,* but do overwrite existing actions */if ((strcmp(a->command, command) == 0)&& (strcmp(a->terminal, cons) == 0)) {a->action = action;return;}last = a;}new_action = xzalloc(sizeof(struct init_action));if (last) {last->next = new_action;} else {init_action_list = new_action;}strcpy(new_action->command, command);new_action->action = action;strcpy(new_action->terminal, cons);messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",new_action->command, new_action->action, new_action->terminal);}
总结:
第一步:new_init_action创建一个init_action结构,填充
第二步:把new_init_action放入init_action_list链表
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) {/* a->terminal of "" means "init's console" */if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {delete_init_action(a);} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {waitfor(a, 0);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);}}}}}
waitfor(a, 0); ---->执行应用程序,等待程序执行完毕
run(a)--->创建process子进程
waitpid(runpid, &status, 0); --->等待结束
static int waitfor(const struct init_action *a, pid_t pid){int runpid;int status, wpid;runpid = (NULL == a)? pid : run(a);while (1) {wpid = waitpid(runpid, &status, 0);if (wpid == runpid)break;if (wpid == -1 && errno == ECHILD) {/* we missed its termination */break;}/* FIXME other errors should maybe trigger an error, but allow* the program to continue */}return wpid;}
delete_init_action(a); ---->在init_action_list链表中删除
init的步骤
第一步:配置文件
配置文件:/dev/console ---> /dev/null ----> /etc/initab ---> 配置文件里指定的应用程序 ---> C库
init本身即busybox
四、编译busybox
1、解压:jar xjf busybox-1.7.0.tar.bz2
2、打开busybox-1.7.0文件夹下的INSTALL文件,可以看到一些编译的教程
Building:
=========
The BusyBox build process is similar to the Linux kernel build:
make menuconfig # This creates a file called ".config"
make # This creates the "busybox" executable
make install # or make CONFIG_PREFIX=/path/from/root install
The full list of configuration and install options is available by typing:
make help
3、执行make menuconfig生成配置文件
因为是给Linux开发板编译的,所以需要用到交叉编译工具
打开Makefile,搜索CROSS,定位到下面代码并进行更改
原代码
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
更改后
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=arm-linux-
4、配置完成后执行make
5、make完成后,千万不要使用make install ,它会加载到PC上去,破坏PC
创建一个文件夹:mkdir -p /work/nfs_root/first_fs
安装到这个文件夹里面: make CONFIG_PREFIX=/work/nfs_root/first_fs install
6、跳转到/work/nfs_root/first_fs查看:cd /work/nfs_root/first_fs
ls -l