systemd - Arch Linux 中文维基

跳至內容

# systemd

出自 Arch Linux 中文维基

翻譯狀態：

- 本文（或部分內容）譯自 Systemd，最近一次同步於 2025-01-24，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- systemd/用戶
- systemd/定時器
- systemd/日誌
- Systemd/FAQ
- init
- 守護程序
- udev
- 性能優化/啟動過程
- 允許用戶關機

摘自項目主頁：

  systemd 是一個 Linux 系統基礎組件的集合，提供了一個系統和服務管理器，運行為 PID 1 並負責啟動其它程序。功能包括：支持並行化任務；同時採用 socket 式與 D-Bus 總線式啟用服務；按需啟動守護進程（daemon）；利用 Linux 的 cgroups 監視進程；支持快照和系統恢復；維護掛載點和自動掛載點；各服務間基於依賴關係進行精密控制。systemd 支持 SysV 和 LSB 初始腳本，可以替代 sysvinit。除此之外，功能還包括日誌進程、控制基礎系統配置，維護登錄用戶列表以及系統帳戶、運行時目錄和設置，可以運行容器和虛擬機，可以簡單的管理網絡配置、網絡時間同步、日誌轉發和名稱解析等。

在歷史上，systemd中的「服務」（service）被稱作守護進程（daemon），它們在後台運行（即沒有UI、不與終端交互），等待特定事件的發生並提供服務。例如，Web伺服器會等待一個請求以提供相應的頁面，SSH伺服器會等待登錄請求。除了這種提供完整功能的，還有一些守護進程的工作是隱藏在幕後的，如負責向日誌文件寫入消息的`syslog`、`metalog`，確保系統時間準確的ntpd。更多信息詳見daemon(7)。

注意：Arch Linux 論壇的這篇帖子 詳細地解釋了 Arch Linux 遷移到 systemd 的原因。

## systemctl 基本用法

監視和控制 systemd 的主要命令是 systemctl。其用途包括查看系統狀態以及管理系統和服務。詳見 systemctl(1)。

提示：

- 在 systemctl 參數中添加 `-H 用戶名@主機名` 可以遠程控制其他機器。該功能使用 SSH 連接到遠程的 systemd 實例。
- Plasma 用戶可以安裝 systemctl 圖形前端 systemdgenie包。安裝後可以在系統管理下找到。

### 使用單元

單元（unit）通常包括但不限於：服務（.service）、掛載點（.mount）、設備（.device）和套接字（.socket）。

使用 systemctl 時，通常需要使用單元文件的全名，包括擴展名（例如 `sshd.socket`）。不過在以下 systemctl 命令中可以使用簡寫：

- 如果無擴展名，systemctl 會假定擴展名為 .service。例如，`netctl` 和 `netctl.service` 是等價的。
- 掛載點會自動轉化為相應的 .mount 單元。例如，`/home` 等價於 `home.mount` 。
- 與掛載點類似，設備會自動轉化為相應的 .device 單元，因此 `/dev/sda2` 等價於 `dev-sda2.device`。

詳見 systemd.unit(5)。

注意：有一些單元的名稱包含一個 `@` 符號（例如：`name@string.service` ），這意味著它是模板單元 `name@.service` 的一個 實例，模板單元的實際文件名中不包括 `string` 部分（如 `name@.service`）。`string` 被稱作實例標識符，在 systemctl 調用模板單元時，會將其當作一個參數傳給模板單元，模板單元會使用這個傳入的參數代替模板中的 `%i` 指示符。在啟動單元時，嘗試從模板單元實例化之前，systemd 會先檢查 `name@string.suffix` 文件是否存在。如果存在，就直接使用這個文件，而不是模板實例化（不過，這種「碰撞」非常少見）。大多數情況下，包含 `@` 標記都意味著這個文件是模板。如果一個模板單元被調用時沒有指定實例標識符，該調用通常會失敗，除非是在某些特殊的 systemctl命令（如`cat`）中使用。

因為調用systemctl時默認了 `--system` 參數，下列命令默認對系統單元進行操作。若要對（調用用戶的）用戶單元進行操作，則需在非root身份下執行systemctl --user。參看systemd/用戶#基礎設置以為所有用戶啟用或禁用單元。

提示：

- 下面的大部分命令都可以跟多個單元名，詳細信息參見 systemctl(1)。
- `--now` 選項可與 `enable`、`disable` 和 `mask` 同時使用，可使這些動作立即生效，而非重啟後生效。
- 一個軟體包可能會為不同的功能提供多個不同的單元。如果你剛安裝了軟體包，可以通過 `pacman -Qql package | grep -Fe .service -e .socket` 命令檢查這個軟體包提供了哪些單元。

