目录

  • busybox(一)浅析
  • 引入
  • 读取inittab
  • 创建执行脚本链表
  • 执行脚本
  • 小结

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 idchar 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为0a->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 busybox(三)最小根文件系统 引入 在busybox(一)浅析中,得 ...

  2. 构建根文件系统之busybox(四)完善

    目录 busybox(四)完善 proc挂载 手动挂载 proc解析 使用脚本自动挂载 使用mount-a挂载 udev/mdev 挂载 使用jffs2 文件系统格式 安装zlib 安装jffs2 生 ...

  3. 构建根文件系统(2)Busybox init 进程

    讲init进程的启动过程从/etc/inittab出发. 内核启动init进程时已经打开/dev/console设备作为控制台,一般情况下Busybox init程序就使用/dev/console, ...

  4. 构建根文件系统之busybox(二)编译

    目录 busybox(二)编译 busybox(二)编译 1.解压,源码包在busybox-1.7.0.tar.bz2, tar xjf busybox-1.7.0.tar.bz2 cd busybo ...

  5. 韦东山衔接班——4.3_构建根文件系统之busybox

    作者:GWD 时间:2019.8.26 注:Linux中交叉编译用CROSS开头 配置编译busybox 1.解压busybox 2.make menuconfig出现配置菜单 在readme或者in ...

  6. 2.3【Linux系统移植之三】:使用BusyBox构建根文件系统(rootfs)

    文章目录 一.搭建NFS服务器 二.使用BusyBox构建跟文件系统 2.1 修改顶层Makefile 2.2 busybox中文支持 2.3 配置busybox 2.4 编译busybox 2.5 ...

  7. 【ARM】使用Busybox构建根文件系统

    Busybox构建根文件系统 介绍 下载 配置busybox 配置交叉编译器 取消静态库编译 添加vi命令的支持 取消简化模块 支持mdev 中文支持 编译 完善根文件系统 创建必要文件夹 复制库 启 ...

  8. 教你用 buildroot 构建根文件系统

    如果想要构建完整的根文件系统,大家一般都是使用buildroot,它不仅包含了 busybox 的功能,而且里面还集成了各种软件,需要什么软件就选择什么软件,不需要我们去移植. 嵌入式系统三大部分:b ...

  9. 构建根文件系统(一)

    接着前边内核移植的文章,记录根文件系统的构建. 这里要用到强大的busybox,我选择的版本是busybox-1.18.5.tar.bz2 ,1.17的也可以:之所以选择这个版本是因为基于现在的交叉编 ...

最新文章

  1. MM--发票校验 及基于采购订单的MIRO发票校验过程
  2. linux光盘补救,Linux_忘记root密码时使用Linux系统光盘进行补救的方法,救援模式即rescue ,这个模式主 - phpStudy...
  3. .NET技术之美-网络编程
  4. python作业:高级FTP程序
  5. Angular常用命令行和指令
  6. 成员变量(全局变量)和局部变量区别
  7. 外卖和快递行业数据_外卖和快递骑手管理“上轨道”
  8. 14个非常棒的 JavaScript 游戏开发框架推荐
  9. vsftpd配置好防火墙后从网页登录ftp却无法访问此页面
  10. 兄弟们,请求支援,怎么实现互通,全部都互通的
  11. StringBuffer 的 各种方法
  12. mysql提高count_mysql count提高方法总结
  13. javascript中Object类原型对象的属性和方法
  14. easyui 提示框组件_jQuery EasyUI 教程-Tooltip(提示框)
  15. 构造c语言的上下文无关文法,正则文法和上下文无关文法
  16. C++多线程并发(五)---原子操作与无锁编程
  17. python requests 代理ip被禁_python requests 测试代理ip是否生效
  18. 中山c 语言培训中心,中山英语口语培训中心
  19. [扩欧]JZOJ 5855 吃蛋糕
  20. 机械键盘改罗技优联无线键盘

热门文章

  1. luoguP1354房间最短路问题
  2. Codeforces Round #297 (Div. 2)C. Ilya and Sticks 贪心
  3. scrum 11.8
  4. 安装两个硬盘时应如何跳线?
  5. UA MATH571A QE练习 R语言 非参数回归 上
  6. FFT和Matlab中操作FFT
  7. 特征和工具概览(SQL Server 2008)
  8. C++ boost 实例学习
  9. BurpSuite pro v2.0.11版
  10. 使用Dockerfile制作镜像