根檔案系統構建

qq_31487199發表於2020-11-05

本文章來源於正點原子資料,記錄下來,以後參考。

1、根檔案系統介紹

linux系統裡面有很多目錄,這些目錄的大致內容如下:
1 、/bin 目錄
bin 檔案就是可執行檔案。此目錄下存放著系統需要的可執行檔案,一般都是一些常用的命令
2 、/dev 目錄
dev 是 device 的縮寫,所以此目錄下的檔案都是和裝置有關的,此目錄下的檔案都是裝置檔案。在Linux 下一切皆檔案。
3 、/etc 目錄
此目錄下存放著各種配置檔案
4 、/lib 目錄
lib 是 library 的簡稱,也就是庫的意思,因此此目錄下存放著 Linux 所必須的庫檔案。這些庫檔案是共享庫,命令和使用者編寫的應用程式要使用這些庫檔案。
5 、/mnt 目錄
臨時掛載目錄,一般是空目錄,可以在此目錄下建立空的子目錄,比如/mnt/sd、/mnt/usb,這樣就可以將 SD 卡或者 U 盤掛載到/mnt/sd 或者/mnt/usb 目錄中。
6 、/proc 目錄
此目錄一般是空的,當 Linux 系統啟動以後會將此目錄作為 proc 檔案系統的掛載點,proc是個虛擬檔案系統,沒有實際的儲存裝置。proc 裡面的檔案都是臨時存在的,一般用來儲存系統執行資訊檔案。
7 、/usr 目錄
要注意,usr 不是 user 的縮寫,而是 Unix Software Resource 的縮寫,也就是 Unix 作業系統軟體資源目錄。既然是軟體資源目錄,因此/usr 目錄下也存放著很多軟體,一般系統安裝完成以後此目錄佔用的空間最多。
8 、/var 目錄
此目錄存放一些可以改變的資料。
9 、/sbin 目錄
此目錄使用者存放一些可執行檔案,但是此目錄下的檔案或者說命令只有管理員才能使用,主要使用者系統管理。
10 、/sys 目錄
系統啟動以後此目錄作為 sysfs 檔案系統的掛載點,sysfs 是一個類似於 proc 檔案系統的特
殊檔案系統,sysfs 也是基於 ram 的檔案系統,也就是說它也沒有實際的儲存裝置。此目錄是系
統裝置管理的重要目錄,此目錄通過一定的組織結構向使用者提供詳細的核心資料結構資訊。
11 、/opt
可選的檔案、軟體存放區,由使用者選擇將哪些檔案或軟體放到此目錄中。

我們構建根檔案系統就是要建立上面這些子目錄以及子目錄中的檔案。

2、busybox移植

2.1 busybox介紹

BusyBox是一個整合了大量linux命令和工具的軟體。
BusyBox 官網下載地址為:https://busybox.net/
在這裡插入圖片描述
在左邊“Get BusyBox”下,點選“Download Source”進入busybox原始碼下載頁面https://busybox.net/downloads/裡面有各個版本的busyboxy原始碼

這裡下載busybox-1.29.0.tar.bz2來移植

2.2 busybox配置及編譯

在ubuntu中解壓原始碼

tar jxvf busybox-1.29.0.tar.bz2

1 、新增編譯器

進入原始碼根目錄,修改頂層 Makefile ,新增編譯器(CROSS_COMPILE為編譯器的絕對路徑),修改 ARCH 和 CROSS_COMPILE

164 CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
190 #ARCH ?= $(SUBARCH)
191 ARCH ?= arm

2 、busybox 中文字元支援

