
A inicialização no meu Ubuntu 17.04 falha e quero depurá-lo.
A inicialização falha aleatoriamente e acredito que seja devido a uma condição de corrida.
Posso pedir systemd
para não paralelizar nenhuma tarefa, para poder ver se isso faz com que a inicialização falhe de maneira previsível?
Responder1
Uma solução alternativa: execute serviços manualmente
eu tive umtravar durante a inicialização. No meu caso, a falha ocorreu depois de atingir o basic.target
alvo, mas antes multi-user.target
, então eu queria descobrir qual dos serviços iniciados multi-user.target
estava causando a falha.
Primeiro, organizei a inicialização com basic.target
mais um shell de root. Você pode fazer isso permanentemente (supondo que você consiga inicializar!) com
systemctl set-default basic.target
systemctl enable debug-shell
O debug-shell
serviço executa um shell root em tty 9.
Você pode obter o mesmo efeito adicionando os parâmetros systemd.unit=basic.target systemd.debug-shell
à linha de comando do kernel. Por exemplo, no Grub, edite a linha de comando para algo como
linux /vmlinuz-4.13.0-38-generic root=/dev/mapper/crypt-root ro systemd.unit=basic.target systemd.debug-shell
A partir deste shell, executei o seguinte script para iniciar os serviços um por um. Observe que isso não foi testado (eu executei uma vez e ele travou conforme esperado no serviço problemático).
#!/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
Adicione dependências extras
O script abaixo declara dependências “Antes” nas unidades do systemd que são dependências diretas de um determinado alvo para forçá-las a serem executadas em uma ordem específica. Você pode querer executá-lo em multi-user.target
ou basic.target
.
Observe queeste script não funciona em geralporque não leva em consideração as dependências existentes: pode causar um loop de dependência. Um script adequado deve coletar as dependências existentes e fazer uma classificação topológica. Resolvi meu problema, então não pretendo mais trabalhar nele; Estou postando caso alguém queira adaptá-lo às suas necessidades.
Observe também que isso não afeta os serviços Upstart e SysVinit.
Faça um backup /etc
antes de executar isso! (Eu recomendo fortemente usaretckeeper.)
#!/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