When you boot the computer, the many messages scrolling by on the console display many automatic initializations and configurations that are being executed. Sometimes you may wish to slightly alter how this stage works, which means that you need to understand it well. That is the purpose of this section.
9.1.1. The systemd init system
The “real init” is currently provided by systemd and this section documents this init system.
Systemd executes several processes, in charge of setting up the system: keyboard, drivers, filesystems, network, services. It does this while keeping a global view of the system as a whole, and the requirements of the components. Each component is described by a “unit file” (sometimes more); the general syntax is derived from the widely-used “*.ini files“ syntax, with key = value
pairs grouped between [section]
headers. Unit files are stored under /lib/systemd/system/
and /etc/systemd/system/
; they come in several flavours, but we will focus on “services” and “targets” here.
A systemd “service file” describes a process managed by systemd. It contains roughly the same information as old-style init-scripts, but expressed in a declaratory (and much more concise) way. Systemd handles the bulk of the repetitive tasks (starting and stopping the process, checking its status, logging, dropping privileges, and so on), and the service file only needs to fill in the specifics of the process. For instance, here is the service file for 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
As you can see, there is very little code in there, only declarations. Systemd takes care of displaying progress reports, keeping track of the processes, and even restarting them when needed.
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
啟始一個程序。