如果預設直接編譯 busybox 的話,在使用 SecureCRT 的時候中文字元是顯示不正常的,中文字
符會顯示為“?”,比如你的中文目錄,中文檔案都顯示為“?”。
所以我們需要修改 busybox 原始碼,取消 busybox 對中文顯示的限制,開啟檔案 busybox-
1.29.0/libbb/printable_string.c,找到函式 printable_string,縮減後的函式內容如下:

	const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
	{
		char *dst;
		const char *s;
	
		s = str;
		while (1) {
			unsigned char c = *s;
			if (c == '\0') {
				/* 99+% of inputs do not need conversion */
				if (stats) {
					stats->byte_count = (s - str);
					stats->unicode_count = (s - str);
					stats->unicode_width = (s - str);
				}
				return str;
			}
			if (c < ' ')
				break;
			/*註釋這兩行*/
			/*if (c >= 0x7f)
				break;*/
			s++;
		}
	
	#if ENABLE_UNICODE_SUPPORT
		dst = unicode_conv_to_printable(stats, str);
	#else
		{
			char *d = dst = xstrdup(str);
			while (1) {
				unsigned char c = *d;
				if (c == '\0')
					break;
				/*修改*/
				//if (c < ' ' || c >= 0x7f)
				if (c < ' ')
					*d = '?';
				d++;
			}
			if (stats) {
				stats->byte_count = (d - dst);
				stats->unicode_count = (d - dst);
				stats->unicode_width = (d - dst);
			}
		}
	#endif
		return auto_string(dst);
	}

