目录

关于根文件系统 rootfs

在 Linux 中, 所有的文件和目录被组织成一个树状的结构, 而根文件系统, rootfs, the root filesystem, 位于文件树的顶层(路径'/'). Linux 内核通过 root = 设置的参数挂载 rootfs. 在根文件系统中也包含了其它文件树的挂载点(mount points), 用于将其它文件(设备)挂载到当前环境中, 形成完整的系统.

在根文件系统中包含了用于系统启动和操作的关键文件. 系统引导启动程序会在根文件系统挂载之后执行初始化脚本(如rcS, init.d, profile).

如果把整个Linux操作系统看作层级关系, 根文件系统是位于内核之上的模块,对于同样的硬件和架构, Linux各个发行版的区别主要在于根文件系统, 而底层的内核部分几乎是一样的. 通过制作根文件系统, 可以更换成其它发行版, 定制自己的最小化安装.

文件准备

底包

本例使用的是稍息版 Debian 10, 替换成 Ubuntu20.04.

从 stretch.tar.bz2 中提取驱动部分, 位于 /lib/modules/4.4.35-hi3798mv2x/

下载 ubuntu-base

从国内镜像站点, 下载 ubuntu-base 包

解压

在本地创建工作目录, 将压缩包解压到工作目录下, 注意要用 sudo + -p(-p, --preserve-permissions)参数, 保留原owner和原权限

mkdir workroot
sudo tar -xpf ubuntu-base-20.04.5-base-arm64.tar.gz -C workroot/

初始的目录大小为77MB左右. 可以检查一下 workroot 下的文件目录, owner是否为 root.

关于为什么要用 sudo

Even if you use tar's --same-owner flag, you will still need to extract the files as root to preserve ownership.

--same-owner flag is on by default for root.

--no-same-owner, extract files as yourself, which is default for ordinary users

准备 resolv.conf

base系统中 resolv.conf 为空, 需要设置 nameserver 否则 chroot 后目标系统 apt install 时无法解析域名

选项一, 复制

复制 resolv.conf 到目标系统

sudo cp /etc/resolv.conf workroot/etc/resolv.conf

选项二, 直接写

echo "nameserver 127.0.0.53" | sudo tee workroot/etc/resolv.conf

复制 qemu-xxx-static

安装 qemu-user-static, 这个包里面有各个架构的二进制执行文件, 会安装到 /usr/bin

sudo apt install qemu-user-static

对于 armhf, 复制 qemu-arm-static; 对于 arm64 复制 qemu-aarch64-static

# armhf
sudo cp /usr/bin/qemu-arm-static workroot/usr/bin/
# arm64
sudo cp /usr/bin/qemu-aarch64-static workroot/usr/bin/

在进行下一步之前检查文件格式是否正确, 32位的 armhf 用 qemu-arm-static, 64位的 arm64 用 qemu-aarch64-static

# armhf
sudo chroot workroot/ /usr/bin/qemu-arm-static /bin/ls
# arm64
sudo chroot workroot/ /usr/bin/qemu-aarch64-static /bin/ls

如果文件架构不匹配, 会提示- /bin/ls: Invalid ELF image for this architecture

修改目标系统软件源

vi workroot/etc/apt/sources.list

替换为USTC源

: %s/http:\/\/ports.ubuntu.com\/ubuntu-ports\//http:\/\/mirrors.ustc.edu.cn\/ubuntu-ports\//gc

挂载目标系统

选项一: 手工挂载

挂载目录

sudo mount -t proc /proc    workroot/proc
sudo mount -t sysfs /sys workroot/sys
sudo mount -o bind /dev workroot/dev
sudo mount -o bind /dev/pts workroot/dev/pts

切换根目录

sudo chroot workroot/

如果前面的检查没问题, 但是这一步总是提示 '/bin/bash': Exec format error, 检查一下 binfmts 是否开启

update-binfmts --display

正常应该显示如下, 对应格式为 enabled,

qemu-aarch64 (enabled):
package = qemu-user-static
...
qemu-arm (enabled):
package = qemu-user-static
...

如果显示为 disabled, 需要检查是否有软件未安装. 安装了 Docker 的 Ubuntu 环境可能会有冲突.

$ mount | grep binfmt
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=18150)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,nosuid,nodev,noexec,relatime)

选项二: 使用脚本挂载

以上的操作, 可以通过一个脚本进行简化