動作 | 命令 | 注釋
--- | --- | ---
分析系統狀態
顯示系統狀態 | `systemctl status` |
列出正在運行的單元 | `systemctl` 或 `systemctl list-units` |
列出失敗的單元 | `systemctl --failed` |
列出已安裝的單元1 | `systemctl list-unit-files` |
顯示特定PID對應進程的狀態 | `systemctl status pid` | cgroup slice，內存占用，父進程
檢查單元狀態
顯示單元的手冊頁 | `systemctl help 單元` | 如果單元支持
顯示單元的狀態 | `systemctl status 單元` | 包括其是否在運行
檢查單元是否配置為自動啟動（enabled） | `systemctl is-enabled 單元` |
啟動（start）、重新啟動和重新加載單元
立即啟動單元 | 以root身份執行`systemctl start 單元` |
立即停止單元 | 以root身份執行`systemctl stop 單元` |
重新啟動單元 | 以root身份執行`systemctl restart 單元` |
重新加載單元及其配置 | 以root身份執行`systemctl reload 單元` |
重新加載 systemd 配置2 | 以root身份執行`systemctl daemon-reload` | 掃描單元的變動
啟用（enable）單元
啟用單元：開機時自動啟動該單元 | 以root身份執行`systemctl enable 單元` |
啟用單元，並立即啟動它 | 以root身份執行`systemctl enable --now 單元` |
取消開機自動啟動單元 | 以root身份執行`systemctl disable 單元` |
重新啟用單元3 | 以root身份執行`systemctl reenable 單元` | 先取消啟用，再啟用
屏蔽單元
屏蔽單元，使其無法啟動4 | 以root身份執行`systemctl mask 單元` |
取消屏蔽單元 | 以root身份執行`systemctl unmask 單元` |

1. systemd.unit(5) § UNIT FILE LOAD PATH 中描述了查找單元文件的路徑。
2. 這不會要求已改變的單元重新加載自己的配置（見重新加載動作）。
3. 可在單元的`[Install]`節發生變更（在上一次啟用後）時使用。
4. 既不能手動啟動，也無法作為依賴啟動。因此屏蔽單元是危險的。 查看已屏蔽的單元：

       # systemctl list-unit-files --state=masked

### 電源管理

安裝 polkit 後才能以普通用戶身份使用電源管理。如果你正登錄在一個本地的 systemd-logind 用戶會話，且當前沒有其它活動的會話，那麼以下命令無需 root 權限即可執行。否則（例如，當前有另一個用戶登錄在某個 tty），systemd 將會自動請求輸入 root 密碼。

動作 | 命令
--- | ---
重啟 | `systemctl reboot`
關機 | `systemctl poweroff`
待機 | `systemctl suspend`
休眠（將內存寫入硬碟） | `systemctl hibernate`
進入混合休眠模式（同時休眠到硬碟並待機） | `systemctl hybrid-sleep`
先待機，在一個特定時間喚醒後進入休眠模式 | `systemctl suspend-then-hibernate`
使用#軟重啟來僅重啟用戶空間 | `systemctl soft-reboot`

#### 軟重啟

軟重啟是一種不涉及內核，僅重啟用戶空間的重啟操作。這個操作由 systemd-soft-reboot.service(8) 實現，並且可以通過 `systemctl soft-reboot` 來進行一次軟重啟。正如 kexec 一樣，這個操作跳過了重新初始化固件，也不會進行內核初始化和初始化 RAM 文件系統。同時，未鎖定的 dm-crypt 設備也將保持解鎖狀態。

當 `/run/nextroot` 包含了一個合法的 rootfs 結構（比如說掛載了另一個發行版的根分區或者另一個快照），軟重啟操作將會切換系統根分區到其中。切換之後並不會丟失一些由內核管理的狀態，比如說網絡連接。

提示：`/run/nextroot/`不一定是一個掛載點或者存在於物理設備上。例如，它可以在 `/run/` tmpfs 中。systemd 將會在軟重啟時自動將`/run/nextroot/` 轉化為一個掛載點。
注意：不要在涉及內核和 initramfs 的更新後執行 `systemctl soft-reboot`。

## 編寫單元文件

`systemd` 單元文件的語法來源於XDG 桌面項配置的.desktop文件，最初的源頭則是Microsoft Windows的.ini文件。單元文件可以從多個地方加載，`systemctl show --property=UnitPath` 可以顯示加載目錄。主要的加載目錄為（按優先級從低到高排列）：

- `/usr/lib/systemd/system/` ：軟體包安裝的單元
- `/etc/systemd/system/` ：系統管理員安裝的單元

注意：

- 當 `systemd` 運行在用戶模式下時，使用的加載路徑是完全不同的。
- systemd 單元名僅能包含 ASCII 字符，下劃線和點號以及有特殊意義的字符('@', '-')。其它字符需要用C風格的"\x2d" 替換或使用對應的預定義語法（「@」，「-」）。參閱 systemd.unit(5) 和 systemd-escape(1) 。

單元文件的語法，可以參考系統已經安裝的單元，也可以參考 systemd.service(5) § EXAMPLES。

