"systemctl disable" can't turn a unit off that the vendor enabled with a dependency symlink below /usr/. Where a mask has been created by hand it removes the mask, which silently enables the unit again. A preset policy of "disable" can't turn such a unit off either. /usr/ is frequently read-only and anything we did there would be undone by the next image update, so let's shadow the symlink instead: disable writes a symlink to /dev/null into the configuration directory, and PID 1 ignores a dependency entry that resolves to /dev/null. Only the symlinks that enabling would create are shadowed, i.e. the ones in the directories the [Install] section names. A static dependency such as the symlink to remote-cryptsetup.target in initrd-root-device.target.wants/ stays untouched. Enable removes the masks again, those of the Also= units included, which is why the removal runs after the symlinks have been applied. Creating a symlink replaces the mask at the same path. Disabling a template masks every instance the vendor enabled, and enabling the template only creates the symlink of its default instance, so the removal afterwards catches the masks of the other instances. Disabling a template also removes the symlinks of its instances. "systemctl disable foo@.service" therefore deletes a foo@bar.service -> /dev/null unit mask, which unmasks the instance. Disable now leaves all masks alone, unit masks included. Static dependencies are left alone throughout, so that a catch-all "disable *" policy can't stop the likes of systemd-journald.service from starting at boot. Nothing is masked where something else already exists in the dependency directory: it already shadows the vendor symlink, and replacing it would destroy it. A preset policy of "disable" deliberately doesn't mask this way and leaves the vendor enablement in place. Preset files never had to name the units the vendor enabled below /usr/, and with a catch-all "disable *" rule a mask would stop all of those units from starting at boot. "systemctl --user disable" warns when a unit stays enabled in global scope, and checks the global state for that. A vendor symlink in /usr/lib/systemd/user/ now counts there, even though the mask the disable just created in the user's configuration shadows it. Let's check the user scope's state instead. It sees the mask, and it still reports a unit enabled in /etc/systemd/user/ as enabled. The changes list gains two types for this, "mask-dependency" and "unmask-dependency", so that callers can tell a mask from a plain unlink. The bus API documents them as such, GetUnitFileLinks() reports the vendor symlink rather than the mask that would shadow it, and so does "is-enabled --full".
System and Service Manager
Details
Most documentation is available on systemd's website.
Assorted, older, general information about systemd can be found in the systemd Wiki.
Information about build requirements is provided in the README file.
Consult our NEWS file for information about what's new in the most recent systemd versions.
Please see the Code Map for information about this repository's layout and content.
Please see the Hacking guide for information on how to hack on systemd and test your modifications.
Please see our Contribution Guidelines for more information about filing GitHub Issues and posting GitHub Pull Requests.
When preparing patches for systemd, please follow our Coding Style Guidelines.
If you are looking for support, please contact our mailing list, join our IRC channel #systemd on libera.chat or Matrix channel
Stable branches with backported patches are available in the stable repo.
We have a security bug bounty program sponsored by the Sovereign Tech Fund hosted on YesWeHack
Repositories with distribution packages built from git main are available on OBS, and also repositories with packages built from the latest stable release
