Nas configurações do systemd, reboot
, poweroff
, halt
e init N
todos são convertidos em vários subcomandos de systemctl
. Eu falarei em termos de systemctl
a partir de agora.
Então, o que acontece quando você emite (por exemplo) um comando systemctl reboot
? Exceto o camada de abstração polkit / logind (que, de qualquer forma, não é usada quando privilégios de root estão disponíveis), este comando se traduz em systemctl isolate reboot.target
, que por sua vez é equivalente a systemctl start --job-mode=isolate reboot.target
.
Na linguagem systemd, para "isolar" uma unidade (seja um alvo, um serviço ou qualquer outra coisa) significa iniciar (ativar) uma determinada unidade junto com todas as suas dependências E parar (desativar) todas as outras unidades, a menos que tenham IgnoreOnIsolate=yes
especificado . Portanto, quando você emite um comando de reinicialização, reboot.target
(com suas dependências) é enfileirado para iniciar e todas as outras unidades são enfileiradas para parar.
Não examinaremos as dependências desses destinos manualmente (embora seja possível com o comando systemctl list-dependencies
). Vamos, em vez disso, olhar para bootup (7) , uma página man descrevendo o que acontece na inicialização / desligamento de um sistema controlado pelo sistema.
O gráfico ASCII correspondente é copiado e colado aqui (FTR, reflete systemd 221).
(conflicts with (conflicts with
all system all file system
services) mounts, swaps,
| cryptsetup
| devices, ...)
| |
v v
shutdown.target umount.target
| |
\_______ ______/
\ /
v
(various low-level
services)
|
v
final.target
|
_____________________________________/ \_________________________________
/ | | \
| | | |
v v v v
systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service
| | | |
v v v v
reboot.target poweroff.target halt.target kexec.target
O esquema é bastante autoexplicativo. A meta especial shutdown.target
por padrão entra em conflito com todas as unidades de serviço (a menos que tenham DefaultDependencies=no
definido).
Portanto, a primeira abordagem seria tornar sua A
service uma dependência de shutdown.target
, para que ela seja ativada em todos os desligamentos. (Observe que isso também exigirá que seja DefaultDependencies=no
.)
No entanto, por padrão, tudo no systemd é feito em paralelo, portanto, o A
service também precisa ser solicitado em relação a B
- para atrasar o desligamento de B
até que A
inicie e conclua sua recuperação de dados. Em systemd.unit (5) , podemos ler:
If one unit with an ordering dependency on another unit is shut down while the latter is started up, the shut down is ordered before the start-up regardless of whether the ordering dependency is actually of type After= or Before=.
Isso é lamentável: independentemente de fazermos A After=B.service
ou Before=B.service
, B será interrompido antes de A ser iniciado.
Então, devemos ir por outro caminho. Podemos criar um serviço normal de Type=oneshot
, que não faz nada ( /bin/true
) na ativação, mas faz o que for necessário na desativação. (Isso também exigirá que ele seja RemainsAfterExit=yes
ou o serviço será automaticamente marcado como inativo assim que /bin/true
sair.) Esse serviço pode ser solicitado em relação a B.service
conforme necessário:
Note that when two units with an ordering dependency between them are shut down, the inverse of the start-up order is applied. i.e. if a unit is configured with After= on another unit, the former is stopped before the latter if both are shut down.
Juntando tudo isso, um arquivo de unidade para A.service
será parecido com isto:
[Unit]
Description=Collect information about B
# we want to deactivate together with B
Requisite=B.service
# we want to deactivate before B deactivates
After=B.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecStop=/path/to/B
[Install]
# replace with whatever is needed
WantedBy=B.service
Observe também que se uma versão recente (≥ 217) do systemd for usada, então ExecStart=/bin/true
pode ser completamente deixado de fora .
Leitura adicional
- página de manual do systemd (1) , seção "Conceitos".
- Página de manual systemd.unit (5) , seção "Opções da Seção [Unidade]".
- Página de manual de inicialização (7) .
- Página de manual systemd.special (5) .