Age | Commit message (Collapse) | Author |
|
It may be desired by users to know what targets a particular service is
installed into. Improve user friendliness by teaching the is-enabled
command to show such information when used with --full.
This patch makes use of the newly added UnitFileFlags and adds
UNIT_FILE_DRY_RUN flag into it. Since the API had already been modified,
it's now easy to add the new dry-run feature for other commands as
well. As a next step, --dry-run could be added to systemctl, which in
turn might pave the way for a long requested dry-run feature when
running systemctl start.
|
|
Introduce a new enum to get rid of some boolean arguments of unit_file_*
functions. It unifies the code, makes it a bit cleaner and extensible.
|
|
Various install-related tweaks
|
|
When a unit file is invalid, we'd return an error without any details:
$ systemctl --root=/ enable testing@instance.service
Failed to enable: Invalid argument.
Fix things to at least print the offending file name:
$ systemctl enable testing@instance.service
Failed to enable unit: File testing@instance.service: Invalid argument
$ systemctl --root=/ enable testing@instance.service
Failed to enable unit, file testing@instance.service: Invalid argument.
A real fix would be to pass back a proper error message from conf-parser.
But this would require major surgery, since conf-parser functions now
simply print log errors, but we would need to return them over the bus.
So let's just print the file name, to indicate where the error is.
(Incomplete) fix for #4210.
|
|
Test case:
[Install]
WantedBy= default.target
Also=getty@%p.service
$ ./systemctl --root=/ enable testing@instance.service
Created symlink /etc/systemd/system/default.target.wants/testing@instance.service → /etc/systemd/system/testing@.service.
Created symlink /etc/systemd/system/getty.target.wants/getty@testing.service → /usr/lib/systemd/system/getty@.service.
$ ./systemctl --root=/ disable testing@instance.service
Removed /etc/systemd/system/getty.target.wants/getty@testing.service.
Removed /etc/systemd/system/default.target.wants/testing@instance.service.
Fixes part of #4210.
Resolving specifiers in DefaultInstance seems to work too:
[Install]
WantedBy= default.target
DefaultInstance=%u
$ systemctl --root=/ enable testing3@instance.service
Created symlink /etc/systemd/system/default.target.wants/testing3@instance.service → /etc/systemd/system/testing3@.service.
$ systemctl --root=/ enable testing3@.service
Created symlink /etc/systemd/system/default.target.wants/testing3@zbyszek.service → /etc/systemd/system/testing3@.service.
|
|
Test case:
[Install]
WantedBy= default.target
Also=foobar-unknown.service
Before:
$ systemctl --root=/ enable testing2@instance.service
Failed to enable: No such file or directory.
After
$ ./systemctl --root=/ enable testing2@instance.service
Failed to enable unit, file foobar-unknown.service: No such file or directory.
|
|
With the following test case:
[Install]
WantedBy= default.target
Also=foobar-unknown.service
disabling would fail with:
$ ./systemctl --root=/ disable testing.service
Cannot find unit foobar-unknown.service. # this is level debug
Failed to disable: No such file or directory. # this is the error
After the change we proceed:
$ ./systemctl --root=/ disable testing.service
Cannot find unit foobar-unknown.service.
Removed /etc/systemd/system/default.target.wants/testing.service.
This does not affect specifying a missing unit directly:
$ ./systemctl --root=/ disable nosuch.service
Failed to disable: No such file or directory.
|
|
We should ignore that unit, but otherwise continue.
|
|
It's a common pattern, so add a helper for it. A macro is necessary
because a function that takes a pointer to a pointer would be type specific,
similarly to cleanup functions. Seems better to use a macro.
|
|
Also rewrap some comments so that they don't have a very long line and a very
short line.
|
|
|
|
https://bugzilla.redhat.com/show_bug.cgi?id=1374371
When root was empty or equal to "/", chroot_symlinks_same was called with
root==NULL, and strjoina returned "", so the code thought both paths are equal
even if they were not. Fix that by always providing a non-null first argument
to strjoina.
|
|
|
|
When told to enable a template unit, and the DefaultInstance specified in that
unit was masked, we would do this. Such a unit cannot be started or loaded, so
reporting successful enabling is misleading and unexpected.
$ systemctl mask getty@tty1
Created symlink /etc/systemd/system/getty@tty1.service → /dev/null.
$ systemctl --root=/ enable getty@tty1
(unchanged)
Failed to enable unit, unit /etc/systemd/system/getty@tty1.service is masked.
$ systemctl --root=/ enable getty@
(before)
Created symlink /etc/systemd/system/getty.target.wants/getty@tty1.service → /usr/lib/systemd/system/getty@.service.
(now)
Failed to enable unit, unit /etc/systemd/system/getty@tty1.service is masked.
The same error is emitted for enable and preset. And an error is emmited, not a
warning, so the failure to enable DefaultInstance is treated the same as if the
instance was specified on the command line. I think that this makes most sense,
for most template units.
Fixes #2513.
|
|
A masked unit is listed in Also=:
$ systemctl cat test1 test2
→# /etc/systemd/system/test1.service
[Unit]
Description=test service 1
[Service]
Type=oneshot
ExecStart=/usr/bin/true
[Install]
WantedBy=multi-user.target
Also=test2.service
Alias=alias1.service
→# /dev/null
$ systemctl --root=/ enable test1
(before)
Created symlink /etc/systemd/system/alias1.service → /etc/systemd/system/test1.service.
Created symlink /etc/systemd/system/multi-user.target.wants/test1.service → /etc/systemd/system/test1.service.
The unit files have no installation config (WantedBy, RequiredBy, Also, Alias
settings in the [Install] section, and DefaultInstance for template units).
This means they are not meant to be enabled using systemctl.
Possible reasons for having this kind of units are:
1) A unit may be statically enabled by being symlinked from another unit's
.wants/ or .requires/ directory.
2) A unit's purpose may be to act as a helper for some other unit which has
a requirement dependency on it.
3) A unit may be started when needed via activation (socket, path, timer,
D-Bus, udev, scripted systemctl call, ...).
4) In case of template units, the unit is meant to be enabled with some
instance name specified.
(after)
Created symlink /etc/systemd/system/alias1.service → /etc/systemd/system/test1.service.
Created symlink /etc/systemd/system/multi-user.target.wants/test1.service → /etc/systemd/system/test1.service.
Unit /etc/systemd/system/test2.service is masked, ignoring.
|
|
Running preset-all on a system installed from rpms or even created
using make install would remove and recreate a lot of symlinks, changing
relative to absolute symlinks. In general relative symlinks are nicer,
so there is no reason to change them, and those spurious changes were
obscuring more interesting stuff.
$ make install DESTDIR=/var/tmp/inst1
$ systemctl preset-all --root=/var/tmp/inst1
(before)
Removed /var/tmp/inst1/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service.
Created symlink /var/tmp/inst1/etc/systemd/system/ctrl-alt-del.target → /usr/lib/systemd/system/exit.target.
Removed /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/remote-fs.target.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/remote-fs.target → /usr/lib/systemd/system/remote-fs.target.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/machines.target → /usr/lib/systemd/system/machines.target.
Created symlink /var/tmp/inst1/etc/systemd/system/sockets.target.wants/systemd-journal-remote.socket → /usr/lib/systemd/system/systemd-journal-remote.socket.
Removed /var/tmp/inst1/etc/systemd/system/sockets.target.wants/systemd-networkd.socket.
Created symlink /var/tmp/inst1/etc/systemd/system/sockets.target.wants/systemd-networkd.socket → /usr/lib/systemd/system/systemd-networkd.socket.
Removed /var/tmp/inst1/etc/systemd/system/getty.target.wants/getty@tty1.service.
Created symlink /var/tmp/inst1/etc/systemd/system/getty.target.wants/getty@tty1.service → /usr/lib/systemd/system/getty@.service.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-journal-upload.service → /usr/lib/systemd/system/systemd-journal-upload.service.
Removed /var/tmp/inst1/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service.
Created symlink /var/tmp/inst1/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service → /usr/lib/systemd/system/systemd-timesyncd.service.
Removed /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-resolved.service.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-resolved.service → /usr/lib/systemd/system/systemd-resolved.service.
Removed /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-networkd.service.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-networkd.service → /usr/lib/systemd/system/systemd-networkd.service.
(after)
Removed /var/tmp/inst1/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service.
Created symlink /var/tmp/inst1/etc/systemd/system/ctrl-alt-del.target → /usr/lib/systemd/system/exit.target.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/machines.target → /usr/lib/systemd/system/machines.target.
Created symlink /var/tmp/inst1/etc/systemd/system/sockets.target.wants/systemd-journal-remote.socket → /usr/lib/systemd/system/systemd-journal-remote.socket.
Created symlink /var/tmp/inst1/etc/systemd/system/multi-user.target.wants/systemd-journal-upload.service → /usr/lib/systemd/system/systemd-journal-upload.service.
|
|
No functional change intended.
|
|
Before, when interating over unit files during preset-all, behaviour was the
following:
- if we hit the real unit name first, presets were queried for that name, and
that unit was enabled or disabled accordingly,
- if we hit an alias first (one of the symlinks chaining to the real unit), we
checked the presets using the symlink name, and then proceeded to enable or
disable the real unit.
E.g. for systemd-networkd.service we have the alias dbus-org.freedesktop.network1.service
(/usr/lib/systemd/system/dbus-org.freedesktop.network1.service), but the preset
is only for the systemd-networkd.service name. The service would be enabled or
disabled pseudorandomly depending on the order of iteration.
For "preset", behaviour was analogous: preset on the alias name disabled the
service (following the default disable policy), preset on the "real" name
applied the presets.
With the patch, for "preset" and "preset-all" we silently skip symlinks. This
gives mostly the right behaviour, with the limitation that presets on aliases
are ignored. I think that presets on aliases are not that common (at least my
preset files on Fedora don't exhibit any such usage), and should not be
necessary, since whoever installs the preset can just refer to the real unit
file. It would be possible to overcome this limitation by gathering a list of
names of a unit first, and then checking whether *any* of the names matches the
presets list. That would require a significant redesign of the code, and be
a lot slower (since we would have to fully read all unit directories to preset
one unit) to so I'm not doing that for now.
With this patch, two properties are satisfied:
- preset-all and preset are idempotent, and the second and subsequent invocations
do not produce any changes,
- preset-all and preset for a specific name produce the same state for that unit.
Fixes #3616.
|
|
|
|
If the directory is missing, we can assume that those pesky symlinks are gone too.
|
|
Under NixOS, the config_path /etc/systemd/system is a symlink to
/etc/static/systemd/system. Commands such as `systemctl list-unit-files`
and `systemctl is-enabled` did not work as the symlink was not followed.
This does not affect how symlinks are treated within the config_path
directory.
|
|
User expectations are broken when "systemctl enable /some/path/service.service"
behaves differently to "systemctl link ..." followed by "systemctl enable".
From user's POV, "enable" with the full path just combines the two steps into
one.
Fixes #3010.
|
|
If for whatever reason the file system is "corrupted", we want
to be resilient and ignore the error, as long as we can load the units
from a different place.
Arch bug https://bugs.archlinux.org/task/49547.
A user had an ntfs symlink (essentially a file) instead of a directory after
restoring from backup. We should just ignore that like we would treat a missing
directory, for general resiliency.
We should treat permission errors similarly. For example an unreadable
/usr/local/lib directory would prevent (user) instances of systemd from
loading any units. It seems better to continue.
|
|
That function doesn't draw anything on it's own, just returns a string, which
sometimes is more than one character. Also remove "DRAW_" prefix from character
names, TREE_* and ARROW and BLACK_CIRCLE are unambigous on their own, don't
draw anything, and are always used as an argument to special_glyph().
Rename "DASH" to "MDASH", as there's more than one type of dash.
|
|
It's quite a bit shorter and just as readable.
(The full sentence with "pointing to" was added to replace a text that used
"ln -s %s %s". Using the "ln" syntax is indeed unclear, because it's not
obvious which is the source and which is the target, and because symlink(2)
uses the opposite order to ln(1). But with the unicode arrow there should
be no ambiguity.)
|
|
Executing 'systemctl enable' on the same unit twice would cause
a warning about a missing [Install] section to be printed. To avoid
this, count all symlinks that "would" be created, and return 1
no matter if we actually created a symlink or skipped creation because
it already exists.
|
|
This fixes 'preset-all' with a unit that is a dangling symlink.
$ systemctl --root=/ preset-all
Unit syslog.service is an alias to a unit that is not present, ignoring.
Unit auditd.service is masked, ignoring.
Unit NetworkManager.service is masked, ignoring.
|
|
$ systemctl --root=/ preset foobar.service
Cannot find unit foobar.service.
Failed to preset: No such file or directory.
$ systemctl --root=/ preset foobar@.service
Cannot find unit foobar@.service.
Failed to preset: No such file or directory.
$ systemctl --root=/ preset foobar@blah.service
Cannot find unit foobar@blah.service or foobar@.service.
Failed to preset: No such file or directory.
|
|
|
|
install: cache the presets before evaluating
|
|
The previous implementation traversed the various config directories,
walking the preset files and parsing each line to determine if a service
should be enabled or disabled. It did this for every service which
resulted in many more file operations than neccessary.
This approach parses each of the preset entries into an array which is
then used to check if each service should be enabled or disabled.
|
|
$ systemctl --root=/ enable templated@bar.mount
Unit type mount cannot be templated.
Failed to enable: Invalid argument.
|
|
[/etc/systemd/system/mnt-test.mount:6] DefaultInstance only makes sense for template units, ignoring.
|
|
This way it can be used in install.c in subsequent commit.
|
|
A downside is that a warning about missing [Install] is printed:
$ systemctl --root=/ enable mnt-test.mount
[/etc/systemd/system/mnt-test.mount:5] Aliases are not allowed for mount units, ignoring.
The unit files have no installation config (WantedBy, RequiredBy, Also, Alias
settings in the [Install] section, and DefaultInstance for template units).
This means they are not meant to be enabled using systemctl.
Possible reasons for having this kind of units are:
1) A unit may be statically enabled by being symlinked from another unit's
.wants/ or .requires/ directory.
2) A unit's purpose may be to act as a helper for some other unit which has
a requirement dependency on it.
3) A unit may be started when needed via activation (socket, path, timer,
D-Bus, udev, scripted systemctl call, ...).
4) In case of template units, the unit is meant to be enabled with some
instance name specified.
That's a bit misleading, but I don't see an easy way to fix this. But
the situation is similar for many other parsing errors, so maybe that's
OK.
|
|
This way it can be used in install.c in subsequent commit.
|
|
This commit improves systemd performance on the systems which have
thousands of units.
|
|
|
|
|
|
Before:
$ systemctl preset getty@.service
Failed to preset unit, file /etc/systemd/system/getty.target.wants/getty@tty1.service
already exists and is a symlink to ../../../../usr/lib/systemd/system/getty@.service.
After:
$ systemctl preset getty@.service
Created symlink /etc/systemd/system/getty.target.wants/getty@tty1.service,
pointing to /usr/lib/systemd/system/getty@.service.
We don't really care where the symlink points to. For example, it might point
to /usr/lib or /etc, and systemd will always load the unit from /etc in
preference to /usr/lib. In fact, if we make a symlink like
/etc/systemd/system/multi-user.target.wants/b.service -> ../a.service, pid1
will still start b.service. The name of the symlink is the only thing that
matters, as far as systemd is concerned. For humans it's confusing when the
symlinks points to anything else than the actual unit file. At the very least,
the symlink is supposed to point to a file with the same name in some other
directory. Since we don't care where the symlink points, we can always replace
an existing symlink.
Another option I considered would be to simply leave an existing symlink in
place. That would work too, but replacing the symlink with the expected value
seems more intuitive.
Of course those considerations only apply to .wants and .requires. Symlinks
created with "link" and "alias" are a separate matter.
Fixes #3056.
|
|
path_kill_slashes was applied to the wrong arg...
|
|
Fixes #1892.
Previously:
Failed to enable unit: Invalid argument
Now:
Failed to enable unit, file /etc/systemd/system/ssh.service already exists.
It would be nice to include the unit name in the message too. I looked into
this, but it would require major surgery on the whole installation logic,
because we first create a list of things to change, and then try to apply them
in a loop. To transfer the knowledge which unit was the source of each change,
the data structures would have to be extended to carry the unit name over into
the second loop. So I'm skipping this for now.
|
|
The advice string didn't talk about template units at all. Extend
it and print when trying to enable a template unit without install info.
Fixes #2345.
|
|
Fixes #2191:
$ systemctl --root=/ enable sddm
Created symlink /etc/systemd/system/display-manager.service, pointing to /usr/lib/systemd/system/sddm.service.
$ sudo build/systemctl --root=/ enable gdm
Failed to enable unit, file /etc/systemd/system/display-manager.service already exists and is a symlink to /usr/lib/systemd/system/sddm.service.
$ sudo build/systemctl --root= enable sddm
$ sudo build/systemctl --root= enable gdm
Failed to enable unit: File /etc/systemd/system/display-manager.service already exists and is a symlink to /usr/lib/systemd/system/sddm.service.
(I tried a few different approaches to pass the error information back to the
caller. Adding a new parameter to hold the error results in a gigantic patch
and a lot of hassle to pass the args arounds. Adding this information to the
changes array is straightforward and can be more easily extended in the
future.)
In case local installation is performed, the full set of errors can be reported
and we do that. When running over dbus, only the first error is reported.
|
|
|
|
Fixes #3047.
|
|
With any masked unit that would that would be enabled by presets, we'd get:
test@rawhide $ sudo systemctl preset-all
Failed to execute operation: Unit file is masked.
test@rawhide $ sudo systemctl --root=/ preset-all
Operation failed: Cannot send after transport endpoint shutdown
Simply ignore those units:
test@rawhide $ sudo systemctl preset-all
Unit xxx.service is masked, ignoring.
|
|
If the error code ever leaks (we print the strerror error instead of providing
our own), the message for ESHUTDOWN is "Cannot send after transport endpoint
shutdown", which can be misleading. In particular it suggest that some
mishandling of the dbus connection occured. Let's change that to ERFKILL which
has the advantage that a) it sounds implausible as actual error, b) has the
connotation of disabling something manually.
|
|
This allows dropping all user configuration and reverting back to the vendor
default of a unit file. It basically undoes what "systemctl edit", "systemctl
set-property" and "systemctl mask" do.
|
|
|