#!/bin/bash
mnt() {
echo "MOUNTING"
sudo mount -t proc /proc ${2}proc
sudo mount -t sysfs /sys ${2}sys
sudo mount -o bind /dev ${2}dev
sudo mount -o bind /dev/pts ${2}dev/pts
sudo chroot ${2}
}
umnt() {
echo "UNMOUNTING"
sudo umount ${2}proc
sudo umount ${2}sys
sudo umount ${2}dev/pts
sudo umount ${2}dev
} if [ "$1" == "-m" ] && [ -n "$2" ] ;
then
mnt $1 $2
elif [ "$1" == "-u" ] && [ -n "$2" ];
then
umnt $1 $2
else
echo ""
echo "Either 1'st, 2'nd or both parameters were missing"
echo ""
echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
echo "2'nd parameter is the full path of rootfs directory(with trailing '/')"
echo ""
echo "For example: ch-mount -m /media/sdcard/"
echo ""
echo 1st parameter : ${1}
echo 2nd parameter : ${2}
fi

需要使用目标系统环境时

./mount.sh -m workroot/

定制 rootfs 内容

root@Box:/# uname -a
Linux Box 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux
# 检查 mount
root@Box:/# mount
/proc on /proc type proc (rw,relatime)
/sys on /sys type sysfs (rw,relatime)
udev on /dev type devtmpfs (rw,nosuid,noexec,relatime,size=6965676k,nr_inodes=1741419,mode=755,inode64)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)

添加驱动文件

仅使用kernel自带的驱动可以启动rootfs, 但是一些板载的外设, 例如SATA硬盘和USB, 会因为没有驱动而无法识别. 需要手动将这些驱动放到rootfs中.

通过uname -r可以看到目标系统的架构为4.4.35-hi3798mv2x, 由此可以确定驱动的路径为

/lib/modules/4.4.35-hi3798mv2x/

从前面准备的底包中, 将驱动部分文件提取后放到这个目录下, 结构类似于

modules
└── 4.4.35-hi3798mv2x
├── kernel
│   ├── crypto
│   ├── drivers
│   ├── fs
│   ├── lib
│   └── net
├── modules.alias
├── modules.alias.bin
├── modules.builtin
├── modules.builtin.alias.bin
├── modules.builtin.bin
├── modules.dep
├── modules.dep.bin
├── modules.devname
├── modules.order
├── modules.softdep
├── modules.symbols
└── modules.symbols.bin

安装基础软件

# 77M -> 300M
apt update
# 300M -> 304M
apt install nano sudo vim-tiny

修改软件源vi /etc/apt/sources.list, 替换为USTC源

: %s/http:\/\/ports.ubuntu.com\/ubuntu-ports\//http:\/\/mirrors.ustc.edu.cn\/ubuntu-ports\//gc

再安装其它软件就快多了

apt upgrade
# 304M -> 440M
apt install openssh-server
# 440M -> 445M
apt install u-boot-tools net-tools sysstat smartmontools network-manager

安装的软件包中

  • openssh-server 提供 ssh 服务
  • u-boot-tools 提供 fw_printenv 和 fw_setenv 方法, 用于修改 UBOOT 启动参数
  • net-tools 提供 ifconfig, netstat 等常用工具
  • sysstat 提供 iostat 等常用工具

基础设置

设置网络

mkdir /etc/network/interfaces.d
echo auto eth0 > etc/network/interfaces.d/eth0
echo iface eth0 inet dhcp >> etc/network/interfaces.d/eth0

给 root 用户设置密码 注意 这一步别忘了

passwd

开启 root 用户 ssh 访问, 编辑 /etc/ssh/sshd_config, 找到

#PermitRootLogin prohibit-password

替换为

PermitRootLogin yes

配置登录的串口, 修改文件 /etc/systemd/system/getty.target.wants/getty@tty1.service

vi /etc/systemd/system/getty.target.wants/getty\@tty1.service

ConditionPathExists=/dev/tty0

修改为实际的名称

ConditionPathExists=/dev/ttyAMA0

清理文件

安装完成后, 清理apt

apt autoremove
apt-get autoclean
apt-get clean
apt clean
# 结束后 368M

取消挂载目标系统

在目标系统上, exit 退出

结束后, 要先取消挂载

选项一: 手工取消挂载

sudo umount workroot/proc
sudo umount workroot/sys
sudo umount workroot/dev/pts
sudo umount workroot/dev

选项二: 通过脚本取消挂载

如果通过脚本, 则是

./mount.sh -u workroot/

制作 rootfs 镜像文件