提示：在單元文件中以`#`開頭的行將被視作注釋，但`#`僅能在一行開頭使用。不要在 systemd 的參數後面使用行末注釋，否則該單元將不能正常啟動。

systemd-analyze(1) 可以幫助你檢查錯誤。請參見那一章節的 `systemd-analyze verify FILE...` 部分。

### 處理依賴關係

使用 systemd 時，可通過正確編寫單元配置文件來解決單元間的依賴關係。典型的情況是，單元A要求單元B在A啟動之前運行。在此情況下，可向單元A配置文件中的 `[Unit]` 段添加 `Requires=B` 和 `After=B` 即可。若此依賴關係是可選的，可添加 `Wants=B` 和 `After=B`。請注意 `Wants=` 和 `Requires=` 並不暗含 `After=` ，即如果 `After=`選項沒有指定，這兩個單元將被並行啟動。

依賴關係通常被用在服務（service）而不是目標（target）上。例如，`network.target` 一般會被某個配置網絡接口的服務引入作為依賴。所以，若要讓自定義單元在系統到達`network.target`後再啟動， 將自定義的單元排在該類配置網絡接口的服務之後即可，因為該類服務啟動時 `network.target` 一定已經啟動。

### 服務（service）類型

編寫自定義的服務（service）文件時，可以選擇幾種不同的服務啟動方式。啟動方式可通過配置文件 `[Service]` 段中的 `Type=` 參數進行設置。

- `Type=simple` ：（默認值） systemd認為該服務將立即啟動且服務進程不會fork。如果其他服務需要在此服務之後啟動，請不要使用此類型，除非它是通過套接字激活的。
- `Type=forking` ：systemd認為當該服務進程fork，且父進程退出後服務啟動成功。對於典型的守護進程，除非你確定此啟動方式無法滿足需求，使用此類型啟動即可。使用此啟動類型應同時指定 `PIDFile=`，以便systemd能夠跟蹤服務的主進程。
- `Type=oneshot` ：這一選項適用於只執行一項任務、隨後立即退出的服務。可能需要同時設置 `RemainAfterExit=yes`使得systemd在服務進程退出之後仍然認為服務處於啟用狀態，這對於改變系統狀態（如掛載分區）的單元尤其適用。對於 simple 和 oneshot 類型的區別，請參閱 [1]。
- `Type=notify` ：與 `Type=simple` 相同，但約定服務會在就緒後向systemd發送一個信號以通知systemd。這一通知的參考實現由 `libsystemd-daemon.so` 提供。
- `Type=dbus` ：若以此方式啟動，當指定的 `BusName` 出現在DBus系統總線上時，systemd認為服務就緒。
- `Type=idle` ：`systemd`會等待所有活動任務都完成後再執行服務進程。其他行為與 `Type=simple` 類似。

`type` 的更多解釋可以參考 systemd.service(5) § OPTIONS。

### 修改現存單元文件

為了避免和 pacman 衝突，不應該直接編輯軟體包提供的文件。有兩種方法可以不改動原始文件就做到修改單元文件：創建一個優先級更高的本地單元文件以覆蓋原有的單元文件或創建一個片段（drop-in snippets），應用到原始單元文件之上。兩種方法都需要在修改後重新加載單元：用 `systemctl edit` 編輯單元(會自動重載單元)或通過下面命令重新加載單元：

    # systemctl daemon-reload

提示：

- `systemd-delta` 命令用來查看哪些單元文件被覆蓋、擴增，哪些被修改。
- 使用 `systemctl cat unit` 可以查看單元的內容和所有相關的片段。

#### 替換單元文件

要替換 `/usr/lib/systemd/system/unit`, 創建文件 `/etc/systemd/system/unit` 並重新啟用單元以更新符號連結：

    # systemctl reenable unit

或者運行：

    # systemctl edit --full unit

這將會在默認編輯器中打開 `/etc/systemd/system/unit`。如果文件不存在，可以將軟體包安裝的版本複製到這裡，在編輯完成之後，會自動加載新版本。

注意：即使 Pacman 更新了新的單元文件，軟體包中的版本也不會被使用，所以這個方式會增加系統維護的難度，推薦使用下面一種方法。

#### 附加配置片段

要為單元文件`/usr/lib/systemd/system/unit`附加配置片段，先創建名為 `/etc/systemd/system/unit.d/` 的目錄，然後放入 `*.conf` 文件，其中可以添加或覆蓋參數。這裡設置的參數優先級高於原來的單元文件。systemd會解析這些參數並將這些文件應用到原單元文件上。

要附加配置片段，最簡單的方法是執行：

    # systemctl edit unit --drop-in=drop_in_name

這將會在編輯器中打開文件 `/etc/systemd/system/unit.d/drop_in_name.conf`，編輯完成之後自動加載。若省略`--drop-in=`選項，systemd將使用默認文件名：`override.conf`。

