• Busybox实践2:分析busybox文件链接原理并编程模拟实现自己的busybox文件


    推荐一个零声学院免费教程,个人觉得老师讲得不错,
    分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
    fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
    TCP/IP,协程,DPDK等技术内容,点击立即学习:

    目录

    前言

        一 busybox文件原理    

            基本原理

            验证一下

            验证1 删掉ls命令:        

            验证2 自己创建一个ls的链接:

    二 用代码来证明原理

    1 先写一个普通的小程序

    2 创建链接,见证奇迹

    三 模拟一个busybox

    1 编写模拟busybox程序代码

    2 运行验证

           1) 验证lk命令        

            2)验证hg命令        

    四 将我的命令lk和hg添加到PATH环境变量

    添加PATH环境变量

    开始验证了

    总结


    前言

            书接上文,前一节已经成功构建了一个最简单的根文件系统,并且在根文件系统中运行了一个静态编译的C程序。本文编写一个busybox模拟程序,来说明busybox文件的实现原理。

        一 busybox文件原理    

            为什么busybox一个文件可以链接成为那么多命令呢

            基本原理

            根据查看BusyBox源码,发现里面有很多xxx_main函数,BusyBox根文件系统运行时,输入的命令,如ls,是以argv[0]的形式,传递给BusyBox的终端交互程序,也就是说,我们输入的这个地方本身就是一个程序,如下所示,它处理我们输入的数据,例如我们输入ls,它就处理ls。

    1. Please press Enter to activate this console.
    2. / #

    如何找的呢,分两步:

    1)它先去PATH对应的环境变量找,找到ls

    2)发现ls是被链接到busybox文件,然后将ls名字传递给busybox文件,busybox文件会接收ls这个参数,并调用相应的ls_main函数,就顺利执行了ls命令

            验证一下

            验证1 删掉ls命令:        

    1. / # which ls
    2. /bin/ls
    3. / # rm /bin/ls
    4. / # ls
    5. -/bin/sh: ls: not found
    6. / # ls

            现在,ls命令已经被删除,且执行时-/bin/sh: ls: not found,说明,并没有去直接执行busybox,这个还是很关键的。这说明即便是busybox自带的命令也要受PATH环境变量的约束。

            验证2 自己创建一个ls的链接:

    如下所示,先验证ls确实不存在,然后创建一个指向busybox的链接,并命名为ls,然后进入根目录,再次测试ls命令,结果证明,ls确实是指向busybox的链接,并且仅仅是一个普通的链接,没有没有什么特别之处,特别的是busybox对于命令行参数的处理,有机会我们也写一个自己的busybox小程序试试。

    1. / # cd bin/
    2. /bin # ls
    3. -/bin/sh: ls: not found
    4. /bin # ln -s busybox ls
    5. / # ls
    6. app bin etc linuxrc sbin test.sh usr
    7. arm_app dev hello.c proc sys tmp var
    8. / #

    二 用代码来证明原理

    这个自己做出来以后才发现,真相原理一直就在眼前,只是我们一直把它神话了。

    1 先写一个普通的小程序

    代码如下所示:保存命名为main.c

    1. #include
    2. int main(int argc,char *argv[])
    3. {
    4. int i = 0;
    5. for(i = 0;i < argc;i++){
    6. printf("argv[%d] = %s .\n",i,argv[i]);
    7. }
    8. return 0;
    9. }

    编译测试

    1. lkmao@ubuntu:~$ gcc main.c -o busy
    2. lkmao@ubuntu:~$ ./busy
    3. argv[0] = ./busy .

    看输出结果,argv[0]是程序名,是busy。

    2 创建链接,见证奇迹

            首先我创建了一个指向busy的链接,命名为lk,

    lkmao@ubuntu:~$ ln -s busy lk
    

    然后执行lk,见证结果啦

    1. lkmao@ubuntu:~$ ./lk
    2. argv[0] = ./lk .

    看到了吧。基本原理就是这样了。

    三 模拟一个busybox

    1 编写模拟busybox程序代码

            修改main.c文件,并重命名为busy.c的代码如下所示:

    1. #include
    2. #include
    3. #define debug(format,...) printf("%s:%s:%d - "format"\n",\
    4. __FILE__,__func__,__LINE__,##__VA_ARGS__);
    5. int main(int argc,char *argv[])
    6. {
    7. int i = 0;
    8. char *cmd;
    9. for(i = 0;i < argc;i++){
    10. debug("argv[%d] = %s .",i,argv[i]);
    11. }
    12. if(argv[0][0] == '.' && argv[0][1] == '/'){
    13. cmd = &argv[0][2];
    14. }else{
    15. cmd = &argv[0][0];
    16. }
    17. if(strcmp("lk",cmd) == 0){
    18. debug("i'm comand lk");
    19. return 0;
    20. }
    21. if(strcmp("hg",cmd) == 0){
    22. debug("i'm comand hg");
    23. return 0;
    24. }
    25. debug("unknown cmd %s",cmd);
    26. debug("do you want \"lk\" or \"hg\"");
    27. return 0;
    28. }

    编译,然后创建相应的链接文件lk和hg。

    1. lkmao@ubuntu:~$ gcc busy.c -o busy
    2. lkmao@ubuntu:~$ ln -s busy lk
    3. lkmao@ubuntu:~$ ln -s busy hg

    2 运行验证

           1) 验证lk命令        

    1. lkmao@ubuntu:~$ ./lk
    2. busy.c:main:11 - argv[0] = ./lk .
    3. busy.c:main:19 - i'm comand lk
    4. lkmao@ubuntu:~$

            2)验证hg命令        

    1. lkmao@ubuntu:~$ ./hg
    2. busy.c:main:11 - argv[0] = ./hg .
    3. busy.c:main:24 - i'm comand hg
    4. lkmao@ubuntu:~$

    好了,执行成功。

    四 将我的命令lk和hg添加到PATH环境变量

    添加PATH环境变量

    创建文件夹mycmd,将文件busy lk hg都放进去

    1. lkmao@ubuntu:~$ mkdir mycmd
    2. lkmao@ubuntu:~$ mv busy lk hg mycmd/
    3. lkmao@ubuntu:~$

    然后通过export命令将mycmd放到PATH环境变量中

    1. lkmao@ubuntu:~$ export PATH=${PATH}:/home/lkmao/mycmd
    2. lkmao@ubuntu:~$ echo $PATH
    3. /home/lkmao/bin:/home/lkmao/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin:/home/lkmao/mycmd
    4. lkmao@ubuntu:~$

    从PATH的值可知,我们已经将/home/lkmao/mycmd添加到了PATH的尾部。

    开始验证了

    验证lk

    1. lkmao@ubuntu:~$ lk
    2. busy.c:main:11 - argv[0] = lk .
    3. busy.c:main:19 - i'm comand lk

    验证hg

    1. lkmao@ubuntu:~$ hg
    2. busy.c:main:11 - argv[0] = hg .
    3. busy.c:main:24 - i'm comand hg

    验证完毕,结果OK.

    总结

            其实这个原理并不复杂,甚至也可以说简单,只是我们把busybox神话了,神话到不敢去探究它的真面目,发现真相的那一刻我惊呆了,这感觉,有点酸爽啊。

  • 相关阅读:
    基于量子随机游走的图像加密算法
    极智AI | TensorRT Parser 构建模型推理方法
    程序员找不到工作,先去外包过渡2年?千万别去
    Roreg复现
    【Vue篇】mac上Vue 开发环境搭建、运行Vue项目(保姆级)
    通过java实体类逆向生成sql
    MongoDB聚合运算符:$bsonSize
    Uni-App中的u-datetime-picker时间选择器Demo
    【Docker】Docker Swarm介绍与环境搭建
    ElementUI基本介绍及登录注册案例演示
  • 原文地址:https://blog.csdn.net/yueni_zhao/article/details/126591774