# 生成一个适当大小的空镜像,这个大小参考du -h workroot
dd if=/dev/zero of=rootfs.img bs=1M count=1024
# 格式化
mkfs.ext4 rootfs.img
# or
mkfs -t ext4 rootfs.img
# 挂载空镜像
mkdir rootfs
sudo mount rootfs.img rootfs/
# 写入文件, 保留权限
sudo cp -rfp workroot/* rootfs/
# 取消挂载
sudo umount rootfs/
# 检查文件系统并自动修复
e2fsck -p -f rootfs.img
# 使镜像紧凑
resize2fs -M rootfs.img

问题和解决

Root 能串口登录, 无法 ssh 登录

这是因为 ssh 默认禁止 root 登录, 编辑 /etc/ssh/sshd_config, 找到

#PermitRootLogin prohibit-password

替换为

PermitRootLogin yes

然后systemctl restart sshd重启 sshd 服务

分区可用空间为0

这是因为镜像压缩后写入, 分区大小就是镜像大小, 需要通过 resize2fs /dev/[partition] 扩充分区

方案一: 使用脚本, 手工执行

创建 /usr/bin/local_resize.sh, 内容如下, chmod +x 设为可执行

#!/bin/bash
rootfs_partition=/dev/$(lsblk -l|grep /|awk '{print $1}')
logger -t "resize-disk[$$]" "resizing $rootfs_partition"
if [ "$(echo $rootfs_partition | grep "mmc")" = "" ];then
rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)[0-9]+/\1/g')
else
rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)p[0-9]+/\1/g')
fi if [ "$rootfs_disk" = "/dev/mmcblk0" ]; then
resize2fs $rootfs_partition 2>&1 > /dev/null
else
rootfs_partition_num=$(echo "$rootfs_partition" |sed -E -e 's/^.*([0-9]+)/\1/g')
startfrom=$(fdisk -l ${rootfs_disk} -o device,start|grep ${rootfs_partition}|awk '{print $2}')
(echo d; echo $rootfs_partition_num; echo n; echo p; echo $rootfs_partition_num; echo $startfrom; echo ; echo p; echo w;) | fdisk $rootfs_disk
sync
resize2fs $rootfs_partition
fi
logger -t "resize-disk[$$]" "resized $rootfs_partition"

方案二: 使用 systemd service 在第一次启动时执行

增加 /usr/sbin/local-resize2fs.sh , chmod +x 设为可执行

#!/bin/bash
if [ ! -f /etc/first_init ]; then
rootfs_partition=/dev/$(lsblk -l|grep /|awk '{print $1}')
logger -t "resize-disk[$$]" "resizing $rootfs_partition"
if [ "$(echo $rootfs_partition | grep "mmc")" = "" ];then
rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)[0-9]+/\1/g')
else
rootfs_disk=$(echo "$rootfs_partition" |sed -E -e 's/^(.*)p[0-9]+/\1/g')
fi if [ "$rootfs_disk" = "/dev/mmcblk0" ]; then
resize2fs $rootfs_partition 2>&1 > /dev/null
else
rootfs_partition_num=$(echo "$rootfs_partition" |sed -E -e 's/^.*([0-9]+)/\1/g')
startfrom=$(fdisk -l ${rootfs_disk} -o device,start|grep ${rootfs_partition}|awk '{print $2}')
#lastsector=$(fdisk -l ${rootfs_disk} -o device,end|grep ${rootfs_partition}|awk '{print $2}')
(echo d; echo $rootfs_partition_num; echo n; echo p; echo $rootfs_partition_num; echo $startfrom; echo ; echo p; echo w;) | fdisk $rootfs_disk
sync
resize2fs $rootfs_partition
fi
echo `date +%s%N` > /etc/first_init
logger -t "resize-disk[$$]" "resized $rootfs_partition"
fi
exit 0

增加service: /etc/systemd/system/resize2fs.service

[Unit]
Description=resize2fs local filesystem
Before=local-fs-pre.target
DefaultDependencies=no [Service]
Type=oneshot
TimeoutSec=infinity
ExecStart=/usr/sbin/local-resize2fs.sh
RemainAfterExit=true [Install]
RequiredBy=local-fs-pre.target

在 /etc/systemd/system/local-fs-pre.target.wants/ 下面增加 resize2fs.service 的软链, 使其生效

参考

Hi3798MV200 恩兔N2 NS-1 (三): 制作 Ubuntu rootfs的更多相关文章

  1. helpera64开发板下制作ubuntu rootfs镜像(二)

    上一篇路径:https://www.cnblogs.com/jizizh/p/10380513.html Helpera64开发板ubuntu剩于工作: 1.背光调节 答:/sys/class/bac ...

  2. helpera64开发板下制作ubuntu rootfs镜像

    下一篇路径:https://www.cnblogs.com/jizizh/p/10499448.html 环境: HelperA64开发板 Linux3.10内核 时间:2019.02.14 目标:定 ...

  3. win7下制作ubuntu系统安装启动盘和U盘安装ubuntu全过程

    在我搞坏了两个系统之后,一切都得从头开始了,这回好了,电脑就是一台裸机了.没办法,重新下win7吧.这个要先做一个win7的启动盘,然后再安装,只能说我技术不行,没能把win7搞定.让大神给装的win ...

  4. 使用systemback制作Ubuntu自定义系统镜像和系统备份(抄)

    使用systemback制作Ubuntu自定义系统镜像和系统备份 2017年06月23日 16:17:51 BWBOT 阅读数:10714   原链接:https://community.bwbot. ...

  5. Windows系统制作Ubuntu启动U盘(命令行)

    背景 现今Ubuntu系统的使用越来越多,考虑到日常办公还是用Windows系统,但开发的需求常常要有Linux系统.因此将Linux系统安装到U盘不失为一种好的选择.在Windows系统上制作Ubu ...

  6. 使用UltraISO制作ubuntu安装u盘启动盘图文教程

    使用UltraISO制作ubuntu安装u盘启动盘图文教程 胖先森关注 0.9572017.09.07 11:06:15字数 770阅读 27,901   制作U盘启动1.gif 1.首先打开Ultr ...

  7. 易企秀 we+ Maka 兔展 四大H5页面制作工具

    H5这个由HTML5简化而来的词汇,正通过微信广泛传播.H5是集文字.图片.音乐.视频.链接等多种形式的展示页面,丰富的控件.灵活的动画特效.强大的交互应用和数据分析,高速低价的实现信息传播,非常适合 ...

  8. 小兔JS教程(三)-- 彻底攻略JS回调函数

    这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...

  9. Photoshop 基础三 制作简单按钮

    要求知识点:移动工具.选择工具.套索工具.多边行工具.文本工具.路径选择工具.裁剪.填充 一.制作简单按钮 1)新建画布,大小随便 2)画圆角矩形工具(同时定义背景色.边框是否需求.边框颜色) 3)打 ...

  10. 吴恩达机器学习笔记(三) —— Regularization正则化

    主要内容: 一.欠拟合和过拟合(over-fitting) 二.解决过拟合的两种方法 三.正则化线性回归 四.正则化logistic回归 五.正则化的原理 一.欠拟合和过拟合(over-fitting ...

随机推荐

  1. 2020-01-04:mysql里的innodb引擎的数据结构,你有看过吗?

    福哥答案2020-01-04: 面试官刚开始问我看过mysql源码没,然后问了这个问题.回答B+树,过不了面试官那关.答案来自<MySQL技术内幕 InnoDB存储引擎 第2版>第四章,时 ...

  2. 2021-04-15:给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果。

    2021-04-15:给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果. 福大大 答案2021-04-15: "b"和&q ...

  3. 2021-09-25:给定一个字符串数组,将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词指字母相同,但排列不同的字符串。示例 1:输入: strs = [“eat“, “tea“, “

    2021-09-25:给定一个字符串数组,将字母异位词组合在一起.可以按任意顺序返回结果列表.字母异位词指字母相同,但排列不同的字符串.示例 1:输入: strs = ["eat" ...

  4. CPU后面的字母含义

    M(Mobile):移动笔记本电脑标准电压,功耗小,适合笔记本,i5-4310M. U(Ultra Low Voltage):移动笔记本电脑超低电压,更小的功耗.如i5-8250U. H(Height ...

  5. SpringCloud+Eureka初识+Ribbon+Feign+Hystrix(服务熔断,服务降级)+hashbroad

    ​Eureka注册中心 1.导包 <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework ...

  6. .NET Core 程序实现 Windows 系统 Development、Staging、Production 三种环境的无感部署

    〇.前言 日常开发中,程序的环境切换是相当频繁的了,如果不同环境中的某些参数不同,那就需要每次编辑之前手动进行修改,比较麻烦,效率低下. 本文将以 .NET Core WebAPI 项目的配置方法为例 ...

  7. 3. docker的实践玩法

    1. docker的进程架构 docker服务进程:就是针对docker服务的命令,启动,重启 接口:通过参数指定容器的IP和端口,实现对容器的远程操作 客户端命令行:对docker的操作命令 最后学 ...

  8. 【LeetCode】Find Pivot Index #724 Rust Solution

    给定一个整数类型的数组 nums,请编写一个能够返回数组 "中心索引" 的方法.我们是这样定义数组 中心索引 的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和.如果数 ...

  9. Python asyncio 库源码分析

    Python asyncio 库源码分析 前言 本着 「路漫漫其修远兮, 吾将上下而求索」 的精神.终于要开始深入研究 Python 中 asyncio 的源码实现啦. 本文章可能篇幅较长,因为是逐行 ...

  10. 【AI在网络安全中的应用:趋势和未来】展望

    目录 [AI在网络安全中的应用:趋势和未来]- 展望 随着数字化和智能化的不断深入,网络安全问题越来越受到人们的关注.其中,人工智能技术在网络安全领域中的应用已成为当前研究的热点之一.本文将探讨AI在 ...