The ignore directive specifies to not do anything with the given
unit and leave existing configuration intact. This allows distributions
to gradually adopt preset files by shipping a ignore * preset file.
Chasing symlinks is a core function that's used in a lot of places
so it deservers a less verbose names so let's rename it to chase()
and chaseat().
We also slightly change the pattern used for the chaseat() helpers
so we get chase_and_openat() and similar.
In various tools and services we have a per-system and per-user concept.
So far we sometimes used a boolean indicating whether we are in system
mode, or a reversed boolean indicating whether we are in user mode, or
the LookupScope enum used by the lookup path logic.
Let's address that, in introduce a common enum for this, we can use all
across the board.
This is mostly just search/replace, no actual code changes.
If any query makes it to the end of install_info_follow() then I think symlink_target is set to NULL.
If that is followed by -EXDEV from unit_file_load_or_readlink(), then that causes basename(NULL)
which segfaults pid 1.
This is triggered by eg. "systemctl status crond" in RHEL9 if
/etc/systemd/system/crond.service
-> /ram/etc/systemd/system/crond.service
-> /usr/lib/systemd/system/.crond.service.blah.blah
-> /usr/lib/systemd/system/crond.service
We would set .path in all cases except INSTALL_CHANGE_AUXILIARY_FAILED, where
we would just just .source. This special case is just not worth it, because
we can't easily assert that .path is set. Let's remove this special case to
help the compiler know that .path is actually set.
Avoids a warning with gcc-13.0.1-0.1.fc38.x86_64.
When switching to an alternative alias provider,
the previous one might have been uninstalled or so.
It should be fine for us to overwrite them directly.
Closes#23694
-1 was used everywhere, but -EBADF or -EBADFD started being used in various
places. Let's make things consistent in the new style.
Note that there are two candidates:
EBADF 9 Bad file descriptor
EBADFD 77 File descriptor in bad state
Since we're initializating the fd, we're just assigning a value that means
"no fd yet", so it's just a bad file descriptor, and the first errno fits
better. If instead we had a valid file descriptor that became invalid because
of some operation or state change, the other errno would fit better.
In some places, initialization is dropped if unnecessary.
Trying to disable a unit with no install info is mostly useless, so
adding a warning like we do for enable (with the new dbus method
'DisableUnitFilesWithFlagsAndInstallInfo()'). Note that it would
still find and remove symlinks to the unit in /etc, regardless of
whether it has install info or not, just like before. And if there are
actually files to remove, we suppress the warning.
Fixes#17689
The name "def.h" originates from before the rule of "no needless abbreviations"
was established. Let's rename the file to clarify that it contains a collection
of various semi-related constants.
We treat symlinks to unit files outside of the search path differently from
symlinks to unit files *in* the search path. The former are "linked" unit
files, while the latter are enablement symlinks and such and will be removed
when disabling the unit.
The history of the check for in_search_path() is interesting: this condition
was added already in the first version of the code in
830964834f. Since the beginning, matching
arguments would simply be ignored. I think this is dubious. The man page says:
> Link a unit file that is *not* in the unit file search paths
> into the unit file search path
But for backwards-compat, let's continue to silently do nothing for files
*in* the search path.
The case of symlinks to unit files underneath the search path, but in some
subdirectory, is less clear. We didn't check for this case, so it was
implicitly allowed. But that's just an oversight, we don't want to allow people
to create additional subhierarchies under our hierarchy. Let's check for this
case and refuse.
Closes#24605.
This adds a check for an allocation error for the calls to install_changes_add()
where we're plannig to return success from the call. In cases where we're
returning failure, it doesn't matter as much: the operation will fail anyway,
and if the allocation fails, we'll just get a less descriptive error message.
The machinery to report a good error message only works if the
error was registered with install_changes_add() and a file name. Otherwise
we only get a generic "Op failed: %m" message.
In some places -EINVAL is replaced by -EUCLEAN, so that we get the proper
error message.
The function was written to only return an error from internal allocation
failures, because when using it to create a bus message, we want to distinguish
a failed operation from an allocation error when sending the reply. But it
turns out that the only caller that makes this distinction checks that the
passed-in errno value ('type') is not negative beforehand. So we can make the
function pass 'type' value through, which makes most of the callers nicer.
No functional change.
Typically the _MAX and _INVALID special enum values use the full type as
prefix, even if the actual values of the enum might not. Let's follow
this rule here too.
We can just make this an enum, as long as we ensure it has enough range,
which we can do by adding -ERRNO_MAX as one possible value (at least on
GNU C). We already do that at multiple other places, so let's do this
here too.
'systemctl unmask foo' will try to remove the symlink to /dev/null under /etc/.
But the unit may also be masked by a symlink under /run/generator, in particular
the one created by systemd-debug-generator based on systemd.mask=foo on the
kernel commandline. The unmask call cannot anything about this: even if it removed
the symlink from /run/generator, it'll be recreated on the next daemon-reload.
Thus, we can only warn about it.
Initially, I wanted to check if 'systemctl.mask' is defined on the kernel
command-line, but that's not effective, because such mask symlinks can be
created by other generators based on other conditions. Checking for runtime
mask is "dumber", but is more robust because it doesn't assume who created the
mask and why.
The handling of InstallInfo is the copied from install_info_symlink_wants().
It's pretty ugly, this whole code should be rewritten from scratch.
The message is printed, but the whole operation is still "successful". This
keep backwards compatibility: people might call unmask to remove filesystem
masks even if there's still a cmdline param in place. We allow 'systemctl
mask' to create such a mask, so 'unmask' should be able to remove it.
Fixes#22689.
We had an anonymous enum with values called UNIT_FILE_…, which could easily be
confused with UNIT_FILE_… from UnitFileFlags enum. This commit renames the enum
values and also the variables which refer to them.
This reverts commit d6c9411072.
I still think this is something that needs to be done, but we're hitting some
unexplained failures, e.g. https://github.com/systemd/systemd/issues/22920.
So let's revert this for now, so -rc2 can be released, with a plan to return
to this after a release.
Closes#22920.
We would only accept "identical" links, but having e.g. a symlink
/usr/lib/systemd/system/foo-alias.service → /usr/lib/systemd/system/foo.service
when we're trying to create /usr/lib/systemd/system/foo-alias.service →
./foo.service is OK. This fixes an issue found in ubuntuautopkg package
installation, where we'd fail when enabling systemd-resolved.service, because
the existing alias was absolute, and (with the recent patches) we were trying
to create a relative one.
A test is added.
(For .wants/.requires symlinks we were already doing OK. A test is also
added, to verify.)
When we have a symlink that goes outside of our search path, we should just
ignore the target file name. But we were verifying it, and rejecting in
the case where a symlink was created manually.
The two states are distinguished, but are treated everywhere identically,
so there is no difference in behaviour except for slighlty different log
output.
We'd say that file is enabled indirectly if we had a symlink like:
foo@.service ← bar.target.wants/foo@one.service
but not when we had
foo@one.service ← bar.target.wants/foo@one.service
The effect of both link types is the same. In fact we don't care
about the symlink target. (We'll warn if it is mismatched, but we honour
it anyway.)
So let's use the original match logic only for aliases.
For .wants/.requires we instead look for a matching source name,
or a source name that matches after stripping of instance.
This is a fairly noticable change, but I think it needs to be done.
So far we'd create an absolute symlink to the target unit file:
.wants/foo.service → /usr/lib/systemd/system/foo.service
or
alias.service → /etc/systemd/system/aliased.service.
This works reasonably well, except in one case: where the unit file
is linked. When we look at a file link, the name of the physical file
isn't used, and we only take the account the symlink source name.
(In fact, the destination filename may not even be a well-formed unit name,
so we couldn't use it, even if we wanted to.) But this means that if
a file is linked, and specifies aliases, we'd create absolute links for
those aliases, and systemd would consider each "alias" to be a separate
unit. This isn't checked by the tests here, because we don't have a running
systemd instance, but it is easy enough to check manually.
The most reasonable way to fix this is to create relative links to the
unit file:
.wants/foo.service → ../foo.service
alias.service → aliased.service.
I opted to use no prefix for aliases, both normal and 'default.target',
and to add "../" for .wants/ and .requires/. Note that the link that is
created doesn't necessarily point to the file. E.g. if we're enabling
a file under /usr/lib/systemd/system, and create a symlink in /etc/systemd/system,
it'll still be "../foo.service", not "../../usr/lib/systemd/system/foo.service".
For our unit loading logic this doesn't matter, and figuring out a path
that actually leads somewhere would be more work. Since the user is allowed
to move the unit file, or add a new unit file in a different location, and
we don't actually follow the symlink, I think it's OK to create a dangling
symlink. The prefix of "../" is useful to give a hint that the link points
to files that are conceptually "one level up" in the directory hierarchy.
With the relative symlinks, systemd knows that those are aliases.
The tests are adjusted to use the new forms. There were a few tests that
weren't really testing something useful: 'test -e x' fails if 'x' is a
a dangling symlink. Absolute links in the chroot would be dangling, even
though the target existed in the expected path, but become non-dangling
when made relative and the test fails.
This should be described in NEWS, but I'm not adding that here, because
it'd likely result in conflicts.