构建Linux根文件系统1. 根文件系统1.1 定义存放系统启动所必需的文件内核映像文件(嵌入式系统中,内核一般单独存放在一个分区中);内核启动后运行的第一个程序(init);shell程序;应用程序所依赖的库;…...1.2 目录结构1.2.1 FHS标准:(Filesystem Hierarchy Standard,文件系统层次标准);定义文件系统中目录、文件存放的原则,不是强制性标准。
1.2.2 目录:/bin存放所有用户都可以使用的、基本的命令;比须和根文件系统在一个分区中。
/sbin存放系统命令,只有管理员可以使用的命令必须和根文件系统在同一分区中。
/---/sbin*基本的系统命令,用于启动系统、修复系统等。
*---/usr/sbin*不是急迫需要使用的系统命令。
*---/usr/local/sbin/本地安装的系统命令。
/dev:存放设备文件。
/etc:存放配置文件。
/lib/---libc.so.*动态链接C库。
*---ld*链接器、加载器。
/---modules内核可加载模块存放的目录。
/home:用户目录。
/root:根用户目录。
/usr存放共享、只读的数据和程序;可以存放在另一个分区中,系统启动后再挂接到根文件系统的/usr目录下。
/var:存放可变的数据。
/procproc文件系统的挂接点;proc文件系统是一个虚拟的文件系统,用来表示系统的运行状态。
/mnt:用于临时挂接某个文件系统的挂接点。
/tmp用于存放临时文件;为减少对Flash的操作,可以在/tmp目录上挂接内存文件系统。
2. Busybox2.1 init进程2.1.1 定义由内核启动的第一个(唯一的一个)用户进程(ID=1);是后续所有进程的发起者,根据配置文件决定启动哪些程序;执行的程序通常是/sbin/init,也可以传入命令行参数指定一个程序作为init进程运行。
2.1.2 内核如何启动init进程内核启动的最后一步是启动init进程,代码在linux内核源码的init/main.c中。
static int noinline init_post(void){free_initmem();unlock_kernel();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();/*打开标准输入(stdin)、标准输出(stdout)、标准错误(stderr);*对应的文件描述符分别是0,1,2。
*///打开/dev/console设备文件,他是init进程的标准输入设备。
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n");//将文件描述符0复制给文件描述符1,2;//标准输入、标准输出、标准错误对应同一个文件(设备)。
(void) sys_dup(0);(void) sys_dup(0);/*ramdisk_execute_command*指定了要执行的程序*1. ”如果命令行参数中指定了rdinit=...”*ramdisk_execute_command等于此指定值。
*2. 如果/init程序存在*ramdisk_execute_command=/init*3. ramdisk_execute_command为空。
*/if (ramdisk_execute_command) {/*run_init_process函数*使用他的参数所指定的程序来创建一个用户进程;*一旦创建进程成功,此函数将不会返回。
*/run_init_process(ramdisk_execute_command);printk(KERN_WARNING "Failed to execute %s\n",ramdisk_execute_command);}/*execute_command*指定了要执行的程序*1. ”如果命令行参数中指定了init=...”* execute_command等于此指定值。
*2. execute_command为空*/if (execute_command) {run_init_process(execute_command);printk(KERN_WARNING "Failed to execute %s. Attempting ""defaults...\n", execute_command);}//依次尝试执行/sbin/init、/etc/init、/bin/init、/bin/sh。
run_init_process("/sbin/init");run_init_process("/etc/init");run_init_process("/bin/init");run_init_process("/bin/sh");panic("No init found. Try passing init= option to kernel.");}static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };static void run_init_process(char *init_filename){argv_init[0] = init_filename;kernel_execve(init_filename, argv_init, envp_init);}2.1.3 Busybox init程序流程设置信号处理函数;初始化控制台;解析inittab。
2.1.4 初始化控制台进程时打开了/dev/console”设备作为控制台,一般情况下Busybox init程内核启动init”序使用/dev/console;如果内核启动init进程时设置了环境变量CONSOLE或是console,则使用环境变量所指定程序中,会检查这个设备是否可以打开,如果不能打开则使用/dev/null”。
的设备。
Busybox init”2.1.5 解析/etc/inittab文件/etc/inittab文件中的每个条目用来定义一个子进程,并确定他的启动方法。
格式:<id>:<runlevels>:<action>:<process><id>:这个子进程要使用的控制台,若省略则使用与init进程一样的控制台。
<runlevels>:对Busybox init程序无意义,省略。
<process>:要执行的程序,可以是可执行程序,或是脚本;如果程序是交互的,字段前加上-”字符。
”<action>:表示init进程如何控制这个子进程/*sysinit*系统启动后最先执行,只执行一次;*init进程等他结束后继续执行其他动作。
*wait*系统执行完sysinit后,只执行一次;*init进程等他结束后继续执行其他动作。
*once*系统执行完wait进程后,只执行一次;*init进程不等待他结束。
*respawn*启动once进程后;*init进程监测发现该子进程退出时,重新启动他。
*askfirst*启动respawn后;*与respawn类似,但init进程等用户输入回车确认后才启动子进程。
*shutdown*系统关机时执行。
*restart*Busybox中配置了CONFIG_FEATURE_USE_INITTAB,并且init进*程接收到SIGHUP信号时,先重新读取、解析/etc/inittab文件,再执行*restart程序。
*ctrlaltdel*按下Ctrl+Alt+Del组合键时执行。
*/2.2 编译和安装Busybox详见文档《系统移植》。
2.3 构建根文件系统2.3.1 创建etc/inittab文件如busybox下的examples/inittab文件:#/etc/inittab::sysinit:/etc/init.d/rcS::askfirst:-/bin/sh::ctrlaltdel:/sbin/reboot::shutdown:/bin/umount -a -r::restart:/sbin/init2.3.2 创建etc/init.d/rcS文件为脚本文件,可在里面添加想自动执行的命令。
如:#!/bin/shifconfig eth0 192.168.1.2mount -a/*ifconfig eth0 192.168.1.2*设置IP地址。
*mount -a*按照文件/etc/fstab中的配置挂接文件系统*/2.3.3 创建etc/fstab文件例如:#device mount-point type options dump fsck orderproc/proc proc defaults00tmpfs/tmp tmpfs defaults00/*device:要挂接的设备。
*mount-point:挂接点。
*type:文件系统类型。
*options:挂接参数。
*dump:决定这个文件系统是否要备份。
*fsck order:决定磁盘的检查顺序。
*/。