busybox最小Linux系统

news/2025/1/7 20:29:50/文章来源:https://www.cnblogs.com/normaldisk/p/18655627

环境

WSL(Ubuntu 22.04)

创建磁盘映像

可以使用fallocate为磁盘映像分配一块空间,或者使用dd if=/dev/zero of=$img bs=1M count=$size_in_MB直接得到一个大小为$size_in_MB大小的文件。

使用mkfs.ext4格式化映像文件,并使用mount -o loop $img mnt将文件挂载。

如果想要在磁盘映像中分区,则可以先使用fdiskcfdisk对磁盘映像进行分区,然后使用losetup -fP $img将文件挂载为回环设备。这里-f参数表示自动寻找可以挂载的回环设备号,-P参数表示探测文件中的分区并分别挂载为回环设备。挂载为回环设备后,再使用mount $loop1 $mnt1等命令挂载回环设备。

构建busybox

下载busybox源码并构建,这里使用的是busybox-1.36.1版本

这里采用的构建选项有

构建静态文件:

Symbol: STATIC [=y]
Prompt: Build static binary (no shared libs)Defined at Config.in:362Location:-> Settings

这个版本默认支持了Unicode,可以不用更改

Symbol: UNICODE_SUPPORT [=y]Prompt: Support UnicodeDefined at libbb/Config.in:311Location:-> Settings

添加了Unicode宽字符支持

Symbol: UNICODE_WIDE_WCHARS [=y]Prompt: Allow wide Unicode characters on outputDefined at libbb/Config.in:390Depends on: UNICODE_SUPPORTLocation:-> Settings-> Support Unicode (UNICODE_SUPPORT [=y])

其他构建选项均可以不更改

使用make构建后,再使用make install即可将完整的busybox、busybox符号链接等文件安装到busybox源码目录下的_install目录内。或者可以通过make install CONFIG_PREFIX=$install将busybox安装到指定目录中。比如这里我们可以使用make install CONFIG_PREFIX=$mnt将busybox安装到已经挂载的磁盘映像中。

构建Linux内核

下载Linux内核源码,这里使用Linux-6.12.7版本

根据自己喜好配置即可

创建rootfs

这里需要创建一个rootfs来作为Linux运行的环境。

查看busybox的安装目录可以发现,目前只有binsbinusr三个目录和linuxrc一个符号链接。对比我们自己的Linux根目录可以发现,我们大概有以下目录

bin boot dev etc home lib mnt opt proc root run sbin sys tmp usr var

那么我们在$mnt目录下创建这些目录即可。

由于mount需要sudo$mnt目录下的文件很可能是root权限,后面一系列操作可能都需要root权限。

现在可以chroot$mnt目录下试试能否使用shell。

运行虚拟机

这里我们使用qemu虚拟机。

将启动命令写成一个脚本

#!/bin/sh
/usr/bin/qemu-system-x86_64\-kernel path/to/bzImage\-hda path/to/rootfs.img\-nographic\-append "console=ttyS0 root=/dev/sda init=/linuxrc"
  • -kernel选项表示设置Linux kernel为bzImage
  • -hda选项表示选择磁盘映像
  • -nographic表示不使用qemu窗口,而是将输出重定向到终端
  • -append表示传递给Linux内核的参数
    • console=ttyS0表示将输出重定向到串口设备ttyS0,这将使qemu将启动阶段的信息输出到终端
    • root=/dev/sda表示根文件系统的位置,虚拟机中一般是sda
    • init=linuxrc表示使用linuxrc作为init进程,也就是Linux下的第一个进程启动,这个linuxrc其实就是我们的busybox

启动配置

此时如果直接运行脚本启动虚拟机可能会报错,因为我们没有配置busybox作为init进程时的行为。

linuxrc会读取/etc/inittab文件,我们将该文件配置如下

::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

该文件内每行有四个字段,格式为<id>:<runlevel>:<action>:<process>

  • <id>指编号,不重复即可
  • <runlevel>指运行级别,可以不指定,指定时表示运行级别为n时激活改行的规则
  • <action>包含一系列动作,表示对登记的<process>在一定条件下执行的动作
  • <process>即要运行的进程,前面加上-表示以交互方式运行

<action>包含以下动作

action 含义
respawn 当process终止后马上启动一个新的
wait 当进入指定的runlevels后process才会启动一次,并且到离开这个runlevels终止
initdefault 设定默认的运行级别,即我们开机之后默认进入的运行级别,不能是0,6,你懂的
sysinit 系统初始化,只有系统开机或重新启动的时候,这个process才会被执行一次
powerwait 当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,会等待这个进程完成之后,再执行相应的process
powerfail 当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,不会等待这个进程完成,它会直接执行相应的process
powerokwait 电源已经故障,但是在等待执行对应操作的时候突然来电了就执行对应的process
powerfailnow 当电源故障并且init被通知UPS电源已经快耗尽执行相对应的process
ctrlaltdel 当用户按下ctrl+alt+del这个组合键的时候执行对应的process
boot 只有在引导过程中,才执行该进程,但不等待该进程的结束;当该进程死亡时,也不重新启动该进程
bootwait 只有在引导过程中,才执行该进程,并等待进程的结束;当该进程死亡时,也不重新启动该进程
off 如果process正在运行,那么就发出一个警告信号,等待20秒后,再通过杀死信号强行终止该process。如果process并不存在那么就忽略该登记项
once 启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程死亡时,init也不重新启动该进程

