FreeBSD 2.2.9 Released!

居然有人想起拿 2.x 來挑逗大家...:FreeBSD 2.2.9 Released!

It is my great pleasure and privilege to announce the availability of FreeBSD 2.2.9-RELEASE. This release is the culmination of SEVENTY-SEVEN months of tireless work by the FreeBSD developers, users, their children, and their pets. Significant features in this release:

遠端升級 FreeBSD (4.x to 5.4)

有很多單位的 server 仍然都保持在 4.x,主要的原因包括了:

  • 4.x 的 performance 比 5.4 好:包括了 SMP、I/O、blah blah... 效率不彰的其中一個原因是因為有很多 kernel code 重新改寫,還沒有經過調校 (像是邏輯上的錯誤造成多跑幾個迴圈,CPU time 多吃了一些但不會因此當機的情況),這方面比起 4.x 所花的時間少太多。
  • 5.x 的系統不穩定:在 5.0 剛出來的時候幾乎是「不能用」的狀態,對一般的電腦每天當個兩次也許沒什麼,但對 server...。這個情況在 5.3 的時候有了改善,但直到 5.4 之後才穩定下來。

但上面所說的這兩點在 6.0 有了變化:

  • 6.x 的 performance 比起 5.x 好太多,主要幾個原因包括了 Giant lock code 愈來愈少、調校了不少子系統,同時,在單 CPU 的機器上比起 4.x 已經差不多。而 6.x 的 Kernel-threading 效率則是超越了 4.x 的 Userland-threading,這點使得不少使用 Thread 的程式受益。
  • 6.x 系統的穩定度已經獲得大幅改善,目前已知的問題裡只剩下 ata driver 比較大,但目前在 6.1-PRERELEASE 已經在處理,所以,6.1-RELEASE 會解決。

基於這些理由,有不少人願意嘗試 6.x。如果是重新安裝當然沒問題,但也有已經安裝好的機器,裡面的資料不方便備份再重灌,而且這些機器並不是很容易接觸到 console (機器在國外,或是進機房需要蓋二三十個章之類的...),這會使得升級上會產生困難,於是就有些人想要搞 remote upgrade for major version changing...

由於 remote upgrade 整個難度在於需要 single user mode 操作的部分,雖然依照官方的說法,4.x to 5.4 與 5.4 to 6.x 都需要 single user mode,但實際上 5.4 to 6.x 可以先從別台抓 6.0 的 libc.so.6libm.so.4 再直接升級 (聽起來很 dirty,不過可以動),所以整個難度在於 4.x to 5.4。

另外一個需要注意的是建議先升級到 4.11 再處理。我曾經試過一台 4.8 要直接跳到 5.4 的,發現在 mergemaster 的地方一直失敗,最後直接到 console 前,在 single user mode 後 make installworld 裝入新的 mergemaster...

至於為什麼會選擇升級到 5.4 (RELENG_5_4) 而不選 5.x (RELENG_5),這是因為 5.x 這陣子在準備 5.5-PRERELEASE,有不少東西改來改去的,遇到時間點不對的情況 checkout 出來的 code 會使得系統爛掉,所以找個確定可以用的版本會比較好。

以下是我從 4.x 升級到 5.4 的方法,主要是參考 5.4 的 /usr/src/UPDATING,以及我之前寫的 遠端從 4.7-x 升級到 5.0-RELEASE 這篇文章。

