[busybox] busybox生成一个最精简rootfs(上)

news2024/9/29 17:57:45

这篇文章是承接着[rootfs]用busybox做一个rootfs(根文件系统)来的,再回看这篇我很久之前写的文章的时候,有一个问题出现在我的脑海中,创建了这个文件那个文件,但确实是每个文件都是必需的吗?

这篇文章我们就来讨论下这个问题。


1 busybox

当我们讨论精简文件问题的时候,busybox由于是直接编译出来的,我们暂且认为编译出来的所有binary都是必需的。

2 只有busybox行不行

busybox提供了rootfs所必须的文件,但是linux boot到最后的时候还会寻找root= 或者 init=,所以我们还需要这么一个文件告诉kernel一些必要的信息。
在这里我们把bootargs设为bootargs=console=ttyS0,115200 earlycon=sbi init=/sbin/init
但是实际上启动的时候会进不了console
在这里插入图片描述

3 考虑添加一个init文件

在这里我们先不去探讨为什么直接设置init=/sbin/init会卡住,这个牵涉到linux启动的一些话题,后面再讨论。
我们只是简单地添加一个init文件,同时,修改bootargs
bootargs=console=ttyS0,115200 earlycon=sbi init=/init
内容如下,不要忘记修改权限$ chmod 0777 init


#!/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin

do_mount_fs() {
    grep -q "$1" /proc/filesystems || return
    test -d "$2" || mkdir -p "$2"
    mount -t "$1" "$1" "$2"
}

do_mknod() {
    test -e "$1" || mknod "$1" "$2" "$3" "$4"
}

mkdir -p /proc
mount -t proc proc /proc

do_mount_fs sysfs /sys
do_mount_fs devtmpfs /dev
do_mount_fs devpts /dev/pts
do_mount_fs tmpfs /dev/shm

mkdir -p /run
mkdir -p /var/run

do_mknod /dev/console c 5 1
do_mknod /dev/null c 1 3
do_mknod /dev/zero c 1 5

# use the /dev/console device node from devtmpfs if possible to not
# confuse glibc's ttyname_r().
# This may fail (E.G. booted with console=), and errors from exec will
# terminate the shell, so use a subshell for the test
if (exec 0</dev/console) 2>/dev/null; then
    exec 0</dev/console
    exec 1>/dev/console
    exec 2>/dev/console
fi

exec /sbin/init "$@"

这时我们发现已经可以进console了。
在这里插入图片描述
但是会有一个讨厌的提示:

can't run '/etc/init.d/rcS': No such file or directory

4 /sbin/init 做了什么

加载内核后,它会立即初始化和配置计算机的内存,并配置连接到系统的各种硬件,包括所有处理器、I/O 子系统和存储设备。 然后内核创建一个根设备,以只读方式挂载根分区,并释放所有未使用的内存。此时,内核被加载到内存中并开始运行。

然而,由于没有用户应用程序允许对系统进行有意义的输入,因此系统无法完成很多工作。为了设置用户环境,内核执行/sbin/init 程序。

/sbin/init 程序(也称为 init)协调引导过程的其余部分并为用户配置环境,即pid=1的进程,运行在内核态,也是唯一一个没有通过fork()或者kernel_thread()创建的进程。当 init 命令启动时,它成为系统上自动启动的所有进程的父进程或祖父进程。
下面从代码来看init做了什么:
busybox/1.36.0/source/init/init.c#L1058

#if ENABLE_FEATURE_USE_INITTAB
	sigaddset(&G.delayed_sigset, SIGHUP);  /* reread /etc/inittab */
#endif
......
check_delayed_sigs(&G.zero_ts);
	--> reload_inittab();
		--> parse_inittab();

再来看解析parse_inittab函数的实现:

/* 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).  If CONFIG_FEATURE_USE_INITTAB
 * _is_ defined, but /etc/inittab is missing, this
 * results in the same set of default behaviors.
 */
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
	char *token[4];
	parser_t *parser = config_open2("/etc/inittab", fopen_for_read);

	if (parser == NULL)