inittab第一行表示在系统启动时,运行/etc/init.d/rcS脚本里的内容。这也是没有inittablinuxrc的默认动作。

接下来我们配置/etc/init.d/rcS脚本的内容

#!/bin/shPATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATHrunlevel=S
umask 022
export PATH LD_LIBRARY_PATH runlevel# devices
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
mount -o remount,rw /mdev -s

我们的脚本配置了环境变量,设备等,需要在系统启动时进行的配置,开启的服务,都可以在该文件中进行配置。

配置完成后一定要赋予/etc/init.d/rcS运行权限,否则启动过程中会报错。

此时启动虚拟机可以看到,我们已经进入了shell。

其他配置文件

虽然我们的Linux已经正常启动,但是不要高兴的太早。

我们在shell中执行export PS1='\u@\h \W',重新登陆,我们预期会显示root@host ~,但是,这里并没有我们的用户名和主机名。

此时我们执行idhostname命令会发现,我们现在虽然是uid=0 gid=0的用户,但是我们没有用户名,主机名也是(none)。执行ifconfig会发现,我们也没有可用网络。

接下来我们将进行这些方面的配置。

我们的Linux已经可以启动,而且busybox内置了vi作为编辑器,接下来的配置可以不通过宿主机,直接在虚拟机中完成。

用户配置

由于root用户本来就存在,我们不能用adduser创建用户,于是我们手动创建用户属性文件。

Linux通过识别/etc/passwd中的用户来判断用户名,我们手动创建这个文件。

添加以下内容

root:x:0:0::/root:/bin/sh

这个文件有7个字段,格式为<user>:<passswd>:<uid>:<gid>:<desc>:<home>:<shell>

其中<passwd>字段内容为加密后的密码,如果设为空则表示不需要密码也可以登录,如果为x表示密码存储在/etc/shadow文件中。

如果我们不创建/etc/shadow文件,passwd命令会将加密的密码存储在/etc/passwd中,所以我们打算创建一个/etc/passwd

我们的Linux和busybox都支持解析/etc/shadow文件,接下来我们手动创建这个文件。

添加以下内容

root::1::::::

这个文件内每行9个字段,格式为login:encyrptedpassword:lastchangedate:min_age:max_age:warning:inactivity:expiration_date:reserved,第一个字段为用户名,第二个字段为加密后的密码,如果为空会登录失败,为*!时情况不确定,Linux console上写*!表示没有密码,但实际测试后发现,为这两个符号时,busybox的login会提示bad salt

后面的几个字段都与密码修改时间有关,分别为

  • lastchange表示上次修改密码的日期的时间,如果该值为0,则表示用户下次登录时必须更改密码
  • minage表示更改密码的间隔日期,为空或为0表示随时可以更改密码
  • maxage表示必须更改密码的日期
  • warning表示在密码到期前n天警告用户需要更改密码
  • inactivity表示密码过期后,n天内可以再更改密码
  • expiration_date表示到期日期,到期后无法再登录
  • reserved最后一个字段为保留字段

有这个文件后我们就可以使用passwd命令更改密码,然后再查看/etc/shadow可以发现密码已经改变了。

然后我们就可以通过登录的方式进入操作系统。

更改/etc/inittab如下

::sysinit:/etc/init.d/rcS
::respawn:/sbin/getty -L console 0 vt100
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

这表示不直接打开一个shell,而是在console这个tty上打开一个login

主机配置

一般我们将主机名写在/etc/hostname中,但是busybox不自动读取这个文件。

于是我们添加配置到/etc/init.d/rcS

#!/bin/sh
...
# hostname
hostname -F /etc/hostname

这代表从/etc/hostname加载主机名

网络配置

同样在/etc/init.d/rcS中添加以下配置

# network
ifconfig lo up
ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up
route add default gw 192.168.1.1 eth0

ip地址随意填写,网关地址填写为qemu外部提供的网卡地址

网卡配置

在WSL中,需要创建一张虚拟网卡设备作为虚拟机的网关。

我们创建一张tap设备,向网卡配置脚本中写入以下内容

ip tuntap add dev tap0 mode tap
ip link set dev tap0 up
ip a add dev tap0 192.168.1.1/24
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.1/24 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward

这个脚本创建了一张tap0网卡,并分配了ip地址192.168.1.1,就是我们的虚拟机的网关地址。

