[Linux]嵌入式系統建置 上課筆記

嵌入式系統建置

實作

之後的命令行會用 #$ 開頭,分別表示使用超級管理員和普通用戶身分執行,過後請注意指令面面如果是寫 # ,請自行切換成 root 身分執行。中掛號 [ ] 中間的東西表示依照情況更改。

想要用超級管理員權限執行可以在指令前加上 sudo ,或是用 sudo su 來切換成 root 身分。沒有裝 sudo 的,向是 Debian 可以使用 su 並輸入 root 帳戶的密碼來切換成 root 身分。

sudo_su

環境是在 Linux 的分支 mint 18.2 下實作,也可以用其他的分支來實作,但請根據實際狀況更改參數等等。

老師說:不要用虛擬機,這樣不專業。

163.13.128.179 會簡稱為 179

準備

之後的實作中,都會將原始碼、壓縮檔放在 ~/rootfs/src 裡面,解壓出來的原始碼會放在 ~/rootfs

注意!

如果是在電腦教室做這些東西的話,最好先創建新的帳戶並給予超級管理員權限,免得其他用這個電腦的人把默認密碼改掉。

新增用戶

新增用戶可以使用 /usr/sbin/adduser ,根據提示來輸入就好。

adduser

給予用戶超級管理員權限有兩種方法。

修改 /etc/sudoers

第一種是把用戶加到 /etc/sudoers 之中。編輯 /etc/sudoers 建議使用 /usr/sbin/visudo 來進行,如果使用一般編輯器更改這個檔案造成格式錯誤等等可能會導致無法開機,如果使用 /usr/sbin/visudo 來進行編輯的話,這個程式會在保存前先進行格式的確認。

$ sudo su
# visudo

新增的格式仿造 root 就好,複製一行,將 root 改成新的用戶名。假設新的用戶名為 new_user ,如下:

new_user	ALL=(ALL:ALL) ALL

visudo

加到群組

第二種是把新的用戶加到 sudo 群組當中,這是我個人比較推薦的方法,但這種方法的前提是在 sudo 這個群組存在且 /etc/sudoers 當中有寫 %sudo ALL=(ALL:ALL) ALL ,通常都是會有的。可以使用 /usr/sbin/usermod 或是直接編輯 /etc/group 來將用戶加到群組中,不建議直接編輯 /etc/group

# usermod -a -G sudo [new_user]

下載檔案

製作嵌入式系統會用到的工具、原始碼等等。

以下檔案從 http://163.13.128.179 下載,所有的 shell script 都要改成可執行,並且使用 vim 將格式轉換成 unix (LF)。

  • S50dropbear
  • busybox-1.22.1.tar.bz2
  • busybox-1.22.1.tar.bz2
  • busybox-config-1.22.1
  • dropbear-2017.75.tar.bz2
  • dropbear-keygen.sh
  • extract-cpio.sh
  • get-ub-lib64.sh
  • linux-4.14.tar.xz
  • linux-4.8.6.tar.xz
  • linux-config-4.8.6
  • make-cpio.sh
  • my-rootfs-01.gz
  • tmpfs-00.gz

下面的檔案可以從官方網站下載。

把 shell script 改成可執行

在 Linux ,分辨一個檔案是不是一個可執行的程式或 shell script,都是看有沒有 x 這個權限的;並不像是 Windows 是看副檔名。如果有就代表這個檔案事可執行的 shell script 或是可執行的程式等等。

$ chmod +x *.sh
格式改為 Unix (LF)

目前主流的作業系統有 Windows 、 mac OS 和 Unix like ,這幾個作業系統用來表示換行也是用不同的方式, Windows 會用 CR LF 來表示換行,舊的 mac OS 用 CR 表示換行, 新的 mac OS 和 Unix like 的作業系統則是使用 LF 來表示換行。如果嘗試執行使用 CR LF 表示換行的 shell script ,可能會導致讀取錯誤無法執行。雖然有些情況下解釋器可能可以照常執行,但並不是每個解釋器都具有這樣的功能,況且 POSIX 規定是使用 LF 來表示換行,如過使用的程式是按照 POSIX 標準來進行開發的話,沒辦法正常執行是正常的。總之,標準都這樣規定了,那就跟著標準走吧。

下面是一個 ASCII 表, CR LF 分別表示第 13 和第 10 個字符(從 0 開始數)。

ASCII Table

使用 vim 操作

功能強大的 vim 裡面帶有轉換的功能,詳細操作如下。

先打開 vim,這裡以 extract-cpio.sh 做示範。

$ vim extract-cpio.sh

打開 vim 後,鍵入以下內容完成修改,保存及退出。 :set ff=unix 表示將換格式轉換成 Unix 的形式, :wq 表示儲存並退出。

:set ff=unix
:wq

vim_set_ff_unix

依賴庫及工具安裝

編譯前,當然是要先把環境準備好。

如果有人下面的程式庫都沒有裝,就開始問說編譯不了,是什麼問題,叫他肉腳。

