嵌入式Linux根文件系统制作

文章架构:
1.根文件系统树制作
2.Linux内核使用initramfs文件系统启动

1.根文件系统树制作

1.1 创建根文件系统树目录结构
根文件系统目录树用来存放Linux基本命令,系统配置、动态库、设备节点、应用程序等所有文件,这些文件是存放在我们Linux服务器上的,在接下来的内容中我们将使用不同的工具将他制作成不同格式的根文件系统。

cd ~/gitee/fl2440/linux/
mkdir rootfs
cd rootfs/
mkdir -p apps,bin,data,dev,info,proc,root,sbin,sys,tmp,var,etc/init.d,mnt/{usb,mmc},usr/{,bin,sbin,lib},lib/{,modules/{,3.0.0}}}
tree
.
|-- bin         系统基本命令bin
|-- sbin         系统管理命令
|-- dev         系统设备节点所在路径
|-- root root    用户home
|-- etc         系统配置文件所在路径
| `-- init.d     系统初始化、启动程序脚本
|-- lib         系统动态库路径
| `-- modules
| `-- 3.0.0     linux内核驱动模块需要该路径
|-- usr
| |-- bin         用户基本命令路径
| |-- lib         用户动态库文件
| `-- sbin         用户管理命令路径
|-- apps         nandflash apps分区挂载点,用来存放应用程序
|-- data         nandflash data分区挂载点,用来存放数据 
|-- info         nandflash info分区挂载点,用来存放设备信息
|-- mnt         系统挂载点
| |-- mmc         SD卡挂载点
| `-- usb         U盘挂载点
|-- proc         linux proc文件系统挂载点
|-- sys         linux sys文件系统挂载点
|-- tmp         linux tmp文件系统挂载点
`-- var         系统日志等文件存放路径
23 directories, 0 files

1.2 安装动态库

Linux下所有的应用程序都离不开动态库,程序在运行时默认会在/lib路径下查找相关的动态库文件。如果动态库不在该路径下,可以通过LD\_LIBRARY\_PATH环境变量来制定其他需要加载的动态库路径,因为开发板上所有程序都是使用交叉编译器编译,所以我们需要将交叉编译器里的动态库文件拷贝到根文件系统属的lib路径下:


cd ~/gitee/fl2440/linux/rootfs/
cd lib/

下面这个命令用来将/opt/xtools/arm920t路径下除gconv相关的所有动态库(.so)文件拷贝到

find /opt/xtools/arm920t/ -name “.so” | grep -v gconv | xargs -i cp -af {} ./

列出所有失效的符号链接文件

ls lib/
ls -l find -L -type l

在上面的输出中有很多红色的文件为失效的符号链接(…/…/lib/libxxxx),我们可以创建并使用下面脚本来重新制作符号链接到本地路径下:

vim symlink.sh
#!/bin/bash
# find all the invalid symlink file and remove "./" before it
for sf in `find -L -type l | cut -d'/' -f2` ; do
    # parser and get symlink target file name
    file=`ls -l $sf | awk -F '/' '{ print $NF }'`
    # remove invalid symlink file and generate new one
    rm -f $sf && ln -s $file $sf
done
bash symlink.sh && rm -f symlink.sh
ls

1.3 安装busybox
Linux形同在执行一条命令时,默认会到/bin、/sbin、/usr/bin、/usr/sbin这些路径下找,如果找不到则提示command not found, 当然我们也可以通过PATH环境变量告诉系统其他命令存放的路径。

cd ~/gitee/fl2440/linux/rootfs/

BusyBox是一个继承了一百多个最常用的Linux命令和工具的软件,如ls、cat、ifconfig、vim、grep、sed、awk、find、mount、telnet等。他集成压缩了Linux的许多工具和命令。我们通过下载busybox源码、配置编译并安装。他们会实现Linux基本命令,他们会被安装到根文件系统树bin、sbin、usr/bin、usr/sbin等路径下。

进入到FL2440项目下创建busybox的工作目录

cd ~/gitee/fl2440/
mkdir 3rdparty
cd 3rdparty

下载解压busybox

wget https://busybox.net/downloads/busybox-1.27.1.tar.bz2
tar -xjf busybox-1.27.1.tar.bz2
cd busybox-1.27.1