注意：

- 附加配置片段中的鍵（配置項）仍必須置於相應的節（section）下。
- 並不是所有參數都會被子配置文件覆蓋。例如要修改 `Conflicts=` 就必須替換原始文件。
- 你可以使用頂級附加配置文件來影響所有相同類型的單元。例如，在 `/etc/systemd/system/service.d/` 中的附加配置文件會影響所有 .service 單元。你可以在#Notifying_about_failed_services中看到一個示例。

#### 重置到軟體包的版本

要回退使用`systemctl edit`對單元進行的所有變更，執行:

    # systemctl revert unit

#### 示例

如果想添加一個額外的依賴，創建如下文件即可：

    /etc/systemd/system/<unit>.d/customdependency.conf

    [Unit]
    Requires=<新依賴>
    After=<新依賴>

要修改一個單元的 `ExecStart` 命令，創建下面文件:

    /etc/systemd/system/unit.d/customexec.conf

    [Service]
    ExecStart=
    ExecStart=<新命令>

修改 `ExecStart` 前必須將其置空，參見 [2] 。所有可能多次賦值的變量都需要這個操作，例如定時器的 `OnCalendar` 。

下面是自動重啟服務的一個例子：

    /etc/systemd/system/unit.d/restart.conf

    [Service]
    Restart=always
    RestartSec=30

### 服務日誌級別

對於直接向 journald 或 syslog 發送日誌的服務，你可以通過在 `[Service]` 部分設置 `LogLevelMax=` 參數來控制其詳細程度，該參數的值可以是 0 到 6 之間的數字。例如：

    /etc/systemd/system/unit.d/override.conf

    [Service]
    LogLevelMax=3

標準的日誌級別與用於過濾 journal 的級別相同。設置較低的數字會排除所有較高且不太重要的日誌消息。

#### 抑制服務的標準輸出

如果服務正在回顯 stdout 和/或 stderr 輸出，默認情況下這些輸出也會進入 journal。可以通過在 `[Service]` 部分設置 `StandardOutput=null` 和/或 `StandardError=null` 來抑制此行為。除了 `null` 之外，還可以使用其他值來進一步調整此行為。參見 systemd.exec(5) § LOGGING_AND_STANDARD_INPUT/OUTPUT。

## 目標（target）

systemd使用目標來通過依賴關係將多個單元組織起來。目標還是系統的標準化同步點（確保系統處於特定狀態）。目標與runlevels的設計目的相似，但兩者也有些許不同。每一個目標都以名稱而不是數字標識，用以達成特定的目的。多個目標可以同時被激活。有的目標繼承另一個目標的所有服務，同時向其中增添一些服務。有些systemd目標模仿了常見的SystemVinit runlevels。

### 獲取當前目標

使用systemd的命令而非`runlevel`：

    $ systemctl list-units --type=target

### 創建自定義目標

在sysvinit中有明確定義的運行級別（如：0、1、3、5、6）與 systemd 中特定的目標存在一一對應的關係。然而，對於用戶自定義運行級別（2、4）卻沒有。如需要同樣功能，建議你以原有運行級別所對應的 systemd 目標為基礎，新建一個`/etc/systemd/system/<目標名>.target`（可參考`/usr/lib/systemd/system/graphical.target`）, 然後創建目錄`/etc/systemd/system/<目標名>.wants`，並向其中加入需啟用的服務連結（指向`/usr/lib/systemd/system/`中的對應文件）。

### 「SysV運行級別」與「systemd目標」對照表

SysV 運行級別 | Systemd 目標 | 注釋
--- | --- | ---
0 | poweroff.target | 關閉系統（halt）
1, s, single | rescue.target | 單用戶模式
2, 4 | multi-user.target | 用戶自定義運行級別，默認與級別3相同。
3 | multi-user.target | 多用戶，無圖形界面。用戶可以通過終端或網絡登錄。
5 | graphical.target | 多用戶，圖形界面。繼承級別3的服務，並啟動圖形界面服務。
6 | reboot.target | 重啟
emergency | emergency.target | 急救模式（Emergency shell）

### 切換當前運行目標

systemd中，目標通過「目標單元」訪問。通過如下命令切換：

    # systemctl isolate graphical.target

該命令僅更改當前運行目標，對下次啟動無影響。這等價於sysvinit中的`telinit 3`或`telinit 5`命令。

### 更改開機默認啟動目標

開機啟動的目標是`default.target`，默認符號連結到`graphical.target`（大致相當於原來的運行級別5）。

用 systemctl 檢查當前的默認啟動目標：

    # systemctl get-default

用systemctl修改`default.target`符號連結以變更開機默認啟動目標：

    # systemctl set-default multi-user.target

    Removed /etc/systemd/system/default.target.
    Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.

另一方法是向bootloader添加內核參數：

- `systemd.unit=multi-user.target` （大致相當於運行級別3）
- `systemd.unit=rescue.target` （大致相當於運行級別1）