安裝編譯過程中會用到的程式庫和工具。

# apt-get install vim
# apt-get install gcc build-essential make
# apt-get install gawk
# apt-get install automake autoconf
# apt-get install minicom lrzsz
# apt-get install ncurses-dev
# apt-get install libncursesw5-dev
# apt-get install libncurses5-dev
# apt-get install libtool bison flex texinfo
# apt-get install binutils-dev libc6-dev linux-libc-dev
# apt-get install netpbm libnetpbm10 libnetpbm10-dev

編譯核心 & 模組

什麼是核心(kernel) & 模組(modules)?

核心就是負責和硬體通訊的一個介面,連接所有的硬體,提供軟體可以存取的一個介面,並且提供應用程式運行環境。

Linux 的核心有一千多萬行的程式碼,是目前世界上最大的開放原始碼專案之一。

注意:核心只是核心,並不是一個作業系統。

詳情請參考: Kernels (https://wiki.archlinux.org/index.php/Kernels)

模組是一小段程式,根據需求,可以隨時被核心加載進核心或是卸載掉。模組讓核心可以不用重開機就可以擴充功能。有些功能或驅動程式在設置時可以設置為核心內建,或是設置成模組化可加載(在 make menuconfig 以字母表示為 M ),如果要讓核心可以動態的加載或卸載模組就要設置成模組化。驅動程式被模組化之後,可以在運行時期安裝或是卸載,可以減少記憶體的使用。

模組相關指令
$ lsmod # 列出已被加載的模組
$ modinfo [module_name] # 顯示模組相關信息
$ systool -v -m [module_name] # 顯示已加載模組的設置
$ modprobe --show-depends [module_name] # 顯示模組依賴
# modprobe [module_name] # 加載指定模組
# modprobe -r [module_name] # 卸載指定模組
# insmod filename [module_path] # 根據檔案加載指定模組
# rmmod [module_name] # 卸載模組
# modprobe [module_name] [parameter_name]=[value] # 手動設置模組參數

詳情請參考 Kernel modules (https://wiki.archlinux.org/index.php/kernel_modules)

設定

先把 179 下載下來的 linux-4.8.6.tar.xz 解壓縮。

$ tar -xf ~/rootfs/src/linux-4.8.6.tar.xz -C ~/rootfs/

這時候 ~/rootfs/ 下會有一個 linux-4.8.6 的檔案夾,是剛剛解壓出來的原始碼。

接下來把老師預先做好的設定檔放進去。

$ cp ~/rootfs/src/linux-config-4.8.6 ~/rootfs/linux-4.8.6/.config

然後就可以逛逛編譯設置了,不過大部分的東西老師都已經設定好了,所以就逛逛就好了。

$ cd ~/rootfs/linux-4.8.6/
$ make menuconfig

kernel_4_8_6_menuconfig

不過其實所有的設定也可以自己去選,不過這可不是一件簡單的事,把所有的設定都看完會花上很長的時間,不是一兩個月,可能是半年一年或更久。

其他設定

核心原始碼本身還有提供許多設定方式,如下:

$ make config # 互動式設置,所有設置會依次詢問
$ make menuconfig # 選單式設置
$ make defconfig # 默認設置(我是都用這個啦...,不過用這個不要跟老師說,他會生氣),會根據當前平台的架構生成設定檔
$ make oldconfig # 升級舊的設定檔,互動升級
$ make olddefconfig # 使用推薦設置升級設定檔
$ make allyesconfig # 全選
$ make allnoconfig # 全不選
$ make allmodconfig # 全模組化
$ make randconfig # 隨機,黑人問號.jpg,要試自己試

編譯核心和模組

都設定完後,就可以開始編譯核心了。編譯會根據 .config 裡面的設定來編譯。

先編譯 bzImage

$ cd ~/rootfs/linux-4.8.6/
$ make -j 8 bzImage

接著編譯和新模組。

$ make -j 8 modules

再來是將和新模組裝到指定的資料夾,因為模組到時候是放在嵌入式的系統裡面,對嵌入式系統來說,檔案所有者應該是 root ,所以要用超級管理員的權限來執行。

# make -j 8 INSTALL_MOD_PATH=${PWD}/mods/ modules_install
# find mods -name source -exec rm {} \;
# find mods -name build -exec rm {} \;

這時候會在 ~/rootfs/linux-4.8.6/arch/x86_64/boot/ 下產生 bzImage ,和 ~/rootfs/linux-4.8.6/mods/ 下產生 lib/ 。可以進去 lib/ 看看,會發現有個 modules 的資料夾,裡面會有 4.8.6 的資料夾,裡面放的文件路徑絕對不要去動。這些模組的路徑都是固定的,如果有動過,核心就會找不到。

關於 make 平行編譯

make 可以自動檢測哪些東西可以同時編譯,對於具有 multi-core 處理器的電腦來說,可以進行更快的編譯。 -j 參數可只指定最多同時多少個執行緒來進行編譯。 --jobs 如果後面不帶參數的話,則是能同時跑多少就同時跑多少。但使用 --jobs 不帶參數時就要小心了,像是 Linux kernel 這麼龐大的原始碼,一般電腦使用 --jobs 不帶參數可是會吃不消的。

範例

像是電腦教室的電腦是使用 Intel Core i7 的,具有 8 個邏輯處理器,這時候就可以使用 -j 8 參數來進行平行編譯。

$ make -j 8 bzImage

想知道有關更多的 make 選項,請閱讀 Summary of Options (https://www.gnu.org/software/make/manual/html_node/Options-Summary.html)

BUSYBOX (瑞士軍刀!!)

BUSYBOX 集合了所有的常用工具,並生成一個非常精悍小巧的可執行文件,雖然比 GNU core utilities 功能弱了一些,但所有常用的功能都包含在裡面了。因為他的小巧精悍,大部分的嵌入式系統都會使用 BUSYBOX 。

可能有人會想說 GNU core utilities 加起來,也不會大到哪裡去啊,但在真實的環境下,可能可以放嵌入式系統的 ROM 也就只有那麼幾十 MB 而已,所以真的沒有那麼多空間可以放這些東西啊。

設定和編譯

老步驟,先解壓出來,複製設定檔,安裝。老師所提供的設定檔是把程式安裝在 tiny 資料夾裡面。

$ cd ~/rootfs/
$ tar -xf src/busybox-1.22.1.tar.bz2
$ cp src/busybox-config-1.22.1 busybox-1.22.1/.config
$ make -j 8
# make install

這時候就可以去 ~/rootfs/busybox-1.22.1/tiny/ 裡面看看有哪些東西了。

busybox_1_22_1_tree_install

busybox_1_22_1_ls_bin

BUSYBOX 編譯出來只有 bin 底下有個 busybox 的可執行程式,其他都是通過連結檔連到 busybox 的,可以看看 busybox 檔案只有多大,而隨便幾個 GNU core utilities 的佔用空間加給來就超過一個 busybox

更多設置

其實 BUSYBOX 也是有提供 make defconfigmake menuconfig 的,可以在設定檔生成後去手動更改設定,不過默認設定檔的安裝目錄是在 ${PWD}/_install 不是 tiny

$ cd ~/rootfs
$ tar -xf src/busybox-1.22.1.tar.bz2
$ make defconfig
$ make menuconfig
$ make --jobs
# make install

busybox_1_22_1_menuconfig

有問題請先看看 FAQ (https://busybox.net/FAQ.html)

initrd

initrd & tmpfs

initrd

initrd 是 initial ram disk 的縮寫,是一個臨時的檔案系統鏡像,裡面僅包含可以啟動作業系統的工具、模組等等。一般的 Linux 分支的 initrd 的存在期間非常短暫,在完成模組加載,使根目錄可以使用後,就會掛載上真正的根目錄(有些分支的 initrd 會提供硬碟修復工具,在真正的根目錄沒辦法被加載的時候就可以使用 initrd 裡面的修復工具);但是在嵌入式系統中, initrd 卻是從開機以後就一直在使用了。

詳細資訊 What's an initial RAM disk? (https://www.ibm.com/developerworks/library/l-initrd/index.html)

tmpfs

tmpfs 是一種檔案系統,所有的檔案都保存在虛擬記憶體當中,任何對文件的操作都不會寫入硬碟,通常是將一個鏡像複製到 /dev/ram 當中,過後的讀寫都會 redirect 到虛擬記憶體中。

詳細資訊 tmpfs (https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt)

製作 rootfs

注意:本製作過程不是從 0 開始。

先用老師提供的腳本解壓出老師特製的半個 rootfs 。

$ cd ~/rootfs/src
# ./extract-cpio.sh my-rootfs-01.gz

這時候會產出一個 system 的資料夾,可以看到裡面有一個類似 FHS 架構。

ls_my_rootfs_01

再把 BUSYBOX 和模組複製進去並重新打包。

$ cd ~/rootfs
# cp -ra busybox-1.27.2/tiny/* linux-4.8.6/mods/* src/system/
$ cd src
# ./make-cpio.sh system my-rootfs-02

這時候就就會在 ~/rootfs/src/ 下產生 my-rootfs-02.gz

叫 rootfs 因為嵌入式系統從開機後就一直掛載著這個檔案系統,叫它 initrd 好像也怪怪的。

首次開機!

前面坐了這麼多事,現在終於要用自己做的 Linux 來開機了,不過在開機之前還是有準備工作要做的。

先把剛剛製作的 rootfs 和 bzImage 複製到 /boot 底下。

# cp ~/rootfs/linux-4.8.6/arch/x86_64/boot/bzImage /boot/bzImage-4.8.6-00
# cp ~/rootfs/src/my-rootfs-02.gz /boot/

grub.cfg

目前大多數的 Linux 分支使用 grub 來開機, mint 18.3 也不例外。一般 grub 的設定檔叫 grub.cfg 擺在 /boot/grub/ 目錄下。

為了讓 grub 可以找到剛剛製作的嵌入式系統,現在就來修改設定檔。

mint 18.3 所用的設定是隱藏選擇介面, 0 秒超時。

先使用文字編輯器打開 /boot/grub/grub.cfg ,注意使用 root 權限。

有圖形化介面的 grub 專用編輯器,有興趣可以裝裝看。

How do I change the GRUB boot order? (https://askubuntu.com/questions/100232/how-do-i-change-the-grub-boot-order#answers)

# gedit /boot/grub/grub.cfg

# vim /boot/grub/grub.cfg

找到以下內容

if [ "${recordfail}" = 1 ] ; then
  set timeout=30
else
  if [ x$feature_timeout_style = xy ] ; then
    set timeout_style=hidden
    set timeout=0
  # Fallback hidden-timeout code in case the timeout_style feature is
  # unavailable.
  elif sleep --interruptible 0 ; then
    set timeout=0
  fi
fi

修改成

if [ "${recordfail}" = 1 ] ; then
  set timeout=30
else
  if [ x$feature_timeout_style = xy ] ; then
    #set timeout_style=hidden
    set timeout=10
  # Fallback hidden-timeout code in case the timeout_style feature is
  # unavailable.
  elif sleep --interruptible 0 ; then
    set timeout=10
  fi
fi

接下來是新建一個選單選擇點。

注意:請寫在第 1 個 menuentry 區塊的下方。

menuentry 'my linux 4.8.6' --class ubuntu --class gnu-linux --class gnu --class os {
      recordfail
      insmod gzio
      insmod part_msdos
      insmod ext2
      linux	/boot/bzImage-4.8.6-00 root=/dev/ram init=/init quiet nozswap noswap
      initrd	/boot/my-rootfs-02.gz
}

保存!重開機!

# reboot

接下來就可以在開機選單裡看到剛剛新加的 my linux 了。

boot_grub_menu

進去後,大概會長這樣。目前只有 tc 這個帳戶,具有 root 權限。

boot_login

現在可以看看 /etc/mtab 這個檔案目前掛載了哪些東西。

# cat /etc/mtab

網路呢?

剛剛這樣建置的系統在大部分的機器上是沒有網路的,因為沒有驅動,或是驅動沒有被加載。這時候先回原本用來建置嵌入式系統的系統,使用 dmesg 指令看看網路卡的設備叫什麼。

注意:在部分的分支, dmesg 是需要 root 權限才能使用的。

dmesg

dmesg 會列出所有開機到目前所有的驅動訊息,但輸出的信息是非常的多,使用 grep 來過濾信息,大部分的乙太網路都是用 eth 最為開頭的。

# dmesg | grep eth

找到相關信息後再去編輯 kernel 的驅動選項。

$ cd ~/rootfs/linux-4.8.6/
$ make menuconfig

打開 make menuconfig 之後,先進驅動頁,找到網路設備支援,再找到乙太網路驅動支持,最後根據剛剛的網路卡信息找到相關驅動。

    Device Drivers  --->
        [*] Network device suuort  --->
            [*]   Ethernet driver support  --->

kermel_menuconfig_ethernet

重新編譯

找到驅動之後,可以選擇為核心內建或是模組化。

如果選擇的是核心內建就在編譯一次核心(記得把新的 bzImage 放到 /boot/ )。

$ make bzImage

如果選的是模組化,那就重新編譯並安裝模組,重新製作 rootfs ,再把新的 rootfs 複製到 /boot/ 之中。

$ make modules

移除原本的模組,並將新的模組放入。

# rm -fr mods
# make INSTALL_MOD_PATH=${PWD}/mods modules_install

將新的模組放進去,並重新製作 initrd 。

# cp -r mods/lib ../src/system
$ cd ../src
# make ./make-cpio.sh system my-rootfs-03

注意:如果上面的操作所產生的新的檔案有新的名稱的話,請記得自行去更改 /boot/grub/grub.cfg

重開機進入新的嵌入式系統,如果剛剛是使用模組化,使用 modprobe 指令來加載新的驅動。

# modprobe [module_name]

不管是剛剛選擇內建或是模組化,現在再用 dmesg 都應該可以看到檢測到乙太網路卡了。

# dmesg | grep eth

ifconfig & route

有網路卡之後還要設置 IP 地址,廣播地址,網關,默認路由等等。

如果剛剛都有正常的話,現在網路卡名稱應該叫 eth0 ,如果不同就依情況更改指令。

先設定網路卡介面的 IP 地址、網段和廣播地址。

# ifconfig eth0 [IP_address] netmast [netmask] broadcast [broadcast]

設定路由表。

# route add -net [network] netmast [netmast] eth0
# route add default gw [gateway] metric 1

啟用網路卡。

# ifconfig eth0 up

敲玩這些指令之後現在應該可以連到網路了,使用 ping 指令看看。

# ping 8.8.8.8

如果有回應代表可以連到 Google 的域名解析伺服器了。

ping_8888

如果上面的指令都沒有出錯,卻又連不到網路,請確定 IP 地址、網段、廣播和網關有沒有弄錯。

更多的工作

現在要從老師提供的 tmpfs-00.gz 開始做起。

$ cd ~/rootfs/src
# rm -fr system
# ./extract-cpio.sh tmpfs-00.gz

get x86_64 libs

老師提供的 get-ub-lib64.sh 會去當前系統抓目前系統中的動態連結庫,並放在當前資料夾中。

$ cd ~/rootfs/src
$ ./get-ub-lib64.sh

這時候看看會發現當前資料夾多了 usr/lib/lib64/ ,裡面都包含了 x86_64 的動態鏈結庫。

將這些庫放到 system/ 中就完成了。

# cp -ar lib/ lib64/ usr/ system/

開機腳本

grub.cfg 中, my linux 4.8.6 指定了 linux 開機參數 init=/init ,那接下來就來看看 /init 裡面寫了什麼東西。

vim_init

/sbin/init 會去抓 /etc/inittab 的內容,接下來就來看看 /etc/inittab

vim_etc_inittab

/etc/inittab 的設定可以看到,第 4 行會去執行 /etc/init.d/rcS

在來看看 /etc/init.d/rcS

vim_etc_initd_rcs

第 16 行跑去執行 /etc/init.d/tc-config

在來看看 /etc/init.d/tc-config ,不過這個檔案還蠻長的,直接用搜索的。

vim_etc_initd_tcconfig

在第 206 行去執行了 /opt/bootsync.sh

/opt/bootsync.sh 是每次開機都會被執行的 shell script ,來看看這個 shell script 到底做了哪些事。

vim_opt_bootsync

在第 2 行執行了 /usr/bin/sethostname 這是老師寫的 shell script ,用來改變主機名。

第 3 行執行了 /opt/bootlocal.sh ,用來設定網路和啟動 BUSYBOX 內建的網頁伺服器。

一般來說,開機時,會先跑開機鏡像中的 /init ,完成初始化掛載硬碟之後才會去跑 /sbin/init

想知道詳細的開機過程請閱:BootProcess (https://wiki.debian.org/BootProcess)

Q: /sbin/init 會去抓 /etc/inittab ?可是我安裝的 Linux distribution 怎麼沒有這個檔案?

A: 因為現在大部分都用 systemd 代替了。

ls_sbin_init

修改主機名

想要修改主機名的話就把這行的參數改成新的主機名;或是乾脆把這行刪掉,把新的主機名寫到 etc/hostname 裡面,和修改 etc/hosts 檔案。

一般 Linux 開機之後,都會去讀取 /etc/hostname 抓主機名稱,所以才會建議改這裡。 /etc/hosts 裡面保存了主機名和 IP 對應的表格,如果修改了主機名,這裡面的主機名也要跟著改,不然很多指令和程式都會出錯。

我建議是用第 2 種方法。

下面來演示第 2 種方法修改。

先把 opt/bootsync.sh 執行 /usr/bin/sethostname 的那行刪掉。

opt_bootsync_d_line_2

接下來是修改 etc/hostname

$ cd ~/rootfs/src/system
# echo "my-linux" > etc/hostname

然後再改 etc/hosts ,改成這樣(記得是用 root 權限開啟編輯器)。

vim_etc_hosts

自動設置網路

自動設置網路的 shell script 老師已經寫好放在 opt/bootlocal.sh 了。以網路環境 IP 被分配為 163.13.129.135 、子網路遮罩 255.255.255.0 、網關 163.13.129.254 作為演示。

改成下面這樣。

opt_bootlocal_00

那如果前面的網路卡驅動程式是編譯成模組,可以加上加載模組的指令,以我的電腦的網路卡模組名稱為 alx 為例,改成下面這樣。

opt_bootlocal_01

需要密碼!

老師所提供的這個半成品的用戶 tc沒有密碼的,沒有密碼很多事都做不了。

/etc/passwd 這個檔案是用來記錄當前系統中有那些用戶,雖然他叫 passwd 但它真的只用來記錄有哪些用戶而已,不過硬要把密碼寫在這裡面也是可以啦,不建議。通常 /etc/passwd 是系統中的所有用戶都可以讀取的,所以把密碼寫在這裡是一件非常危險的事情。

/etc/shadow 這個檔案才是用來儲存密碼的,這個檔案只有 rootshadow 群組才有權限讀取。把密碼寫在這裡面才是安全的啊!這裡面的密碼通常也不會用明文保存,都是保存經過雜湊過的結果,免得真的有意外發生然後裡面的內容被不懷好意的人看到,也沒辦法知道真實的密碼。

要創建一個密碼的雜湊會用到 mkpasswd 這個指令,這個指令是在 whois 這個 package 裡面的,如果你正在用的 Linux distribution 沒有的話請根據正在使用的 package manager 安裝。使用 APT 的可以敲以下指令安裝。

# apt-get install whois

安裝完後就可以用 mkpasswd 這個指令了。簡單的介紹一下 mkpasswd 的參數, -m 表示設定雜湊演算法,比較常用的有 md5, sha-256, sha-512 ,沒事的話我都建議使用 sha-512 演算法來做雜湊。

$ mkpasswd -m sha-512

敲完之後它會叫你輸入密碼,輸入的時候不會顯示,輸入完之後直接按 enter 就好了。按完 enter 之後它就會把雜湊值印出來。

mkpasswd_sha_512

最後再把這個砸奏值寫到 etc/shadow 之中。

vim_shadow

完成後在重新製作 initrd ,再放進 /boot 之中,老步驟,該改的自己改。

剛開機的時候還是自動登陸了,不過可以登出在登錄看看是不是打了新的密碼才能進去。

順便說一下 vim 的小技巧,在普通模式下按 v 後移動光標可以選取內容,選取完後按 y 可以複製選取內容, d 可以剪下選取內容。輸入 :e 後面接檔案名可以切換檔案,按 p/P 可以貼上。

好像有點舊了?

老師所用的 kernel 和 BUSYBOX 都不是最新的,來換成目前最新的版本試試。

升級核心

要升級之前要先有新版的原始碼,目前(2018/1/8)最新的版本是 4.14.12 ,去 https://www.kernel.org 把它下載下來。

kernel_org_2018_01_08

把 source code 解壓出來。

$ cd ~/rootfs
$ tar -xf src/linux-4.14.12.tar.xz
設定檔

這時候再將 4.8.6 的設定檔放進去,並更新設定檔。跟新這個步驟是很重要的,核心版本升級的時候通常會伴隨一些設定上或是驅動程式的更新,如果沒有更新舊編譯... 我也沒試過啦,反正要更新就是了。裡面的選項非常多,如果一個一個手動設置的話會花上很多時間,而且可能又對該項目不清楚,也有可能遺漏某些設置,所以還是推薦使用自動升級。

$ cp src/linux-config-4.8.6 linux-4.14.12/.config
$ make oldconfig

這時候它會一個一個問說要不要變更某個選項,這時候都選建議的設置舊好,選項非常的多,連按 enter 也會按很久。這時候就可以使用 yes 這個指令來完成,這個指令會自動連續輸出 y 直到接收的程式結束為止,把它改成 yes "" 就相當於是一直在按 enter 了,非常的方便。

$ cd linux-4.14.12
$ yes "" | make oldconfig

不過這樣還是很麻煩,他們在 Makefile 還提供了 olddefconfig 來自動完成所有的工作。

$ make olddefconfig
編譯

4.14.9 版本之後,編譯 Linux kernel 需要多安裝一個依賴程式庫了,安裝完後才能編譯。

make_bzImage_failed_libelf

這時候去安裝 libelf-dev 就好了。

# apt-get install libelf-dev

Executable and Linkable Format(https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)

接下來就是編譯 bzImage 了。

$ make -j 8 bzImage

接下來是 modules ,不過還是一樣的老步驟。

$ make -j 8 modules
# make -j 8 INSTALL_MOD_PATH=${PWD}/mods modules_install

然後在把新的 modules 放到 ~/rootfs/src/system 當中, kernel & modules 的部分就完成了。

BUSYBOX

最新的 BUSYBOX 可以去 https://busybox.net 下載,目前(2017/1/8)最新的版本是 1.28.0 。 (不過目前 1.28.0 的版本有問題,請改用 1.27.2

下載好之後解壓。

$ cd ~/rootfs
$ tar -xf src/busybox-1.28.0.tar.bz2

解壓完後,複製並更新設定檔。

$ cp src/config-1.22.1 busybox-1.28.0/.config
$ yes "" | make oldconfig

編譯並安裝。

$ make
# make install

製作新的 initrd

$ cd ~/rootfs/src
# cp -ra ../busybox-1.28.0/tiny/* ../linux-4.14.12/mods/lib system
# ./make-cpio system my-initrd-02

做好之後也是去改開機選單,把新的 initrd 和 bzImage 放進 /boot

完成!!

這時候趕快看看自己建置的嵌入式系統。是不是很有成就感呢?全世界目前應該還沒有多少人在用最新的核心,而你就是其中一個。

new_kernel

Dropbear SSH

目前的嵌入式系統是沒辦法進行遠端連入的,要用 SSH 的話 openssh-server 是個不錯的選擇,有非常強大的功能,但對於嵌入式系統來說 openssh-server 又太過龐大。這時候 Dropbear 就是個不錯的選擇了, Dropbear 有對容量進行優化,占用的空間非常的小,該有的功能也有,對一個嵌入式系統來說是一個不二的選擇。

製作

當然,要安裝也是要先從原始碼開始編譯。先從它的官方網站下載最新的原始碼,目前(2017/1/8)最新的版本是 2017.75

https://matt.ucc.asn.au/dropbear/dropbear.html

下載下來之後解壓。

$ cd ~/rootfs
$ tar -xf src/dropbear-2017.75.tar.bz2
檢查環境

在編譯之前, Dropbear 會先檢查一次編譯環境,確認該有的依賴庫都有了才會生成 Makefile 。如果有缺哪個依賴庫的話,它會提示缺了哪個。有缺在安裝就好,不用緊張。

$ cd dropbear-2017.75
$ ./configure

檢查的時候可以加上 --prefix 參數指定依賴庫的路徑,默認會去 /usr/lib 檢查。

當最後出現

confifure: Now edit options.h to choose features.

才表示成功的完成環境的檢查。

dropbear_finished

編譯

編譯的時候加上參數 DESTDIR ,它編譯完之後就會把相對的檔案放指定的位置。

# make DESTDIR=${PWD}/_install install
製作密鑰並放入安裝目錄
# ./dropbearkey -t dss -s 1024 -f dropbear_dss_host_key
# ./dropbearkey -t rsa -f dropbear_dss_host_key
# ./dropbearkey -t ecdsa -f dropbear_dss_host_key
# mkdir -p _install/etc/dropbear
# mv dropbear_dss_host_key _install/etc/dropbear
# mv dropbear_rsa_host_key _install/etc/dropbear
# mv dropbear_ecdsa_host_key _install/etc/dropbear
將執行檔從 usr/local 移動到 usr
# mv _install/usr/local/* _install/usr
# rmdir _install/usr/local
去除不中重要的資訊
# strip _install/usr/bin/*
# strip _install/usr/sbin/*
加入啟動腳本
# mkdir -p _install/etc/init.d
# cp S50dropbear _install/etc/init.d
# chown 0.0 _install/etc/init.d/S50dropbear
移除說明文件
# rm -fr _install/usr/share

目前的狀況應該要是這樣的。

tree_dropbear

安裝
# cp -r _install/* ../src/system
啟動執行

opt/bootsync.sh 結尾加上

/etc/init.d/S50dropbear start &

opt_bootlocal_start_dropbear

測試

在另一台主機使用 ssh 指令連入。

ssh_dropbear

自製懶人編譯腳本

新建檔案,將以下內容複製貼上並放到 Dropbear 目錄下運行即可。此腳本僅限給高手使用(注意:本腳本生成的開基啟動腳本名稱是 dropbear )。

#!/bin/bash

# make dropbear easily

# please change your work directory to the dropbear directory

INS_DIR=${PWD}/"_install"
USR=${INS_DIR}/"usr"
LOCAL=${USR}/"local"
BIN=${USR}/"bin"
SBIN=${USR}/"sbin"
ETC=${INS_DIR}/"etc"
CFG_DIR=${ETC}/"dropbear"
INITD=${ETC}/"init.d"

STRUP=${PWD}/"dropbear"
DSS=${PWD}/"dropbear_dss_host_key"
RSA=${PWD}/"dropbear_ras_host_key"
ECDSA=${PWD}/"dropbear_ecdsa_host_key"
CONFIG=${PWD}/"configure"
MKFILE=${PWD}/"Makefile"
KEYGEN=${PWD}/"dropbearkey"

CFG_LOG=${PWD}/"configure.log"
MK_LOG=${PWD}/"make.log"

[ ${UID} -ne 0 ] && echo "please run $0 as root" && exit 1

#[ ! -e ${STRUP} ] && echo "${STRUP} is missing" && exit 1

if [ ! -e ${MKFILE} ]; then
  [ ! -e ${CONFIG} ] && echo "${CONFIG} doesn't exist" && exit 1
  echo "checking environment..."
  ${CONFIG} > ${CFG_LOG} ||
  ( echo "failed to make Makefile, saved log at ${CFG_LOG}" && exit 1 )
  echo "configuration log saved at ${CFG_LOG}"
fi

[ -e ${INS_DIR} ] && ( rm -fr ${INS_DIR} ||
    ( echo "failed to remove ${INS_DIR}" && exit 1 ) )

echo "making dropbear"
make DESTDIR=${INS_DIR} install > ${MK_LOG} ||
( echo "failed to make dropbear, saved log at ${MK_LOG}" && exit 1 )
echo "making log saved at ${MK_LOG}"

[ ! -e ${KEYGEN} ] && echo "${KEYGEN} doesn't exist" && exit 1
echo "generating keys"
[ ! -e ${DSS} ] && ( ${KEYGEN} -t dss -s 1024 -f ${DSS} ||
    ( echo "failed to generate DSS key" && exit 1 ) )
[ ! -e ${RSA} ] && ( ${KEYGEN} -t rsa -f ${RSA} ||
    ( echo "failed to generate RSA key" && exit 1 ) )
[ ! -e ${ECDSA} ] && ( ${KEYGEN} -t ecdsa -f ${ECDSA} ||
    ( echo "failed to generate ECDSA key" && exit 1 ) )

echo "making config file"
mkdir ${ETC} || exit 1
mkdir ${CFG_DIR} || exit 1
cp ${DSS} ${CFG_DIR} || exit 1
cp ${RSA} ${CFG_DIR} || exit 1
cp ${ECDSA} ${CFG_DIR} || exit 1

mv ${LOCAL}/* ${USR} || exit 1
rm -fr ${LOCAL} || exit 1
strip ${BIN}/*
strip ${SBIN}/*

cat > ${STRUP} << EOF || (echo "failed to write to ${STRUP}" && exit 1)
#!/bin/sh
#
# Starts dropbear sshd.
#

# Make sure the dropbearkey progam exists
 [ -f /usr/bin/dropbearkey ] || exit 0

# Check for the Dropbear RSA key
if [ ! -f /etc/dropbear/dropbear_rsa_host_key ] ; then
	echo Generating RSA Key...
	/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi

# Check for the Dropbear DSS key
if [ ! -f /etc/dropbear_dss_host_key ] ; then
	echo Generating DSS Key...
	/usr/bin/dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
fi

umask 077
export XTABLES_LIBDIR=/usr/lib/xtables

start() {
 	echo -n "Starting dropbear sshd: "
	start-stop-daemon --start --quiet --pidfile /var/run/dropbear.pid --exec /usr/sbin/dropbear
	echo "OK"
}

stop() {
	echo -n "Stopping sshd: "
	start-stop-daemon --stop --quiet --pidfile /var/run/dropbear.pid
	echo "OK"
}

restart() {
	stop
	start
}

case "$1" in
  start)
  	start
	;;
  stop)
  	stop
	;;
  restart|reload)
  	restart
	;;
  *)
	echo $"Usage: $0 {start|stop|restart}"
	exit 1
esac

exit $?

EOF

mkdir ${INITD} || exit 1
cp ${STRUP} ${INITD} || exit 1

echo "done"
exit 0

$ cd ~/rootfs/dropbear-2017.75
$ touch make-dropbear.sh
$ gedit make-dropbear.sh
$ chmod +x make-dropbear.sh
# ./make-dropbear.sh

vsftpd

現在的系統並沒有 ftp 的功能,所以要安裝 vsftpd 。 vsftpd 也是一個經過優化專門用於嵌入式系統的程式。

vsftpd 的原始碼可以在 https://security.appspot.com/vsftpd.htm 下載,目前 (2018/1/9)最新的版本是 3.0.3

下載下來後也是先解壓縮。

$ cd ~/rootfs
$ tar -xf src/vsftpd-3.0.3.tar.gz
$ cd vsftpd-3.0.3

這時候看看解壓完的樣子。

ls_vsftpd_before_compilation_3_0_3

這裡面有幾個比較重要的文件,像是 READMEINSTALL ,這幾個比較重要的說明文件建議有空的時候看一看。還有一個是 FAQ ,問問題之前一定要看! (frequently asked questions)

解壓出來之後就進行編譯,這個的編譯比較簡單。

$ make -j 8

這時候看看編譯完的樣子。

ls_vsftpd_after_compiled_3_0_3

安裝

vsftpd 的安裝要手動進行,有點麻煩。

編譯完後有兩個重要的檔案,分別是 vsftpdvsftpd.conf ,一個是編譯完的可執行檔,另一個是默認設定檔。

這時候先將 vsftpd 放到 usr/sbinvsftpd.conf 放到 etc

$ cd ~/rootfs/src
# cp ../vsftpd-3.0.3/vsftpd system/usr/sbin
# cp ../vsftpd-3.0.3/vsftpd.conf system/etc
創建 ftp 用戶

創建 ftp 用戶需要修改 3 個文件,分別是 etc/passwdetc/shadowetc/group

先來修改 etc/passwd

# vim system/etc/passwd

打開後新增以下內容

ftp:x:10:10:ftp:/var/ftp:/bin/sh

vim_etc_passwd_ftp

修改 etc/shadow

# vim system/etc/shadow

打開後新增以下內容

ftp:*:13525:0:99999:7:::

vim_etc_shadow_ftp

修改 etc/group

# vim system/etc/group

打開後新增以下內容

ftp:x:10:

vim_etc_group_ftp

修改設定檔

默認的設定檔只能用於匿名登陸,要修改設定檔才能讓本地用戶登陸。

# vim system/etc/vsftpd.conf

如果要關閉匿名用戶登陸, 將 anonymous_enable 設成 NO

允許本地用戶登陸 local_enable 設成 YES

允許本地用戶寫入 write_enable 設成 YES

vi_etc_vsftpd_conf1

這時候在新建 usr/share/empty 資料夾。

# mkdir -p system/usr/share/empty
開機啟動

讓 vsftpd 可以開機就啟動最簡單的方式就是把它加到 opt/bootsync.sh 裡面。

打開 opt/bootsync.sh

# vim system/opt/bootsync.sh

打開過後在最後面加上

/usr/sbin/vsftpd &

這樣就完成了最簡單的開基啟動了!

vi_opt_bootsync_vsftpd

測試

在弄完剛剛的安裝和設定之後,重新製作 initrd 並重新開機進入到我們製作的嵌入式系統。

在另一台主機使用 ftp 指令連入。

ftp_test

Show Comments