类似Linux内核,对busybox进行配置,选择哪些Linux命令需要编译,哪些不需要

export TERM=vt100
make menuconfig
Busybox Settings --->
    [ ] Enable options for full-blown desktop systems 我们的Linux不带桌面,可以去掉这个选项节约代码
    [*] Build BusyBox as a static binary (no shared libs) 使用静态链接,不使用动态库
    (/opt/xtools/arm920t/bin/arm-linux-) Cross Compiler prefix 设置自己的交叉编译器路径
    (../../linux/rootfs/) BusyBox installation prefix 设置busybox的安装路径,它应该是根文件系统树的路径
Linux System Utilities --->
    [ ] nsenter 将该选项去掉,否则编译出现错误: undefined reference to `setns'
Coreutils --->
    [*] sync 
    [ ] Enable -d and -f flags (requires syncfs(2) in libc) 将该选项去掉,否则编译出现错误: undefined reference to `syncfs'
Miscellaneous Utilities --->
    [*] flashcp Norflash拷贝命令
    [*] flash_eraseall Norflash和Nandflash的擦除命令
    [*] flash_lock Norflash的写保护命令
    [*] flash_unlock Norflash的解写保护命令
Print Utilities ---> 打印机我们不用的话,里面的全部不要选,可以节约空间
Mail Utilities ---> 邮件收发我们不用的话,里面的全部不要选,可以节约空间 

编译并安装busybox到根文件系统树路径下:

make && make install

切换到根文件系统树路径下,创建符号链接指向busybox程序,如果使用initramfs根文件系统启动需要该命令:

cd …/…/linux/rootfs/
ln -s bin/busybox init

1.4 创建/dev路径下的设备节点
Linux下所有的东西都是文件,其中设备也是当作文件来处理。/dev路径下存放所有的Linux的设备文件,我们需要使用root权限执行mknod命令在这里创建系统启动必须的设备文件节点,其他的设别节点将有mdev动态创建。

cd ~/gitee/fl2440/linux/rootfs/
sudo mknod -m666 dev/null c 1 3
sudo mknod -m666 dev/console c 5 1
sudo mknod -m666 dev/ttyS0 c 4 64

1.5 创建/var路径下文件
/var路径会存放系统运行时的一些文件(如系统日志文件/var/log/messages), 我们在该路径下创建相应的符号链接到/tmp路径下。

ln -s /tmp var/lock
ln -s /tmp var/log
ln -s /tmp var/run
ln -s /tmp var/tmp

1.6 创建/etc路径下文件
1.6.1创建/etc/inittab文件
Linux内核自举启动完成之后,最后将创建init进程并执行根文件系统中的/init或/initrc程序,该程序解析并执行/etc/inittab配置文件,在此文件中配置了init进程在系统启动要启动哪些应用程序。

cd ~/gitee/fl2440/linux/rootfs/
vim etc/inittab
# Copyright (C) 2012 LingYun I.o.T Studio < iot-yun.com > 
# Author: <[email protected] QQ:281143292>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console.
# If specified, then /dev/$id device must exist
# runlevels == ignored, busybox doesn't support it
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
# mount all the file systems specified in /etc/fstab
::sysinit:/bin/mount -a
# Use mdev to auto generate device nod and auto mount SD card and USB storage
::sysinit:/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
::sysinit:/sbin/mdev -s
#make shm, pts support
::sysinit:/bin/mkdir -p /dev/pts
::sysinit:/bin/mkdir -p /dev/shm
::sysinit:/bin/mount -t devpts devpts /dev/pts
#Set hostname
null::sysinit:/bin/hostname -F /etc/hostname
#Enable console logon
null::respawn:/sbin/getty -L ttyS0 115200 vt100
# now run any rc scripts, which used to start other application
null::wait:/etc/init.d/rcS
# system daemon
null::respawn:/sbin/syslogd -n
null::respawn:/sbin/klogd -n
# Stuff to do before rebooting
null::shutdown:/bin/killall klogd
null::shutdown:/bin/killall syslogd
null::shutdown:/bin/umount -a -r