### 默認目標順序

Systemd 根據下面順序選擇 `default.target`：

1. 上面的內核參數
2. `/etc/systemd/system/default.target` 軟連結
3. `/usr/lib/systemd/system/default.target` 軟連結

## systemd組件

systemd的部分組件如下：

- kernel-install——一個用以自動將內核及對應的initramfs鏡像移動到boot分區的腳本；
- systemd-analyze(1)——可用於確定啟動性能、統計信息並檢索其他狀態和跟蹤信息，以及驗證單元文件的正確性。它還用於訪問高級調試所需的特殊功能。
- systemd-boot——簡單的UEFI啟動管理器；
- systemd-creds——安全地存儲並獲取systemd單元使用的credentials；
- systemd-cryptenroll——Enroll PKCS#11, FIDO2, TPM2 token/devices to LUKS2 encrypted volumes；
- systemd-firstboot——負責在系統第一次啟動前的設置初始化；
- systemd-homed——portable human-user accounts；
- systemd-logind(8)——會話管理；
- systemd-networkd——網絡配置管理；
- systemd-nspawn——輕量namespace容器；
- systemd-repart——創建分區表，添加或擴大分區；
- systemd-resolved——網絡域名解析；
- systemd-run(1) / run0(1)——以交互式的方式臨時的提升或獲得不同的權限。
- systemd-stub(7)——用於創建統一內核鏡像的UEFI boot stub；
- systemd-sysusers(8)——在安裝軟體包或系統啟動時創建系統用戶和組、將用戶加入組；
- systemd-timesyncd——通過網絡同步系統時間；
- systemd/Journal——系統日誌；
- systemd/Timers——用於控制.service文件或事件的間隔或實時計時器，可替代cron。

### systemd.mount - 掛載

systemd負責掛載`/etc/fstab`中指定的分區和文件系統。systemd-fstab-generator(8)將`/etc/fstab`中的所有條目翻譯為systemd單元。該過程將在系統啟動或系統管理器的配置被重新加載時執行。

systemd擴展了通常fstab的用法並提供了更多掛載選項。這些掛載選項可影響掛載點單元的依賴關係。例如，它們可以確保某一掛載操作只會在連接網絡或另一分區掛載後進行。systemd的特定掛載選項（大多以`x-systemd.`開頭）的完整列表見systemd.mount(5) § FSTAB。

automounting是這些掛載選項的一個例子。它意味著資源只會在請求時掛載，而非在系統啟動時自動掛載，詳見fstab#通過 systemd 自動掛載。

#### GPT分區自動掛載

在UEFI啟動的系統上，GPT分區如`root`、`home`、`swap`等可以根據Discoverable Partitions Specification自動掛載。因此，可在fstab中省略自動掛載的分區。此外，若根分區已被自動掛載，可省去內核命令行中的`root=`。詳見systemd-gpt-auto-generator(8)。

使用GPT分區自動掛載的先決條件有：