注 釋 20 − 21 行 , 修 改 34 − 35 行 \color{#FF0000}{註釋20-21行,修改34-35行} 20213435

開啟檔案 busybox-1.29.0/libbb/unicode.c 修改如下:

static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{
	char *dst;
	unsigned dst_len;
	unsigned uni_count;
	unsigned uni_width;

	if (unicode_status != UNICODE_ON) {
		char *d;
		if (flags & UNI_FLAG_PAD) {
			d = dst = xmalloc(width + 1);
			while ((int)--width >= 0) {
				unsigned char c = *src;
				if (c == '\0') {
					do
						*d++ = ' ';
					while ((int)--width >= 0);
					break;
				}
				/*修改下面的這行程式碼*/
				/**d++ = (c >= ' ' && c < 0x7f) ? c : '?';*/
				*d++ = (c >= ' ') ? c : '?';
				src++;
			}
			*d = '\0';
		} else {
			d = dst = xstrndup(src, width);
			while (*d) {
				unsigned char c = *d;
				/*修改下面的一行程式碼*/
				/*if (c < ' ' || c >= 0x7f)*/
				if (c < ' ')
					*d = '?';
				d++;
			}
		}
		if (stats) {
			stats->byte_count = (d - dst);
			stats->unicode_count = (d - dst);
			stats->unicode_width = (d - dst);
		}
		return dst;
	}
	......
	return dst;
}

3 、配置 busybox

預設配置 make defconfig
全選配置 make allyesconfig
最小配置 make allnoconfig 一般使用這個
輸入上面三個命令中的其中一個後,就會在根目錄生成 .config 檔案。
make menuconfig 開啟圖形話配置介面

a.不選用靜態編譯

->Settings
	->Build static binary (no shared libs)

不 能 勾 選 這 個 選 項 \color{#FF0000}{不能勾選這個選項}

b.vi風格的編輯

-> Settings  
  │       -> vi-style line editing commands

勾 選 這 個 \color{#00FF00}{勾選這個}

c.Simplified modutils

-> Linux Module Utilities
	-> Simplified modutils

不 勾 選 這 個 選 項 \color{#FF0000}{不勾選這個選項}

d.其他配置

-> Linux System Utilities
	->mdev (16 kb)  

在這裡插入圖片描述
如 圖 所 示 全 部 選 中 \color{#00FF00}{如圖所示全部選中}

e.使能 busybox 的 unicode 編碼以支援中文

-> Settings 
	-> Support Unicode 
		-> Check $LC_ALL, $LC_CTYPE and $LANG environment variables 

選 中 上 面 的 兩 個 \color{#00FF00}{選中上面的兩個}

4 、編譯 busybox

編譯命令:
make install CONFIG_PREFIX=/home/XXX/nfsroot/rootfs
COFIG_PREFIX指定編譯結果的存放目錄 ,如果不指定目錄 , 編譯結果在 _install 目錄中編譯結果
此時,rootfs 目錄下有 bin、sbin 和 usr 這三個目錄,以及 linuxrc 這個檔案。如果 bootargs 設定init=/linuxrc,那麼 linuxrc 就是可以作為使用者空間的 init 程式,所以使用者態空間的 init 程式是 busybox 來生成的。此時的根檔案系統還不能使用,還需要一些其他的檔案。

2.3 向根檔案系統新增 lib

a.將交叉編譯環境下lib庫拷貝到/rootfs/lib

進入rootfs中,建立lib目錄 make lib

	 cp /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*.a lib/ -d
	 cp /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*so* lib/ -d

“-d” 表示符號連結拷貝
先將 rootfs/lib 中的 ld-linux-armhf.so.3 檔案刪除掉,命令
如下:
rm ld-linux-armhf.so.3

從編譯器中拷貝 ld-linux-armhf.so.3

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp ld-linux-armhf.so.3 ~/imx-share/nfsroot/rootfs/lib/

進入下目錄:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
此目錄下也有很多的的so和.a 庫檔案,我們將其也拷貝到 rootfs/lib 目錄中

 cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
 cp *so* *.a ~/imx-share/nfsroot/rootfs/lib/ -d

a.將交叉編譯環境下lib庫拷貝到 rootfs/usr/lib

在rootfs中的usr目錄建lib目錄 mkdir usr/lib
進入/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib目錄

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a ~/imx-share/nfsroot/rootfs/usr/lib/ -d

2.4 建立其他資料夾

在根檔案系統中建立其他資料夾,如 dev、proc、mnt、sys、tmp 和 root
在這裡插入圖片描述

三、測試

NFS掛載根檔案系統

root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gw-ip:<hostname>:<device>:<autoconf>:<dns0-ip>:<\dns1-ip>

<server-ip>:伺服器 IP 地址,也就是存放根檔案系統主機的 IP 地址,那就是 Ubuntu 的 IP地址,比如我的 Ubuntu 主機 IP 地址為 192.168.1.250。
<root-dir> :根檔案系統的存放路徑,比如我的就是/home/zuozhongkai/linux/nfs/rootfs。
<nfs-options>:NFS 的其他可選選項,一般不設定。
<client-ip> :客戶端 IP 地址,也就是我們開發板的 IP 地址,Linux 核心啟動以後就會使用此 IP 地址來配置開發板。此地址一定要和 Ubuntu 主機在同一個網段內,並且沒有被其他的裝置使用
<server-ip> :伺服器 IP 地址,前面已經說了。
<gw-ip> :閘道器地址,我的就是 192.168.1.1。
<netmask>:子網掩碼,我的就是 255.255.255.0。
<hostname>:客戶機的名字,一般不設定,此值可以空著。
<device> :裝置名,也就是網路卡名,一般是 eth0,eth1….,正點原子的 I.MX6U-ALPHA 開
發板的 ENET2 為 eth0,ENET1 為 eth1。如果你的電腦只有一個網路卡,那麼基本只能是 eth0。
這裡我們使用 ENET2,所以網路卡名就是 eth0。
<autoconf> :自動配置,一般不使用,所以設定為 off。
<dns0-ip> :DNS0 伺服器 IP 地址,不使用。
<dns1-ip> :DNS1 伺服器 IP 地址,不使用。

設定上面的格式 bootargs 環境變數的 root 值如下:
root=/dev/nfs rw nfsroot=192.168.1.172:/home/xxxxx/nfsroot/rootfs ip=192.168.1.187:192.168.1.172:192.168.1.1:255.255.255.0::eth0:off
設定bootargs

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.1.172:/home/xxxxx/nfsroot/rootfs ip=192.168.1.187:192.168.1.172:192.168.1.1:255.255.255.0::eth0:off'
saveenv

boot啟動核心

報錯:
can’t run ‘/etc/init.d/rcS’: No such file or directory

四、完善根檔案系統

a.建立/etc/init.d/rcS

rcS 是個 shell 指令碼,Linux 核心啟動以後需要啟動一些服務,而 rcS 就是規定啟動哪些檔案
的指令碼檔案。在 rootfs 中建立/etc/init.d/rcS 檔案,然後在 rcS 中輸入如下所示內容:

1 #!/bin/sh
2 
3 PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
4 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
5 export PATH LD_LIBRARY_PATH
6 
7 mount -a
8 mkdir /dev/pts
9 mount -t devpts devpts /dev/pts
10 
11 echo /sbin/mdev > /proc/sys/kernel/hotplug
12 mdev -s

第 1 行,表示這是一個 shell 指令碼。
第 3 行,PATH 環境變數儲存著可執行檔案可能存在的目錄,這樣我們在執行一些命令或
者可執行檔案的時候就不會提示找不到檔案這樣的錯誤。
第 4 行,LD_LIBRARY_PATH 環境變數儲存著庫檔案所在的目錄。
第 5 行,使用 export 來匯出上面這些環境變數,相當於宣告一些“全域性變數”。
第 7 行,使用 mount 命令來掛載所有的檔案系統,這些檔案系統由檔案/etc/fstab 來指定,
所以我們一會還要建立/etc/fstab 檔案。
第 8 和 9 行,建立目錄/dev/pts,然後將 devpts 掛載到/dev/pts 目錄中。
第 11 和 12 行,使用 mdev 來管理熱插拔裝置,通過這兩行,Linux 核心就可以在/dev 目錄
下自動建立裝置節點。關於 mdev 的詳細內容可以參考 busybox 中的 docs/mdev.txt 文件。
示例程式碼 38.4.1.1 中的 rcS 檔案內容是最精簡的,大家如果去看 Ubuntu 或者其他大型 Linux
作業系統中的 rcS 檔案,就會發現其非常複雜。因為我們是初次學習,所以不用搞這麼複雜的,
而且這麼複雜的 rcS 檔案也是藉助其他工具建立的,比如 buildroot 等。
建立好檔案/etc/init.d/rcS 以後一定要給其可執行許可權!否則有can’t run ‘/etc/init.d/rcS’: Permission denied報錯
使用如下命令給予/ec/init.d/rcS 可執行許可權:
chmod 777 rcS

繼續啟動核心 有報錯:
Freeing unused kernel memory: 400K (80910000 - 80974000)
mount: can’t read ‘/etc/fstab’: No such file or directory
/etc/init.d/rcS: line 11: can’t create /proc/sys/kernel/hotplug: nonexistent directory
mdev: /sys/dev: No such file or directory

“mount -a”掛載所有根檔案系統的時候需要讀取/etc/fstab,因為/etc/fstab 裡面定義了該掛載哪些檔案

b.建立/etc/fstab

在 rootfs中建立/etc/fstab 檔案,fstab在Linux開機以後自動配置哪些需要自動掛載的分割槽,格式如下:

	<file system> <mount point> <type> <options> <dump> <pass>

<file system>:要掛載的特殊的裝置,也可以是塊裝置,比如/dev/sda 等等。
<mount point>:掛載點。
<type>:檔案系統型別,比如 ext2、ext3、proc、romfs、tmpfs 等等。
<options>:掛載選項,在 Ubuntu 中輸入“man mount”命令可以檢視具體的選項。一般使用defaults,也就是預設選項defaults 包含了 rw、suid、 dev、 exec、 auto、 nouser 和 async。
<dump>:為 1 的話表示允許備份,為 0 不備份,一般不備份,因此設定為 0。
<pass>:磁碟檢查設定,為 0 表示不檢查。根目錄‘/’設定為 1,其他的都不能設定為 1,
其他的分割槽從 2 開始。一般不在 fstab 中掛載根目錄,因此這裡一般設定為 0。

fstab檔案內容如下:
1 #
2 proc /proc proc defaults 0 0
3 tmpfs /tmp tmpfs defaults 0 0
4 sysfs /sys sysfs defaults 0 0

c.建立/etc/inittab

參考https://www.cnblogs.com/uestc-mm/p/11985696.html
當核心初始化後,就會啟動第一個程式 init,init程式 會讀取/etc/inittab檔案,執行裡面的內容來進行初始化工作
/etc/inittab檔案中每個登記項的結構都是一樣的,共分為以冒號“:”分隔的4個欄位.具體如下:

<id>:<runlevels>:<action>:<process>

<id>:每個指令的識別符號,不能重複。但是對於 busybox 的 init 來說,有著特殊意義。對於 busybox 而言用來指定啟動程式的控制 tty,一般我們將串列埠或者 LCD 螢幕設定為控制 tty。
<runlevels> :對 busybox 來說此項完全沒用,所以空著。
<action>:動作,用於指定可能用到的動作。busybox 支援的動作如所示:

sysinit  在系統初始化的時候 process 才會執行一次。
respawn  當 process 終止以後馬上啟動一個新的。
askfirst
和 respawn類似,在執行 process 之前在控制檯上顯示“Please press Enter to activate
this console.”。只要使用者按下“Enter”鍵以後才會執行 process。
wait  告訴 init,要等待相應的程式執行完以後才能繼續執行。
once  僅執行一次,而且不會等待 process 執行完成。
restart  當 init 重啟的時候才會執行 procee。
ctrlaltdel  當按下 ctrl+alt+del 組合鍵才會執行 process。
shutdown  關機的時候執行 process。

<process> :具體的動作,比如程式、指令碼或命令等。
參考 busybox 的 examples/inittab 檔案,我們也建立一個/etc/inittab,在裡面輸入如下內容:

1 #etc/inittab
2 ::sysinit:/etc/init.d/rcS
3 console::askfirst:-/bin/sh
4 ::restart:/sbin/init
5 ::ctrlaltdel:/sbin/reboot
6 ::shutdown:/bin/umount -a -r
7 ::shutdown:/sbin/swapoff -a

第 2 行,系統啟動以後執行/etc/init.d/rcS 這個指令碼檔案。
第 3 行,將 console 作為控制檯終端,也就是 ttymxc0。
第 4 行,重啟的話執行/sbin/init。
第 5 行,按下 ctrl+alt+del 組合鍵的話就執行/sbin/reboot,看來 ctrl+alt+del 組合鍵用於重
啟系統。
第 6 行,關機的時候執行/bin/umount,也就是解除安裝各個檔案系統。
第 7 行,關機的時候執行/sbin/swapoff,也就是關閉交換分割槽。
/etc/inittab 檔案建立好以後就可以重啟開發板即可,至此!根檔案系統要建立的檔案就已經
全部完成了。

五、根檔案系統其他功能測試

1、軟體執行測試

在rootfs中,寫一個hello.c 程式,用交叉編譯器編譯,開機後,測試是否能執行

2、中文字元測試

在rootfs 中,新建一箇中文目錄和中文檔案,測試能否正常顯示

3、程式開機自動測試

l i n u x 啟 動 後 , 自 動 執 行 程 序 \color{#00FF00}{linux啟動後,自動執行程式} linux
修改/etc/init.d/rcS ,增加以下內容

	14 #開機自啟動程式
	15 cd /drivers
	16 ./hello &
	17 cd /

開機,看hello程式能否自動執行

4、外網連線測試
ping www.baidu.com

測試失敗 / # ping www.baidu.com
ping: bad address ‘www.baidu.com’
需要設定域名伺服器
在 rootfs 中新建檔案/etc/resolv.conf 內容如下:

1 nameserver 114.114.114.114
2 nameserver 192.168.1.1

紅 色 \color{#FF0000}{紅色}
橙 色 \color{#FF7D00}{橙色}
黃 色 \color{#FFFF00}{黃色}
綠 色 \color{#00FF00}{綠色}
藍 色 \color{#0000FF}{藍色}
靛 色 \color{#00FFFF}{靛色}
紫 色 \color{#FF00FF}{紫色}

相關文章