我试图阻止用户在不从机器上物理移除闪存卡的情况下关闭或重新启动。为此,我编写了一个 SystemD 服务,removeflash.service:
[Unit]
Description=Prompt user to remove flash card
[Service]
ExecStop=/usr/lib/systemd/flashshutdown.sh
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Requires=rsyslog.service
flashshutdown.sh是一个bash脚本,如下:
#! /bin/bash
#
while [ -e /dev/flash ] ; do
echo "Please remove flash card"
logger "GHB: Please remove flash card"
sleep 5
done
我没想到 echo 在关闭时会做任何事情,而且它没有。但是,我希望 logger 命令能够工作。没有Requires=rsyslog.service,我的服务在rsyslog.service关闭后就退出了;我插入了防止这种情况发生的要求,但唯一的区别是,removeflash.service 的关闭在关闭顺序中较早。幸运的是,systemd 本身向控制台输出一条消息,表明它正在运行提示用户删除闪存卡的作业,这一事实挽救了该服务的目的。
向控制台发出消息的正确方法是什么?
答案1
服务管理下的服务的标准输出和错误(无论是 s6、runit、perp、daemontools、nosh 服务管理还是 systemd)不是控制台。它是连接到某种形式的日志编写器的管道。
对于 systemd 服务,如果您想更改,您需要在 .INI 文件中使用 aTTYPath=/dev/console
和 a来更改此设置StandardOutput=tty
StandardInput=tty
读(但你不)以及写作。见证 systemd 预先提供的debug-shell.service
.
这是一个通用原则,并非 systemd 特定的。守护进程上下文涉及(除其他外)不是拥有一个控制终端并且没有终端的打开文件描述符,并且在适当的服务管理(例如所有 daemontools 系列)下,这就是一个开始于,当主管/服务管理器派生服务进程时该服务进程开始的状态。因此,要使用控制台,服务必须显式打开它。
在 systemd 中,上述TTYPath
设置StandardInput
会导致分叉子进程在正确执行服务程序之前打开控制台。它隐藏在 systemd 内部,您实际上看不到它。在run
类似nosh服务的程序中,run
程序在执行主程序之前显式地使用一些nosh工具集链加载工具来执行相同的操作(emergency-login
在本例中):
%猫 /etc/service-bundles/services/emergency-login@console/service/run #!/bin/nosh #紧急超级用户登录控制台 设定值 vc-get-tty 控制台 打开控制 tty vc-reset-tty --硬重置 line-banner“紧急模式登录。” 紧急登录 %
讽刺的是,您不需要该logger
命令或任何系统日志依赖项。写这个交互式提示没有意义到日志。但原则上,您确实应该以非特权方式运行此服务。它不是需要超级用户权限,无论它做什么。
#!/bin/bash
另一条原则是,除非您确实需要,否则不要使用您的脚本是将使用 Bashisms。过去几十年来,Debian Linux 和 Ubuntu Linux 上系统引导/关闭的最大加速之一是/bin/sh
从 Bourne Again shell切换到 Debian Almquist shell。如果您要编写一个像这样简单的脚本,请使其符合 POSIX 并使用#!/bin/sh
反正,即使您不使用 Debian/Ubuntu,并且在 Debian/Ubuntu 上您将获得 Debian Almquist shell 权益作为奖励。
此外,如果您决定使用更多玻璃 TTY 消息,则使用类似 的工具dialog
,您将需要设置TERM
环境变量,以便您的程序可以查找正确的转义和控制序列以在 terminfo 数据库中发出。再次见证debug-shell.service
。 (在上述run
程序中,为了进行比较,vc-get-tty
工具集TERM
。)
同样,你会想要脚本错误被记录。因此标准错误应该指向带有 的日志StandardError=journal
。这是一个 nosh 服务run
程序,它说明了与此等效的功能,并且还显示了删除实际上不需要它们的程序的用户权限,在 systemd .INI 文件中将是User=daemon
:
%猫 /etc/service-bundles/services/monitor-fsck-progress/service/run #!/bin/nosh #用于监视 fsck 进度的本地套接字 本地流套接字监听 --systemd-compatibility --backlog 2 --mode 0644 /run/fsck.progress 设定值 setlogin——守护进程 vc-get-tty 控制台 fdmove -c 4 2 打开控制 tty FD移动 2 4 setuidgid——守护进程 。/服务 %
在这种情况下运行的程序./service
在控制台上呈现全屏 TUI,同时其错误被发送到日志记录服务。这是一般在服务管理器下需要做的事情,以便运行服务等程序,与控制台对话。
当然,任何这样的全屏 TUI 程序都会与 systemd 的“A stop job is running”(也写入控制台)发生冲突。但这是你的问题。 ☺