在Linux中使用systemd在引导阶段如何读取用户输入

时间:2020-02-23 14:40:17  来源:igfitidea点击:

在本文中,我将共享一个示例systemd单位文件,该文件可在RHEL/CentOS 7/8 Linux中与systemd一起使用shell脚本在引导阶段读取用户输入。
对于系统管理员来说,可能有一些任务,例如设置主机名或者某些要求他(她)在引导阶段出现之前在引导阶段读取用户输入的操作。
然后根据用户输入,使用后台脚本执行某些任务。

使用RHEL/CentOS 7/8 Linux中的systemd单元服务文件可以做到这一点。

第1步:systemd概述

希望我们已经熟悉以下主题

  • systemd概述以及它与旧版SysV脚本的区别

  • 如何在Linux中创建systemd单位文件

创建示例脚本

在启动阶段,我们将使用带有直到循环的自定义小脚本来读取用户输入。
因此,除非脚本获得用户输入,否则它将不允许引导阶段完成。

[root@centos-8 ~]# cat /tmp/welcome.sh
#!/bin/bash
until [[ -n ${REPLY} ]]; do
    read -ep "Enter your name: "
done
echo "WELCOME ${REPLY^^}"; sleep 5

此处,脚本将提示"输入姓名",然后将等待用户输入。
如果我们在启动阶段调用此脚本,则该脚本将在启动阶段读取用户输入并进行相应的操作。

创建系统单元服务文件以在引导阶段读取用户输入

现在,我们需要一个systemd单元服务文件,该文件将在引导阶段调用脚本以读取用户输入。
该文件应该位于/usr/lib/systemd/system /或者/etc/systemd/system /中。
下面是一个示例的systemd单元服务文件:

[root@centos-8 ~]# cat /etc/systemd/system/take-user-input.service
[Unit]
Description=Get user input at boot stage
After=network.target
Before=sshd.service systemd-logind.service [email protected]
[Service]
Type=oneshot
TTYPath=/dev/tty13
ExecStartPre=/usr/bin/chvt 13
ExecStart=/tmp/welcome.sh
ExecStartPost=/usr/bin/chvt 1
TimeoutStartSec=0
StandardInput=tty
TTYVHangup=yes
TTYVTDisallocate=yes
[Install]
WantedBy=default.target
RequiredBy=sshd.service systemd-logind.service [email protected]

其中

After=   	If the script needs any other system facilities (networking, etc), modify the [Unit] section to include appropriate 
		After=, Wants=, or Requires= directives, as described in: man systemd.unit
Before=   	If the script needs to be run before other services--for example, prior to starting sshd or console/graphical 
		logins--ensure there is a Before=XYZ.service in the [Unit] section and a corresponding RequiredBy=XYZ.service 
		in the [Install] section.
TTYPath=   	Specify a tty number here (the writer's choice of tty13 here was mostly arbitrary; however, keep in mind that 
		numbers higher than 12 require the chvt command to access them).
ExecStartPre=/usr/bin/chvt 13   This changes the physical console to tty13 (i.e., the tty specified with TTYPath=).
ExecStart=   The full path to the main script, including any desired script arguments.
ExecStartPost=/usr/bin/chvt 1   This changes the physical console back to tty1 after the script finishes (this line 
				is not always necessary, e.g., if a display manager starts after the script, it will 
				probably steal focus by changing the physical console back to whichever tty it is running on).
TimeoutStartSec=    When a service doesn't signal start-up completion within TimeoutStartSec, systemd considers the service failed; 
		    for long-running shell scripts it is essential to modify TimeoutStartSec or disable the timeout logic altogether 
		    as above, with TimeoutStartSec=0. See man systemd.service for more details
StandardInput=tty   This line is absolutely necessary; without specifying the value tty here, this setting defaults to null. 
					(Note that StandardOutput= and StandardError= can also be independently set; 
					however, by default they inherit their value from StandardInput=.)
For more information check man page of systemd.exec

刷新systemd配置文件

[root@centos-8 ~]# systemctl daemon-reload

启用服务以在下次启动时自动启动

[root@centos-8 ~]# systemctl enable take-user-input.service
Created symlink /etc/systemd/system/default.target.wants/take-user-input.service → /etc/systemd/system/take-user-input.service.
Created symlink /etc/systemd/system/sshd.service.requires/take-user-input.service → /etc/systemd/system/take-user-input.service.
Created symlink /etc/systemd/system/systemd-logind.service.requires/take-user-input.service → /etc/systemd/system/take-user-input.service.
Created symlink /etc/systemd/system/[email protected]/take-user-input.service → /etc/systemd/system/take-user-input.service.

现在我们已经完成了所有工作,继续重新启动Linux节点。

验证systemd单元文件配置

重启后连接到Linux主机的GUI控制台,因为我使用的是Oracle VirtualBox,所以我将连接到虚拟机的控制台。

如我们所见,其中引导已停止,正在等待我们的脚本/tmp/welcome.sh中的用户输入。

输入后,将继续引导Linux OS。

在此阶段,我们已在激活sshd之前显式使用了" Before = sshd.service"和" After = network.target"来执行脚本,因此尽管网络应该处于活动状态,但sshd在此阶段将不活动。