systemctl --dry-run není simulace pro všechny podpříkazy
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Během read-only inventury (příprava plánu změny, nic se nemělo měnit) padl dotaz
„co přesně by enable udělal?” a odpověď se hledala příkazem s --dry-run.
Výstup vypadal jako popis plánu:
Created symlink /etc/systemd/system/multi-user.target.wants/<unit> → /usr/local/lib/<app>/<konkrétní-verze>/<unit>O dvacet minut později se při další kontrole ukázalo, že symlink skutečně existuje,
is-enabled se změnil z linked na enabled a jednotka by nastartovala při příštím bootu.
Žádné potvrzení se nevyžadovalo, žádné varování se nevypsalo.
Root cause
Sekce “Root cause”--dry-run není globální vlastnost systemctl. Podporuje ho jen část podpříkazů
(typicky ty pro řízení stavu systému). U enable/disable v ověřované verzii příznak
neplatí a je tiše ignorován — příkaz proběhne ostře.
Zrádné je hlášení: Created symlink … je v systemd stejná věta pro reálné provedení
i pro simulaci. Čtenář v režimu „dry-run” ji přirozeně přečte jako budoucí čas
(„vytvořil by”), přitom popisuje hotový fakt. Že šlo o reálný zápis, prozradí až:
# časové razítko odpovídá okamžiku "simulace"find /etc/systemd -newermt "<dnešek>" -printf '%TY-%Tm-%Td %TH:%TM:%TS %p -> %l\n'journalctl --since "<čas>" | grep Reloading # systemd[1]: Reloading.Druhý, tišší problém: symlink, který enable vytvoří, míří na kanonizovanou cestu
(rozřešený symlink), tedy na konkrétní verzi balíku — ne na stabilní přepínací symlink.
U verzovaných instalací s atomickým přepínáním current → verze-N to znamená, že po
příštím přepnutí by boot spouštěl jednotku staré verze, případně by odkaz osiřel.
Fix
Sekce “Fix”Zjišťování bez mutace. [Install] sekce plně určuje, co enable udělá — stačí ji přečíst:
sed -n '/\[Install\]/,$p' /etc/systemd/system/<unit> # např. jen WantedBy=multi-user.targetsystemctl show <unit> -p UnitFileState -p WantedBy -p NeedDaemonReloadZápis persistence bez enable. Když [Install] obsahuje jen WantedBy=, je celý efekt
jeden symlink — dá se vytvořit atomicky a se stabilním cílem:
W=/etc/systemd/system/multi-user.target.wantsTMP="$W/.<unit>.$$-$RANDOM.tmp" # běhově unikátní jménoln -s /usr/local/lib/<app>/current/<unit> "$TMP" # BEZ -f: existující objekt = chyba, ne tichý přepis[ "$(readlink "$TMP")" = /usr/local/lib/<app>/current/<unit> ] || exit 1mv -T "$TMP" "$W/<unit>" # jediná publikační mutace (atomický rename)Cíl je stabilní current/, takže persistence se přepíná spolu s balíkem.
Kontrola rezidua musí počítat se skrytým jménem. Dočasné jméno začíná tečkou, takže běžný shell glob ho mine:
# ŠPATNĚ – skryté položky nevidíls <unit>*.tmp 2>/dev/null# SPRÁVNĚfind "$W" -maxdepth 1 -name '.<unit>.*.tmp' -print -quitLekce
Sekce “Lekce”- „Bezpečný” flag u mutujícího příkazu není bezpečnostní hranice; hranicí je výběr příkazu.
- Hlášení nástroje může být formulačně shodné pro simulaci i provedení — důkazem stavu je filesystem a žurnál, ne text na stdout.
- Po každé takové operaci ohraničit rozsah (
find -newermt,journalctl --since) — bez toho se nedá tvrdit, co všechno se změnilo.