使用BusyBox制作根文件系统的理论分析
以下內(nèi)容源于朱有鵬嵌入式課程的學(xué)習(xí),如有侵權(quán),請告知刪除。
一、inittab文件介紹
#first:run the system script file ::sysinit:/etc/init.d/rcS //sysinit表示控制臺啟動(命令行)之前執(zhí)行,所以視頻中會打印不能運行rcS,因為剛開始沒有配置該文件 ::askfirst:-/bin/sh //askfirst促使按回車鍵 ::ctrlaltdel:-/sbin/reboot //ctrlaltdel表示按下ctrl和delet鍵,但在scrt中體現(xiàn)不了效果。 #umount all filesystem ::shutdown:/bin/umount -a -r #restart init process ::restart:/sbin/init(1)inittab的工作原理
- /linuxrc 執(zhí)行時調(diào)用該文件。
(2)inittab在/etc目錄下
- 屬于運行時配置文件,是文本格式的(內(nèi)容由一系列遵照一個格式組織的字符組成);
- /linuxrc?會按照一定的格式,去解析這個inittab文本文件,然后根據(jù)解析的內(nèi)容來決定要怎么工作。
- 第一個:#開始的行是注釋;
- 第二個:冒號在里面是分隔符,分隔開各個部分。
- 第三個:inittab內(nèi)容是以行為單位的,行與行之間沒有關(guān)聯(lián),每行都是一個獨立的配置項,每一個配置項表示一個具體的含義。
- 第四個:每一行的配置項都是由3個冒號分隔開的4個配置值共同確定的,這四個配置值是id:runlevels:action:process。
- 第五個:action是一個條件/狀態(tài),process是一個可被執(zhí)行的程序的pathname,當滿足action的條件時就會執(zhí)行process這個程序。
- 第六個:明白各個action的意思。
(4)由busybox的源代碼可知,busybox最終進入一個死循環(huán)。
- 在這個死循環(huán)中去反復(fù)檢查是否滿足各個action的條件,如果某個action的條件滿足就會去執(zhí)行對應(yīng)的process。
(5)當將(使用busybox生成的)sbin/、bin/目錄拷貝到/root/rootfs下,然后創(chuàng)建etc目錄,再在etc/目錄下添加了linuxrc,最小的根文件系統(tǒng)就完成了(可以進入命令行了,但是會提示如下信息:)
二、rcS文件介紹
#!/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/binrunlevel=S prevlevel=Numask 022export PATH runlevel prevlevelmount -aecho /sbin/mdev > /proc/sys/kernel/hotplug mdev -s/bin/hostname -F /etc/sysconfig/HOSTNAMEifconfig eth0 192.168.1.101、/etc/init.d/rcS文件
- 在開機時,linuxrc會調(diào)用此文件。
- 此文件是linux的運行時配置文件中最重要的一個,其他的一些配置都是由這個文件引出來的。
- 這個文件可以很復(fù)雜也可以很簡單(嵌入式一般不用像ubuntu那么復(fù)雜),里面可以有很多的配置項。
2、PATH=xxx
(1)從shell腳本的語法角度分析,該行定義了一個變量PATH,值等于后面的字符串。
(2)用export導(dǎo)出這個PATH,那么PATH就變成一個環(huán)境變量。
(3)PATH這個環(huán)境變量(環(huán)境變量可以有很多個,這里只是PATH這個環(huán)境變量)
- 是linux系統(tǒng)內(nèi)部定義的一個環(huán)境變量;
- 操作系統(tǒng)去執(zhí)行程序時會默認到PATH指定的各個目錄下去尋找。
- 如果找不到就認定這個程序不存在,如果找到了就去執(zhí)行它。
- 將一個可執(zhí)行程序的目錄導(dǎo)出到PATH,可以不帶路徑地執(zhí)行這個程序。
(4)rcS中為什么要導(dǎo)出PATH?
- 希望進入命令行后,PATH環(huán)境變量中就有默認的/bin /sbin /usr/bin /usr/sbin 這幾個常見的可執(zhí)行程序的路徑,從而可以直接使用ls、cd等命令。
(5)為什么還沒添加rcS文件,系統(tǒng)啟動就有PATH中的值?
- 因為busybox用代碼硬編碼為我們導(dǎo)出了一些環(huán)境變量,其中就有PATH。
3、runlevel=
(1)runlevel也是一個shell變量,并且被導(dǎo)出為環(huán)境變量。
(2)runlevel這個環(huán)境變量到底有什么用?類似于window中的啟動模式識別,如安全模式,普通模式。百度。
(3)runlevel=S表示將系統(tǒng)設(shè)置為單用戶模式。
4、umask=
(1)umask是linux的一個命令,作用是設(shè)置linux系統(tǒng)的umask值。
(2)umask值決定當前用戶在創(chuàng)建文件時的默認權(quán)限。
5、mount -a
(1)mount命令是用來掛載文件系統(tǒng)的;
(2)mount -a是掛載所有的應(yīng)該被掛載的文件系統(tǒng)。
- 在busybox中mount -a時,busybox會去查找一個文件/etc/fstab文件;
- 這個文件按照一定的格式列出來所有應(yīng)該被掛載的文件系統(tǒng)(包括了虛擬文件系統(tǒng))。
- 比如下面圖片(版本不一樣,內(nèi)容會不一樣):
6、mdev
(1)mdev是udev的嵌入式簡化版本
- udev/mdev是用來配合linux驅(qū)動工作的一個應(yīng)用層的軟件;
- udev/mdev的工作就是配合linux驅(qū)動生成相應(yīng)的/dev目錄下的設(shè)備文件。
(2)在rcS文件中沒有mdev配置項時,/dev目錄下啟動后是空的;在rcS文件中添加上mdev有關(guān)的2行配置項后,再次啟動系統(tǒng)后發(fā)現(xiàn)/dev目錄下生成很多的設(shè)備驅(qū)動文件。
(3)/dev目錄下的設(shè)備驅(qū)動文件就是mdev生成的,這就是mdev的效果和意義。
7、hostname
(1)hostname是linux中的一個shell命令。
- hostname xxx 執(zhí)行后可以用來設(shè)置當前系統(tǒng)的主機名為xxx,直接hostname不加參數(shù)可以顯示當前系統(tǒng)的主機名。
(2)/bin/hostname -F /etc/sysconfig/HOSTNAME,指定一個主機名配置文件/etc/sysconfig/HOSTNAME)。
(3)在制作根文件系統(tǒng)時,要創(chuàng)建/etc/sysconfig/HOSTNAME文件,然后在里面敲入文本xjh后保存。
8、ifconfig
- 如果希望開機進入命令行后,ip地址就是一個指定的ip地址(譬如192.168.1.30),需要在rcS文件中ifconfig eth0 192.168.1.30;
- 如果沒有配置,完全啟動后會沒有ip地址,但可以在完全啟動后用ifconfig eth0 xxxxxxxxx來設(shè)置。
三、rcS文件實戰(zhàn)
1、PATH、runlevel
(1)rcS文件明明存在但是卻提示不存在
- 原因是rcS文件是在windows下創(chuàng)建的,行尾換行符為'\r\n';
- 但是因為ubuntu中的vi對行尾做了優(yōu)化,所以在ubuntu中是看不出來多了東西的。
- 但是在securecrt(vim 打開)下一看就發(fā)現(xiàn)每一行末尾多出來了一個^M。
- 解決方法是在securecrt下打開,然后刪除^M,或者利用一些軟件工具。
(2)啟示
- shell腳本文件如果格式不對,運行時可能會被提示文件不存在。
- 有時候一個應(yīng)用程序執(zhí)行時也會提示文件不存在,問題可能是這個程序所調(diào)用的一個動態(tài)鏈接庫找不到。
(3)測試結(jié)果
- PATH本來在busybox中就已經(jīng)用代碼導(dǎo)出過了,所以rcS中再次導(dǎo)出沒有任何明顯的現(xiàn)象,因此看不出什么差別;
- runlevel(是一個命令,可以看到當前運行級別)實際執(zhí)行結(jié)果一直是unknown,問題在于busybox并不支持runlevel這個特性。
2、umask測試
(1)umask是022的時候,默認touch創(chuàng)建一個文件的權(quán)限是644
(2)umask是044的時候,默認touch創(chuàng)建一個文件的權(quán)限是622
(3)umask是444的時候,默認touch創(chuàng)建一個文件的權(quán)限是222
- umask的規(guī)律就是:umask值和默認創(chuàng)建文件的權(quán)限值加起來是666。
3、mount測試
(1)掛載時全部出錯:
- 所謂掛載點就是我們要將目標文件系統(tǒng)(當然這里都是虛擬文件系統(tǒng))掛載到當前文件系統(tǒng)中的某一個目錄中,這個目錄就是掛載點。
- 解決方案就是自己在制作的rootfs根目錄下創(chuàng)建這些掛載點目錄即可。
- 驗證是否掛載成功,可以看掛載時輸出信息;還可以啟動后去看proc和sys文件夾,如果有文件出現(xiàn)則證明掛載成功了,如果沒東西就證明失敗了。
四、profile文件和用戶登錄理論
# Ash profile # vim: syntax=sh# No core files by default ulimit -S -c 0 > /dev/null 2>&1USER="`id -un`" LOGNAME=$USER PS1='[\u@\h \W]\# ' PATH=$PATHHOSTNAME=`/bin/hostname`export USER LOGNAME PS1 PATH
1、profile文件添加
(1)之前添加了/bin/hostname,在/etc/sysconfig/HOSTNAME文件中定義了一個hostname(xjh)。
- 效果:命令行下hostname命令查到的host名字確實是xjh,但是沒有顯示命令行的提示符#。
(2)解決方法,將提供的profile文件放入/etc/目錄下即可。
(3)添加了之后的實驗現(xiàn)象:命令行提示符前面顯示:[@xjh ]#
- 表明profile文件起作用了,因為hostname顯示出來了。
- 但是登錄用戶名沒顯示出來。[xxx@xjh]#
- 原因是我們直接進入了命令行而沒有做登錄。等后續(xù)添加了用戶登錄功能,并且成功登陸后這個問題就能解決。
(4)profile文件工作原理
- profile文件被busybox(init進程)自動調(diào)用的,所以是認名字的。
2、如何看到用戶登錄界面
(1)linux中的原則是,用一個小程序來完成一個功能。
- 如果產(chǎn)品需要很復(fù)雜的綜合型的功能,先使用很多個小程序完成其中的一個功能,然后再將這些小程序集成起來完成整個大功能的產(chǎn)品。
- 這種集成很多個小程序來完成一個大的功能的思路,有很多種技術(shù)實現(xiàn)。譬如shell腳本,還有一些別的技術(shù),譬如linux啟動中的inittab。
(2)intttab中有一個配置項 ::askfirst:-/bin/sh
- 這個配置項作用就是當系統(tǒng)啟動后,如果按回車就去執(zhí)行/bin/sh,執(zhí)行這個就會出現(xiàn)命令行。
- 因此我們這樣的安排就會直接進入命令行而不會出現(xiàn)登錄界面。
(3)要出現(xiàn)登錄界面,就不能直接執(zhí)行/bin/sh,而應(yīng)該執(zhí)行一個負責(zé)出現(xiàn)登錄界面并且負責(zé)管理用戶名和密碼的一個程序。
- busybox中集成了該程序(就是/bin/login或者/sbin/gettty);
- 在inittab中用/bin/login或者/sbin/getty去替代/bin/sh。
3、用戶名和密碼的設(shè)置
(1)用戶名和密碼的設(shè)置是和登錄程序有關(guān)聯(lián)的,但是/bin/login和/sbin/getty在用戶名和密碼的管理上是一樣的。
- 其實常見的所有的linux系統(tǒng)的用戶名和密碼的管理幾乎都是一樣的。
(2)密碼一般都是用加密文字的,而不是用明文。
- 系統(tǒng)中的密碼,存儲在系統(tǒng)中的一個專門用來存密碼的文件中;
- 用明文存密碼有風(fēng)險,因此linux系統(tǒng)都是用密文來存儲密碼的。
五、用戶登錄實戰(zhàn)
1、添加/bin/login到sysinit
(1)在inittab中修改,去掉/bin/sh,換上/bin/login,則系統(tǒng)啟動后出現(xiàn)登錄界面??梢暂斎胗脩裘兔艽a。
(2)實驗現(xiàn)象:成功出現(xiàn)用戶登錄界面,但是死活密碼不對。
2、添加passwd和shadow文件
(1)為什么用戶名和密碼不對?因為根本沒有為root用戶設(shè)置密碼。
(2)linux系統(tǒng)中用來描述用戶名和密碼的文件是passwd和shadow文件,這兩個文件都在etc目錄下。
- passwd文件中存儲的是用戶的密碼設(shè)置,shadow文件中存儲的是加密后的密碼。
(3)直接復(fù)制ubuntu系統(tǒng)中的/etc/passwd和/etc/shadow文件到當前制作的rootfs目錄下,然后再做修改即可。假如只有root用戶。
- 每個文件都只保留root的內(nèi)容;
- 從passwd文件中可知,需要將/root改為/root/rootfs/root/目錄,bash(busybox不支持bash)改為sh
- shadow只保留root的內(nèi)容,然后剩下的不用修改,密碼和拷貝源一樣。
(4)shadow中默認有一個加密的密碼口令,這個口令和拷貝源的shadow本身有關(guān)。
- 比如拷貝源的ubuntu中root用戶的密碼是root,那么復(fù)制過來后登陸時的密碼還是root。
3、重置密碼實踐
(1)ubuntu剛裝好時,默認用普通用戶登錄,默認root用戶是關(guān)閉的。
- 普通用戶的密碼是在裝系統(tǒng)的時候設(shè)置的,普通用戶登陸后使用su passwd?root給root用戶設(shè)置密碼,設(shè)置了密碼后root用戶才可以登錄。
(2)原因是root用戶在/etc/shadow文件中加密口令是空白的,所以是不能登錄的。
(3)busybox中因為沒有普通用戶,因此如果root用戶的加密口令是空的,則默認無密碼直接登錄。登陸了之后,可以用passwd root給root用戶設(shè)置密碼。
(4)遺忘操作系統(tǒng)的密碼的解決方法
- 用其他系統(tǒng)(WindowsPE系統(tǒng)或者ubuntu的單用戶模式等)來引導(dǎo)啟動,啟動后掛載到我們的硬盤上,然后找到/etc/shadow文件,去掉密文密碼后保存。
- 然后再重啟系統(tǒng)后密碼就沒了。
4、getty實戰(zhàn)
(1)inittab中最常見的用于登錄的程序不是/bin/login,反而是/sbin/getty。
(2)這兩個的差別不詳,但是在busybox中這兩個是一樣的。這兩個其實都是busybox的符號鏈接而已,因此不用嚴格區(qū)分這兩個。
(3)我們可以在inittab中用getty替換login程序來實現(xiàn)同樣的效果。
六、動態(tài)鏈接庫的拷貝
1、靜態(tài)編譯鏈接helloworld程序并執(zhí)行
(1)自己寫一個helloworld程序,然后交叉編譯連接,然后丟到開發(fā)板根文件系統(tǒng)中,開機后去運行。
(2)如果使用gcc編譯則可以在主機ubuntu中運行,但是不能在開發(fā)板運行;要在開發(fā)板運行需要用arm-linux-gcc來交叉編譯,但是此時編譯文件不能在主機ubuntu中運行。
- 可以用file xx命令來查看一個elf可執(zhí)行程序是哪個架構(gòu)的。
(3)靜態(tài)鏈接:arm-linux-gcc hello.c -o hello_satic -static(即在命令后添加-static)
(4)實驗結(jié)果:靜態(tài)編譯連接后生成的hello_satic已經(jīng)可以成功運行。
2、動態(tài)編譯連接helloworld程序并執(zhí)行
(1)動態(tài)鏈接:arm-linux-gcc hello.c -o hello_dynamic
(2)實驗結(jié)果:-sh: ./hello_dynamic: not found,運行時提示找不到程序。
(3)錯誤分析
- hello程序中調(diào)用了printf函數(shù);
- printf函數(shù)在動態(tài)連接時要在運行時環(huán)境(開發(fā)板的rootfs)去尋找對應(yīng)的庫文件(開發(fā)板rootfs部署的動態(tài)鏈接庫中包含printf函數(shù)的那個庫文件)。
- 如果找到則printf函數(shù)會被成功解析,hello_dynamic程序就會被執(zhí)行;如果找不到則程序不能被執(zhí)行,命令行提示錯誤信息-sh: ./hello_dynamic: not found
(4)解決方案:將arm-linux-gcc的動態(tài)鏈接庫文件復(fù)制到開發(fā)板rootfs的/lib目錄下即可解決。
3、找到并復(fù)制動態(tài)鏈接庫文件到rootfs中
(1)arm-2009q3這個交叉編譯工具鏈的動態(tài)鏈接庫在/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib目錄下。
- 其他的一些交叉編譯工具鏈中動態(tài)鏈接庫的目錄不一定在這里,需要查找,查找的方法就是find。
- find -name "*.so"
(2)復(fù)制動態(tài)鏈接庫到roots/lib目錄下。
- 復(fù)制時要注意參數(shù)用-rdf,主要目的就是符號鏈接復(fù)制過來還是符號鏈接。
- 復(fù)制命令:cp lib/*so* /root/porting_x210/rootfs/rootfs/lib/ -rdf
(3)再次測試./hello_dynamic看看是否可以運行,實驗結(jié)果是可以運行。
4、使用strip工具去掉庫中符號信息
- 動態(tài)鏈接庫so文件中包含了調(diào)試符號信息,這些符號信息在運行時是沒用的(調(diào)試時用的),這些符號會占用一定空間。
- 在傳統(tǒng)的嵌入式系統(tǒng)中flash空間是有限的,為了節(jié)省空間常常把這些符號信息去掉。這樣節(jié)省空間并且不影響運行。
- 去掉符號命令:arm-linux-strip *so*,實際操作后發(fā)現(xiàn)庫文件由3.8M變成了3.0M,節(jié)省了0.8M的空間。
七、開機自啟動與主流rcS格式介紹
1、修改rcS實現(xiàn)開機自啟動
(1)開機自啟動指的是讓一些應(yīng)用程序能夠開機后自動執(zhí)行;
(2)開機自啟動的實現(xiàn)原理
- 在(開機會自動執(zhí)行的)腳本rcS中添加(執(zhí)行某個程序的)代碼。
2、前臺運行與后臺運行
(1)程序運行時占用當前的控制臺,因此在這個程序結(jié)束前,我們都無法使用控制臺,這就叫前臺運行。
- 默認執(zhí)行程序就是前臺運行的。
(2)后臺運行就是讓這個程序運行,并且同時讓出控制臺。
- 程序可以照常運行,而且不影響當前控制臺的使用。
- 讓一個程序后臺運行的方法就是 ./xxx &
3、開機裝載驅(qū)動等其他開機自動執(zhí)行
4、實際開發(fā)中rootfs的rcS是怎樣的?
(1)以X210開發(fā)板九鼎科技做的rootfs中rcS部分來分析;
- 分析inittab發(fā)現(xiàn),sysinit執(zhí)行rcS,shutdown時執(zhí)行rcK;
- 分析/etc/init.d/rcS和rcK文件發(fā)現(xiàn),rcS和rcK都是去遍歷執(zhí)行/etc/init.d/目錄下的S開頭的腳本文件,區(qū)別是rcS傳參是start,rcK傳參是stop。
(2)由此可知
- 正式產(chǎn)品中的rcS和rcK都是一個引入,而不是真正干活的。
- 真正干活的配置腳本是/etc/init.d/S??*。
- 這些文件中肯定有一個判斷參數(shù)是start還是stop,然后start時去做一些初始化,stop時做一些清理工作。
八、制作ext2格式的鏡像并燒錄啟動
1、確定文件夾格式的rootfs可用(用NFS啟動方式驗證此文件夾格式的rootfs可用)
- 設(shè)置bootargs為nfs啟動方式;
- 然后使用剛才在主機ubuntu中做好的文件夾格式的rootfs來啟動;
- 查看啟動效果,作為將來用ext2格式的鏡像燒錄時的參照物。
2、動手制作ext2格式的鏡像
利用文件夾格式的rootfs,通過一些操作得到鏡像格式的rootfs。
(1)執(zhí)行下面命令
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240 losetup /dev/loop1 rootfs.ext2 mke2fs -m 0 /dev/loop1 10240 mount -t ext2 /dev/loop1 ./ext2_rootfs/ //這里的./ext2_rootfs/即我們的/root/rootfs? (2)復(fù)制./rootfs中的內(nèi)容,用cp ../rootfs/* ./ -rf,注意ubuntu中rootfs的具體路徑(3)執(zhí)行下面命令
umount /dev/loop1 losetup -d /dev/loop1 (4)完成后得到的rootfs.ext2,即做好的rootfs鏡像,可以燒錄。3、燒錄鏡像并設(shè)置合適的bootargs
(1)使用fastboot燒錄制作好的rootfs.ext2到開發(fā)板inand中
- fastboot flash system rootfs.ext2
- 燒錄完成后重啟系統(tǒng)
(2)設(shè)置bootargs
- set bootargs console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext2
(3)啟動后發(fā)現(xiàn)現(xiàn)象和之前nfs方式啟動掛載rootfs相同;
至此rootfs制作實驗圓滿完成。
總結(jié)
以上是生活随笔為你收集整理的使用BusyBox制作根文件系统的理论分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apizza--特别好用的 Http请
- 下一篇: 【洛谷 2661】信息传递