#endif
	{
		/* No inittab file - set up some default behavior */
		/* Sysinit */
		new_init_action(SYSINIT, INIT_SCRIPT, "");		// --> # define INIT_SCRIPT  "/etc/init.d/rcS"
		/* Askfirst shell on tty1-4 */
		new_init_action(ASKFIRST, bb_default_login_shell, "");
//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
		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);
		/* 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 */
		new_init_action(SHUTDOWN, "swapoff -a", "");
		/* Restart init when a QUIT is received */
		new_init_action(RESTART, "init", "");
		return;
	}

#if ENABLE_FEATURE_USE_INITTAB
	/* optional_tty:ignored_runlevel:action:command
	 * Delims are not to be collapsed and need exactly 4 tokens
	 */
	while (config_read(parser, token, 4, 0, "#:",
				PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
		/* order must correspond to SYSINIT..RESTART constants */
		static const char actions[] ALIGN1 =
			"sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
			"ctrlaltdel\0""shutdown\0""restart\0";
		int action;
		char *tty = token[0];

		if (!token[3]) /* less than 4 tokens */
			goto bad_entry;
		action = index_in_strings(actions, token[2]);
		if (action < 0 || !token[3][0]) /* token[3]: command */
			goto bad_entry;
		/* turn .*TTY -> /dev/TTY */
		if (tty[0]) {
			tty = concat_path_file("/dev/", skip_dev_pfx(tty));
		}
		new_init_action(1 << action, token[3], tty);
		if (tty[0])
			free(tty);
		continue;
 bad_entry:
		message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
				parser->lineno);
	}
	config_close(parser);
#endif
}

根据上面的code flow,我们还需要创建一个/etc/inittab,如果不存在这个的话它会去找/etc/rcS等文件,说明如下:

# Note: BusyBox init works just fine without an inittab. If no inittab is
# found, it has the following default behavior:
#   ::sysinit:/etc/init.d/rcS
#   ::askfirst:/bin/sh
#   ::ctrlaltdel:/sbin/reboot
#   ::shutdown:/sbin/swapoff -a
#   ::shutdown:/bin/umount -a -r
#   ::restart:/sbin/init
#   tty2::askfirst:/bin/sh
#   tty3::askfirst:/bin/sh
#   tty4::askfirst:/bin/sh

5 inittab文件

busybox已经提供了一个example,这里我们直接拿过来,注意需要修改一下,因为我们没打算用账号密码登录,如果有必要,可以创建/etc/passwd文件,但是密码不是明文存储的,有兴趣的读者可以研究一下。
我们直接把这个文件夹都copy过来,
busybox-1.36.0/examples/bootfloppy/etc/inittab

::sysinit:/etc/init.d/rcS
# ::respawn:-/bin/sh		# -->注掉这一行,开机不需要登录
console::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

6 /etc/init.d/rcS

rcS也有一个example,内容如下

#! /bin/sh

/bin/mount -a

还有一种写法,就比较灵活了

#!/bin/sh


# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do

     # Ignore dangling symlinks (if any).
     [ ! -f "$i" ] && continue

     case "$i" in
	*.sh)
	    # Source shell script for speed.
	    (
		trap - INT QUIT TSTP
		set start
		. $i
	    )
	    ;;
	*)
	    # No sh extension, so fork subprocess.
	    $i start
	    ;;
    esac
done

这种写法会遍历/etc/init.d/下所有S打头的配置文件,可以在这里做网络或者其他一些东西的初始化。

7 /etc/profile

/etc/profile文件主要设置一些全局环境变量之类的。

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
 
if [ "${PS1-}" ]; then
  if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
    # The file bash.bashrc already sets the default PS1.
    # PS1='\h:\w\$ '
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
  else
    if [ "`id -u`" -eq 0 ]; then
      PS1='# '
    else
      PS1='$ '
    fi
  fi
fi
 
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

在这里插入图片描述

8 /etc/fstab

/etc/fstab文件主要设置一些文件系统的挂载点之类的。

# stock fstab - you probably want to override this with a machine specific one

proc                 /proc                proc       defaults              0  0
devpts               /dev/pts             devpts     mode=0620,ptmxmode=0666,gid=5      0  0
tmpfs                /run                 tmpfs      mode=0755,nodev,nosuid,strictatime 0  0

# uncomment this if your device has a SD/MMC/Transflash slot
#/dev/mmcblk0p1       /media/card          auto       defaults,sync,noauto  0  0