注意,以下的步驟不適合對 不熟的人使用。同時,我們也不保證以下的步驟能夠達成你想要的目的,如果您使用以下步驟而造成任何問題,我們不負任何責任

  • 開兩個 login shell,都先 su 成 root,也就是說下面的指令不要透過 處理,原因後述。
  • 先把 /usr/src 下的東西更新到 RELENG_5_4,可以透過 或是 更新。
  • 修改 /etc/rc.conf,將 background_fsck="NO" 加上去以避免不穩定的 background fsck 造成系統出問題。
  • /etc/make.conf 的設定,主要是要把 CPUTYPE=some_kind_of_cpu 改成 CPUTYPE?=some_kind_of_cpu,以及把 CFLAGSCXXFLAGSCOPTFLAGS 拿掉,改用系統預設值。
  • 更新完以後執行 make buildworld,此時另外一個窗可以開始改 kernel config file,建議整個重寫會比較安全。(如果你認為你對 有經驗的話,可以用 vimdiff 同步改)
  • buildworld 完以後開始 make buildkernel
  • buildworldbuildkernel 都成功後,將 /sys/i386/conf/GENERIC.hints 複製一份到 /boot/device.hints

    cp /sys/i386/conf/GENERIC.hints /boot/device.hints

  • 接下來到 /usr/src/sys/boot 下執行 make STRIP="" install 更新 boot loader。
  • 然後跑 make installkernel,此時會建立 /etc/pam.d 這個目錄,這會使得 sshd 無法登入,這也就是先前要求你先登入且先變成 root 的原因。
  • 下面的步驟在 UPDATING 裡要求你要在 single user mode 做,這時候就要想辦法解決:
  • 先到其他台 (5.x 或 6.x 的機器) 執行 dd if=/dev/random of=blah count=1 bs=4k,然後將產生出來的 blah (應該是 4096 bytes) 複製到要升級機器上的 /entropy
  • mergemaster -p 同步 /etc/master.passwd/etc/group (主要是補上幾個 user 與 group)。不過有些人可能會 mergemaster 的 merge 功能覺得太簡陋,如果你對 vimdiff 熟悉,可以用 vimdiff /etc/master.passwd /usr/src/etc/master.passwd 同步,再用 mergemaster -p 更新其他的部分。記得,做完後要進入 vipw 再強制寫入,讓系統將 master.passwd 的內容同步到 /etc/pwd.db/etc/spwd.db。而 /etc/group 的部分改完就會生效,不需要用程式處理。
  • 執行 rm -rf /usr/include/g++
  • 使用 mergemaster -i 更新系統檔案。(主要是 /etc 下的 scripts)
  • 接著,最後的 installworld 仍然要在 single user mode 下執行,所以我們要修改 /etc/rc 的開頭,使得重新開機後在 single user mode 下執行 installworld,然後重新開機:
    if [ -r /not.ok ]; then
      /sbin/mount -u /
      /sbin/mount -a
      /bin/rm -f /not.ok
      cd /usr/src
      /usr/bin/make installworld DESTDIR=/
      cd /
      /sbin/umount -a
      /sbin/reboot
    fi

    然後把 /not.ok 生出來:

    touch /not.ok

    接著重開機等個十到二十分鐘 (看機器的速度),祈禱他成功 :p

升級完畢以後,記得把 /etc/pam.conf 砍掉。

另外,雖然有 compatible library 可以用,但還是要找個時間把系統的 packages 重新安裝,這點可以透過 幫你處理,不過有一些 packages 已經放在 base system 了,在 升級完畢後應該就不會有 dependency,可以直接移掉:

  • devel/libgnugetopt
  • devel/readline
  • net/portsnap
  • sysutils/rc_subr

FreeBSD ports 的 libtool 大變動

在 rafan 板上看到 移除,然後把 搞定,結果因為 pkg-plist 會跟著改變,整個 ports tree (~14000 ports) 裡面有 ~2000 ports 需要 recompile:

  Log:
  Conversion to a single libtool environment.
  
  Approved by:    portmgr (kris)

完整的 cvs log 在這 (注意:網頁很大!):cvs commit by Ade Lovett,看起來是故意在 RELEASE 前 (5.5-RELEASE 及 6.1-RELEASE) 弄出來,讓新的系統就直接是新的環境。

Lightbulb

看到的笑話:How Many Gizmodo Writers Does It Take to Change a Light Bulb?

我看到之後第一個想到的是 的 FAQ:How many FreeBSD hackers does it take to change a lightbulb? (有中文版的翻譯,即 要幾個 FreeBSD hacker 才能換掉一個電燈泡?)

不過 的比較有趣 :p (尤其是更熟悉 的權力運作後再來看這個笑話)

管理一堆 FreeBSD 的方法

本來是放在 的,想了一下還是這邊也放一份好了,如果有什麼意見的話麻煩提供一下 :p

以前在計中弄二三十台 FreeBSD 的時候就是用 screen + portupgrade 一次把幾十台機器升級,升級完整個重開機就好了,不用管什麼東西升級完要重跑。安裝新軟體如果需要指定 WITH_BLAH=yes 或是其他的東西,記得到每台上面的 /usr/local/etc/pkgtools.conf 改一下。(以前的 ports 還沒有 OPTIONS 這個功能)

這個模式在我一個人管的時候很好,但是當要傳承的時候就糟糕了:要瞭解這種方法的人大概都需要玩過一陣子 FreeBSD,知道只靠系統基本的套件管理是不夠的,才會有感覺。D2 上面是到了 ronnywang 才接下去。現在在交大資工當系計中助教也遇到同樣的問題。

