FHS | 文件系统层次结构标准
- 在 [挂载目录篇] 中提到内核为了兼容文件系统的差异性,引出了目录树的概念,目录树是由各个文件系统像搭积木一样拼接起来的,任何文件系统只需要挂载到一个目录上就能对接进来,内核抽象出统一的挂载接口,各文件系统自己实现这些接口就行. 既然目录如此重要, 就需要规范管理, 类Unix都遵循 FHS 规范,鸿蒙同样遵循.
- 文件系统层次结构标准(英语:Filesystem Hierarchy Standard,FHS)定义了Linux操作系统中的主要目录及目录内容。FHS由Linux基金会维护。 当前版本为3.0版,于2015年发布。基本目录如下:
/ 根目录
/home 用户主文件夹
/etc 系统主要的配置文件几乎都放置在这个目录内
/root 系统管理员(root)的主文件夹
/bin 可以被 root 与一般账号所使用
/sbin 这些命令只有 root 才能够利用来“设置”系统
/lib 放置的则是在开机时会用到的函数库
/opt 用于安装第三方应用程序的
/dev 任何设备与接口设备都是以文件的形式存在于这个目录当中
/proc 一个虚拟的文件系统, 它放置的数据都是在内存当中
/sys 也是一个虚拟的文件系统,主要也是记录与内核相关的信息
/media 放置的就是可删除的设备
/mnt 暂时挂载某些额外的设备
/srv 一些网络服务启动之后,这些服务所需要取用的数据目录
/tmp 正在执行的程序暂时放置文件的地方, 系统会不定期删除
/usr “UNIX 操作系统软件资源” 所放置的目录
/usr/bin/: 绝大部分的用户可使用命令都放在这里
/usr/include/:C/C++等程序语言的头文件 header 与包含文件include放置处
/usr/lib/: 包含各应用软件的函数库、目标文件以及一些不被一般用户惯用的执行文件或脚本
/usr/local/: 系统管理员在本机自行安装下载的软件建议安装到此目录
/usr/sbin/: 非系统正常运行所需的系统命令
/usr/share/: 放置共享文件的地方
/usr/src/: 一般源码建议放置到这里
/var 该目录主要针对常态性可变动文件
/var/cache/: 应用程序本身运行过程中会产生的一些暂存文件
/var/lib/: 程序本身执行的过程中,需要的数据文件放置的目录
/var/lock/: 目录下的文件资源一次只能被一个应用程序所使用
/var/log/: 放置登录文件的目录
/var/mail/: 放置个人电子邮件信箱的目录
/var/run/: 某些程序或服务启动后的PID目录
/var/spool/: 放置排队等待其他应用程程序使用的数据
什么是根文件系统
看网上有很多的文章,但基本全是一大抄,说是内核启动时所mount的第一个文件系统,这话固然是没错, 但想重新定义下这个概念, 所谓 根文件系统 就是先挂到根目录/
上的文件系统. 核心是根目录 /
. /
目录并不必先属于哪个文件系统,否则就是先有蛋还是先有鸡的问题,所以别被蒙圈了,它跟其他文件系统没有任何区别,只是它先来,把坑/
给占了,后续来的只能挂到它下面的目录上,最终形成整颗目录树.
理解了上面,就容易明白以下几个问题:
- 一个系统可以存在多个不同的文件系统,谁做根文件系统只决于内核在启动阶段想让谁做.
- 文件系统可存在于诸多介质上,例如:硬盘(mmc),闪存(flash),内存(RAM).每种介质上有其最合适配套的文件系统,mmc一般是(fat,ext),flash包括(jffs2),内存(proc,sys,tmpfs,ramfs)
- 文件系统可简单,可复杂,只要能实现内核定义的三类接口就可以称之为文件系统,哪三类接口:
- 挂载接口:
MountOps ops
- 操作
inode
节点接口:VnodeOps *vop
- 操作
file
接口:file_operations_vfs *fop
,这个接口底层实际操作的是inode
所指向的数据块.
- 不管怎样,内核启动后必须得有一个文件系统用于挂载到
/
下. 鸿蒙根文件系统目录结构如下:
.
├── app
├── bin
│ ├── init
│ ├── shell
│ └── tftp
├── data
│ └── system
│ └── param
├── etc
├── lib
│ ├── libc++.so
│ └── libc.so
├── system
│ ├── external
│ └── internal
└── usr
├── bin
└── lib
这些数据是怎么来的呢 ? 比如:libc.so
这种C库函数,启动后就马上需要使用的, 这需要先外部制作好,烧录到flash的指定位置. 同时注意鸿蒙制作的根文件系统并没有 /dev
目录,这个在 设备文件篇 中详细说明.
根文件系统制作过程
以liteos_a
内核为例,其提供了制作根文件系统的方法:
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a$ make help
-------------------------------------------------------
1.====make help: get help infomation of make
2.====make: make a debug version based the .config
3.====make debug: make a debug version based the .config
4.====make release: make a release version for all platform
5.====make release PLATFORM=xxx: make a release version only for platform xxx
6.====make rootfsdir: make a original rootfs dir
7.====make rootfs FSTYPE=***: make a original rootfs img
8.====make test: make the testsuits_app and put it into the rootfs dir
9.====make test_apps FSTYPE=***: make a rootfs img with the testsuits_app in it
xxx should be one of (hi3516cv300 hi3516ev200 hi3556av100/cortex-a53_aarch32 hi3559av100/cortex-a53_aarch64)
*** should be one of (jffs2)
其中第七项 make rootfs
, FSTYPE
支持 jffs2
,vfat
文件格式系统
本篇跟踪敲下 make rootfs FSTYPE=jffs2
后发生了什么
查看 kernel/liteos_a/Makefile
#执行 make rootfs FSTYPE=jffs2 一切从这里开始
$(ROOTFS): $(ROOTFSDIR) #依赖于 ROOTFSDIR
$(HIDE)$(LITEOSTOPDIR)/tools/scripts/make_rootfs/rootfsimg.sh $(ROOTFS_DIR) $(FSTYPE) #制作镜像文件
$(HIDE)cd $(ROOTFS_DIR)/.. && zip -r $(ROOTFS_ZIP) $(ROOTFS) #打rootfs.zip包
解读
- 编译整个内核的目标文件
$(LITEOS_TARGET): $(__LIBS) sysroot
$(HIDE)touch $(LOSCFG_ENTRY_SRC)
#逐个编译子目录中的 makefile
$(HIDE)for dir in $(LITEOS_SUBDIRS); \
do $(MAKE) -C $$dir all || exit 1; \
done
# 生成 liteos.map
$(LD) $(LITEOS_LDFLAGS) $(LITEOS_TABLES_LDFLAGS) $(LITEOS_DYNLDFLAGS) -Map=$(OUT)/$@.map -o $(OUT)/$@ --start-group $(LITEOS_LIBDEP) --end-group
# $(SIZE) -t --common $(OUT)/lib/*.a >$(OUT)/$@.objsize
$(OBJCOPY) -O binary $(OUT)/$@ $(LITEOS_TARGET_DIR)/$@.bin #生成 liteos.bin 文件
$(OBJDUMP) -t $(OUT)/$@ |sort >$(OUT)/$@.sym.sorted #生成 liteos.sym.sorted 文件
$(OBJDUMP) -d $(OUT)/$@ >$(OUT)/$@.asm # 生成 liteos.asm文件
- 使用
$(APPS)
编译 kernel/liteos_a/apps 目录下的各个APP
如(init
,shell
,tftp
),这些APP也称为内置到内核的APP,
# 编译多个应用程序
$(APPS): $(LITEOS_TARGET) sysroot #依赖于 LITEOS_TARGET , sysroot
$(HIDE)$(MAKE) -C apps all #执行apps目录下Makefile 的all目标, -C代表进入apps目录,
- 使用 tools/scripts/make_rootfs/rootfsdir.sh 创建根系统下的各个目录(
/bin
,/app
,/lib
).
#创建根文件系统的各个目录
mkdir -p ${ROOTFS_DIR}/bin ${ROOTFS_DIR}/lib ${ROOTFS_DIR}/usr/bin ${ROOTFS_DIR}/usr/lib ${ROOTFS_DIR}/etc \
${ROOTFS_DIR}/app ${ROOTFS_DIR}/data ${ROOTFS_DIR}/proc ${ROOTFS_DIR}/dev ${ROOTFS_DIR}/data/system ${ROOTFS_DIR}/data/system/param \
${ROOTFS_DIR}/system ${ROOTFS_DIR}/system/internal ${ROOTFS_DIR}/system/external ${OUT_DIR}/bin ${OUT_DIR}/libs
if [ -d "${BIN_DIR}" ] && [ "$(ls -A "${BIN_DIR}")" != "" ]; then
cp -f ${BIN_DIR}/* ${ROOTFS_DIR}/bin
if [ -e ${BIN_DIR}/shell ] && [ "${BIN_DIR}/shell" != "${OUT_DIR}/bin/shell" ]; then
cp -f ${BIN_DIR}/shell ${OUT_DIR}/bin/shell #拷贝 shell 到根文件系统的 /bin下
fi
if [ -e ${BIN_DIR}/tftp ] && [ "${BIN_DIR}/tftp" != "${OUT_DIR}/bin/tftp" ]; then
cp -f ${BIN_DIR}/tftp ${OUT_DIR}/bin/tftp #拷贝 tftp 到根文件系统的 /bin下
fi
fi
cp -f ${LIB_DIR}/* ${ROOTFS_DIR}/lib #将c/c++ .so 库拷贝到根文件系统的 /lib
cp -f ${LIB_DIR}/* ${OUT_DIR}/libs
- 使用
prepare
创建musl
目录,并将 c/c++ 库拷贝到该目录下
prepare: #准备工作,创建 musl 目录,用于拷贝 c/c++ .so库
$(HIDE)mkdir -p $(OUT)/musl
ifeq ($(LOSCFG_COMPILER_CLANG_LLVM), y) #使用clang-9 ,鸿蒙默认用这个编译
$(HIDE)cp -f $$($(CC) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CFLAGS) -print-file-name=libc.so) $(OUT)/musl #将C库复制到musl目录下
$(HIDE)cp -f $$($(GPP) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CXXFLAGS) -print-file-name=libc++.so) $(OUT)/musl #将C++库复制到musl目录下
else
$(HIDE)cp -f $(LITEOS_COMPILER_PATH)/target/usr/lib/libc.so $(OUT)/musl
$(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libstdc++.so.6 $(OUT)/musl
$(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libgcc_s.so.1 $(OUT)/musl
$(STRIP) $(OUT)/musl/*
endif
- **tools/scripts/make_rootfs/rootfsimg.sh ** 生成镜像文件 rootfs_jffs2.img , 调用
mkfs.jffs2
来制作jffs2
文件格式的镜像.
ROOTFS_IMG=${ROOTFS_DIR}"_"${FSTYPE}".img"
JFFS2_TOOL=mkfs.jffs2 #linux 下 制作 jffs2镜像文件的工具
WIN_JFFS2_TOOL=mkfs.jffs2.exe #windows 下 制作 jffs2镜像文件的工具
chmod -R 755 ${ROOTFS_DIR}
if [ -f "${ROOTFS_DIR}/bin/init" ]; then
chmod 700 ${ROOTFS_DIR}/bin/init 2> /dev/null
fi
if [ -f "${ROOTFS_DIR}/bin/shell" ]; then
chmod 700 ${ROOTFS_DIR}/bin/shell 2> /dev/null
fi
if [ "${FSTYPE}" = "jffs2" ]; then
if [ "${system}" != "Linux" ] ; then
tool_check ${WIN_JFFS2_TOOL}
${WIN_JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096
else
tool_check ${JFFS2_TOOL}
${JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096
fi
elif [ "${FSTYPE}" = "yaffs2" ]; then
# to do
fi
- 最后用 zip 命令将
rootfs
打包成rootfs.zip
,至此完成了鸿蒙根系统的制作过程.
将增加了一个out
目录,内容如下:
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a/out/hi3518ev300$ ls
bin lib liteos liteos.asm liteos.bin liteos.map liteos.sym.sorted musl obj rootfs rootfs_jffs2.img rootfs.zip
-
rootfs
便为制作的鸿蒙根文件系统 -
rootfs_jffs2.img
为镜像文件,可以烧到flash
中.
启动过程
这里列出启动根文件系统的相关代码
STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
UINT32 taskID;
TSK_INIT_PARAM_S sysTask;
(VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;
sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
sysTask.pcName = "SystemInit";
sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
sysTask.uwResved = LOS_TASK_STATUS_DETACHED;
#if (LOSCFG_KERNEL_SMP == YES)
sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endif
return LOS_TaskCreate(&taskID, &sysTask);
}
解读
- 首先内核开了一个叫
SystemInit
任务来处理系统初始化代码,任务入口函数为SystemInit
-
SystemInit
层层调用到MountPartitions
,挂载分区.
SystemInit(void)
...
OsMountRootfs()
AddPartitions //注册分区驱动程序
MountPartitions()
#define ROOT_DEV_NAME "/dev/spinorblk0"
#define ROOT_DIR_NAME "/"
ret = mount(ROOT_DEV_NAME, ROOT_DIR_NAME, fsType, mountFlags, NULL);//
在 设备文件篇 中将详细说明 /dev/spinorblk0
的来源,简单的说就根文件系统烧录在nor flash
介质设备的第一个分区上,分区名称/dev/spinorblk0
只是表示一个“虚”的设备文件名而已,其背后是个实实在在的文件系统.现将它挂到 /
上,结果是nor flash
的第一个分区成了根文件系统.
经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?
为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。
《鸿蒙 (Harmony OS)开发学习手册》(共计892页)
如何快速入门?
1.基本概念
2.构建第一个ArkTS应用
3.……
开发基础知识:
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……
基于ArkTS 开发
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……
鸿蒙开发面试真题(含参考答案)
OpenHarmony 开发环境搭建
《OpenHarmony源码解析》
- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ……
- 系统架构分析
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……
OpenHarmony 设备开发学习手册
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。