其中用到的程式碼可能會有變化。根據實際情況理解。
整體設計
make-tinycore-linux 是一個把以下流程跑一遍的腳本:
1 | apply_build_rc ---------------------- 應用 build.rc 設定(如果有) |
每一個流程都對應著一個 bash 函数,函數定義的順序也剛好就是執行順序。
整個腳本可以分成以下階段:
- 配置处理:apply_build_rc, apply_tc_settings, prepare_workspace
- 系统下载:prepare_tinycore_linux_image
- 軟件依賴處理:prepare_packages
- 修改階段:extract_rootfs, apply_packages, apply_additional_patches
- 構建階段:generate_new_rootfs, copy_core
配置處理
於 apply_build_rc 之前,腳本還會作一系列檢查:
- 當前用戶是否為 root。畢竟 rootfs 內的大部分檔案權限都是 root。
- 檢查依賴的命令是否存在。当前来说 curl、unsquashfs、cpio、zcat、uniq 都是必须的。
這時候以下命令被定義:
- require:檢查給定命令是否存在
- DOWNLOAD:下載檔案
- FETCH:獲取 http 檔案內容
- cache_files_enabled: 判斷檔案緩存是否被啟用
apply_build_rc 會在當前目錄尋找 build.rc
。如果存在,則應用它。所以,變量都可從此文件中修改。
apply_tc_settings 根據設定的 TC_VERSION
和 TC_ARCH
來決定遠端 repo 裡,內核和 initrd 的的檔案名。若為 x86,則為 vmlinuz 和 core.gz;若為 x86_64,則為 vmlinuz64 和 corepure64.gz。這兩個變量的默認值是 13
和 x86_64
。
prepare_workspace 做了如下事情:
- 檢查 build 檔案夾是否存在。若不存在則創建。
- 安裝退出鉤子。當腳本結束時選擇是否執行鉤子(通過
DO_NOT_CLEAN_UP
控制)
系統下載
prepare_tinycore_linux_image 很簡單:
- 如果沒有緩存,下載內核
- 如果沒有緩存,下載 initrd
如果緩存被關閉,將會安裝對應的刪除鉤子。
軟件依賴處理
prepare_packages 會定義三個函數:
- resolve_packages
- resolve_package_recursively
- download_and_unpack_packages
主要的流程是先 resolve_package,然後 download_and_unpack_packages。但為了實現遞歸依賴處理,需要 resolve_package_recursively 來幫忙。它的原理很簡單:
1 | resolve_package_recursively() { |
wc -l
是計算输入文件行數的意思,但它的輸出数字开头會包含空格,所以用 tr -d [:space:]
過濾掉空格之後就只剩下数字了。tr -d
意思是刪除匹配的字符,而這裡匹配的是空格。。
cat "$pkgdep" | sed '/^$/d'
中 sed
用於過濾掉包依賴列表裡的空行。从 http 服务器获取的内容是不可控的,为了防止空行带来的问题,我这里用 sed
清除掉所有空行,同时 resolve_package_recursively
在遇到空包名的時候也會退出循環。雙保險
以上過程最後,會產出一個 PACKAGE_LISR
的文件,包含去重之後的結果。這個文件列表就可以拿去對照著從 tinycore 下載軟件了。
每次下載包含下載和解包兩個操作。當緩存中(build/tcz
)存在這個包,則跳過下載。加載完成後,開啟一個 sub-shell 來執行解包。
1 | download_and_unpack_packages() { |
unsquashfs 使用 quiet 可以只輸出進度條。配合只顯示進度條的 DOWNLOAD 命令(稍後會講的),看著就很不錯。
修改
修改的第一步是先解包。
extract_rootfs
就是簡單地把 initrd 解壓出來
1 | ( mkdir -p "$rootfs"; cd "$rootfs"; gzip -d -c "$BUILD_DIR/$TC_RAMDISK" | cpio -idm ) |
apply_packages
把解包後的軟件拷貝到 rootfs 檔案夾,維持原有權限設置,覆蓋內容。
1 | cp -Rp "$BUILD_DIR/squashfs-root/usr/." "$BUILD_DIR/rootfs/usr/" |
apply_additional_patches
檢查 build.rc
中是否有定義 additional_patchs
。若有,則執行
1 | apply_additional_patchs() { |
構建
這一階段就是把 rootfs 重新打包成 initrd。然後把內核複製到目的地,完工。
1 | generate_new_rootfs() { |
DOWNLOAD 和 FETCH
我使用了 DOWNLOAD 和 FETCH 兩個指令來區分文件下載和信息獲取操作。
1 | CURL_DOWNLOAD="curl -L -# --retry 10 --retry-all-errors --connect-timeout 5 --speed-limit 10 --speed-time 5" |
--retry
指定重試次數;-L
跟隨跳轉;-s
是安靜模式,不輸出信息;-f
是遇到错误时安静不输出;--retry-all-errors
任何錯誤出現都重試;--connect-timeout
連接超時秒數;--speed-limit
低於這個速度重試;--speed-time
速度低於指定速度多久之後重試,如果不指定速度,則默認為 1;-#
打印一個進度條。
下回分解
下一篇文章將講解內核啟動後的配置過程是如何實現的。
(未完待續)