重启rc.local没执行解决方法

发布时间 2023-09-04 18:04:45作者: 背对背依靠

背景:

在早期的 SysV init 系统中,/etc/rc.local 是在所有其他 init 脚本执行完毕后自动执行的一个脚本,为系统管理员提供了一个在系统启动时运行自定义命令的便捷方法。

随着 systemd 成为许多主流 Linux 发行版的默认 init 系统,因为systemd 使用服务单位(unit files)来控制启动进程,而不是传统的 init 脚本。所以/etc/rc.local 不再自动开机执行了。

但是为了兼容使用习惯,许多基于 systemd 的系统提供了一个名为 rc-local.service 的特殊服务,它专门用于执行 /etc/rc.local 脚本。这样,那些还依赖于 /etc/rc.local 的系统管理员或旧的应用程序仍然可以在 systemd 环境中运行它。

systemctl status rc-local.service 

image

[Unit]
Description=/etc/rc.local Compatibility
Documentation=man:systemd-rc-local-generator(8)
ConditionFileIsExecutable=/etc/rc.local #  当文件是可执行的时,这个服务才会启动
After=network.target

[Service]
Type=forking  # 启动模式为forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes # 指定的进程已经退出,服务的状态仍然会被视为 "active"。
GuessMainPID=no

rc.local脚本的systemd文件使用forking这种启动模式的原因:
因为rc.local脚本里面可以放一系列的命令、或者后台进程、守护进程等。选择 forking 类型可以让 systemd 更好地处理这种情况,因为很多传统的守护进程在启动时都会 fork。

例如:

vim /etc/rc.local
#!/bin/sh -e
echo "hell world"
exit 0

在这种情况下,systemd会看到主进程(也就是此脚本)已经成功地退出并返回了退出码0。因此,当你使用forking类型的服务描述符来启动这个脚本时,systemd会认为rc-local.service服务已经成功启动。

forking类型的服务描述符预期服务在其启动过程中至少进行一次fork操作,且原始进程(即由ExecStart启动的进程)在初始化完成后退出。这通常是传统的UNIX守护进程的行为。
然而,如示例所示,如果一个脚本或程序并没有进行fork操作,但仍然正常退出(例如返回退出码0),systemd仍然会认为这个服务按预期启动了,即使实际上并没有任何后台进程在运行。