当前位置: 首页 > news >正文

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

https://ke.qq.com/course/417774?flowToken=1010783

目录

前言

    一 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。

Please press Enter to activate this console.
/ #

如何找的呢,分两步:

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

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

        验证一下

        验证1 删掉ls命令:        

/ # which ls
/bin/ls
/ # rm /bin/ls
/ # ls
-/bin/sh: ls: not found
/ # ls

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

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

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

/ # cd bin/
/bin # ls
-/bin/sh: ls: not found
/bin # ln -s busybox ls
/ # ls
app      bin      etc      linuxrc  sbin     test.sh  usr
arm_app  dev      hello.c  proc     sys      tmp      var
/ #

二 用代码来证明原理

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

1 先写一个普通的小程序

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

#include <stdio.h>

int main(int argc,char *argv[])
{
    int i = 0;
    for(i = 0;i < argc;i++){
        printf("argv[%d] = %s .\n",i,argv[i]);
    }
    return 0;
}

编译测试

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

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

2 创建链接,见证奇迹

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

lkmao@ubuntu:~$ ln -s busy lk

然后执行lk,见证结果啦

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

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

三 模拟一个busybox

1 编写模拟busybox程序代码

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

#include <stdio.h>
#include <string.h>

#define debug(format,...)   printf("%s:%s:%d - "format"\n",\
    __FILE__,__func__,__LINE__,##__VA_ARGS__);
int main(int argc,char *argv[])
{
    int i = 0;
    char *cmd;
    for(i = 0;i < argc;i++){
        debug("argv[%d] = %s .",i,argv[i]);
    }
    if(argv[0][0] == '.' && argv[0][1] == '/'){
        cmd = &argv[0][2];
    }else{
        cmd = &argv[0][0];
    }
    if(strcmp("lk",cmd) == 0){
        debug("i'm comand lk");
        return 0;
    }

    if(strcmp("hg",cmd) == 0){
        debug("i'm comand hg");
        return 0;
    }
    debug("unknown cmd %s",cmd);
    debug("do you want \"lk\" or \"hg\"");
    return 0;
}

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

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

2 运行验证

       1) 验证lk命令        

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

        2)验证hg命令        

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

好了,执行成功。

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

添加PATH环境变量

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


lkmao@ubuntu:~$ mkdir mycmd
lkmao@ubuntu:~$ mv busy lk hg mycmd/
lkmao@ubuntu:~$

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

lkmao@ubuntu:~$ export PATH=${PATH}:/home/lkmao/mycmd
lkmao@ubuntu:~$ echo $PATH
/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
lkmao@ubuntu:~$

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

开始验证了

验证lk

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

验证hg

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

验证完毕,结果OK.

总结

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

相关文章:

  • 12030.LMK03000时钟合成器
  • el-table表格进行排序 清除排序和清除排序箭头的高亮图标
  • 5G网络用户面时延测量
  • StreamSets解析MySQL Binlog写入Kafka
  • android开发获取View坐标位置的几种方式
  • antv x6连线与取消连线的操作+自定义连接桩+节点选择/框选
  • TIA博途V17中ProDiag功能的使用方法示例(一)PLC数据类型的监控
  • 面试常见场景题智力题概率题
  • 【顶顶通呼叫中心中间件(mod_cti 基于 FreeSWITCH)-拨号方案和路由配置】
  • M1Mac使用UTM虚拟机最小化安装x86_64架构的Archlinux
  • sql2java:WhereHelper基于Beanshell(bsh)动态生成SQL语句
  • 谷歌推广详细教程,Google Ads广告投放指南
  • 蔡甸17万亩粮田丰收 国稻种芯:夏汛蓄洪水护住28天抗旱期
  • 比赛团队队名及口号
  • MECT4CNER 代码遇到的问题
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【笔记】你不知道的JS读书笔记——Promise
  • canvas 绘制双线技巧
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JS+CSS实现数字滚动
  • Laravel Telescope:优雅的应用调试工具
  • Mybatis初体验
  • storm drpc实例
  • webpack+react项目初体验——记录我的webpack环境配置
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 工作中总结前端开发流程--vue项目
  • 开源地图数据可视化库——mapnik
  • 判断客户端类型,Android,iOS,PC
  • 如何胜任知名企业的商业数据分析师?
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 我这样减少了26.5M Java内存!
  • 学习使用ExpressJS 4.0中的新Router
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 用jQuery怎么做到前后端分离
  • 1.Ext JS 建立web开发工程
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​ArcGIS Pro 如何批量删除字段
  • ​如何在iOS手机上查看应用日志
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #QT(TCP网络编程-服务端)
  • (007)XHTML文档之标题——h1~h6
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (C语言)fread与fwrite详解
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (javascript)再说document.body.scrollTop的使用问题
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (一)kafka实战——kafka源码编译启动
  • (转)http协议
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)socket Aio demo
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。