我的 Ubuntu 17.04 启动失败,我想调试它。
启动随机失败,我相信这是由于竞争条件造成的。
我可以要求systemd
不要并行化任何任务,这样我就可以看看这是否会导致引导失败?
答案1
解决方法:手动运行服务
我曾有一个启动时崩溃。就我而言,崩溃是在达到basic.target
目标之后但之前multi-user.target
,所以我想找出哪个服务启动multi-user.target
导致了崩溃。
首先,我安排启动以basic.target
添加 root shell。您可以永久执行此操作(假设您成功启动!)
systemctl set-default basic.target
systemctl enable debug-shell
该debug-shell
服务在 tty 9 上运行 root shell。
systemd.unit=basic.target systemd.debug-shell
通过在内核命令行中添加参数可以获得相同的效果。例如,在 Grub 中,将命令行编辑为类似的内容
linux /vmlinuz-4.13.0-38-generic root=/dev/mapper/crypt-root ro systemd.unit=basic.target systemd.debug-shell
在这个 shell 中,我运行了以下脚本来一一启动服务。请注意,这在很大程度上未经测试(我运行了一次,它在有问题的服务上按预期崩溃了)。
#!/bin/sh
wants=$(systemctl show -p Wants multi-user.target | sed 's/^Wants=//' | tr ' ' '\n' | sort)
log=/var/tmp/multi-user-steps-$(date +%Y%m%d-%H%M%S)
log () {
echo "$* ..." | tee -a "$log"
sync
"$@"
ret=$?
echo "$* -> $ret" | tee -a "$log"
sync
return $ret
}
# systemd services
for service in $wants; do
log systemctl start $service
sleep 2
done
# upstart services
for conf in /etc/init/*.conf; do
service=${conf##*/}; service=${service%.conf}
log service ${service} start
sleep 2
done
# sysvinit services
for service in /etc/rc3.d/S*; do
log ${service} start
sleep 2
done
添加额外的依赖项
下面的脚本声明了对 systemd 单元的“之前”依赖关系,这些单元是给定目标的直接依赖关系,以强制它们按特定顺序运行。您可能想在multi-user.target
或上运行它basic.target
。
注意这个脚本一般不起作用因为它没有考虑现有的依赖关系:它可能会导致依赖循环。正确的脚本应该收集现有的依赖关系并进行拓扑排序。我已经解决了我的问题,所以我不想再继续解决它了;我将其发布,以防有人想要对其进行调整以适应他们的需求。
另请注意,这不会影响 Upstart 和 SysVinit 服务。
/etc
在运行之前先备份! (我强烈建议使用等等管理员.)
#!/bin/sh
set -e
if [ $# -eq 0 ] || [ "$1" = "--help" ]; then
cat <<EOF
Usage: $0 TARGET
Linearize the dependencies of a systemd target so it starts deterministically.
This scripts adds systemd unit files called linearize-for*.conf containing
extra Before= dependencies for each dependency of TARGET.
EOF
fi
service_dir=/etc/systemd/system
target=$1
wants=$(systemctl show -p Wants "$target" | sed 's/[^= ]*=//' |
tr ' ' '\n' | sort)
previous=
for want in $wants; do
[ -d "$service_dir/$want.d" ] || mkdir "$service_dir/$want.d"
cat <<EOF >"$service_dir/$want.d/linearize-for-${target%.*}.conf"
[Unit]
Before=$previous
EOF
previous=$want
done