1.6.2 创建/etc/fstab文件
Linux下的mount -a命令将自动挂载/etc/fstab文件中指定的所有需要系统自动挂载的文件。在/etc/inittab中会使用该命令在上电时自动挂载相应的文件系统,这里面主要是挂载一些伪文件系统,这些伪文件系统主要是导出Linux内核运行的相关信息,如比较重要的tmpfs、sysfs、proc文件系统等。

cd ~/gitee/fl2440/linux/rootfs/
vim etc/fstab
# /etc/fstab: static file system information.
#
# <file system> <mount pt> <type> <options> <dump> <pass>
/dev/root / ext2 rw,noauto 0 1
proc /proc proc defaults 0 0
usbfs /proc/bus/usb usbfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
ramfs /tmp ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0

1.6.3 创建hostname文件
/etc/hostname文件指定主机名,/etc/inittab文件中通过 hostname -F /etc/hostname 命令设置主机名

cd ~/gitee/fl2440/linux/rootfs/
vim etc/hostname

zhaoyuxinFL2440

1.6.4 创建系统启动脚本
系统所有的启动脚本我们都将放在/etc/init.d路径下,接下来我们将创建这些系统启动脚本:

cd ~/gitee/fl2440/linux/rootfs/
ls etc/
cd etc/init.d

启动脚本一、 /etc/init.d/rcS
/etc/inittab脚本会使用命令/etc/init.d/rcS启动所有其它的应用程序,下面创建etc/rcS脚本,该脚本将执行/etc/init.d/下所有文件名以S开头且后面紧跟至少包括2个字符的文件。

vim rcS

\#!/bin/sh
\#Copyright © 2012 LingYun I.o.T Studio < iot-yun.com >
\#Start all scripts in /etc/init.d, executing them in numerical order.
for i in /etc/init.d/S??* ; do
$i
done

我们需要将该脚本给执行的权限才能执行
chmod a+x rcS

启动脚本二、 /etc/init.d/S10\_network
假设我们希望系统启动时自动设置网卡的IP地址,则可以创建一个文件名以S开头且后面紧跟至少包括2个字符的启动脚本,并给执行权限。

vim S10\_network

\#!/bin/sh
ifconfig eth0 192.168.**. netmask 255.255.255.0 up

我们需要将该脚本给执行的权限才能执行
chmod a+x S10\_network

启动脚本三、 /etc/init.d/S99\_rcsApp
今后我们很多应用程序将会存放在/apps分区下,有时我们希望这些应用程序的启动脚本也存放在该分区下以便于管理。这时我们可以参考rcS脚本的实现机制,让它也执行在/apps/etc下的所有启动脚本。

vim S99\_rcsApp

\#!/bin/sh
\#Copyright © 2012 LingYun I.o.T Studio < iot-yun.com >
\#Start all scripts in /apps/etc/init.d, executing them in numerical order.
for i in /apps/etc/init.d/S??* ; do
$i
done

我们需要将该脚本给执行的权限才能执行
chmod a+x S99\_rcsApp

1.6.5 创建shell的配置文件
在Linux服务器上,我们可以通过修改/.bash\_profile或/.bashrc文件来修改Shell的配置文件,如修改PATH、LD\_LIBRARY\_PATH环境变量等,也可以在里面定义命令别名。在嵌入式环境下,我们这些Shell的配置保存在/etc/profile文件中。这时我们可以创建该文件配置嵌入式环境busybox里的shell(ash)

cd ~/gitee/fl2440/linux/rootfs/etc/
vim profile
# Busybox Shell(ash) configure file
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/apps/bin:/apps/tools
export PS1='\w >: '
export USER=`id -un`
export LOGNAME=$USER
export HOSTNAME=`/bin/hostname`
export HISTSIZE=500
export HISTFILESIZE=500
export PAGER='/bin/more'
export EDITOR='/bin/vi'
export INPUTRC=/etc/inputrc
export LD_LIBRARY_PATH=/lib:/usr/lib:/apps/lib
export network_cfg_dir=/apps/etc/network
### Some alias command
alias vim='vi'
alias ll='ls -l'
alias l.='ls -d .*'
alias df='df -h'

1.6.6 创建Linux登录帐号文件
Linux系统中的登录帐号信息保存在/etc/group、/etc/passwd和/etc/shadow文件中。

  • /etc/group文件保存了用户组信息;
  • /etc/passwd文件保存了用户信息;
  • /etc/shadow文件保存来相应用户的密码;

