在系統從 ubuntu 9.04 升至 9.10 後,本人系統的控制台就一直不能使,而且 vbox 在每次系統重啟後都要執行 `sudo /etc/init.d/vboxdrv setup `重新編譯一次核心。由於其它方面沒感不便,對這兩小問題也就忍了。
最近想裝 NV 的官方驅動,安裝要求關閉 X ,就不得不面對這個問題了。
首先想到的是問題出在啟動過程中出現的問題,ubuntu 使用 upstart 來引導系統,upstart 啟動過程可參考 Upstart: Ubuntu 的基於事件的啟動進程 有比較詳細的描述。在系統終端中輸入命令 "runlevel" 返回結果 unknown ,正確的應該返回 “N 2” ,ubuntu 預設的runlevel 是 2。在對 /etc/event.d/ 中檔案和 /etc/rc2.d 以及 /etc/rcS.d 目錄下的檔案進行檢查後發現,runlevel 在 /etc/event.d/rc-default 的檔案中 進行了設定,也就是 telint 2 這句。
此時在系統終端中輸入命令 `telint 2` 會發現 終端1 中出現了 "login:" 提示符。從 /etc/event.d/rc2 中得知,在系統終端中輸入命令 `sudo /etc/init.d/rc 2` 後出現了一堆說初始化資訊,其中包括 vbox 的,對了還 cups 的,每次要用印表機都要手動啟動 cups 服務。做到這裡開始懷疑是 upstart 沒有正常執行這些指令碼。在上面兩個指令碼中加入了 log 輸出,發現根本沒執行。
於是開始懷疑 upstart 出了問題,於是升級 upstart 從 9.10 預設的 upstart_0.6.3-11 升級到 upstart_0.6.5-3 (可從 http://archive.ubuntu.com/ubuntu/pool/main/u/upstart/ 下載,可能會需要一個 dbus 檔案鈧自己網上下載),安裝以後問題照舊。於是又回來懷疑是設定檔的問題。從一國外論壇上看到說 下載
upstart_0.3.9-8_i386.deb, upstart-compat-sysv_0.3.9-8_i386.deb,upstart-logd_0.3.9-8_i386.deb,system-services_0.3.9-8_i386.deb 四個檔案,然後使用命令 `dpkg -x xx.deb dir` 將這些檔案解壓到一個目錄中,再將目錄下的子目錄 etc/event.d/ 裡的設定檔全部複製到系統 '/etc/event.d/' 目錄中,重啟後問題依舊。
但是從 http://archive.ubuntu.com/ubuntu/pool/main/u/upstart/ 中可以看到 upstart 版本 0.6.* 都只有一個檔案而 0.3* 版本有四個檔案,於是開始懷疑,0.6以後的版本有重大修改,可能不再使用 /etc/event.d/ ,本人是謹慎形的,不敢直接在本機上刪除 /etc/event.d/ 目錄來實驗。於是乘吃午飯時間下了一個 9.10 的iso 在 vbox 裝上,發現全新安裝的 9.10 中並無 /etc/event.d/ 目錄,證明此前猜測正確。
/etc/ 目錄是啟動設定檔存在的目錄是不容懷疑的,剩下的就懷疑 /etc/init/ 目錄下的檔案了,經 md5 比較發現 host 系統與 vbox 中的 9.10 的 /etc/init/rc-sysinit.conf 存在差異,查看 rc-sysinit.conf 檔案發現開頭存在 “env DEFAULT_RUNLEVEL=2” 的配置說明,而且在最後有
“telinit "${DEFAULT_RUNLEVEL}" ” 的 commond 所以懷疑是此檔案中存在問題。將 vbox 中 9.10 的 “env DEFAULT_RUNLEVEL=2” 改為 “env DEFAULT_RUNLEVEL=3” 後 reboot ,執行 runlevel 得到傳回值 “N 3”。現在可以確定是 host 中這個指令碼沒正確執行,於是從 vbox 的 9.10 中複製了 rc-sysinit.conf 到 host 中,重啟 host 一切正常。
結論 upstart 0.6* 以後的版本只有一個檔案了,取消了 /etc/event.d/ 將相應功能移到了 /etc/init/ 中。
兩份 rc-sysinit.conf 比較
host 上錯誤的 rc-sysinit.conf
# rc-sysinit - System V initialisation compatibility<br />#<br /># This task runs the old System V-style system initialisation scripts,<br /># and enters the default runlevel when finished.<br />description"System V initialisation compatibility"<br />author"Scott James Remnant <scott@netsplit.com>"<br />start on filesystem<br />stop on runlevel<br /># Default runlevel, this may be overriden on the kernel command-line<br /># or by faking an old /etc/inittab entry<br />env DEFAULT_RUNLEVEL=2<br /># There can be no previous runlevel here, but there might be old<br /># information in /var/run/utmp that we pick up, and we don't want<br /># that.<br />#<br /># These override that<br />env RUNLEVEL=<br />env PREVLEVEL=<br />task<br />script<br /> # Check for default runlevel in /etc/inittab<br /> if [ -r /etc/inittab ]<br /> then<br />eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="/1";/p' /etc/inittab || true)"<br /> fi<br /> # Check kernel command-line for typical arguments<br /> for ARG in $(cat /proc/cmdline)<br /> do<br />case "${ARG}" in<br />-b|emergency)<br /> # Emergency shell<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin<br /> ;;<br />[0123456sS])<br /> # Override runlevel<br /> DEFAULT_RUNLEVEL="${ARG}"<br /> ;;<br />-s|single)<br /> # Single user mode<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S<br /> ;;<br />esac<br /> done<br /> # Run the system initialisation scripts<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS<br /> # Switch into the default runlevel<br /> telinit "${DEFAULT_RUNLEVEL}"<br />end script
正確的 rc-sysinit.conf
# rc-sysinit - System V initialisation compatibility<br />#<br /># This task runs the old System V-style system initialisation scripts,<br /># and enters the default runlevel when finished.<br />description"System V initialisation compatibility"<br />author"Scott James Remnant <scott@netsplit.com>"<br />start on filesystem<br />stop on runlevel<br /># Default runlevel, this may be overriden on the kernel command-line<br /># or by faking an old /etc/inittab entry<br />env DEFAULT_RUNLEVEL=2<br /># There can be no previous runlevel here, but there might be old<br /># information in /var/run/utmp that we pick up, and we don't want<br /># that.<br />#<br /># These override that<br />env RUNLEVEL=<br />env PREVLEVEL=<br />task<br />script<br /> # Check for default runlevel in /etc/inittab<br /> if [ -r /etc/inittab ]<br /> then<br />eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="/1";/p' /etc/inittab || true)"<br /> fi<br /> # Check kernel command-line for typical arguments<br /> for ARG in $(cat /proc/cmdline)<br /> do<br />case "${ARG}" in<br />-b|emergency)<br /> # Emergency shell<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin<br /> ;;<br />[0123456sS])<br /> # Override runlevel<br /> DEFAULT_RUNLEVEL="${ARG}"<br /> ;;<br />-s|single)<br /> # Single user mode<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S<br /> ;;<br />esac<br /> done<br /> # Run the system initialisation scripts<br /> [ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS<br /> # Switch into the default runlevel<br /> telinit "${DEFAULT_RUNLEVEL}"<br />end script
兩份檔案唯一的區別是 第9行,正常的檔案中的是 start on filesystem,有問題的檔案中是 start on filesystem and net-device-up IFACE=lo 。所以懷疑這句話使 upstart 根本就沒啟動。
網上搜了一下,只有一條說是 bug 的,還是翻牆出去的,真無語。