iptables命令创建了一条nat规则,将内部发出的源地址为192.168.1.0/24网段的数据包改为从eth0发出,这样就可以让虚拟机连接到外部网络了。

此时进入虚拟机,执行ping 192.168.1.1发现有网络连接。

然后执行cat nameserver 8.8.8.8 > /etc/resolv.conf配置域名解析服务器。

此时执行ping www.baidu.com就可以ping通了。

由于busybox没有自带curl,执行echo -e "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n" | nc www.baidu.com 80代替,可以收到html网页内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/864994.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA-Day 06:if语句的三种形式

if语句的三种形式if(表达式){语句体}如果小括号里的表达式结果为真,则执行大括号中的语句体,如下图例子所示:2.if(表达式){语句体}else{语句体} 如果小括号里的表达式为真,则执行else前的大括号中的语句体,如果小括号里的表达式为假,则执行else后的大括号中的语句体。如下图…

Redis可视化工具 Another Redis Desktop Manager工具使用详细教程(附下载链接)

Redis 可视化工具推荐:Another Redis Desktop Manager Redis 是一种高性能的键值数据库,广泛应用于缓存和消息队列等场景。对于开发者来说,命令行工具固然强大,但操作繁琐。而一款高效易用的可视化工具可以极大地提升使用效率。本篇将为大家推荐一款开源、跨平台且功能强大…

跟狂神学习第一天,了解Markdown语法

Markdown学习 一个#+空格+标题名字=大标题/一级标题 二级标题 两个#+空格+标题 = 二级标题 三个#+空格+标题 = 三级标题 .......(以此类推) 一直到六级标题 字体 hello! 粗体:文字两边同时加两个* hello! 斜体:文字两边同时加一个* hello! 斜体加粗:文字两边同时加三个…

Ubuntu换源自用备用

Ubuntu换源(本地) 作者 原文链接:https://blog.csdn.net/MacWx/article/details/137689898 查询系统版本 lsb_release -a系统版本是 Ubuntu 20.04.6 LTS,注意这个开发代号Codename,Ubuntu每一个版本都有一个代号,这个一定要跟国内源对应,否则会出问题。 阿里云Ubuntu镜像…

大规模高性能云网络技术思路

控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服务的规模来部署满足需求的实例。具体网络控制面技术方案如图本文分享自天翼云开发者社区《大规模高性能云网络技术思路》,作者:程****超 控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服…

Python开发环境部署教程

本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行开发,适合新手和需要精细配置的开发者。本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行…

基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发

本文将基于云效 Flow 流水线 Windows 构建环境和云效 Packages Nuget 制品仓库手把手教你如何开发并部署一个 .NET 应用,从环境搭建到实战应用发布的详细教程,帮助你掌握 .NET 开发的核心技能。作者:陆冬澄、周静 在现代软件研发体系中,.NET 平台由于其强大的功能、灵活性和…

初创团队如何借助看板工具简化任务管理

在初创企业的构建过程中,团队管理和项目推进常常面临诸多挑战。由于资金、人员和时间的限制,如何高效地组织和管理项目成为了每个初创团队需要面对的重要课题。幸运的是,借助现代化的看板文档工具,初创团队可以大幅提升其工作效率和协作效果,确保在快速变化的市场环境中保…

GA/T1400视图库平台EasyCVR小知识:如何评估现有监控系统的技术状况?

在当今社会,随着技术的不断发展和安全需求的日益提高,监控系统在各个领域的应用越来越广泛。为了确保监控系统的有效性和可靠性,定期对其技术状况进行全面评估是非常必要的。 通过对监控系统的系统功能、性能、安全性、硬件设备、软件系统以及维护管理等方面的细致检查与分析…

Java SpringBoot 图片转PDF示例

一个SpringBoot工程里面用到了第三方签章服务,支持PDF多页盖章,用户上传的是多张图片格式的文件,所以需要将图片转成PDF。 用了几个扩展包,出现过版本不兼容、转完的PDF带水印、还有操作复杂的。 最后借助 aspose-pdf 这个扩展包实现了,这里记录一下简单的 Demo。 pom.xml…

LDAPS 636端口无法连接 报服务器不在工作

LDAPS 636端口无法连接 报服务器不在工作的解决办法 AD与第三方系统集成,需要用到389和636两个端口,389是普通连接,636是SSL,二者所能做的操作不同。如果两个端口都已放通,能telnet通,正常是可以直接用389连接的,但连上后只能看都一些基本的属性信息,OU及人员信息无法…

给 Postgres 写一个向量插件 - 向量类型

在这篇文章中,我们将为 Postgres 实现 vector 类型: CREATE TABLE items (v vector(3));Postgres 扩展结构和 pgrx 包装器 在实现它之前,让我们先看看典型的扩展结构,以及 pgrx 如何为我们简化它。 典型的 Postgres 扩展可以大致分为 2 层:实现,通常使用 C 等低级语言完成…