title: busybox(一)浅析

tag: arm

date: 2018-11-13 23:02:33

busybox(一)浅析

源码包在busybox-1.7.0.tar.bz2,一个命令对应着一个c文件,执行init命令,则是有init.c,有函数init_main

int init_main(int argc, char **argv);

最终的目的是启动客户的应用程序,需要指定具体的环境

1. 配置文件读取
2. 解析配置文件
3. 执行用户程序

help

相关的帮助可以搜索下/examples下的文件,比如搜索inittab,里面有相关说明

#define SYSINIT     0x001		//执行一次等待结束后从链表删除
#define RESPAWN 0x002 //while循环执行
#define ASKFIRST 0x004 //while循环执行,会打印信息,等待回车
#define WAIT 0x008 //执行一次等待结束后从链表删除,在SYSINIT后
#define ONCE 0x010 //与SYSINIT 区别在于不等待其执行结束
#define CTRLALTDEL 0x020 //输入信号后执行
#define SHUTDOWN 0x040 //输入信号后执行
#define RESTART 0x080 //输入信号后执行

流程图

引入

init_main函数入口分析,Linux 是按照run_init_process("/sbin/init");形式调用,没有传递参数,所以执行else分支,解析配置表

if (argc > 1
&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
) {
/* Start a shell on console */
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
/* Not in single user mode -- see what inittab says */ /* NOTE that if CONFIG_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();
}

读取inittab

parse_inittab();读取inittab配置表,可以搜索下example下查看例子帮助,查阅如下格式

Format for each entry: <id>:<runlevels>:<action>:<process>
<id>: WARNING: This field has a non-traditional meaning for BusyBox init!
<runlevels>: The runlevels field is completely ignored.
<action>: Valid actions include: sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, and shutdown.
<process>: Specifies the process to be executed and it's command line.
标识 作用
id 自动加上/dev/的前缀,用作终端,stdin,stdout,stderr:printf,scanf,err 可以省略
runlevels 可以忽略
action 指示何止执行
process 应用程序或者可执行脚本

最终执行new_init_action运行脚本程序

默认的配置表读取

#define INITTAB      "/etc/inittab"	/* inittab file location */
static void parse_inittab(void)

file = fopen(INITTAB, "r");

创建执行脚本链表


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);
break;
}
}

当不存在这个配置表的时候也会有一个默认配置文件,这里以默认的其中一个脚本解析

new_init_action(ASKFIRST, bb_default_login_shell, VC_2);

# define VC_2 "/dev/tty2"
#define ASKFIRST 0x004
const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"

也就是最终执行

new_init_action(ASKFIRST, "-/bin/sh", "/dev/tty2");
ASKFIRST 执行的时机
-/bin/sh 脚本程序
/dev/tty2 id终端,加上了/dev/,符合上述描述

分析下new_init_action函数内部,

  1. 创建 init_action结构,包含inittab中的信息
  2. 加入到init_action_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;
} struct init_action {
struct init_action *next;
int action;
pid_t pid; //对应进程id, process id
char command[INIT_BUFFS_SIZE]; //对应应用程序
char terminal[CONSOLE_NAME_SIZE]; //对应终端
};

由此,可以理解当配置文件不存在的时候,会去创建配置表

	#define INITTAB      "/etc/inittab"	/* inittab file location */
file = fopen(INITTAB, "r"); if (file == NULL) {
/* No inittab file -- set up some default behavior */
/* 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;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>↓
创建类似的inittatb ↓
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>↓
::CTRLALTDEL:reboot
::SHUTDOWN:umount -a -r
::RESTART:init
::ASKFIRST:-/bin/sh:
tty2::ASKFIRST:-/bin/sh
tty3::ASKFIRST:-/bin/sh
tty4::ASKFIRST:-/bin/sh
::SYSINIT:/etc/init.d/rcS

执行脚本

脚本有多种类型,不同类型执行方式与时机不同

#define SYSINIT     0x001		//执行一次等待结束后从链表删除
#define RESPAWN 0x002 //while循环执行
#define ASKFIRST 0x004 //while循环执行,会打印信息,等待回车
#define WAIT 0x008 //执行一次等待结束后从链表删除,在SYSINIT后
#define ONCE 0x010 //与SYSINIT 区别在于不等待其执行结束
#define CTRLALTDEL 0x020 //输入信号后执行
#define SHUTDOWN 0x040 //输入信号后执行
#define RESTART 0x080 //输入信号后执行
run_actions(SYSINIT);
waitfor(a, 0);//执行a,等待执行结束
run(a);//执行创建process子进程
waitpid(runpid, &status, 0);
delete_init_action(a);//删除链表
/* Next run anything that wants to block */
run_actions(WAIT);
waitfor(a, 0);//执行a,等待执行结束
run(a);//执行创建process子进程
waitpid(runpid, &status, 0);
delete_init_action(a);//删除链表
/* Next run anything to be run only once */
run_actions(ONCE);
run(a);
delete_init_action(a);
/* Now run the looping stuff for the rest of forever */
while (1) {//重新运行pid已经退出的子进程
run_actions(RESPAWN);
if (a->pid == 0) { //默认pid为0
a->pid = run(a);} run_actions(ASKFIRST);
if (a->pid == 0) {
a->pid = run(a);}
//打印"\nPlease press Enter to activate this console. ";,
//等待输入回车
//创建子进程
wpid = wait(NULL);//等待子进程退出
while (wpid > 0) {
a->pid--;//推出后pid=0
}
}
}