下面我们需要在根文件系统中创建这些系统帐号文件,在这里我们只创建root帐号,其他帐号的过程类似。当然也可以在系统启动后以root帐号权限来添加。

cd ~/gitee/fl2440/linux/rootfs/etc

一、 /etc/group文件

vim group

root : x : 0 : root

该文件的格式为:
groupname:password:gid:members

  • 第一个字段为用户组名称;
  • 第二个字段为用户组密码,当为x时密码是映射到/etc/gshadow中的,是非逆的;
  • 第三个字段为GID,及组号,为正整数或0,0被付于了root用户组;系统通常会预留一些较靠前的GID给系统虚拟用户之用,每个系统预留的GID都不同,一般普通用户的GID从500开始;
  • 第四个字段为用户列表,每个用户间用逗号分隔;

二、 /etc/passwd文件

vim passwd

root : x:0:0:root:/:/bin/sh

该文件的格式为:
username:password:uid:gid:fullname:homedir:shell

  • 第一个字段为登录用户名
  • 第二个字段为密码,这里设置为x表示密码被映射到/etc/shadow文件中
  • 第三个字段为用户ID(UID)
  • 第四个字段为用户所属组ID(GID)
  • 第五个字段为用户名全称
  • 第六个字段为用户根目录
  • 第七个字段为用户所用shell的类型

Unix系统最初是用明文保存密码的,后来由于安全的考虑,采用crypt()算法加密密码并存放在/etc/passwd文件。现在,由于计算机处理能力的提高,使密码破解变得越来越容易。/etc/passwd文件是所有合法用户都可访问的,大家都可互相看到密码的加密字符串,这给系统带来很大的安全威胁。现代的Unix系统使用影子密码系统,它把密码从/etc/passwd文件中分离出来,真正的密码保存在/etc/shadow文件中,shadow文件只能由超级用户访问。这样入侵者就不能获得加密密码串,用于破解。使用shadow密码文件后,/etc/passwd文件中所有帐户的password域的内容为"x",如果password域的内容
为"*",则该帐号被停用。

三、 /etc/shadow文件
/etc/shadow文件保存了相应帐号的密文,这个文件内容不能直接创建。如果我们想在嵌入式Linux系统中设置root的登录密码为123456,则我们先在自己的Linux服务器或虚拟机上修改root密码为123456,然后再将Linux服务器或虚拟机上的/etc/shadow文件里root帐号的密码密文部分拷贝出来,创建根文件系统树里的etc/shadow时将密文部分用这个密文替换。这个程做完后记得将自己的Linux服务器或虚拟机的root密码还原回去。

sudo passwd root 修改自己Linux主机上的root密码为 123456

Changing password for user root.
New password:
BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password:
passwd: all authentication tokens updated successfully.

sudo cat /etc/shadow | grep root 记录下来root帐号的加密密文信息

root:666Gc/FAOs5$P2Dww7IlmliXKW5HRd6QJVGBExGmU7.H6Ec9p95PTtQwP063GZee1ouvNejpScs0OazVFXpiBsiDl1KlUkrTw1:17467:0:99999:7:::dockerroot:!!:17139::::::

sudo passwd root 恢复自己Linux主机上的root密码

Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[[email protected]\_master ~]$
现在我们创建根文件系统树下的/etc/shadow文件, 参考下文内容只将上面root帐号的加密密文部分(666Gc****lUkrTw1)拷贝过来,其它部分保持不变:

vim shadow

root:*6Gc/FAOs5Gc/FAOs5Gc/FAOs5P2Dww7IlmliXKW5HRd6QJVGBExGmU7.H6Ec9p95PTtQwP063GZee1ouvNejpScs0OazVFXpiBsiDl1KlUkrTw1:0:0:99999:7:::