Reference:

  1. 1.2. A Detailed Look at the Boot Process
  2. busybox启动流程简单解析:从init到shell login
  3. Bash PS1 customization examples
  4. How to Change / Set up bash custom prompt (PS1) in Linux

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Graph Neural Network(GNN)图神经网络

Graph Neural Network(GNN)图神经网络&#xff0c;是一种旨在对图结构数据就行操作的深度学习算法。它可以很自然地表示现实世界中的很多问题&#xff0c;包括社交网络&#xff0c;分子结构和交通网络等。GNN旨在处理此类图结构数据&#xff0c;并对图中的节点和边进行预测或执…

PLECS中DLL模块的使用

之前发布了一篇文章&#xff0c;介绍如何使用PSIM中的DLL模块。而本篇文章的内容与之类似&#xff0c;不过主角换成了PLECS。 PLECS和PSIM类似&#xff0c;也属于电力电子仿真软件&#xff0c;使用方便&#xff0c;仿真速度快&#xff0c;和Matlab也有一定的联系&#xff0c;有…

关于Java多线程你了解多少

&#x1f3e1;个人主页 &#xff1a; 守夜人st &#x1f680;系列专栏&#xff1a;Java …持续更新中敬请关注… &#x1f649;博主简介&#xff1a;软件工程专业&#xff0c;在校学生&#xff0c;写博客是为了总结回顾一些所学知识点 目录多线程多线程的创建继承Thread类实现R…

主板EC程序烧写异常致无法点亮修复经验

主板型号&#xff1a;Gigabyte AB350M-Gaming3 官网上明确写着支持R5 5500&#xff0c;但按照如下步骤实践下来实际是不支持的 升级biosF31到F40版本的注意事项&#xff1a; 步骤&#xff1a; 1 使用Q-Flash先将bios升级到f31版本&#xff1b;2 然后下载提示中的ECFW Update To…

常见排序算法——冒泡排序和选择排序

常用算法 一、排序算法 1.1、冒泡排序 冒泡排序(Bubble Sorting)的基本思想是&#xff1a;通过对待排序序列从前向后&#xff08;从下标较小的元素开始&#xff09;&#xff0c;依次比较相邻元素的值&#xff0c;若发现逆序则交换&#xff0c;使值较大的元素逐渐从前移向后部…

Fiddler 模拟弱网环境测试

为什么要进行弱网环境测试&#xff1f; 由于用户自身的网络环境波动&#xff0c;或者是本身网络环境就较为恶劣&#xff0c;导致会出现一些意想不到的非功能性bug&#xff0c;影响用户体检。比如 利用Fiddler&#xff0c;Charles等具有代理服务器功能的网络流量分析软件来实现…

操作留痕功能实现与探讨

操作留痕功能实现与探讨 背景 接手了一个单体应用项目&#xff0c;看系统介绍&#xff0c;说实现了【高性能的操作日志留痕】功能&#xff0c;就有点好奇它是怎么设计的&#xff0c;是阻塞队列还是怎样的线程池。结果我打开代码一看&#xff0c;真的是笑洗个人了。它是做了一…

Mysql全解[基础篇]

目录MySQL概述数据库相关概念MySQL数据库版本docker部署单机节点sqlmode说明连接mysql数据模型关系型数据库&#xff08;RDBMS&#xff09;数据模型mysql版本对比MySQL 5.5MySQL 5.6MySQL 5.7MySQL 8.0SQLSQL通用语法SQL分类DDL数据库操作表操作数据类型数值类型字符串类型日期…

操作系统——12.处理机调度的概念、层次

这篇文章我们来讲一下处理机调度的概念和层次 目录 1.概述 2.调度的基本概念 3.调度的三个层次 3.1高级调度 3.2中级调度 3.3.低级调度 3.4三种调度的对比 4.挂起状态与七状态模型 5.小结 1.概述 首先&#xff0c;我们来看一下本节的知识框架图&#xff1a; 2.调度的…

连接Oracle数据库失败(ORA-12514)故障排除

文章目录症状产生原因解决办法欢迎加下方我的微信&#x1f447;&#xff0c;拉你入学习群点击试看博主的专著《MySQL 8.0运维与优化》&#xff08;清华大学出版社&#xff09;ORA-12514的故障是很多新手在连接Oracle数据库时经常遇到故障&#xff0c;它通常表示无法连接到数据库…