小结

  1. 打开终端 dev/console
  2. 打开dev/null ,用作不设置终端id的时候的定位
  3. 读取配置文件etc/inittab ,需要存在配置文件的可执行程序或者脚本
  4. 执行脚本

所以一个最小的根文件系统必备的一些资源

dev/console
dev/null
sbin/init-------------busybox提供,至少需要这个应用程序,这是linux启动的第一个应用程序
etc/inittab-----------配置文件,定义了一些应用程序
配置文件制定的应用程序----配置文件指定的应用程序
C库--------------------应用程序的C库

busybox(一)浅析的更多相关文章

  1. busybox(三)最小根文件系统

    目录 busybox(三)最小根文件系统 引入 构建终端 构造inittab 配置应用程序 构建C库 制作映像文件yaffs title: busybox(三)最小根文件系统 tag: arm dat ...

  2. 浅析busybox如何集成到openwrt

    背景 近日添加了一个包到openwrt中,在此过程中又对openwrt多了一些认识 这个包本身自带了kconfig,可直接在这个包里面执行make menuconfig进行配置,然后执行make 但要 ...

  3. 浅析手机抓包方法实践(zt)

    原文:http://drops.wooyun.org/tips/12467 0x00 摘要 在移动逆向分析以及 App 开发的时候,总会需要对其网络行为进行监控测试,本文总结一些抓包思路,并对其使用方 ...

  4. Linux 设备模型浅析之 uevent 篇(2)

    Linux 设备模型浅析之 uevent 篇 本文属本人原创,欢迎转载,转载请注明出处.由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@gma ...

  5. 浅析busybox-1.12.0中ash的脚本命令局限性

    浅析busybox-1.12.0中ash的脚本命令局限性 LUTHER= 表示将LUTHER清空,将其变为null echo ${LUTHER:-111}如果执行该句之前LUTHER变量不存在,那么显 ...

  6. 8.云原生之Docker容器镜像构建最佳实践浅析

    转载自:https://www.bilibili.com/read/cv15220861/?from=readlist 本章目录 0x02 Docker 镜像构建最佳实践浅析 1.Dockerfile ...

  7. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  8. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  9. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

随机推荐

  1. Android View相关知识问答

    Android View相关核心知识问答 Activity Window View之间的三角关系 你真的了解View的坐标吗? 在渲染前获取 View 的宽高 5种手势工具类 浅析Android的窗口

  2. Django 下载和初识

    Django Django官网下载页面 安装(安装最新LTS版): pip3 install django==1.11.9 创建一个django项目: 下面的命令创建了一个名为"mysite ...

  3. BZOJ2434 [NOI2011] 阿狸的打字机 【树链剖分】【线段树】【fail树】【AC自动机】

    题目分析: 画一下fail树,就会发现就是x的子树中属于y路径的,把y剖分一下,用线段树处理 $O(n*log^2 n)$. 代码: #include<bits/stdc++.h> usi ...

  4. 洛谷P4782 2-SAT问题

    2-SAT问题 这是一道2-SAT的模板题.对于2-SAT问题的每一个条件,我们需要把他们转化成可接受的条件.即"若变量A的赋值为x,则变量B的赋值为y",其中x,y均等于0或1. ...

  5. HBase电子书

    HBase 不睡觉书  https://pan.baidu.com/s/1d4u7pPAu_B3sW5w9x1ARdA HBase2018年年度总结 https://pan.baidu.com/s/1 ...

  6. Random Maze HDU - 4067(预定义状态建边(贪心建边))

    Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  7. 【XSY2716】营养餐 博弈论

    题目描述 给你一棵有根树,每个点有两个属性\(a,b\) 两人轮流操作,每次要减小一个点的\(a\)值,要求 \[ a_x\geq\sum_{i\in child(x)}a_ib_i \] 保证初始状 ...

  8. 【BZOJ1015】【JSOI2008】星球大战 并查集

    题目大意 给你一张\(n\)个点\(m\)条边的无向图,有\(q\)次操作,每次删掉一个点以及和这个点相邻的边,求最开始和每次删完点后的连通块个数. \(q\leq n\leq 400000,m\le ...

  9. Min_25

    可以用来筛出一个积性函数的前缀和.这个积性函数要满足当\(x\)是质数时,\(f(x)\)可以快速求出,\(f(x^k)\)也可以快速算出. 首先我们要处理出一个\(g(x)=\sum_{x\in p ...

  10. poj2373 Dividing the Path (单调队列+dp)

    题意:给一个长度为L的线段,把它分成一些份,其中每份的长度∈[2A,2B]且为偶数,而且不能在某一些区间内部切开,求最小要分成几份 设f[i]为在i处切一刀,前面的满足要求的最小份数,则f[L]为答案 ...