该文件的格式为:
username:password:last\_change:min\_change:max\_change:warm:failed\_expire:expiration:reserved

  • 第一字段:用户名(也被称为登录名),在/etc/shadow中,用户名和/etc/passwd 是相同的,这样就把passwd 和shadow中用的用户记录联系在 一起;这个字段是非空的;
  • 第二字段:密码加密后的密文,这个字段是非空的;
  • 第三字段:上次修改密码的时间;这个时间是从1970年01月01日算起到最近一次修改口令的时间间隔(天数);
  • 第四字段:两次修改密码间隔最少的天数;如果这个字段的值为空,帐号永久可用;
  • 第五字段:两次修改密码间隔最多的天数;如果这个字段的值为空,帐号永久可用;
  • 第六字段:提前多少天警告用户密码将过期;如果这个字段的值为空,帐号永久可用;
  • 第七字段:在密码过期之后多少天禁用此用户;如果这个字段的值为空,帐号永久可用;
  • 第八字段:用户过期日期;此字段指定了用户作废的天数(从1970年的1月1日开始的天数),如果这个字段的值为空,帐号永久可用;
  • 第九字段:保留字段,目前为空,以备将来发展之用;

1.6.6 创建Linux其他文件
切换到根文件系统树etc路径下:

cd ~/gitee/fl2440/linux/rootfs/etc/
ls

fstab group hostname init.d inittab passwd profile shadow

一、 /etc/resolv.conf文件
该文件用来设置Linux系统的DNS服务器,DNS服务器用来将域名转换成IP地址。

vim resolv.conf

nameserver 114.114.114.114
nameserver 4.2.2.2

二、 /etc/hosts文件
/etc/hosts文件存放本机静态绑定的域名,如下面在本机上域名localhost就会被解析成127.0.0.1,不需要DNS来做解析。

vim hosts

127.0.0.1 localhost

三、 /etc/TZ文件
/etc/TZ文件配置了系统的时区

vim TZ

MST7MDT

四、 /etc/issue文件
/etc/issue文件里存放在console上登录系统时提示的警告信息

vim issue

Copyright © 2012 LingYun I.o.T Studio< iot-yun.com >
Default Logon Username: root Password: 123456

至此Linux根文件系统树所需要的基本文件都已经有了,接下来我们可以使用Linux内核启动这个根文件系统。可以查看一下文件系统目录树的大小:

du -sh rootfs

12M rootfs

2.Linux内核使用initramfs文件系统启动

2.1 initramfs文件系统简介
initramfs是Linus开发的一种基于内存的根文件系统,在编译Linux内核的时候,它会直接把根文件系统树打包进内核的镜像文件中(zImage),这也意味着该镜像文件同时包含了Linux内核和根文件系统。因为根文件系统是内核打包进去的,所以内核自己知道根文件系统的位置,这样u-boot也就不需要通过bootargs参数告诉内核根文件系统的信息,此外也不需要额外烧录根文件系统镜像文件,如ubifs、yaffs2、jffs2等。在今后做其他根文件系统的时候,请务必在内核中禁用initramfs,否则Linux内核将优先使用initramfs启动了。

因为initramfs是基于内存的根文件系统,所以大家在开发板上对根文件系统里的任何文件的操作,包括创建、删除、修改在重启后都会丢失。因此如果想要更改根文件系统里的文件,必须修改根文件系统树,然后重新编译Linux内核并使用u-boot重新烧录。

2.2 内核配置及编译
Linux内核使用initramfs启动,只需要在make menuconfig作下面修改,然后重新编译即可。

cd linux-3.0
General setup --->
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
    (../../linux/rootfs/) Initramfs source file(s) 指定前面制作的根文件系统树所在的路径
 Device Drivers --->
     [*] Block devices --->
         < > Network block device support
         < > Low Performance USB Block driver
         < > RAM block device support 务必将这个ramdisk选项取消掉,否则initramfs根文件系统不能启动,默认用作initrd启动。
         < > ATA over Ethernet support
make
mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n “Linux Kernel” -d arch/arm/boot/zImage linuxrom-s3c2440.bin

2.3 u-boot系统启动和环境变量配置
使用u-boot重新启动Linux系统:

set bootargs ‘console=tty0 console=ttyS0,115200 mem=64M rw loglevel=7’
save
tftp 30008000 linuxrom-s3c2440.bin;bootm 30008000

因为initramfs是建立在内存上的根文件系统,在该文件系统路径下所有的文件修改掉电后都会丢失。所以我们在根路径下创建文件后,把开发板重启后发现该文件丢失了。

标签: bin, Linux, 文件, root, etc, 文件系统, initramfs

相关文章推荐

添加新评论,含*的栏目为必填