问题背景
cron_for_fix.service
系统预设了包含死循环逻辑的脚本,并将其注册为 Type=oneshot 的 Systemd 服务,会导致系统启动序列发生严重阻塞。这不仅会使系统无法进入完整的 multi-user.target 状态,还会导致所有依赖该状态的服务(例如自定义的硬盘控温脚本)处于永久等待(Waiting)状态而失效。
问题表现
- 服务启动卡死:执行
systemctl restart <service> 时终端无响应,无法退出。
- 硬件保护失效:自定义的硬盘风扇控制脚本(hdd-fan.service)状态长期为
inactive (dead),即使已设置为 enabled。
- 系统状态异常:执行
systemctl list-**s 会发现大量任务处于 waiting 状态,multi-user.target 无法达成。
- 典型案例:
/usr/trim/bin/cron_for_fix.sh 包含 while true 循环,其对应的 cron_for_fix.service 类型为 oneshot。
根本原因分析
Systemd 对 Type=oneshot 的处理机制要求脚本必须执行完毕并退出,才会继续推进启动队列。
在以下配置中:
逻辑冲突:脚本由于 while true 永远不会退出,Systemd 因此永久等待 cron_for_fix.service 完成,从而挂起了整个 multi-user.target 的达成。所有配置了 After=multi-user.target 的服务都会被“锁死”。
复现步骤
- 创建一个包含死循环的脚本并赋予执行权限。
- 创建一个 Systemd 服务文件,设置
Type=oneshot 并指向该脚本。
systemctl enable 并重启系统。
- 尝试启动任何依赖
multi-user.target 的其他服务,观察是否卡住。
建议修复方案
- 修正服务类型:对于需要长期驻留后台的循环脚本,必须使用
Type=simple 而非 Type=oneshot。
- 优化依赖顺序:对于涉及硬件安全(如风扇控制、过热保护)的关键服务,建议将
After= 依赖项从 multi-user.target 提升至 basic.target 或 sysinit.target,以确保即使应用层服务阻塞,底层保护依然有效。
- 规范配置检查:在系统集成自定义脚本时,建议增加对
oneshot 类型服务是否包含阻塞逻辑的审计。
环境信息: