我在去年折騰過一陣 FreeBSD ,當時是安裝在家中的舊電腦上當 NAS 用的。最近 另一台電腦的硬盤壞掉,就把裝着 FreeBSD 的硬盤拆下來湊合用了;然後經過一 番研究,我將 FreeBSD 安裝到了閒置的 U 盤上。
這本來應該是很簡單的事情,但是我只有一隻 U 盤,沒有光驅,所以這隻 U 盤既 是安裝目標,又是安裝介質……
FreeBSD 的版本和安裝映像的格式
FreeBSD 在十月份剛剛發布了新版本 11.0 ,而我的安裝介質是 U 盤,所以用的 是 memstick 映像 (不同安裝映像的區別見 FreeBSD Handbook 2.3.1 )。
這個 memstick 映像是帶有分區表的完整磁盤映像,使用 file 命令可以看到 分區表是 GPT 格式(以下命令都是在 Linux 下執行的,「❯」和「#」字符是 shell 命令行提示符):
1 2 | ❯ file FreeBSD-11.0-RELEASE-amd64-memstick.img FreeBSD-11.0-RELEASE-amd64-memstick.img: GPT partition table, version 1.0, GUID: fd366718-85e7-11e6-a2f6-002590ec6166, disk size: 1433746 sectors of 512 bytes |
所以我們可以用 gdisk 命令看看這個映像上都有哪些分區:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ❯ gdisk FreeBSD-11.0-RELEASE-amd64-memstick.img GPT fdisk (gdisk) version 1.0.1 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Command (? for help): p Disk FreeBSD-11.0-RELEASE-amd64-memstick.img: 1433746 sectors, 700.1 MiB Logical sector size: 512 bytes Disk identifier (GUID): FD366718-85E7-11E6-A2F6-002590EC6166 Partition table holds up to 4 entries First usable sector is 3, last usable sector is 1433743 Partitions will be aligned on 1-sector boundaries Total free space is 0 sectors (0 bytes) Number Start (sector) End (sector) Size Code Name 1 3 1602 800.0 KiB EF00 2 1603 1727 62.5 KiB A501 3 1728 1431695 698.2 MiB A503 4 1431696 1433743 1024.0 KiB A502 Command (? for help): |
在第一個 Command 提示符處我們輸入 p 命令打印分區表,可以看到一共 四個分區:
- EFI 系統分區;
- FreeBSD 啓動分區;
- FreeBSD 系統分區(「/」目錄);
- FreeBSD 交換(Swap)分區。
直接用 dd 命令將這個映像寫到 U 盤上,我們就可以使用 U 盤啓動電腦了(請務 必將 sdb 替換成正確的設備名稱):
1 | # dd if=FreeBSD-11.0-RELEASE-amd64-memstick.img of=/dev/sdb bs=1M conv=sync |
Live 系統的限制
經由這個 U 盤啓動的電腦會進入一個完整的 FreeBSD 系統(姑且稱之爲 Live 系 統)。我們的安裝目標就是這隻 U 盤,是不是直接用這個 Live 系統就可以了呢?
這取決於我們的需求。這個 Live 系統和許多嵌入式系統類似,根目錄 / 是只 讀的,而且根目錄所在的分區只有不到 700M, 將來更新系統或者安裝新軟件的時候 會非常麻煩。
當然,我們也沒辦法通過執行安裝程序將 FreeBSD 安裝到同一個 U 盤上,所以只 能儘量調整 U 盤上的分區以符合我們的要求。大概有兩個方法:
- 在 U 盤上新建一個可讀寫的分區,日常使用中新增的數據放到這個分區裡;
- 調整分區表,將根目錄所在分區擴大,並掛載爲讀寫模式。
爲了最大限度地利用 U 盤,除了 FreeBSD 用到的分區外,我還希望創建一個 NTFS 分區,這樣「理論上」這個 U 盤也可以在其他 Windows/Linux 機器上使用。
既然如此,我決定先嘗試第一種方法,因爲看起來比較簡單。
GPT 分區表的坑
我的 U 盤有 32G 空間,但是上面寫入的分區表只使用了約 700M, 我們來試試創 建一個 4G 大的分區:
1 2 3 4 5 6 | # gdisk /dev/sdb ...(各種信息)... Command (? for help): n No table partition entries left Command (? for help): |
這裡的 n 命令就是「新建分區」的意思,但是 gdisk 給我們扔來一條 錯誤信息,說是「沒有分區表條目了」。誒? GPT 照理說應該能支持四個以上分 區的,這是怎麼回事?
Google 一番之後我在 維基百科 上看到了 GPT 的具體結構,原來 GPT 的 頭部(header)和分區表是分開存儲的。 Header 的大小是固定的,位於第二個 扇區(sector),而分區表由第三個扇區開始,長度是可變的,具體長度由 header 中的一個字段指定。
回顧前面我們用 gdisk 看到的映像分區信息,第一個分區是從第四個扇區 (sector 3)開始的,所以我們只有一個扇區的空間分配給了分區表。每個分區 表條目是 128 字節,所以一個 512 字節的扇區只能保存四個條目。
在這個情況下,要增加分區表條目,就只能將分區表後面的各個分區依次向後移 動,以騰出空間。
既然都要這樣大動干戈了,我還是採用第二種方法,順勢將 FreeBSD 的根目錄 擴大好了。
調整分區
前面已經說過了,我們要進行兩個操作:
- 把所有分區向後移動,騰出分區表的空間;
- 擴大 FreeBSD 根目錄所在分區。
我的系統現在是 Linux, 而貌似沒有哪個 Linux 下的磁盤工具提供了「移動 分區以及其中的數據」這樣的功能,所以我們只能親自上陣了。
GPT 分區表的默認條目數是 128, 所以我決定騰出 128 * 128 / 512 = 32 個 扇區的空間。減去已經存在的一個扇區,我們需要將所有分區向後移動 31 個 扇區(我的 U 盤可以採用 512 字節的扇區大小,但是請注意並不是所有存儲 設備都可以,進行計算前請務必確認你的扇區大小)。
在 Linux/Unix 下,「所有硬件設備都是文件」,所以我們可以用讀寫普通文 件的方式去移動分區數據:
1 2 | # dd if=/dev/sdb of=./partition_data skip=3 bs=512 count=$((1433743 + 1 - 3)) status=progress # dd if=./partition_data of=/dev/sdb seek=34 bs=512 status=progress conv=notrunc |
第一個命令將 U 盤中所有分區的數據讀出,暫存在 partition_data 文件 內;第二個命令將暫存的數據重新寫入 U 盤,不過與讀出時的位置相比向後偏 移了 31 個扇區。
移動數據之後,分區表也要做相應的修改,才能對應上新的分區位置。我的做 法是用 gdisk 將所有分區刪除,然後再重建,不過起始和結束位置都 +31 (向後移動 31 個扇區)。
現在我們可以修改 GPT header 裡的分區表大小了:
1 2 3 4 5 6 7 8 9 | # gdisk /dev/sdb ...(各種信息)... Command (? for help): x Expert command (? for help): s Current partition table size is 4. Enter new size (4 up, default 128): 128 Expert command (? for help): w |
最後不要忘記用 w 命令寫入更改後的數據。現在我們可以創建最多 128 個分區了。但是在創建任何新分區之前,我們要先擴大 FreeBSD 根目錄所在 的第三個分區,而這個操作需要使用 FreeBSD 系統,因爲用到 FreeBSD 下的 growfs 命令。
我們用調整過的 U 盤啓動電腦,進入 U 盤上的 FreeBSD live 系統(用戶名 是 root, 密碼爲空),先確認一下分區情況(以下命令都在 FreeBSD 下 執行;請注意設備名稱,你的 U 盤不一定是 da0 ):
1 | # gpart show /dev/da0 |
可以看到 freebsd-ufs 分區之後緊跟着一個 freebsd-swap 分區。 Swap 分 區保存的是臨時數據,完全可以刪掉,不過還是讓我們先確認一下該分區有沒 有被掛載:
1 | # swapinfo |
如果這個 swap 分區沒有在 swapinfo 裡列出,我們就可以把它刪除了:
1 | # gpart delete -i 4 /dev/da0 |
然後將根目錄所在的分區擴大到 4G (當然你也可以選擇其他大小,如果準 備安裝桌面環境的話需要 2G 以上的空間):
1 | # gpart resize -i 3 -s 4G /dev/da0 |
分區上的文件系統也需要作出調整,才能使用整個擴大後的分區:
1 | # growfs /dev/da0p3 |
至此我們已經完成了 U 盤分區的調整。爲了保險起見我們還可以添加一個更 大的 swap 分區:
1 | # gpart add -t freebsd-swap -s 512M /dev/da0 |
將根目錄掛載爲可讀寫模式
要將根目錄掛載爲讀寫模式很簡單,進入系統後用 mount 命令重新掛載 一次就可以了:
1 | # mount -rw / |
要在每次啓動時都進入讀寫模式,則需要更改 /etc/fstab 文件:
1 | /dev/ufs/FreeBSD_Install / ufs ro,noatime 1 1 |
將這一行選項部分的 ro 改爲 rw 即可:
1 | /dev/ufs/FreeBSD_Install / ufs rw,noatime 1 1 |
另外這裡還有一個坑:由於根目錄是只讀的,所以 /var 和 /tmp 目錄被掛載爲 md 文件系統(相當於 ram disk, 見 man mdconfig ), 大小分別爲 32M 和 20M, 這在很多情況下都不夠用,但是我找了很久都沒發 現這兩個目錄是在哪裡被掛載的, /etc/fstab 根本沒有對應的條目, 直到在 /etc/defaults/rc.conf 裡見到這幾個選項:
1 2 3 4 5 6 | tmpmfs="AUTO" tmpsize="20m" tmpmfs_flags="-S" varmfs="AUTO" varsize="32m" varmfs_flags="-S" |
看來 FreeBSD 還真是在嵌入式領域有着廣泛應用啊,竟然有兩個 rc 腳本 ( /etc/rc.d/var 和 /etc/rc.d/tmp )專門處理根目錄爲只讀的 情況。由於我們的根目錄是可讀寫的,而且內核支持更方便的 tmpfs, 我在 /etc/rc.conf 裡將這兩個腳本關掉:
1 2 | tmpmfs="NO" varmfs="NO" |
當然 /etc/fstab 也要作出相應調整,將 tmpfs 掛載上去:
1 2 | tmpfs /tmp tmpfs rw,nosuid,noexec,mode=01777 0 0 tmpfs /var/tmp tmpfs rw,nosuid,noexec,mode=01777 0 0 |
這裡的掛載選項是爲了加強安全性,有興趣的同學可以自行 google. 重啓電 腦並選擇用 U 盤引導,我們就有一個與普通硬盤安裝相差無幾的 FreeBSD 系統了。
網絡設置
接下來你可能想要開始用 pkg 或者 ports 安裝軟件了,但是我們 還沒有網絡呢。普通網卡比較簡單,一般只要插上網線然後執行 dhclient 或者用 ifconfig 手動配置 IP 地址就足夠了,這裡主要討論無線網絡的 配置。
我個人不想在 Live 系統的配置文件裡保存特定的網絡信息,因爲這樣 U 盤 插到別的網絡環境中時不夠靈活,所以採用全手動的配置方式。如果你覺得無 所謂,可以按照 官方文檔 進行自動配置。
我們 U 盤上的 FreeBSD 系統在啓動時是默認不啓用無線網絡的,甚至連網卡 驅動都沒有加載,我們首先要確認當前機器上的無線網卡型號:
1 | # pciconf -lv | grep -A5 -B5 -i wireless |
對於最常見的 Atheros 和 Intel 的無線網卡,驅動已經編譯到 FreeBSD 11.0 的默認內核裡了,所以我們不需要做額外操作;對於其他型號的網卡,就可能 需要找一下對應的驅動模塊,然後用 kldload 命令載入。
確認驅動被正確載入之後,我們新建一個名爲 wlan0 的無線設備:
1 | # ifconfig wlan0 create wlandev ath0 |
這裡的 ath0 是 Atheros 網卡的默認名稱,可以通過查閱對應驅動的文檔 獲得。此命令成功後再次執行 ifconfig 命令,會列出 wlan0 設備。
然後寫一個關於無線網絡的配置文件:
1 2 3 4 5 6 | # cat << EOF > ./wpa_supplicant.conf network={ ssid="<網絡名稱>" psk="<WiFi密碼>" } EOF |
執行 wpa_supplicant 命令進行連接:
1 | # wpa_supplicant -i wlan0 -c ./wpa_supplicant.conf -B |
最後,如果你的網絡使用 DHCP 分配地址,執行 dhclient 獲得一個 IP:
1 | # dhclient -b wlan0 |
這時我們的電腦就上線了,可以執行 freebsd-update 和 pkg 之類的在 線工具更新或者安裝軟件。