busybox(一)浅析

目录

  • busybox(一)浅析

    • 引入
    • 读取inittab
    • 创建执行脚本链表
    • 执行脚本
    • 小结


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库

原文地址:https://www.cnblogs.com/zongzi10010/p/10023707.html

时间: 2024-10-12 11:03:59

busybox(一)浅析的相关文章

busybox(三)最小根文件系统

目录 busybox(三)最小根文件系统 引入 构建终端 构造inittab 配置应用程序 构建C库 制作映像文件yaffs title: busybox(三)最小根文件系统 tag: arm date: 2018-11-14 17:57:08 --- busybox(三)最小根文件系统 引入 在busybox(一)浅析中,得出结论,一个最小的根文件系统需要以下几个元素 dev/console dev/null sbin/init-------------busybox提供,至少需要这个应用程序

Busybox构建根文件系统和制作Ramdisk

定制根文件系统的方法很多,最常用的是使用BusyBox来构建定制根文件系统.它集成压缩了Linux的许多工具和命令,可以使用户迅速方便地建立一套相对完整.功能丰富的文件系统,其中包括大量常用的应用程序.下面详细介绍有关Busybox定制根文件系统. 一.系统环境: 1.操作系统:Ubuntu140.4 2.交叉编译工具:gcc version 6.1.1 20160711 (Linaro GCC 6.1-2016.08) 3.busybox源码包:busybox-1.26.2 二.构建rootf

Python之encode与decode浅析

 Python之encode与decode浅析 在 python 源代码文件中,如果你有用到非ASCII字符,则需要在文件头部进行字符编码的声明,声明如下: # code: UTF-8 因为python 只检查 #.coding 和编码字符串,为了美观等原因可以如下写法: #-*-coding:utf-8-*- 常见编码介绍: GB2312编码:适用于汉字处理.汉字通信等系统之间的信息交换. GBK编码:是汉字编码标准之一,是在 GB2312-80 标准基础上的内码扩展规范,使用了双字节编码.

浅析PHP的开源产品二次开发的基本要求

浅析PHP的开源产品二次开发的基本要求 第一, 基本要求:HTML(必须要非常熟悉),PHP(能看懂代码,能写一些小系统,如:留言板,小型CMS),Mysql(至少会一种数据库),Javascript(能看懂,能改现成的一些代码),Div+Css(能进行界面的调整,明白CSS是怎么使用的) 第二, 熟悉开源产品的使用,比如 Dedecms,你要知道怎么登录,怎么新建栏目,怎么添加文章,模板标签的使用方法,模型的概念和使用方法等等一些功能 第三, 要熟悉这个开源产品的数据库结构,还要理解里面核心文

word-break|overflow-wrap|word-wrap——CSS英文断句浅析

---恢复内容开始--- word-break|overflow-wrap|word-wrap--CSS英文断句浅析 一 问题引入 今天在再次学习 overflow 属性的时候,查看效果时,看到如下结果,内容在 div 中国换行了,可是两个 P 元素的内容并没有换行,搜索一番没有找到系统的答案,截图到群里请教大神,才知道是英文断句的问题,但是还是不太明白.之前没有遇到这种情况,为了彻底搞清楚,英文断句,又开始学习英文断句到底是怎么回事. 二 换行 每种语言里都有换行,就中文而言,我们最小语言单位

浅析vanish

浅析 VANISH --一种cache 第一部分:理解vanish的准备工作 1.对CDN的小剖析 CDN  content  delivery  network  内容分发(推送)网络,是在现有的Internet中增加一层新的网络架构,将网络内容发布到最接近用户的网络边缘(边缘服务器),使用户最近取得所需内容,解决网络拥挤状态,提高用户访问网站的速度. CDN网络架构主要有两部分组成,中心和边缘两部分,中心指CDN网管中心和DNS重定向解析中心,负责全局负载均衡.边缘主要指异地节点,CDN分发

使用busybox制作rootfs

Build Busybox as a static binary(no shared libs),如果选择上,则busybox将以静态形式进行编译,否则将以动态方式编译.此外,还需要对交叉编译环境进行配置,选择其中的Cross Compiler Perfix,输入交叉编译器的前缀,我们的嵌入式平台上使用的是arm-uclinux-linu TAG: busybox  rootfs 1  获取源码解压 从busybox的官方主页http://www.busybox.net ,下载busybox的源

健康,home? [java的内存浅析]

健康,home? [java的内存浅析] 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 乐观上上,how can other kno u,u r yourself!I must be strong and carry on. -泥沙砖瓦浆木匠 一.闲谈下 201407月记着那时候身体垮了下来,呵呵.想说,对自己的说,也是对大家的负责吧.那时候胸疼胸闷,然后几乎累垮了,我还坚持了一星期,那一星期真的迷迷糊糊.完全不能

Mysql查询优化器浅析

--Mysql查询优化器浅析 -----------------------------2014/06/11 1 定义 Mysql查询优化器的工作是为查询语句选择合适的执行路径.查询优化器的代码一般是经常变动的,这和存储引擎不太一样.因此,需要理解最新版本的查询优化器是如何组织的,请参考相应的源代码.整体而言,优化器有很多相同性,对mysql一个版本的优化器做到整体掌握,理解起mysql新版本以及其他数据库的优化器都是类似的. 优化器会对查询语句进行转化,转化等价的查询语句.举个例子,优化器会将