python+pytest接口自动化框架(5)-requests发送post请求

在HTTP协议中&#xff0c;与get请求把请求参数直接放在url中不同&#xff0c;post请求的请求数据需通过消息主体(request body)中传递。且协议中并没有规定post请求的请求数据必须使用什么样的编码方式&#xff0c;所以其请求数据可以有不同的编码方式&#xff0c;服务端通过请…

专访阮健丨压力就是动力,危机也是转机

48岁的阮健加入酷雷曼已经三个年头&#xff0c;从最初的孤身一人至今&#xff0c;他已经拥有了一个五六人的VR全景团队。 阮健团队的拍摄设备 “人的一生真的是充满不确定性的&#xff0c;那些年我辗转好几个行业的时候&#xff0c;也会一边抱怨行业不景气一边又想着怎么多干点…

Vue3 企业级项目实战:全新优化升级

Vue3 企业级项目实战 - 程序员十三 - 掘金小册Vue3 Element Plus Spring Boot 企业级项目开发&#xff0c;升职加薪&#xff0c;快人一步。。「Vue3 企业级项目实战」由程序员十三撰写&#xff0c;2744人购买https://s.juejin.cn/ds/S2RkR9F/ 写下这些文字的时候是2022年9月…

无需公网IP,安全稳定实现U8C异地访问

用友是全球领先的企业云服务与软件提供商&#xff0c;在财务、人力、供应链、采购、制造、营销、研发、项目、资产、协同等领域为客户提供数字化、智能化、社会化的企业云服务产品与解决方案。 U8C是用友针对成长型、创新型企业&#xff0c;提供企业级ERP整体解决方案。在系统…

ChunJun 1.16 Release版本即将发布,bug 捉虫活动邀您参与!

亲爱的社区小伙伴们&#xff0c;历时数月&#xff0c;我们很高兴地宣布&#xff0c;ChunJun 即将迎来 1.16 Release 版本的正式发布。在新版本中&#xff0c;ChunJun 新增了一批常用功能&#xff0c;进行了多项功能优化和问题修复&#xff0c;并在用户使用体验上进行了极大地改…

systemctl 启动/停止/重新加载 nginx

systemctl 启动/停止/重新加载 nginx 一、新建nginx.service脚本 sudo vim /usr/lib/systemd/system/nginx.service然后按iii进入编辑模式&#xff0c;粘贴如下内容&#xff0c;其中/usr/local/nginx/是进行make && make install之后的文件夹路径&#xff0c;需要根据…

虚拟地址空间

本节目录1.如何理解区域划分2.为什么一个变量可以存储两个不同的值&#xff1f;3.深入理解虚拟地址空间为什么要有地址空间&#xff1f;4.理解什么是挂起&#xff1f;1.虚拟地址空间究竟是什么&#xff1f;2.映射关系的维护是谁做的&#xff1f;1.如何理解区域划分 所谓的区域…

STM32F1,F4,L1系列禁止JTAG和SW引脚方法

STM32F1系列 程序中在使用到JTAG、SWD的某个IO 时&#xff0c;需要禁用掉相关调试方法后&#xff0c;再配置相应的IO方式。在需要相应的接口配置前使用这些代码。 对于F1系列&#xff0c;调用函数进行专门的禁止。 标准库配置方式&#xff1a; RCC_APB2PeriphClockCmd(RCC_A…

【蓝桥杯嵌入式】LCD屏的原理图解析与代码实现(第十三届省赛为例)——STM32

&#x1f38a;【蓝桥杯嵌入式】专题正在持续更新中&#xff0c;原理图解析✨&#xff0c;各模块分析✨以及历年真题讲解✨都在这儿哦&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列专栏 - 蓝…

智能家居Homekit系列一智能触摸开关

触摸开关&#xff0c;即通过触摸方式控制的墙壁开关&#xff0c;其感官场景如同我们的触屏手机&#xff0c;只需手指轻轻一点即可达到控制电器的目的&#xff0c;随着人们生活品质的提高&#xff0c;触摸开关将逐渐将换代传统机械按键开关。 触摸开关控制原理 触摸开关我们把…