嵌入式交叉编译环境基于fakeroot构建根文件系统 背景在嵌入式开发过程中通常都需要使用交叉编译环境。行业中好的实践是要求使用普通用户进行系统构建包括制作根文件系统rootfs。在制作 rootfs 时需要注意目录和文件的权限以及所属用户和与用户组。权限来说没有难点难点主要在于所属用户和所属组的设置上。使用普通用户制作 rootfs 时文件和目录默认都属于当前构建时的所使用的用户此时如果直接打包制作 rootfs那么普通用户的UID和GID会被带入到所制作的 rootfs 中最终烧写到系统中所有文件和目录的 UID 和 GID 都不是0即不属于 root 用户通常都应该是 root后面也会讲构建出普通用户的情况造成系统运行异常。最直接的想法是打包制作rootfs之前通过chown命令调整目录和文件的所属者和所属组。事实上普通用户构建时直接使用chown命令进行操作会出现无权限错误。为解决上述问题本篇文档将介绍一下fakeroot的使用。fakeroot介绍fakeroot是什么fakeroot是一个 Linux/Unix 工具用于模拟 root 权限环境让普通用户在不拥有真实 root 权限的情况下执行一些需要 root 权限的操作如修改文件所有者、打包软件等。它不会真正提升用户权限而是通过“欺骗”程序使其误以为运行在 root 环境下。fakeroot作用模拟 root 权限的文件操作允许普通用户执行chown、chmod、mknod等需要 root 权限的命令但实际上不会真正修改系统文件权限仅记录在虚拟环境中。例如在构建 Debian 软件包.deb时文件默认需要属于root:root但普通用户可以用fakeroot伪装成 root 完成打包。安全隔离避免直接使用sudo或真实 root 权限防止误操作破坏系统文件。兼容性支持某些工具或脚本强制要求 root 权限才能运行fakeroot可以绕过这一限制如部分旧版打包工具。工作原理fakeroot通过 LD_PRELOAD 机制注入一个虚拟环境拦截文件权限相关的系统调用如chown、stat返回伪造的结果给程序。所有操作仅存在于内存中退出fakeroot后虚拟环境消失不影响真实系统。fakeroot与真实root的区别特性fakeroot真实root(sudo/su)权限模拟 root实际仍是普通用户拥有完整的系统权限安全性安全不会修改真实文件高风险可能误操作系统文件使用场景打包、测试、虚拟操作需要真实特权操作时依赖密码不需要需要 root 密码或 sudo 权限fakeroot使用说明交互模式直接输入fakeroot进行虚拟环境。lijinzheLIJINZHE:~$ fakeroot # 进入fakeroot虚拟环境 rootLIJINZHE:~# rootLIJINZHE:~# pwd /home/lijinzhe rootLIJINZHE:~# rootLIJINZHE:~# whoami root rootLIJINZHE:~# rootLIJINZHE:~# mkdir fakeroot-test rootLIJINZHE:~# rootLIJINZHE:~# touch fakeroot-test/file rootLIJINZHE:~# rootLIJINZHE:~# ls -ald fakeroot-test/ drwxrwxr-x 2 root root 4096 8月 15 17:54 fakeroot-test/ # 虚拟环境中创建目录归属root用户 rootLIJINZHE:~# rootLIJINZHE:~# ls -al fakeroot-test/ 总计 8 drwxrwxr-x 2 root root 4096 8月 15 17:54 . drwxr-x--- 48 root root 4096 8月 15 17:54 .. -rw-rw-r-- 1 root root 0 8月 15 17:54 file # 虚拟环境中创建文件归属root用户 rootLIJINZHE:~# rootLIJINZHE:~# exit # 退出虚拟环境 exit lijinzheLIJINZHE:~$ lijinzheLIJINZHE:~$ ls -ald fakeroot-test/ drwxrwxr-x 2 lijinzhe lijinzhe 4096 8月 15 17:54 fakeroot-test/ # 实际创建目录归属普通用户 lijinzheLIJINZHE:~$ lijinzheLIJINZHE:~$ ls -al fakeroot-test/ 总计 8 drwxrwxr-x 2 lijinzhe lijinzhe 4096 8月 15 17:54 . drwxr-x--- 48 lijinzhe lijinzhe 4096 8月 15 17:55 .. -rw-rw-r-- 1 lijinzhe lijinzhe 0 8月 15 17:54 file # 实际创建文件归属普通用户脚本自提升在脚本开头添加以下代码脚本会自动在 fakeroot 环境中执行。主要用于在该脚本中编写根文件系统打包流程可避免调用脚本者忘记使用 fakeroot 调用脚本。#!/bin/bashif[$(id-u)!0];thenexecfakerootbash$0$fi特别注意当exec fakeroot bash $0 $这条命令被执行的话这条命令之前的所有命令都会执行两遍。单命令模式直接在命令前加fakeroot执行单个需要 root 权限的操作# 模拟 root 打包文件$ fakeroottarczf rootfs.tar.gz /path/to/rootfs/*# 模拟 root 修改文件所有者$ fakerootchownroot:root /path/to/file# 模拟 root 创建设备节点$ fakerootmknod/path/to/dev/sda b80保存和恢复状态-s和-i选项fakeroot 的核心功能可以将虚拟环境的状态保存到文件并在后续恢复实现跨会话的权限持久化。-s和-i功能说明选项功能使用场景注意事项-s file保存当前虚拟环境状态到文件编译阶段结束后保存权限记录文件保存的是伪权限映射不是真实文件-i file从文件加载虚拟环境状态打包阶段或后续构建中恢复权限状态文件可以不存在若文件不存在会提示警告但仍正常执行命令只是权限按系统真实值处理-s和-i同时使用加载旧状态保存新状态增量构建累积权限记录状态文件可以是同一个先加载(-i)执行操作再保存(-s)使用示例保存权限状态到文件$ fakeroot-sstate.fakechownwww-data:www-data file2.txt此时将file2.txt归属于www-data的伪权限映射保存到state.fake文件中。加载之前保存的权限状态$ fakeroot-istate.faketar-czffile2.tar.gz file2.txt $tartvzf file2.tar.gz -rw-rw-r-- www-data/www-data02026-05-2918:12 file2.txt加载state.fake后tar打包时看到的是www-data归属因此压缩包内的文件权限记录为www-data。增量构建 – 加载旧状态更新后保存回同一文件$ fakeroot-istate.fake-sstate.fakechownwww-data:www-data2fakeroot: databasefilestate.fake does not exist. $echo$?0$catstate.fakedev805,ino70011732,mode100664,uid33,gid33,nlink1,rdev0$ fakeroot-istate.fake-sstate.faketar-czfrootfs.tar.gz2$tartvzf rootfs.tar.gz -rw-rw-r-- www-data/www-data02026-06-0915:272增量构建会加载state.fake中已有的记录并在退出时将任何新的更改保存回同一个文件实现累积更新。fakeroot 在-i指定的状态文件不存在时fakeroot 仅输出警告信息不会中断执行且返回值仍为 0执行成功。