zoukankan      html  css  js  c++  java
  • 制作根文件系统之Busybox init进程的启动过程分析

    先来介绍一下什么是Busybox:它是将众多的UNIX命令集合进一个很小的可执行程序中。

    制作根文件系统之内核如何启动init进程中遗留了一个问题是/linuxrc是内核启动的第一个应用程序,那么它是什么?我们看到移植好的根文件系统环境,输入ls -al /linuxrc。可以看到:

    lrwxrwxrwx    1 1000     1000           11 Jul 26  2018 linuxrc -> bin/busybox

    /linuxrc其实是指向Busybox的,它其实是Busybox下的一个程序,所以我们需要分析Busybox的源码来研究/linuxrc这个程序做的事情,当在移植好的根文件系统环境下输入/linuxrc可以看到:

    # busybox linuxrc
    init started: BusyBox v1.7.0 (2018-07-26 12:50:40 CST)
    starting pid 796, tty '': '/etc/init.d/rcS'
    
    Please press Enter to activate this console.

    这就是执行linuxrc程序之后出现的界面,现在还不确定/linuxrc是Busybox下哪个文件,我们搜索“init started”,在busybox-1.7.0initInit.c中找到了它

    935    message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner);

    我们看到调用它的是init_main函数,接下去就是分析这个函数,init_main函数的功能大概可以概括为

    1、设置处理信号函数

    2、读取配置文件、解析配置文件

    3、根据配置文件执行用户的程序或脚本

    下面分别介绍

    1、设置处理信号函数,restart, ctrlaltdel, and shutdown是一些按键事件,这些处理函数在接收到按下相关按键的信号后,进行处理

    905        signal(SIGHUP, exec_signal);
    906        signal(SIGQUIT, exec_signal);
    907        signal(SIGUSR1, shutdown_signal);
    908        signal(SIGUSR2, shutdown_signal);
    909        signal(SIGINT, ctrlaltdel_signal);
    910        signal(SIGTERM, shutdown_signal);
    911        signal(SIGCONT, cont_handler);
    912        signal(SIGSTOP, stop_handler);
    913        signal(SIGTSTP, stop_handler);

    2、读取和解析配置文件,先看一下配置文件的格式,文档位于example/inittab中

    # inittab的格式为:
    # <id>:<runlevels>:<action>:<process>
    # id => /dev/id,用作终端:stdin、stdout、stderr:printf、scanf、err
    # runlevels:忽略
    # action     :执行时机Valid actions include: sysinit, respawn, askfirst, wait, once,
                                                  restart, ctrlaltdel, and shutdown.
    # process   :应用程序或脚本

    接着回到init_main函数,看到

    967    parse_inittab();//解析inittab参数

    找到parse_inittab函数,位于busybox-1.7.0initInit.c中

    755    static void parse_inittab(void)
    756    {
                ...
                ...
    764            file = fopen(INITTAB, "r");//以只读方式打开/etc/inittab    
                ...
    788            while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
                    ...
    836                        for (a = actions; a->name != 0; a++) {
    837                            if (strcmp(a->name, action) == 0) {
    838                                if (*id != '') {
    839                                    if (strncmp(id, "/dev/", 5) == 0)//去掉开头的/dev/
    840                                        id += 5;
    841                                    strcpy(tmpConsole, "/dev/");
    842                                    safe_strncpy(tmpConsole + 5, id,
    843                                        sizeof(tmpConsole) - 5);
    844                                    id = tmpConsole;
    845                                }
    846                                new_init_action(a->action, command, id);//创建一个init_action结构,以解析出来的参数填充它,然后将这个结构放入init_action_list链表
    847                                break;
    848                            }
    849                        }
                    ...
                    }
    857    }

    这个函数的功能解释为打开/etc/inittab文件然后处理它,这个文件是以配置文件的格式存放的。看到函数最后会创建一个init_action结构,这个结构就是将配置文件里的内容一个个取出来,然后放在里面。最后链接到init_action_list链表中

    72    struct init_action {
    73        struct init_action *next;
    74        int action;
    75        pid_t pid;//进程号  by andy
    76        char command[INIT_BUFFS_SIZE];//要执行的脚本命令
    77        char terminal[CONSOLE_NAME_SIZE];//终端
    78    };

    这里再举个例子,下面是某个配置文件。以第一个为例子。action为askfirst执行时机;command为执行的命令或脚本为-/bin/sh;terminal为使用的中断为console

    console::askfirst:-/bin/sh
    ::sysinit:/etc/init.d/rcS

    3、根据配置文件执行用户的程序或脚本

    接着看到,每个执行时机执行的内容,以下均为简写。

    busybox-> init_main
            parse_inittab 
                file = fopen(INITTAB, "r");//打开配置文件/etc/inittab
                new_init_action    //a、创建一个init_action结构,填充
                        //b、将这个结构放入init_action_list链表
            run_actions(SYSINIT);
                waitfor(a, 0);             //执行应用程序,等待它执行完毕
                    run(a)       //创建process子进程
                    waitpid(runpid, &status, 0);//等待它结束
                delete_init_action(a);//在init_action_list链表里删除
            run_actions(WAIT);
                waitfor(a, 0);             //执行应用程序,等待它执行完毕
                    run(a)       //创建process子进程
                    waitpid(runpid, &status, 0);//等待它结束
                delete_init_action(a);//在init_action_list链表里删除
            run_actions(ONCE);
                run(a);                       //创建process子进程
                delete_init_action(a);//在init_action_list链表里删除
            while(1)   {
                run_actions(RESPAWN);
                    if (a->pid == 0) {
                        a->pid = run(a);
                    }
                run_actions(ASKFIRST);
                    if (a->pid == 0) {
                        a->pid = run(a);
                            打印:Please press Enter to activate this console.
                            等待回车
                            创建子进程
                    }
                wpid = wait(NULL);//等待子进程退出
                while (wpid > 0) {
                a->pid = 0;//退出后就设置pid=0
                   }
            其余三个restart, ctrlaltdel, and shutdown执行时机在按下按键的时候发生事件
            }

    大致总结一下每个执行时机:

    SYSINIT:第一个执行,创建子进程,等待进程结束,将它从init_action_list链表里删除

    WAIT:第二个执行,创建子进程,等待进程结束,将它从init_action_list链表里删除

    ONCE:第三个执行,创建子进程,将它从init_action_list链表里删除

    RESPAWN:循环执行

    ASKFIRST:循环执行,打印:Please press Enter to activate this console,等待回车后,创建子程序-/bin/sh,就不再返回了

    restart, ctrlaltdel, and shutdown:在按键按下的时候随时执行

    这样就分析完了Busybox的init程序,ASKFIRST时机相关的脚本或命令执行以后,因为脚本有-/bin/sh,所以最终会进入sh进程。它位于shellAsh.c下的ash_main函数,这个函数就不分析了。到这里从uboot开始一直到根文件系统下的第一个用户程序全部分析完成。

  • 相关阅读:
    【GIS】Vue、Leaflet、highlightmarker、bouncemarker
    【PHP】xampp配置多个监听端口和不同的网站目录(转)
    【ArcGIS】栅格分析-问题之001(转)
    java登录央行征信网站
    登录中国人民银行征信中心
    爬取百度百科上中国所有城市的信息
    pycharm pro版本激活
    一种爬虫架构分享
    中国联通短信验证码
    中国联通通话记录、身份认证、上网记录等信息
  • 原文地址:https://www.cnblogs.com/andyfly/p/9419359.html
Copyright © 2011-2022 走看看