
man 7 daemon
當傳統的 SysV 守護程式啟動時,它應該執行以下步驟作為初始化的一部分。請注意,這些步驟對於新型守護程序來說是不必要的(見下文),並且只有在必須與 SysV 相容時才應實施。
[...]
6. 在子進程中,呼叫setsid()從任何終端分離並建立一個獨立的會話。
7. 在子進程中,再次呼叫 fork(),確保守護程序永遠不會再次重新取得終端。
但將此與沒有 SysV 相容性痕跡的啟動進程進行比較:
$ ps -efj
UID PID PPID PGID SID C STIME TTY TIME CMD
root 1 0 1 1 0 May10 ? 00:06:44 /sbin/init
...
root 185 1 185 185 0 May10 ? 00:09:48 /lib/systemd/systemd-journald
root 16434 1 16434 16434 0 May26 ? 00:00:11 /usr/sbin/rsyslogd -n
rsyslog.service
和的進程systemd-journal.service
都是會話領導者 (SID = PID)。
看起來,如果這些程式被配置為登入 TTY,它們就會將 TTY 作為控制終端,並在 TTY 掛起/接收到 Ctrl+C 時分別收到不需要的/致命訊號。除非他們記得在開啟 TTY 檔案時設定 O_NOCTTY。
如果您的程式支援將訊息寫入自訂文件,那麼在編寫或轉換程式以作為沒有任何 SysV 相容性的 systemd 服務運行時,這似乎是一個小陷阱。這個提倡systemd風格的文件似乎沒有指出這一點。該文件暗示了相反的情況,堅持認為必須使用雙分叉來避免 SysV 上的這種情況,然後在描述本機 systemd 服務將使用的步驟時沒有提到這一點。
那是對的嗎? systemd 是否提供了一些針對我忽略的保護措施,或者該問題是否在 systemd 文件的其他地方指出?
答案1
systemd 是否針對這種情況提供了一些保護 [...]?
你假設它應該。相反,請考慮諸如 之類的設置TTYPath
和諸如 之類的服務[email protected]
。獲得控制終端的能力實際上是必要的,以便服務管理可以包含 TTY 登入服務,而這正是需要做到的。
真正防止這種情況發生的是放棄在 處自動分配控制終端open()
,並放棄舊的語義。或者會防止它。在 Linux 上情況並非如此,但在 FreeBSD、NetBSD、OpenBSD 和 Hurd 上,現在O_NOCTTY
的 標誌open()
完全是多餘的。這僅有的獲取控制終端的方法是透過明確要求它,使用ioctl(…TIOSCTTY)
.事實上,自 4.4BSD 時代以來,這種情況已經持續了近四分之一個世紀。
同時,在 Linux 上養成的習慣已經存在很久了,早在 systemd 之前:O_NOCTTY
到處。 ☺
(是的,GNU 和 musl C 庫不會為您提供此功能fopen()
。這是仍然是有用機制的幾個原因之一fdopen()
。)
使用 nosh 工具集進行服務管理service-manager
對此採取了略有不同的策略。不是總是將守護程序設定為會話領導者,而是為每個服務分配自己的核心會話對象,然後該對象就看不到任何用處,只有特定的服務也會setsid
明確地連結;例如使用的服務,當然是設定控制終端的服務,以及服務。 (如服務來源中所述,請呼叫自身。)ttylogin@*
open-controlling-tty
agetty@*
agetty
getty@*
mgetty
setsid()
進一步閱讀
- 喬納森·德博因·波拉德 (2018)。
setsid
。小吃指南。軟體. - 喬納森·德博因·波拉德 (2018)。
open-controlling-tty
。小吃指南。軟體. - 喬納森·德博因·波拉德 (2015)。 」繼承與守護程式謬誤
」。
service
命令不再有問題。諾什簡介。軟體. - 喬納森·德博因·波拉德 (2001)。 」不要
fork()
為了「將守護程式置於後台」。」。設計 Unix 守護程式時要避免的錯誤。經常給的答案。 - 喬納森·德博因·波拉德。 」虛擬終端登入」。小吃指南。軟體.
- 喬納森·德博因·波拉德。 」真實終端登入」。小吃指南。軟體.
- http://git.musl-libc.org/cgit/musl/tree/src/stdio/__fmodeflags.c
- https://github.com/lattera/glibc/blob/a2f34833b1042d5d8eeb263b4cf4caaea138c4ad/libio/fileops.c#L274
答案2
systemd 不保護服務程式不取得控制終端。當開啟使用者指定的日誌檔案時,他們必須使用該O_NOCTTY
標誌來保護自己。
$ rpm -q systemd
systemd-238-8.git0e0aa59.fc28.x86_64
$ systemctl cat test
# /etc/systemd/system/test.service
[Service]
Type=simple
ExecStart=/bin/sh -c "exec cat </dev/tty10 >/dev/tty10"
$ systemctl status test
● test.service
Loaded: loaded (/etc/systemd/system/test.service; static; vendor preset: disabled)
Active: active (running) since Fri 2018-06-01 11:28:41 BST; 1min 35s ago
Main PID: 12173 (cat)
Tasks: 1 (limit: 4915)
Memory: 180.0K
CGroup: /system.slice/test.service
└─12173 cat
Jun 01 11:28:41 alan-laptop systemd[1]: Started test.service.
$ ps -ejf
UID PID PPID PGID SID C STIME TTY TIME CMD
...
root 12173 1 12173 12173 0 11:28 tty10 00:00:00 cat
我還確認切換到 tty10 並按 Ctrl+C 會停止該cat
過程。