一種想法是利用 package 更新 (這個在將 ccbsd*.csie.nctu.edu.tw 重灌成 FreeBSD 6 已經實行一段時間了),但目前最大的問題在於使用 package 會:

  • 無法善用每台機器的 CPUTYPE。
  • 某些 ports 無法產生 package,像是 screen (技術問題)、jdk (授權問題)。

另外,有時候會發生套件安裝好,但是無法產生 package 的慘劇。這個方法其實問題還蠻多的。

我昨天又想到了另外一個作法,我不知道可不可行,不過看起來會比原來的方法好,但是重新安裝機器時的速度一定會比 package 的方法慢:

  • 每天在 ccduty 上產生 package list (像是 sysutils/screen 這種字串,一行一個),排序後塞入 svn repository。另外將 /usr/local/etc/pkgtools.conf 也塞進去。
  • 要安裝新機器的時候,先將 /usr/local/etc/pkgtools.conf 抓回來,再用 cat ports-list.txt | xargs portinstall 把軟體安裝進去。

也許 ccbsd8 可以試看看這種方式。

FreeBSD Jail 裡面透過 Ports 升級軟體的方法

FreeBSD 6.0 與 jail 這篇裡面我提到了安裝的方法,另外也提到如何跟 host 共用 ports 的方法。但是如果你想要使用 portupgrade 升級軟體,你會發現因為沒有辦法寫入 /usr/ports (要更新 INDEX.db) 而失敗。( 跑來跟我幹剿 XD)

我發現這個問題可以想辦法避開寫入 /usr/ports 就可以了,在 portupgrade 的 manpage 裡面有提到 PORTS_DBDIR 這個變數:

PORTS_DBDIR    Alternative location for the ports database files.
               Default is ``$PORTSDIR''.

於是只要在 /usr/local/etc/pkgtools.conf 裡面設定:

ENV['PORTS_DBDIR'] ||= '/tmp'

指到 /tmp 就可以解決了。

FreeBSD 6.0 與 jail

因為要惡搞一些東西,不方便在現有的系統上跑,於是就跑去弄個 jail 出來用。比起 FreeBSD 4.x 需要自己寫一些 shell script 丟到 /usr/local/etc/rc.d/ 下,6.0 下的 jail 已經整合到系統內了,所以不太需要在自己寫 shell script。

而且 6.x 的 jail 也修掉不少 bug,像是 dmesg 偶而會出不來 (喂喂),reboot 不會理你 (喂喂)... 另外 df 也只會看到 /,不會看到其他的 slice 了。

要生出 jail 的環境,先是:

make buildworld
make installworld DESTDIR=/da1/jail0
make distribution DESTDIR=/da1/jail0

然後改 /da1/jail0/etc/master.passwd,把自己加進去,用 pwd_mkdb -d /da1/jail0/etc /da1/jail0/etc/master.passwd 重新編過一次,記得把家目錄開好 :p

然後是 /etc/rc.conf

ifconfig_fxp1_alias0="inet 192.168.113.10/24"
jail_enable="YES"
jail_list="testbase"
jail_testbase_devfs_enable="YES"
jail_testbase_devfs_ruleset="devfsrules_jail"
jail_testbase_exec="/bin/sh /etc/rc"
jail_testbase_hostname="testbase"
jail_testbase_ip="192.168.113.10"
jail_testbase_rootdir="/da1/jail0"
pf_enable="YES"

接下來弄 pf 的設定,所以去改 /etc/pf.conf

nat on fxp0 from 192.168.113.0/24 to any -> (fxp0)
nat on fxp1 from 192.168.113.0/24 to any -> (fxp0)

接下來把 jail 裡面的東西設一設,像是 resolv.conf

最後用系統給的 jail 就可以啟動了:

/etc/rc.d/jail start

第一次跑起來應該會卡在 ssh 產生金鑰的地方,所以就去喝個飲料之類的 :p (也可以自己先在 host 產生好,不過我這邊懶得講了,請自己去 /etc/rc.d/sshd 翻,需要三組金鑰)

弄完以後就可以 ssh 進去玩了,如果要跟 host 共用 ports directory,可以用 mount_nullfs 以 read-only 掛上來 (security issue),然後修改 /etc/make.conf,把本來會寫入的部分都改到 /tmp 下:

DISTDIR=        /tmp/distfiles
WRKDIRPREFIX=   /tmp/WRKDIR

這樣應該就沒什麼大問題了 :D