- 使用mkinitcpio時，需要systemd hook。
- 所有自動掛載的分區必須與ESP分區在同一塊物理硬碟上。
- 必須設置正確的GPT分區類型。詳見Partitioning#Partition scheme。
- 引導加載程序必須設置LoaderDevicePartUUIDEFI變量，以便識別使用的EFI系統分區。systemd-boot，systemd-stub(7)，GRUB (使用grub-mkconfig生成`grub.cfg`），rEFInd（默認未啟用）支持該特性。若使用自定義的`grub.cfg`，則需要加載bli模塊。 可通過執行`bootctl`並檢查`Boot loader sets ESP information`的狀態進行確認，或在用統一內核鏡像啟動時檢查`Stub sets ESP information`的狀態。

udev會創建一個指向根卷塊設備的`/dev/gpt-auto-root`符號連結。如果根分區使用LUKS加密，`/dev/gpt-auto-root`將指向解鎖/映射的卷，而`/dev/gpt-auto-root-luks`將指向加密分區。

提示：某個分區的自動掛載可通過如下兩種方式關閉：修改分區的類型GUID或設置分區屬性的63"do not automount"位，詳見gdisk#Prevent GPT partition automounting。

##### /var

要自動掛載`/var`分區，分區的PARTUUID必須與以machine ID為密鑰，分區類型UUID為消息的SHA256 HMAC哈希計算結果相同。可通過如下命令得到符合要求的PARTUUID：

    $ systemd-id128 -u var-partition-uuid

注意：systemd-id128(1)從`/etc/machine-id`讀取machine ID，因此必須在系統安裝後才能得到符合要求的PARTUUID。

### systemd-sysvcompat

systemd-sysvcompat包（由base包需要）的主要工作是提供傳統的Linux init可執行文件。在由systemd控制的系統上，`init`只是一個到`systemd`可執行文件的符號連結。

此外，該包還提供了SysVinit用戶可能需要的功能的4個快捷方式：halt(8)，poweroff(8)，reboot(8)和shutdown(8)。這4個命令都是到`systemctl`的符號連結，其行為受systemd控制。因此，在#電源管理中提到的規則對它們同樣適用。

在由systemd控制的系統上，可通過`init=`內核啟動參數取消對System V的兼容性支持。詳見/bin/init is in systemd-sysvcompat ?。

### systemd-tmpfiles - 臨時文件

systemd-tmpfiles創建，刪除並清理臨時文件/文件夾。systemd-tmpfiles讀取`/etc/tmpfiles.d/`、`/usr/lib/tmpfiles.d/`中的配置文件（前者比後者優先級高）以確定執行什麼操作。

這些配置文件通常與服務文件一同提供，並以`/usr/lib/tmpfiles.d/<程序>.conf`風格命名。例如，Samba守護進程需要`/run/samba`目錄存在且權限設置正確，因此samba包中附帶了如下配置：

    /usr/lib/tmpfiles.d/samba.conf

    D /run/samba 0755 root root

配置文件也可能用於在啟動時向特定文件中寫入值。例如，要禁止系統從USB設備喚醒。在之前可使用`/etc/rc.local`在啟動時執行`echo USBE > /proc/acpi/wakeup`，而現在可以這麼做：

    /etc/tmpfiles.d/disable-usb-wake.conf

    #    Path                  Mode UID  GID  Age Argument
    w    /proc/acpi/wakeup     -    -    -    -   USBE

可以通過在參數中使用 `\n` 或者在多行配置的情況下用 `w+` 類型來進行追加（包括第一行）。

    /etc/tmpfiles.d/disable-usb-wake.conf

    #    Path                  Mode UID  GID  Age Argument
    w+   /proc/acpi/wakeup     -    -    -    -   USBE
    w+   /proc/acpi/wakeup     -    -    -    -   LID0

詳見systemd-tmpfiles(8)、tmpfiles.d(5)。

注意：若要向`/sys`中的配置文件寫入值，可能不能使用該方法。因為systemd-tmpfiles-setup服務可能在相關模塊加載前運行。在這種情況下，可先通過`modinfo <模塊名>`檢查該模塊是否可通過設定模塊參數來修改相應的選項。若有對應的模塊參數，可通過/etc/modprobe.d目錄中的配置文件設定相應參數以達到修改選項的目的。否則，將只能通過udev 規則來在設備被識別時設定相應屬性。

### Drop-in 配置文件

本文或本章節的事實準確性存在爭議。

原因： 本頁面是關於PID 1（init）的，單元文件的drop-in配置已經提到。Drop-in是一個通用概念，加上其他systemd組件有專門的wiki頁面。因此本節似乎不屬於這裡。（在 Talk:Systemd#YHNdnzj : Configuration files in conf.d / drop-in snippets: misplaced? 中討論）

為了避免與pacman更新衝突，不應直接編輯由軟體包提供的配置文件。為此，許多（但不是所有）systemd軟體包提供了一種修改配置的方式，但不直接修改原始文件，而是通過創建drop-in片段來實現。請檢查軟體包手冊以查看是否支持drop-in配置文件。

要為單元文件`/etc/systemd/unit.conf`創建drop-in配置文件，請創建目錄`/etc/systemd/unit.conf.d/`並在其中放置.conf文件以覆蓋或添加新選項。systemd將解析並應用這些文件到原始單元之上。

檢查整體配置：

    $ systemd-analyze cat-config systemd/unit.conf

應用的drop-in片段文件及其內容將列在最後。重啟服務以使更改生效。

## 小技巧

這篇文章的某些內容需要擴充。

原因：我們應該在某個地方明確記錄套接字激活相對於簡單服務啟動的優勢。這在頁面開頭和相關頁面（如Avahi）中簡要提到。 (在 Talk:Systemd 中討論)

### 激活套接字

有一些包提供了一個 .socket 單元。例如，cups包 提供了一個 `cups.socket` 單元[3]。如果 `cups.socket` 被啟用（並且 `cups.service` 保持關閉），systemd 並不會立刻啟動 CUPS，它會監聽適當的套接字並且當任何一個程序嘗試連接 CUPS 服務中的一個時，systemd 會啟動 `cups.service` 並且透明地將這些埠的控制權移交給 CUPS 進程。

### GUI配置工具

- systemadm — 用於systemd單元的圖形化瀏覽器。可顯示單元列表，並能按類型篩選。

  https://cgit.freedesktop.org/systemd/systemd-ui/ || systemd-ui包

- SystemdGenie — 基於KDE的systemd管理工具。

  https://invent.kde.org/system/systemdgenie || systemdgenie包

### 在網絡已連接後再啟動某服務

如果需要將某服務延遲到網絡已連接後再啟動, 直接在 .service 文件中包含以下依賴項：

    /etc/systemd/system/<單元名>.service

    [Unit]
    ...
    Wants=network-online.target
    After=network-online.target
    ...

要使`network-online.target`正確反映網絡狀態，必須啟用所使用的網絡管理器的網絡等待服務。

- 若使用NetworkManager, `NetworkManager-wait-online.service`應該與`NetworkManager.service`一同啟用。可通過`systemctl is-enabled NetworkManager-wait-online.service`進行檢查。若服務沒用啟用，重新啟用`NetworkManager.service`。
- 若使用netctl, 啟用`netctl-wait-online.service` (除非使用了netctl-auto； 詳見FS#75836)。
- 若使用systemd-networkd, `systemd-networkd-wait-online.service`應該與`systemd-networkd.service`一同啟用。可通過`systemctl is-enabled systemd-networkd-wait-online.service`進行檢查。若服務沒用啟用，重新啟用`systemd-networkd.service`。

如果需要更為詳細的解釋，請查看網絡配置同步點中的討論。

若某服務需要執行DNS查詢，其應該被排在`nss-lookup.target`後：

    /etc/systemd/system/<單元名>.service

    [Unit]
    ...
    Wants=network-online.target
    After=network-online.target nss-lookup.target
    ...

詳見systemd.special(7) § Special Passive System Units.

要`nss-lookup.target`發揮作用，必須有一個單元通過`Wants=nss-lookup.target`引入`nss-lookup.target`，並通過`Before=nss-lookup.target`排在`nss-lookup.target`之前。一般情況下，上述配置由本地DNS解析器完成。

檢查哪一個正在運行的單元引入了`nss-lookup.target`：

    $ systemctl list-dependencies --reverse nss-lookup.target

### 默認啟用新安裝的單元

Arch Linux附帶的`/usr/lib/systemd/system-preset/99-default.preset`包含`disable *`，這會導致默認情況下的systemctl preset是禁用所有新安裝的的單元。因此某個新包安裝後, 用戶必須手動啟用新單元。

若上述行為不符合預期, 創建一個從`/etc/systemd/system-preset/99-default.preset`到`/dev/null`的符號連結來覆蓋該配置文件，這會導致 systemctl preset無視單元類型直接啟用所有單元，除非systemctl preset的配置目錄中有文件另有聲明。用戶單元不受影響。詳見systemd.preset(5)。

注意：若某個軟體包含有多個互相衝突的單元，默認啟用所有單元可能會出現問題。systemctl preset原本旨在供發行版或系統管理員使用。在有兩個衝突單元將被同時啟用的情況下，應明確在systemctl preset的配置文件中禁用其中一個單元，詳見systemd.preset(5)。

### 應用程式環境沙盒

可通過一個單元文件創建一個沙盒以在加固的虛擬環境中隔離應用程式及其進程。systemd充分利用namespaces，一系列允許/拒絕 capabilities 和 cgroups，以通過可拓展的執行環境設置（systemd.exec(5)）將進程禁錮在容器中。

將現有systemd單元文件進行沙盒化加固通常需要結合使用strace包，stderr和journalctl(1)等進行大量試驗。因此，最好先在上游文檔中搜索已完成的測試以作為試驗的基礎。

首先，最好通過以下命令獲得特定單元可能的加固選項作為基礎：

    $ systemd-analyze security <单元>

關於如何使用 systemd 部署沙盒的一些示例：

- `CapabilityBoundingSet`定義了一個列表，以指明某個單元可以/不能使用哪些capabilities(7)。詳見systemd.exec(5) § CAPABILITIES。
  - 例如，對`CAP_SYS_ADM` capability的控制應該是安全沙盒的目標: `CapabilityBoundingSet=~ CAP_SYS_ADM`

### 通知失敗的單元

本文或本章節可能需要合併到systemd/Timers#MAILTO。

附註： 相同話題，不同解決方案（在 Talk:Systemd 中討論）

要在服務故障時發出通知，可在相應服務的單元文件中添加`OnFailure=`設置，這可通過#附加配置片段完成。若要在每一個服務的單元文件中添加該設置，可使用一個頂層附加配置片段，詳見systemd.unit(5)。

為服務單元創建頂層附加配置片段：

    /etc/systemd/system/service.d/toplevel-override.conf

    [Unit]
    OnFailure=failure-notification@%n.service

這將向每個服務單元文件中添加`OnFailure=failure-notification@%n.service`。若單元甲失敗，會啟動`failure-notification@單元甲.service`來遞送相關通知（或執行其它配置的動作）。

創建`failure-notification@.service`模板單元：

    /etc/systemd/system/failure-notification@.service

    [Unit]
    Description=Send a notification about a failed systemd unit

    [Service]
    Type=oneshot
    ExecStart=/path/to/failure-notification.sh %i
    # 以臨時用戶/組運行並啟用其他安全措施
    DynamicUser=true

接下來可創建`failure-notification.sh`腳本，定義執行的操作或發送通知的方式（郵件、桌面通知、gotify、XMPP等）。`%i`將被替換為失敗單元的名稱並作為參數被傳遞給`failure-notification.sh`腳本。

為防止`failure-notification@.service`的實例啟動失敗時引發`failure-notification@.service`實例的遞歸性啟動，在`failure-notification@.service`單元的配置目錄下創建一個與頂層附加配置片段文件名相同的空的附加配置片段（該空的附加配置片段比全局附加配置片段優先級更高）：

    # mkdir -p /etc/systemd/system/failure-notification@.service.d
    # touch /etc/systemd/system/failure-notification@.service.d/toplevel-override.conf

## 疑難解答

### 尋找失敗的單元

要尋找啟動失敗的systemd單元，執行：

    $ systemctl --state=failed

可通過它們的日誌查找失敗的原因。詳見systemd/Journal#過濾輸出。

### 診斷系統啟動問題

systemd有許多用於調試系統啟動過程中的問題的選項。要捕獲在systemd接管啟動流程前的日誌，參閱boot debugging。還可參閱此系統調試文檔。

### 診斷一個服務

如果某個 systemd 服務的工作狀況不合預期或想了解發生了什麼的更多信息，將`SYSTEMD_LOG_LEVEL`環境變量的值設為`debug`。例如，要以調試模式運行systemd-networkd守護進程：

在此服務的配置文件中加入如下配置片段：

    [Service]
    Environment=SYSTEMD_LOG_LEVEL=debug

或者手動設置該環境變量以達到相同效果：

    # SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd

之後，重新啟動systemd-networkd並以`-f`/`--follow`啟動journalctl觀察該單元的日誌。

### 關機/重啟十分緩慢

如果關機十分緩慢（甚至跟死機了一樣），很可能是某個拒不退出的服務在作怪。對於每個服務systemd會等待一段時間，然後再嘗試殺死它。要確定是否受到該問題影響，詳見 systemd 文檔中的Shutdown completes eventually 這篇文章。

一個常見的原因是存在一個擱置的關機或掛起進程。要確認是否為這種情況，執行下列命令中的任何一個並觀察有無類似的輸出：

    # systemctl poweroff

    Failed to power off system via logind: There's already a shutdown or sleep operation in progress

    # systemctl list-jobs

      JOB UNIT                    TYPE  STATE
    ...
    21593 systemd-suspend.service start running
    21592 suspend.target          start waiting
    ..

該問題的解決方法是取消這些關機/掛起工作：

    # systemctl cancel
    # systemctl stop systemd-suspend.service

並再次嘗試關機或重啟。

### 一些短命進程似乎沒有產生任何日誌輸出

對於短命的服務進程（啟動後迅速失敗），若以root身份執行`journalctl -u <單元名>`可能看不到任何輸出，此時可轉而使用進程的PID。例如，若`systemd-modules-load.service`單元失敗，通過`systemctl status systemd-modules-load`得到的對應進程PID為123，以root身份執行`journalctl -b _PID=123`或許就能得到日誌輸出。上述問題的原因是日誌元數據（如`_SYSTEMD_UNIT`、`_COMM`）以異步方式被採集，且依賴於`/proc`中相應進程的目錄。修復該問題需要修改內核以通過socket提供需要的數據（類似於`SCM_CREDENTIALS`）。簡而言之，該問題是一個bug，只需記住由於systemd的設計，在啟動後迅速失敗的單元可能不會列印任何輸出到系統日誌中。

### systemd-tmpfiles-setup.service在系統啟動時失敗

自systemd 219開始，`/usr/lib/tmpfiles.d/systemd.conf`為`/var/log/journal`下的目錄指定了ACL選項。因此存放日誌的文件系統必須啟用ACL支持。

如何在存放`/var/log/journal`的文件系統上啟用ACL的說明見Access Control Lists#啟用 ACL。

### 在遠程主機上關閉救援（emergency）模式

當救援模式被觸發時，機器不會連接網絡，因此對於託管於Azure或Google Cloud的遠程主機，或許需要關閉救援模式。

要關閉救援模式，屏蔽`emergency.service`和`emergency.target`。

## 參見

- Wikipedia:systemd
- 官方網站
  - systemd 優化
  - systemd 常見問題解答
  - systemd 技巧與竅門
- systemd(1)
- 其他發行版
  - Gentoo:Systemd
  - Debian:Systemd
  - Ubuntu:Systemd
  - Fedora:Systemd
  - openSUSE:Systemd
- 如何使用 Systemctl 管理 Systemd 服務和單元
- 使用 systemd-logind 進行會話管理
- Emacs 對 Systemd 文件的語法高亮
- 兩篇 部分介紹文章，發表於 The H Open 雜誌。

分類：​

- 初始化

隱藏分類：​

- 使用「模板:準確性」標記的頁面或章節
- 使用「模板:合併」標記的頁面或章節

systemd
新增話題