此 “真正啟動” 是由 systemd 提供的,在本節說明該啟動系統。
Systemd 執行多個程序,設定系統:鍵盤、驅動程式、檔案系統、網路、服務等。同時全面檢視系統,以及必要的配件。每個配件都視為一個 “單元檔案” (有時為多個);通用的語法源自於常用的 “*.ini files“ 語法,包括配對的 key = value
列在 [section]
標頭內。單元檔案儲存在 /lib/systemd/system/
與 /etc/systemd/system/
內;以多種風貌呈現,目前專注在 “服務” 與 “目標”。
systemd “服務檔案” 描述被 systemd 管理的程序。包括與舊型的 init-scripts 相同的資料,但以宣告 (同時較為簡潔) 的方式表述。Systemd 處理大量重複的工作 (啟動與終止程序、檢查其狀態、日註記錄、去除特權等),以及祗供特定程序使用的服務檔案。例如,以下是 SSH 用到的服務檔:
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=sshd.service
如上文所示,程式碼極少,祗有宣告。Systemd 管理顯示進度報表、追蹤程序、以及必要的重啟。
systemd 的 “目標檔案” 描述系統的現狀,包括可操作的服務。不妨視為相當於舊型的執行階段作業。其中一個目標是 local-fs.target
;進入之後,系統的其他部份假設所有的在地檔案系統均己掛載並可近用。其他的目標包括 network-online.target
與 sound.target
。目標的相依性可以列在目標檔案內 (於 Requires=
列) 或使用符號連結至在 /lib/systemd/system/targetname.target.wants/
資料夾內的服務檔案。例如,/etc/systemd/system/printer.target.wants/
包括一個連結至 /lib/systemd/system/cups.service
;systemd 將確保 CUPS 已執行至 printer.target
。
單元檔案是宣告性的而不是腳本或程式,不能直接執行,祗能被 systemd 解譯;因些有些工具允許管理者與 systemd 互動且控制系統的狀態與其元件。
第一種這類工具是 systemctl
。未使用參數執行時,它列出 systemd 已知的所有單元檔 (除了已經停用的),及其現況。systemctl status
則以更佳的角度檢視服務,以及相關的程序。若提供服務的名稱 (如 systemctl status ntp.service
),則送回更多詳細的資料,以及與該服務有關的最後幾個日誌檔 (還有更多的)。
執行 systemctl start servicename.service
就能以人工方式啟動服務。同樣的,執行 systemctl stop servicename.service
就能停止已完成的服務;其他的次命令包括 reload
與 restart
。
以 systemctl enable servicename.service
(或 disable
) 控制啟動服務 (即開機後自動啟動)。is-enabled
可以檢查服務的狀態。
systemd 重要的功能之一是包括登入的組件 journald
。做為補充 syslogd
之類傳統登入系統的組件,但加入額外的功能包括在服務與其產生訊息間的正式連結,以及補捉由初始過程產生的錯誤訊息。在 journalctl
命令的協助下,稍後可顯示該等訊息。不需任何參數,它溢出系統啟動後發生的所有日誌訊息;不過很少用到它。多數時間,把它做為服務的辨識器:
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 10:08:49 CEST, end at Tue 2015-03-31 17:06:02 CEST. --
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Received SIGHUP; restarting.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:32 mirtuel sshd[1151]: Accepted password for roland from 192.168.1.129 port 53394 ssh2
Mar 31 10:09:32 mirtuel sshd[1151]: pam_unix(sshd:session): session opened for user roland by (uid=0)
另個有用的命令列旗標是 -f
,用於指示 journalctl
繼續顯示溢出的新增訊息 (大部份是在 tail -f file
之內)。
若服務狀況不如預共,第一個步驟是以 systemctl status
檢查該服務是否真的已啟動;若沒有,則第一個命令給的訊息就不足以診斷問題之所在,檢查 journald 產生的日誌檔。例如,假設 SSH 伺服器未啟動時:
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: failed (Result: start-limit) since Tue 2015-03-31 17:30:36 CEST; 1s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Process: 1188 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=255)
Main PID: 1188 (code=exited, status=255)
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 17:29:27 CEST, end at Tue 2015-03-31 17:30:36 CEST. --
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Received SIGHUP; restarting.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:30:10 mirtuel sshd[1147]: Accepted password for roland from 192.168.1.129 port 38742 ssh2
Mar 31 17:30:10 mirtuel sshd[1147]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Mar 31 17:30:35 mirtuel sshd[1180]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1182]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1184]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1186]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1188]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
vi /etc/ssh/sshd_config
#
systemctl start ssh.service
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Tue 2015-03-31 17:31:09 CEST; 2s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1222 (sshd)
CGroup: /system.slice/ssh.service
└─1222 /usr/sbin/sshd -D
#
檢查服務的狀態 (失敗) 後,再檢查日誌檔;它們會指出組態的錯誤。編輯組態檔並修正錯誤後,重啟服務,確認執行中。
System V 初始系統 (簡稱初始) 執行若干程序,根據
/etc/inittab
檔案的指令做事。第一個執行的程式 (對映於
sysinit 步驟) 是
/etc/init.d/rcS
,一個執行在
/etc/rcS.d/
資料夾內所有程式的腳本。
在這些裡面,可找到負責的程式:
到了這個地步,init
接手並啟動執行階段預設的程式 (通常是執行階段 2)。它執行 /etc/init.d/rc 2
,一個啟動列在 /etc/rc2.d/
之內的所有服務並命名為 “S” 字母開頭。接著的兩位數,曾經做為服務啟動的順序,不過現在的預設啟動系統使用 insserv
,根據腳本的相依性自動決定其先後順序。每個啟動腳本宣告的情況必須符合啟動或停止服務 (例如,必須在另個服務之前或之後啟動);init
再依此情況啟動它們。不再考慮靜態的腳本編號 (但仍需按相依性使用 “S” 及兩個數字與實際的腳本名稱)。通常,基本的服務 (諸如以 rsyslog
登入,或以 portmap
指定埠口) 先列出來,然後才是標準服務與圖形介面 (gdm3
)。
這種以相依性為基礎的啟動系統可以自動重新編號,避免人工作業的繁瑣,且限縮可能的人為錯誤,因為其排序係依照參數而訂。另個優點是可以同時啟動多個互相獨立的服務,藉以加速啟動程序。
init
區隔多個執行階層,所以可以用 telinit new-level
命令切換。立即,init
在新的執行階層再次執行 /etc/init.d/rc
。這個腳本可執行缺失的服務並停止不再用到的服務。為了做到這個程度,它參照 /etc/rcX.d
的內容 (X 代表新的執行階層)。以 “S” (表示開始 “Start”) 開始的腳本是將啟動的服務;以 “K” (表示砍掉 “Kill”) 開始的腳本是將停止的服務。腳本不會啟動已經在前個執行階層執行的服務。
預設,Debian 的 System V init 使用四個不同的執行階層:
0 層,祗是暫時的,電腦進入關機程序。所以,祗包括若干 “K” 腳本。
1 層,也稱為單一使用者模式,對應於系統的降級模式;祗包括基本服務,並試圖維護與一般使用者非必要的運作。
2 層是標準運作,包括網路服務、圖形介面、使用者登入等。
6 層類似 0 層,除了在重開機之前先執行關機。
其他的階層,尤其是 3 至 5 階。它們預設的組態等同於階層 2,但是管理者可以修改它們 (在對應的 /etc/rcX.d
資料夾新增或刪除腳本) 以適應特定的需求。
在 /etc/rcX.d
資料夾內的腳本祗是符號連結 — 安裝套件時由 update-rc.d
程式產生 — 指向儲存在 /etc/init.d/
l裡的實際腳本。管理者可以使用調整後的參數重新執行 update-rc.d
以微調運行層級的服務。The update-rc.d(1) 手冊詳細地描述其語法。請注意移除所有的符號連結 (使用 remove
參數) 不是停用該服務的好方法。應該是,在特定的執行層級組態其為不啟動 (在前個執行層級已有的服務應保留對應的呼叫停止它)。因為 update-rc.d
介面有點麻煩,建議使用較為友善的 rcconf
(從 rcconf 套件取用) 介面。
最後,init
啟動虛擬終端機 (getty
) 的控制程式。顯示提示符號,等待使用者名稱,然後執行 login user
啟始一個程序。