1
0
mirror of https://github.com/systemd/systemd synced 2026-04-23 23:44:50 +02:00

Compare commits

...

57 Commits

Author SHA1 Message Date
Luca Boccassi
8c70e8024b NEWS: specify that public headers are still C89 2022-03-29 21:54:01 +01:00
Luca Boccassi
7503fbd4a6 NEWS: mention that C11 is now used 2022-03-29 21:52:21 +01:00
Zbigniew Jędrzejewski-Szmek
0f6f9dc6cf NEWS: add entry for the unit enablement stuff
It should be merged soon.
2022-03-29 22:39:32 +02:00
Zbigniew Jędrzejewski-Szmek
c3a053c241 test-systemctl-enable: skip test for %v if kver is not a valid instance
On arm, we'd fail with:
target@v:5.16.8-200.fc35.armv7hl+lpae.socket: not a valid unit name "target@v:5.16.8-200.fc35.armv7hl+lpae.socket": Invalid argument
2022-03-29 22:39:32 +02:00
наб
d66b77b4d8 test-copy: use non-0 data block in copy_holes
Some filesystems (e.g. zfs with compression!=off, which is the default
configuration) automatically hole-punch all-zero blocks ‒ write a block
full of ones instead
2022-03-29 21:10:43 +02:00
Zbigniew Jędrzejewski-Szmek
53877d0385
Merge pull request #22649 from keszybz/symlink-enablement-yet-again-punish-me-harder
Fixups to the unit enablement logic
2022-03-29 21:10:03 +02:00
Zbigniew Jędrzejewski-Szmek
f8e07c5cb6
Merge pull request #22871 from yuwata/udev-worker-error-code
udev: append error code on failure
2022-03-29 21:08:44 +02:00
Zbigniew Jędrzejewski-Szmek
a6ea4dc13e meson: bump numbers for v251-rc1 2022-03-29 19:46:47 +02:00
Zbigniew Jędrzejewski-Szmek
7384940857 NEWS: update contributor list 2022-03-29 19:45:11 +02:00
Zbigniew Jędrzejewski-Szmek
e0a5fc7267 tools/git-contrib: list contributions not only from Weblate
It seems that --invert-grep used to affect --author, but now it doesn't (with
git-2.35.1-1.fc36.x86_64), so effectively we would only show the one entry that
was supposed to be filtered out.
2022-03-29 19:42:01 +02:00
Zbigniew Jędrzejewski-Szmek
942473dcc3 NEWS: two more small features and some rewordings 2022-03-29 19:36:29 +02:00
Yu Watanabe
10176f0011 test: add tests for worker error code 2022-03-30 01:27:29 +09:00
Yu Watanabe
6467bda59d udev: append error code in broadcasted message
So, libudev listners can easily detect errors.

Addresses https://github.com/systemd/systemd/pull/22717#discussion_r834420878.
2022-03-30 01:27:29 +09:00
Yu Watanabe
71978a79fd sd-device: introduce device_add_propertyf() 2022-03-30 01:27:29 +09:00
Zbigniew Jędrzejewski-Szmek
b380b64383 Rename UnitFileScope to LookupScope
As suggested in
8b3ad3983f (r837345892)

The define is generalized and moved to path-lookup.h, where it seems to fit
better. This allows a recursive include to be removed and in general makes
things simpler.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
5c29de29b4 test-systemctl-enable: disable the test for %a for now 2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
2a2d002fb0 test-systemctl-enable: also use freshly-built systemd-id128
Tests were failing on centos7 because systemd-id128 is not in path.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
d6c51c485a test-systemctl-enable: use magic syntax to allow inverted tests
Inspired by 7910ec3bcde2ee0086b3e49f8aaa2a9f13f58d97.
'! true' passes, because it's a conditional expression.
But '( ! true )' fails, because '( … )' creates a subshell, i.e. a separate
program, and '! true' becomes the return value of that program, and the whole
thing apparently is not a conditional expression for the outer shell.

This is shorter, so let's just do this.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
3fc53351dc shared/install: when creating symlinks, accept different but equivalent symlinks
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.)
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
84fdced62c test-systemctl-enable: make shellcheck happy
Quoting is not necessary in many places, but I think it's nicer
to use it consistently.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
48eadb9d9b shared/install: fix handling of a linked unit file
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.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
48ed75adab shared/install: split UNIT_FILE_SYMLINK into two states
The two states are distinguished, but are treated everywhere identically,
so there is no difference in behaviour except for slighlty different log
output.
2022-03-29 16:17:57 +02:00
Zbigniew Jędrzejewski-Szmek
bd177c6215 basic/unit-file: reverse negative conditional
Having the reverse condition first makes changes that I want to do
later awkward, so reverse it as a separate step first.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
38e8a6c7fd shared/install: stop passing duplicate root argument to install_name_printf()
All callers were just passing info + info->root, we can simplify this.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
466f6979c9 shared/install: when looking for symlinks in .wants/.requires, ignore symlink target
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.servicebar.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.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
d6c9411072 shared/install: create relative symlinks for enablement and aliasing
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.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
9f61c9f79e shared/install: also remove symlinks like .wants/foo@one.service → ../foo@one.service
So far 'systemctl enable' would create absolute links to the target template
name. And we would remove such symlinks just fine. But the user may create
symlinks manually in a different form. In particular, symlinks for instanced
units *must* have the instance in the source name, and then it is natural to
also include it in the target name (.wants/foo@one.service../foo@one.service
rather than .wants/foo@one.service → ../foo@.service). We would choke on such
links, or not remove them at all. A test is added:

before:

+ build-rawhide/systemctl --root=/tmp/systemctl-test.001xda disable templ1@.service
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@seven.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@six.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@five.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@four.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@three.service".
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.

after:

+ build-rawhide/systemctl --root=/tmp/systemctl-test.QVP0ev disable templ1@.service
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service".
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
7a6c73dabf shared/install: skip unnecessary chasing of symlinks in disable
We use the symlink source name and destination names to decide whether to remove
the symlink. But if the source name is enough to decide to remove the symlink,
we'd still look up the destination for no good reason. This is a slow operation,
let's skip it.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
85516075a2 test-systemctl-enable: enhance the test for unit file linking
Current behaviour is wrong, but it cannot be shown in this test, because we
don't have a running systemd instance here.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
40276314af shared/install: do not try to resolve symlinks outside of root directory
I linked a file as root, so I had a symlink /root/test.service ← /etc/systemd/system/test.service.
To my surpise, when running test-systemctl-enable, it failed with a cryptic EACCES.
The previous commit made the logs a bit better. Strace shows that we
were trying to follow the symlink without taking --root into account.

It seems that this bug was introduced in 66a19d85a533b15ed32f4066ec880b5a8c06babd:
before it, we'd do readlink_malloc(), which returned a path relative to root. But
we only used that path for checking if the path is in remove_symlinks_to set, which
contains relative paths. So if the path was relative, we'd get a false-negative
answer, but we didn't go outside of the root. (We need to canonicalize the symlink
to get a consistent answer.) But after 66a19 we use chase_symlinks(), without taking
root into account which is completely bogus.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
212a24f0bb shared/install: when we fail to chase a symlink, show some logs
When chase_symlinks() fails, we'd get the generic error:

  Failed to disable: Permission denied.

Let's at least add the failure to changes list, so the user gets
a slightly better message. Ideally, we'd say where exactly the permission
failure occured, but chase_symlinks() is a library level function and I don't
think we should add logging there. The output looks like this now:

  Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service": Permission denied
  Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service": Permission denied
  Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service: Permission denied.
  Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service: Permission denied.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
0c003e8305 test-systemctl-enable: extend the test for repeated WantedBy/RequiredBy
I was considering deduplicating the list of target units in
WantedBy/RequiredBy. But to do this meaningfully, we'd need to do alias
expansion first, i.e. after the initial parsing is done. This seems to be
more trouble than it would be worth.

Instead, I added tests that we're doing the right thing and creating symlinks
as expected. For duplicate links, we create the link, and on the second time we
see that the link is already there, so the output is correct.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
29a7c59abb shared/install: fix reenable on linked unit files 2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
ec7eaff3c2 shared/install: split unit_file_{disable,enable}() so _reenable doesn't do setup twice
It was pretty ugly that we were creating LookupPaths twice.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
20d68b3aec install: when linking a file, create the link first or abort
We'd create aliases and other symlinks first, and only then try to create
the main link. Since that can fail, let's do things in opposite order, and
abort immediately if we can't link the file itself.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
17a2679e99 man: fix invalid description of template handling in WantedBy=
We don't need to talk about Alias=. The approach of using Alias= to enable
units is still supported, but hasn't been advertised as the way to do thing
for many years. Using it as an explanation is just confusing.

Also, the description of templated units did not take DefaultInstance=
into account. It is updated and extended.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
f663e6468f shared/install: also check for self-aliases during installation and ignore them
We had a check that was done in unit_file_resolve_symlink(). Let's move
the check to unit_validate_alias_symlink_or_warn(), which makes it available
to the code in install.c.

With this, unit_file_resolve_symlink() behaves almost the same. The warning
about "suspicious symlink" is done a bit later. I think this should be OK.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
99aad9a2b9 systemctl: fix silent failure when --root is not found
Some calls to lookup_path_init() were not followed by any log emission.
E.g.:
$ SYSTEMD_LOG_LEVEL=debug systemctl --root=/missing enable unit; echo $?
1

Let's add a helper function and use it in various places.

$ SYSTEMD_LOG_LEVEL=debug build/systemctl --root=/missing enable unit; echo $?
Failed to initialize unit search paths for root directory /missing: No such file or directory
1
$ SYSTEMCTL_SKIP_SYSV=1 build/systemctl --root=/missing enable unit; echo $?
Failed to initialize unit search paths for root directory /missing: No such file or directory
Failed to enable: No such file or directory.
1

The repeated error in the second case is not very nice, but this is a niche
case and I don't think it's worth the trouble to trying to avoid it.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
0d11db5982 shared/install: return failure when enablement fails, but process as much as possible
So far we'd issue a warning (before this series, just in the logs on the server
side, and before this commit, on stderr on the caller's side), but return
success. It seems that successfull return was introduced by mistake in
aa0f357fd833feecbea6c3e9be80b643e433bced (my fault :( ), which was supposed to
be a refactoring without a functional change. I think it's better to fail,
because if enablement fails, the user will most likely want to diagnose the
issue.

Note that we still do partial enablement, as far as that is possible. So if
e.g. we have [Install] Alias=foo.service foobar, we'll create the symlink
'foo.service', but not 'foobar', since that's not a valid unit name. We'll
print info about the action taken, and about 'foobar' being invalid, and return
failure.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
cbfdbffb61 shared/install: propagate errors about invalid aliases and such too
If an invalid arg appears in [Install] Alias=, WantedBy=, RequiredBy=,
we'd warn in the logs, but not propagate this information to the caller,
and in particular not over dbus. But if we call "systemctl enable" on a
unit, and the config if invalid, this information is quite important.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
32450f5348 shared/install: simplify unit_file_dump_changes()
No functional change.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
172e9cc3ee shared/specifier: fix %u/%U/%g/%G when called as unprivileged user
We would resolve those specifiers to the calling user/group. This is mostly OK
when done in the manager, because the manager generally operates as root
in system mode, and a non-root in user mode. It would still be wrong if
called with --test though. But in systemctl, this would be generally wrong,
since we can call 'systemctl --system' as a normal user, either for testing
or even for actual operation with '--root=…'.

When operating in --global mode, %u/%U/%g/%G should return an error.

The information whether we're operating in system mode, user mode, or global
mode is passed as the data pointer to specifier_group_name(), specifier_user_name(),
specifier_group_id(), specifier_user_id(). We can't use userdata, because
it's already used for other things.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
4a84db4c0c shared/install: move scope into InstallContext
This makes it easier to pass it around in preparation for future changes.

While at it, let's rename InstallContext c → ctx, and InstallInfo i → info.
'c' and 'i' are bad names for variables that are passed through multiple layers
of functions calls. It's easier to follow what is happening with a meaningful
variable names.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
19b9d5d0d1 shared/install: provide proper error messages when invalid specifiers are used
$ build/systemctl --root=/tmp/systemctl-test.KXY8fu enable some-some-link6@.socket
Failed to enable unit, invalid specifier in "target@C:%C.socket".
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
6ec4c852c9 shared/specifier: provide proper error messages when specifiers fail to read files
ENOENT is easily confused with the file that we're working on not being
present, e.g. when the file contains %o or something else that requires
os-release to be present. Let's use -EUNATCH instead to reduce that chances of
confusion if the context of the error is lost.

And once we have pinpointed the reason, let's provide a proper error message:

+ build/systemctl --root=/tmp/systemctl-test.TO7Mcb enable some-some-link6@.socket
/tmp/systemctl-test.TO7Mcb/etc/systemd/system/some-some-link6@.socket: Failed to resolve alias "target@A:%A.socket": Protocol driver not attached
Failed to enable unit, cannot resolve specifiers in "target@A:%A.socket".
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
7962116fc8 shared/specifier: clarify and add test for missing data
In systemd.unit we document that unset fields resolve to "". But we didn't
directly test this, so let's do that. Also, we return -ENOENT if the file
is missing, which we didn't document or test.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
3a84a3c9df man/os-release: add a note about repeating entries
We didn't actually say that keys should not be repeated. At least the
examples in docs (both python and shell) would do that, and any simple
parser that builds a dictionary would most likely behave the same way.
But let's document this expectation, but also say how to deal with malformed
files.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
25407ad2a7 basic/env-file: make load-env-file deduplicate entries with the same key
We generally assume parsing like the shell would do it, so the last value
should win when there are repeats.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
80e72f80bc test-os-util: add basic tests for os-release parsing 2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
df78419d10 basic: add new variable $SYSTEMD_OS_RELEASE to override location of os-release
The test for the variable is added in test-systemctl-enable because there we
can do it almost for free, and the variable is most likely to be used with
'systemctl enable --root' anyway.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
ecd6c000d3 man: clarify the descriptions of aliases and linked unit files
This just describes the rules that are implemented by the manager, and this
pull request does not change any of them.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
367c47c886 tests: add helper for creating tempfiles with content
I put it in tests because I think we're most likely to use it in tests.
If necessary, it can be moved somewhere else later.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
50c5f5a3d9 test: add test for systemctl link & enable
This test has overlap with test-install-root, but it tests things at a
different level, so I think it's useful to add. It immediately shows various
bugs which will be fixed in later patches.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
e75a26d045 shared/install: add a bit more quoting
When we are printing a valid unit name, quoting isn't necessary, because
unit names cannot contain whitespace or other confusing characters. In particular
if the unit name is prefixed by " unit " or something else that clearly
identifies the string as a unit name, quoting would just add unnecessary
noise. But when we're printing paths or invalid names, it's better to add
quotes for clarity.
2022-03-29 16:17:56 +02:00
Zbigniew Jędrzejewski-Szmek
047d37dc3d shared/install: reuse the standard symlink verification subroutine
We save a few lines, but the important thing is that we don't have two
different implementations with slightly different rules used for enablement
and loading. Fixes #22000.

Tested with:
- the report in #22000, it now says:
$ SYSTEMD_LOG_LEVEL=debug systemctl --root=/ enable test.service
Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias.
unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring.
running_in_chroot(): Permission denied
Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias.
unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring.
Failed to enable unit, refusing to operate on linked unit file test.service

- a symlink to /dev/null:
...
unit_file_resolve_symlink: linked unit file: /etc/systemd/system/test3.service → /dev/null
Failed to enable unit, unit /etc/systemd/system/test3.service is masked.

- the same from the host:
...
unit_file_resolve_symlink: linked unit file: /var/lib/machines/rawhide/etc/systemd/system/test3.service → /var/lib/machines/rawhide/dev/null
Failed to enable unit, unit /var/lib/machines/rawhide/etc/systemd/system/test3.service is masked.

- through the manager:
$ sudo systemctl enable test.service
Failed to enable unit: Refusing to operate on alias name or linked unit file: test.service
$ sudo systemctl enable test3.service
Failed to enable unit: Unit file /etc/systemd/system/test3.service is masked.

As seen in the first example, the warning is repeated. This is because we call
the lookup logic twice: first for sysv-compat, and then again for real. I think
that since this is only for broken setups, and when sysv-compat is enabled, and
in an infrequent manual operation, at debug level, this is OK.
2022-03-29 16:16:02 +02:00
Zbigniew Jędrzejewski-Szmek
48542eac39 basic/stat-util: add null_or_empty_path_with_root() 2022-03-29 15:07:05 +02:00
Zbigniew Jędrzejewski-Szmek
9825181143 basic/unit-file: split out the subroutine for symlink verification
The old logs used __func__, but this doesn't make sense now, because the
low-level function will be used in other places. So those are adjusted to be
more generic.
2022-03-29 14:19:28 +02:00
85 changed files with 2688 additions and 1425 deletions

101
NEWS
View File

@ -1,12 +1,15 @@
systemd System and Service Manager
CHANGES WITH 251 in spe:
CHANGES WITH 251:
Backwards-incompatible changes:
* The minimum kernel version required has been bumped from 3.13 to 3.15,
and CLOCK_BOOTTIME is now assumed to always exist.
* C11 with GNU extensions (aka "gnu11") is now used to build our
components. Public API headers are still restricted to ISO C89.
* In v250, a systemd-networkd feature that automatically configures
routes to addresses specified in AllowedIPs= was added and enabled by
default. However, this causes network connectivity issues in many
@ -46,7 +49,7 @@ CHANGES WITH 251 in spe:
commands its executes into PCR 8, which makes it very hard to use
reasonably, hence separate ourselves from that and use PCR 12
instead, which is what certain Ubuntu editions already do. To retain
compatibility with systems running older systemd systems a new Meson
compatibility with systems running older systemd systems a new meson
option 'efi-tpm-pcr-compat' has been added (which defaults to false).
If enabled, the measurement is done twice: into the new-style PCR 12
*and* the old-style PCR 8. It's strongly advised to migrate all users
@ -68,7 +71,7 @@ CHANGES WITH 251 in spe:
(as exposed via the SystemCallFilter= setting in service unit files).
It is apparently used by the linker now.
Changes for Boot Loader Specification, kernel-install and sd-boot:
Changes in the Boot Loader Specification, kernel-install and sd-boot:
* kernel-install's and bootctl's Boot Loader Specification Type #1
entry generation logic has been reworked. The user may now pick
@ -123,6 +126,11 @@ CHANGES WITH 251 in spe:
os-release. Together, this means that on multiboot installations,
entries should be grouped and sorted in a predictable way.
* The sort order of boot entries has been updated: entries which have
the new field sort-key= are sorted by it first, and all entries
without it are ordered later. After that, entries are sorted by
version so that newest entries are towards the beginning of the list.
* The kernel-install tool gained a new 'inspect' verb which shows the
paths and other settings used.
@ -139,7 +147,7 @@ CHANGES WITH 251 in spe:
* 'bootctl list' gained support for a new --json= switch to output boot
menu entries in JSON format.
Changes for homed:
Changes in systemd-homed:
* Starting with v250 systemd-homed uses UID/GID mapping on the mounts
of activated home directories it manages (if the kernel and selected
@ -175,7 +183,7 @@ CHANGES WITH 251 in spe:
handling, and improving compatibility with home directories intended
to be portable like the ones managed by systemd-homed.
Changes for shared libraries:
Changes in shared libraries:
* A new libsystemd-core-<version>.so private shared library is
installed under /usr/lib/systemd/system, mirroring the existing
@ -183,19 +191,20 @@ CHANGES WITH 251 in spe:
installation size to be reduced by binary code reuse.
* The <version> tag used in the name of libsystemd-shared.so and
libsystemd-core.so can be configured. Distributions may build
subsequent versions of the systemd package with unique tags (e.g. the
full package version), thus allowing multiple installations of those
shared libraries to be available at the same time. This is intended
to fix an issue where programs that link to those libraries would
fail to execute because they were installed earlier or later than the
appropriate version of the library.
libsystemd-core.so can be configured via the meson option
'shared-lib-tag'. Distributions may build subsequent versions of the
systemd package with unique tags (e.g. the full package version),
thus allowing multiple installations of those shared libraries to be
available at the same time. This is intended to fix an issue where
programs that link to those libraries would fail to execute because
they were installed earlier or later than the appropriate version of
the library.
* The sd-id128 API gained a new call sd_id128_to_uuid_string() that is
similar to sd_id128_to_string() but formats the ID in RFC 4122 UUID
format instead of simple series of hex characters.
Changes for PID1 and systemctl:
Changes in PID1, systemctl, and systemd-oomd:
* A new set of service monitor environment variables will be passed to
OnFailure=/OnSuccess= handlers, but only if exactly one unit lists the
@ -219,6 +228,13 @@ CHANGES WITH 251 in spe:
(Only supported on kernels ≥5.6.)
* Units that were killed by systemd-oomd will now have a service result
of 'oom-kill'. The number of times a service was killed is tallied
in the 'user.oomd_ooms' extended attribute.
The OOMPolicy= unit file setting is now also honoured by
systemd-oomd.
* In unit files the new %y/%Y specifiers can be used to refer to
normalized unit file path, which is particularly useful for symlinked
unit files.
@ -257,7 +273,14 @@ CHANGES WITH 251 in spe:
* systemctl's --timestamp= option gained a new choice "unix", to show
timestamp as unix times, i.e. seconds since 1970, Jan 1st.
Changes for journald:
* 'systemctl enable' and similar commands will now create relative
symlinks in .wants/ and .requires/ and for aliases. Most of the time
systemd itself doesn't care, but absolute symlinks were causing wrong
behaviour in case of aliases to linked unit files. The change was
necessary to fix this aspect. Absolute links are interpreted as
before, and it is still possible to create them via other means.
Changes in systemd-journald:
* The journal JSON export format has been added to listed of stable
interfaces (https://systemd.io/PORTABILITY_AND_STABILITY/).
@ -270,7 +293,7 @@ CHANGES WITH 251 in spe:
https://systemd.io/JOURNAL_EXPORT_FORMATS
https://systemd.io/BUILDING_IMAGES
Changes for udev:
Changes in udev:
* Two new hwdb files have been added. One lists "handhelds" (PDAs,
calculators, etc.), the other AV production devices (DJ tables,
@ -297,7 +320,7 @@ CHANGES WITH 251 in spe:
* .link files gained support for [Link] SR-IOVVirtualFunctions= setting
and [SR-IOV] section to configure SR-IOV virtual functions.
Changes for networkd:
Changes in systemd-networkd:
* The default scope for unicast routes configured through [Route]
section is changed to "link", to make the behavior consistent with
@ -336,13 +359,13 @@ CHANGES WITH 251 in spe:
server name, and file name sent in the DHCP packet (e.g. to configure
PXE boot).
Changes for resolved:
Changes in systemd-resolved:
* systemd-resolved is started earlier (in sysinit.target), so it
available earlier and will also be started in the initrd if installed
there.
Changes for disk encryption:
Changes in disk encryption:
* systemd-cryptenroll can now control whether to require the user to
enter a PIN when using TPM-based unlocking of a volume via the new
@ -354,7 +377,7 @@ CHANGES WITH 251 in spe:
used, to ensure that communication between CPU and discrete TPM chips
cannot be eavesdropped to acquire disk encryption keys.
Changes for hostnamed:
Changes in systemd-hostnamed:
* HARDWARE_VENDOR= and HARDWARE_MODEL= can be set in /etc/machine-info
to override the values gleaned from the hwdb.
@ -366,7 +389,7 @@ CHANGES WITH 251 in spe:
* hostnamed's D-Bus interface gained a new method GetHardwareSerial()
for reading the hardware serial number, as reportd by DMI.
Changes for other components:
Changes in other components:
* /etc/locale.conf is now populated through tmpfiles.d factory /etc/
handling with the values that were configured during systemd build
@ -377,6 +400,10 @@ CHANGES WITH 251 in spe:
* The userdbctl tool will now show UID range information as part of the
list of known users.
* A new build-time configuration setting default-user-shell= can be
used to set the default shell for user records and nspawn shell
invocations (instead of of the default /bin/bash).
Experimental features:
* sd-boot gained a new *experimental* setting "reboot-for-bitlocker" in
@ -394,6 +421,34 @@ CHANGES WITH 251 in spe:
installation itself, or container images, portable service images,
and other assets. See the new systemd-sysupdate man page for updates.
Contributions from: 4piu, Adam Williamson, adrian5, Albert Brox,
AlexCatze, Alfonso Sánchez-Beato, Alvin Šipraga, Andrea Pappacoda,
Andy Chi, Anita Zhang, Antonio Alvarez Feijoo,
Arfrever Frehtes Taifersar Arahesis, ash, Bastien Nocera, Be,
bearhoney, Benjamin Berg, Christian Brauner, Clyde Byrd III,
Curtis Klein, Daan De Meyer, Danilo Krummrich, David, David Bond,
Davide Cavalca, David Tardon, dependabot[bot], Donald Chan,
Dorian Clay, Eduard Tolosa, Erik Sjölund, Evgeny Vereshchagin,
Federico Ceratto, Franck Bui, Frantisek Sumsal, Gaël PORTAY,
Georges Basile Stavracas Neto, Goffredo Baroncelli, Grigori Goronzy,
Hans de Goede, Heiko Becker, Hugo Carvalho, James Hilliard,
Jan Janssen, Jason A. Donenfeld, Joan Bruguera, Joerie de Gram,
Josh Triplett, Julia Kartseva, ksa678491784, Lan Tian, Laura Barcziova,
Lennart Poettering, Leviticoh, licunlong, Lidong Zhong, lincoln auster,
Lubomir Rintel, Luca Boccassi, Luca BRUNO, Ludwig Nussel,
Marcel Hellwig, march1993, Marco Scardovi, Markus Weippert,
Martin Wilck, Matija Skala, Matthias Lisin, Matt Walton, Max Gautier,
Michael Biebl, Michael Olbrich, Michal Koutný, Mike Gilbert,
Morten Linderud, Nishal Kulkarni, Noel Kuntze, Peter Hutterer,
Peter Morrow, Pigmy-penguin, prumian, Richard Neill,
Rike-Benjamin Schuppner, Romain Naour, Ruben Kerkhof, Ryan Hendrickson,
Santa Wiryaman, Seth Falco, Stephen Hemminger, tawefogo,
Temuri Doghonadze, Thomas Batten, Thomas Haller, Tobias Stoeckmann,
Tyson Whitehead, Vishal Chillara Srinivas, Vivien Didelot, Weblate,
Xiaotian Wu, yangmingtai, YmrDtnJu, Yonathan Randolph, Yu Watanabe,
Zbigniew Jędrzejewski-Szmek, наб
— Warsaw, 2022-03---
CHANGES WITH 250:
@ -495,9 +550,9 @@ CHANGES WITH 250:
time-out for the boot.
* A new setting DefaultOOMScoreAdjust= is now supported in
/etc/systemd/system.conf + /etc/systemd/user.conf that may be used to
set the default process OOM score adjustment value for processes
forked off the service manager. For per-user service managers this
/etc/systemd/system.conf and /etc/systemd/user.conf. It may be used
to set the default process OOM score adjustment value for processes
started by the service manager. For per-user service managers this
now defaults to 100, but for per-system service managers is left as
is. This means that by default now services forked off the user
service manager are more likely to be killed by the OOM killer than

View File

@ -43,6 +43,11 @@ All tools:
debugging, in order to test generators and other code against specific kernel
command lines.
* `$SYSTEMD_OS_RELEASE` — if set, use this path instead of `/etc/os-release` or
`/usr/lib/os-release`. When operating under some root (e.g. `systemctl
--root=…`), the path is taken relative to the outside root. Only useful for
debugging.
* `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful
for debugging.

View File

@ -75,6 +75,10 @@
from earliest boot on, and hence must be located on the root file
system.</para>
<para><filename>os-release</filename> must not contain repeating keys. Nevertheless, readers should pick
the entries later in the file in case of repeats, similarly to how a shell sourcing the file would. A
reader may warn about repeating entries.</para>
<para>For a longer rationale for <filename>os-release</filename>
please refer to the <ulink
url="http://0pointer.de/blog/projects/os-release">Announcement of <filename>/etc/os-release</filename></ulink>.</para>

View File

@ -138,7 +138,7 @@
a symlink, so when <command>systemd</command> is asked through D-Bus to load
<filename>dbus-org.freedesktop.network1.service</filename>, it'll load
<filename>systemd-networkd.service</filename>. As another example, <filename>default.target</filename>
the default system target started at boot — is commonly symlinked (aliased) to either
the default system target started at boot — is commonly aliased to either
<filename>multi-user.target</filename> or <filename>graphical.target</filename> to select what is started
by default. Alias names may be used in commands like <command>disable</command>,
<command>start</command>, <command>stop</command>, <command>status</command>, and similar, and in all
@ -154,8 +154,12 @@
template instance (e.g. <literal>alias@inst.service</literal>) may be a symlink to different template
(e.g. <literal>template@inst.service</literal>). In that case, just this specific instance is aliased,
while other instances of the template (e.g. <literal>alias@foo.service</literal>,
<literal>alias@bar.service</literal>) are not aliased. Those rule preserve the requirement that the
instance (if any) is always uniquely defined for a given unit and all its aliases.</para>
<literal>alias@bar.service</literal>) are not aliased. Those rules preserve the requirement that the
instance (if any) is always uniquely defined for a given unit and all its aliases. The target of alias
symlink must point to a valid unit file location, i.e. the symlink target name must match the symlink
source name as described, and the destination path must be in one of the unit search paths, see UNIT FILE
LOAD PATH section below for more details. Note that the target file may not exist, i.e. the symlink may
be dangling.</para>
<para>Unit files may specify aliases through the <varname>Alias=</varname> directive in the [Install]
section. When the unit is enabled, symlinks will be created for those names, and removed when the unit is
@ -175,11 +179,18 @@
exists for <varname>Requires=</varname> type dependencies as well, the directory suffix is
<filename>.requires/</filename> in this case. This functionality is useful to hook units into the
start-up of other units, without having to modify their unit files. For details about the semantics of
<varname>Wants=</varname>, see below. The preferred way to create symlinks in the
<filename>.wants/</filename> or <filename>.requires/</filename> directory of a unit file is by embedding
the dependency in [Install] section of the target unit, and creating the symlink in the file system with
the <command>enable</command> or <command>preset</command> commands of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<varname>Wants=</varname> and <varname>Requires=</varname>, see below. The preferred way to create
symlinks in the <filename>.wants/</filename> or <filename>.requires/</filename> directories is by
specifying the dependency in [Install] section of the target unit, and creating the symlink in the file
system with the <command>enable</command> or <command>preset</command> commands of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. The
target can be a normal unit (either plain or a specific instance of a template unit). In case when the
source unit is a template, the target can also be a template, in which case the instance will be
"propagated" to the target unit to form a valid unit instance. The target of symlinks in
<filename>.wants/</filename> or <filename>.requires/</filename> must thus point to a valid unit file
location, i.e. the symlink target name must satisfy the described requirements, and the destination path
must be in one of the unit search paths, see UNIT FILE LOAD PATH section below for more details. Note
that the target file may not exist, i.e. the symlink may be dangling.</para>
<para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory
<filename>foo.service.d/</filename> may exist. All files with the suffix
@ -501,13 +512,30 @@
<programlisting>systemd-analyze --user unit-paths</programlisting>
</para>
<para>Moreover, additional units might be loaded into systemd from
directories not on the unit load path by creating a symlink pointing to a
unit file in the directories. You can use <command>systemctl link</command>
for this operation. See
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for its usage and precaution.
</para>
<para>Moreover, additional units might be loaded into systemd from directories not on the unit load path
by creating a symlink pointing to a unit file in the directories. You can use <command>systemctl
link</command> for this; see
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. The file
system where the linked unit files are located must be accessible when systemd is started (e.g. anything
underneath <filename>/home/</filename> or <filename>/var/</filename> is not allowed, unless those
directories are located on the root file system).</para>
<para>It is important to distinguish "linked unit files" from "unit file aliases": any symlink where the
symlink <emphasis>target</emphasis> is within the unit load path becomes an alias: the source name and
the target file name must satisfy specific constraints listed above in the discussion of aliases, but the
symlink target doesn't have to exist, and in fact the symlink target path is not used, except to check
whether the target is within the unit load path. In constrast, a symlink which goes outside of the unit
load path signifies a linked unit file. The symlink is followed when loading the file, but the
destination name is otherwise unused (and may even not be a valid unit file name). For example, symlinks
<filename index='false'>/etc/systemd/system/alias1.service</filename><filename index='false'>service1.service</filename>,
<filename index='false'>/etc/systemd/system/alias2.service</filename><filename index='false'>/usr/lib/systemd/service1.service</filename>,
<filename index='false'>/etc/systemd/system/alias3.service</filename><filename index='false'>/etc/systemd/system/service1.service</filename>
are all valid aliases and <filename index='false'>service1.service</filename> will have
four names, even if the unit file is located at
<filename index='false'>/run/systemd/system/service1.service</filename>. In contrast,
a symlink <filename index='false'>/etc/systemd/system/link1.service</filename><filename index='false'>../link1_service_file</filename>
means that <filename index='false'>link1.service</filename> is a "linked unit" and the contents of
<filename index='false'>/etc/systemd/link1_service_file</filename> provide its configuration.</para>
</refsect1>
<refsect1>
@ -1876,34 +1904,31 @@
<term><varname>WantedBy=</varname></term>
<term><varname>RequiredBy=</varname></term>
<listitem><para>This option may be used more than once, or a
space-separated list of unit names may be given. A symbolic
link is created in the <filename>.wants/</filename> or
<filename>.requires/</filename> directory of each of the
listed units when this unit is installed by <command>systemctl
enable</command>. This has the effect that a dependency of
type <varname>Wants=</varname> or <varname>Requires=</varname>
is added from the listed unit to the current unit. The primary
result is that the current unit will be started when the
listed unit is started. See the description of
<varname>Wants=</varname> and <varname>Requires=</varname> in
the [Unit] section for details.</para>
<listitem><para>This option may be used more than once, or a space-separated list of unit names may
be given. A symbolic link is created in the <filename>.wants/</filename> or
<filename>.requires/</filename> directory of each of the listed units when this unit is installed by
<command>systemctl enable</command>. This has the effect of a dependency of type
<varname>Wants=</varname> or <varname>Requires=</varname> being added from the listed unit to the
current unit. The primary result is that the current unit will be started when the listed unit is
started, see the description of <varname>Wants=</varname> and <varname>Requires=</varname> in the
[Unit] section for details.</para>
<para><command>WantedBy=foo.service</command> in a service
<filename>bar.service</filename> is mostly equivalent to
<command>Alias=foo.service.wants/bar.service</command> in the
same file. In case of template units listing non template units,
<command>systemctl enable</command> must be called with an
instance name, and this instance will be added to the
<filename>.wants/</filename> or
<filename>.requires/</filename> list of the listed unit. E.g.
<command>WantedBy=getty.target</command> in a service
<filename>getty@.service</filename> will result in
<command>systemctl enable getty@tty2.service</command>
creating a
<filename>getty.target.wants/getty@tty2.service</filename>
link to <filename>getty@.service</filename>.
</para></listitem>
<para>In case of template units listing non template units, the listing unit must have
<varname>DefaultInstance=</varname> set, or <command>systemctl enable</command> must be called with
an instance name. The instance (default or specified) will be added to the
<filename>.wants/</filename> or <filename>.requires/</filename> list of the listed unit. For example,
<command>WantedBy=getty.target</command> in a service <filename>getty@.service</filename> will result
in <command>systemctl enable getty@tty2.service</command> creating a
<filename>getty.target.wants/getty@tty2.service</filename> link to
<filename>getty@.service</filename>. This also applies to listing specific instances of templated
units: this specific instance will gain the dependency. A template unit may also list a template
unit, in which case a generic dependency will be added where each instance of the listing unit will
have a dependency on an instance of the listed template with the same instance value. For example,
<command>WantedBy=container@.target</command> in a service <filename>monitor@.service</filename> will
result in <command>systemctl enable monitor@.service</command> creating a
<filename>container@.target.wants/monitor@.service</filename> link to
<filename>monitor@.service</filename>, which applies to all instances of
<filename>container@.target</filename>.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
project('systemd', 'c',
version : '250',
version : '251',
license : 'LGPLv2+',
default_options: [
'c_std=gnu11',
@ -13,8 +13,8 @@ project('systemd', 'c',
meson_version : '>= 0.53.2',
)
libsystemd_version = '0.33.0'
libudev_version = '1.7.3'
libsystemd_version = '0.34.0'
libudev_version = '1.7.4'
conf = configuration_data()
conf.set_quoted('PROJECT_URL', 'https://www.freedesktop.org/wiki/Software/systemd')
@ -2450,7 +2450,7 @@ public_programs += executable(
install_rpath : rootlibexecdir,
install : true)
public_programs += executable(
systemctl = executable(
'systemctl',
systemctl_sources,
include_directories : includes,
@ -2464,6 +2464,7 @@ public_programs += executable(
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
public_programs += systemctl
if conf.get('ENABLE_PORTABLED') == 1
dbus_programs += executable(
@ -3282,13 +3283,22 @@ executable(
install : true,
install_dir : rootlibexecdir)
public_programs += executable(
systemd_id128 = executable(
'systemd-id128',
'src/id128/id128.c',
include_directories : includes,
link_with : [libshared],
install_rpath : rootlibexecdir,
install : true)
public_programs += systemd_id128
if want_tests != 'false'
test('test-systemctl-enable',
test_systemctl_enable_sh,
# https://github.com/mesonbuild/meson/issues/2681
args : [systemctl.full_path(),
systemd_id128.full_path()])
endif
public_programs += executable(
'systemd-path',

View File

@ -74,7 +74,7 @@ static int log_helper(void *userdata, int level, int error, const char *file, in
return r;
}
static int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root) {
static int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root) {
_cleanup_(manager_freep) Manager *m = NULL;
Unit *u;
int r, q = 1;

View File

@ -78,7 +78,7 @@ static int acquire_host_info(sd_bus *bus, HostInfo **hi) {
if (!host)
return log_oom();
if (arg_scope != UNIT_FILE_SYSTEM) {
if (arg_scope != LOOKUP_SCOPE_SYSTEM) {
r = bus_connect_transport(arg_transport, arg_host, false, &system_bus);
if (r < 0) {
log_debug_errno(r, "Failed to connect to system bus, ignoring: %m");
@ -183,7 +183,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
_cleanup_free_ char *pretty_times = NULL;
bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM;
bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM;
BootTimes *boot;
UnitTimes *u;
int n, m = 1, y = 0, r;
@ -201,7 +201,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
if (n < 0)
return n;
if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) {
if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) {
n = acquire_host_info(bus, &host);
if (n < 0)
return n;

View File

@ -2646,7 +2646,7 @@ static int offline_security_check(Unit *u,
static int offline_security_checks(char **filenames,
JsonVariant *policy,
UnitFileScope scope,
LookupScope scope,
bool check_man,
bool run_generators,
unsigned threshold,
@ -2758,7 +2758,7 @@ static int offline_security_checks(char **filenames,
static int analyze_security(sd_bus *bus,
char **units,
JsonVariant *policy,
UnitFileScope scope,
LookupScope scope,
bool check_man,
bool run_generators,
bool offline,

View File

@ -67,9 +67,9 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
"Please try again later.\n"
"Hint: Use 'systemctl%s list-jobs' to see active jobs",
times.finish_time,
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user");
if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) {
if (arg_scope == LOOKUP_SCOPE_SYSTEM && times.security_start_time > 0) {
/* security_start_time is set when systemd is not running under container environment. */
if (times.initrd_time > 0)
times.kernel_done_time = times.initrd_time;

View File

@ -21,9 +21,9 @@ int verb_unit_files(int argc, char *argv[], void *userdata) {
char **v;
int r;
r = lookup_paths_init(&lp, arg_scope, 0, NULL);
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, NULL);
if (r < 0)
return log_error_errno(r, "lookup_paths_init() failed: %m");
return r;
r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL);
if (r < 0)

View File

@ -9,9 +9,9 @@ int verb_unit_paths(int argc, char *argv[], void *userdata) {
_cleanup_(lookup_paths_free) LookupPaths paths = {};
int r;
r = lookup_paths_init(&paths, arg_scope, 0, NULL);
r = lookup_paths_init_or_warn(&paths, arg_scope, 0, NULL);
if (r < 0)
return log_error_errno(r, "lookup_paths_init() failed: %m");
return r;
STRV_FOREACH(p, paths.search_path)
puts(*p);

View File

@ -242,7 +242,7 @@ static void set_destroy_ignore_pointer_max(Set** s) {
set_free_free(*s);
}
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
const ManagerTestRunFlags flags =
MANAGER_TEST_RUN_MINIMAL |
MANAGER_TEST_RUN_ENV_GENERATORS |

View File

@ -17,7 +17,7 @@ typedef enum RecursiveErrors {
int verify_generate_path(char **var, char **filenames);
int verify_prepare_filename(const char *filename, char **ret);
int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
const char* recursive_errors_to_string(RecursiveErrors i) _const_;
RecursiveErrors recursive_errors_from_string(const char *s) _pure_;

View File

@ -89,7 +89,7 @@ usec_t arg_fuzz = 0;
PagerFlags arg_pager_flags = 0;
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
const char *arg_host = NULL;
UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM;
RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES;
bool arg_man = true;
bool arg_generators = false;
@ -114,7 +114,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_unit, freep);
STATIC_DESTRUCTOR_REGISTER(arg_profile, freep);
int acquire_bus(sd_bus **bus, bool *use_full_bus) {
bool user = arg_scope != UNIT_FILE_SYSTEM;
bool user = arg_scope != LOOKUP_SCOPE_SYSTEM;
int r;
if (use_full_bus && *use_full_bus) {
@ -351,15 +351,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_SYSTEM:
arg_scope = UNIT_FILE_SYSTEM;
arg_scope = LOOKUP_SCOPE_SYSTEM;
break;
case ARG_USER:
arg_scope = UNIT_FILE_USER;
arg_scope = LOOKUP_SCOPE_USER;
break;
case ARG_GLOBAL:
arg_scope = UNIT_FILE_GLOBAL;
arg_scope = LOOKUP_SCOPE_GLOBAL;
break;
case ARG_ORDER:
@ -500,12 +500,12 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now.");
if (arg_scope == UNIT_FILE_GLOBAL &&
if (arg_scope == LOOKUP_SCOPE_GLOBAL &&
!STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --global only makes sense with verbs dot, unit-paths, verify.");
if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER)
if (streq_ptr(argv[optind], "cat-config") && arg_scope == LOOKUP_SCOPE_USER)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --user is not supported for cat-config right now.");

View File

@ -22,7 +22,7 @@ extern usec_t arg_fuzz;
extern PagerFlags arg_pager_flags;
extern BusTransport arg_transport;
extern const char *arg_host;
extern UnitFileScope arg_scope;
extern LookupScope arg_scope;
extern RecursiveErrors arg_recursive_errors;
extern bool arg_man;
extern bool arg_generators;

View File

@ -16,9 +16,8 @@ static int parse_env_file_internal(
FILE *f,
const char *fname,
int (*push) (const char *filename, unsigned line,
const char *key, char *value, void *userdata, int *n_pushed),
void *userdata,
int *n_pushed) {
const char *key, char *value, void *userdata),
void *userdata) {
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
_cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
@ -99,7 +98,7 @@ static int parse_env_file_internal(
if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
r = push(fname, line, key, value, userdata);
if (r < 0)
return r;
@ -142,7 +141,7 @@ static int parse_env_file_internal(
if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
r = push(fname, line, key, value, userdata);
if (r < 0)
return r;
@ -261,7 +260,7 @@ static int parse_env_file_internal(
if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
r = push(fname, line, key, value, userdata);
if (r < 0)
return r;
@ -299,8 +298,7 @@ static int check_utf8ness_and_warn(
static int parse_env_file_push(
const char *filename, unsigned line,
const char *key, char *value,
void *userdata,
int *n_pushed) {
void *userdata) {
const char *k;
va_list aq, *ap = userdata;
@ -322,9 +320,6 @@ static int parse_env_file_push(
free(*v);
*v = value;
if (n_pushed)
(*n_pushed)++;
return 1;
}
}
@ -340,16 +335,13 @@ int parse_env_filev(
const char *fname,
va_list ap) {
int r, n_pushed = 0;
int r;
va_list aq;
va_copy(aq, ap);
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
va_end(aq);
if (r < 0)
return r;
return n_pushed;
return r;
}
int parse_env_file_sentinel(
@ -370,8 +362,7 @@ int parse_env_file_sentinel(
static int load_env_file_push(
const char *filename, unsigned line,
const char *key, char *value,
void *userdata,
int *n_pushed) {
void *userdata) {
char ***m = userdata;
char *p;
int r;
@ -388,78 +379,69 @@ static int load_env_file_push(
if (r < 0)
return r;
if (n_pushed)
(*n_pushed)++;
free(value);
return 0;
}
int load_env_file(FILE *f, const char *fname, char ***rl) {
char **m = NULL;
_cleanup_strv_free_ char **m = NULL;
int r;
r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
if (r < 0) {
strv_free(m);
r = parse_env_file_internal(f, fname, load_env_file_push, &m);
if (r < 0)
return r;
}
*rl = m;
*rl = TAKE_PTR(m);
return 0;
}
static int load_env_file_push_pairs(
const char *filename, unsigned line,
const char *key, char *value,
void *userdata,
int *n_pushed) {
char ***m = userdata;
void *userdata) {
char ***m = ASSERT_PTR(userdata);
int r;
r = check_utf8ness_and_warn(filename, line, key, value);
if (r < 0)
return r;
/* Check if the key is present */
for (char **t = *m; t && *t; t += 2)
if (streq(t[0], key)) {
if (value)
return free_and_replace(t[1], value);
else
return free_and_strdup(t+1, "");
}
r = strv_extend(m, key);
if (r < 0)
return -ENOMEM;
return r;
if (!value) {
r = strv_extend(m, "");
if (r < 0)
return -ENOMEM;
} else {
r = strv_push(m, value);
if (r < 0)
return r;
}
if (n_pushed)
(*n_pushed)++;
return 0;
if (value)
return strv_push(m, value);
else
return strv_extend(m, "");
}
int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
char **m = NULL;
_cleanup_strv_free_ char **m = NULL;
int r;
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
if (r < 0) {
strv_free(m);
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
if (r < 0)
return r;
}
*rl = m;
*rl = TAKE_PTR(m);
return 0;
}
static int merge_env_file_push(
const char *filename, unsigned line,
const char *key, char *value,
void *userdata,
int *n_pushed) {
void *userdata) {
char ***env = userdata;
char *expanded_value;
@ -488,7 +470,7 @@ static int merge_env_file_push(
log_debug("%s:%u: setting %s=%s", filename, line, key, value);
return load_env_file_push(filename, line, key, value, env, n_pushed);
return load_env_file_push(filename, line, key, value, env);
}
int merge_env_file(
@ -500,7 +482,7 @@ int merge_env_file(
* plus "extended" substitutions, unlike other exported parsing functions.
*/
return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
return parse_env_file_internal(f, fname, merge_env_file_push, env);
}
static void write_env_var(FILE *f, const char *v) {

View File

@ -170,13 +170,19 @@ int open_extension_release(const char *root, const char *extension, char **ret_p
}
}
} else {
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT,
const char *var = secure_getenv("SYSTEMD_OS_RELEASE");
if (var)
r = chase_symlinks(var, root, 0,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
if (r != -ENOENT)
break;
}
else
FOREACH_STRING(path, "/etc/os-release", "/usr/lib/os-release") {
r = chase_symlinks(path, root, CHASE_PREFIX_ROOT,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
if (r != -ENOENT)
break;
}
}
if (r < 0)
return r;

View File

@ -232,7 +232,7 @@ bool path_is_user_config_dir(const char *path) {
}
static int acquire_generator_dirs(
UnitFileScope scope,
LookupScope scope,
const char *tempdir,
char **generator,
char **generator_early,
@ -244,17 +244,17 @@ static int acquire_generator_dirs(
assert(generator);
assert(generator_early);
assert(generator_late);
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL));
if (scope == UNIT_FILE_GLOBAL)
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EOPNOTSUPP;
if (tempdir)
prefix = tempdir;
else if (scope == UNIT_FILE_SYSTEM)
else if (scope == LOOKUP_SCOPE_SYSTEM)
prefix = "/run/systemd";
else {
/* UNIT_FILE_USER */
/* LOOKUP_SCOPE_USER */
const char *e;
e = getenv("XDG_RUNTIME_DIR");
@ -288,21 +288,21 @@ static int acquire_generator_dirs(
}
static int acquire_transient_dir(
UnitFileScope scope,
LookupScope scope,
const char *tempdir,
char **ret) {
char *transient;
assert(ret);
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL));
if (scope == UNIT_FILE_GLOBAL)
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EOPNOTSUPP;
if (tempdir)
transient = path_join(tempdir, "transient");
else if (scope == UNIT_FILE_SYSTEM)
else if (scope == LOOKUP_SCOPE_SYSTEM)
transient = strdup("/run/systemd/transient");
else
return xdg_user_runtime_dir(ret, "/systemd/transient");
@ -313,7 +313,7 @@ static int acquire_transient_dir(
return 0;
}
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
static int acquire_config_dirs(LookupScope scope, char **persistent, char **runtime) {
_cleanup_free_ char *a = NULL, *b = NULL;
int r;
@ -322,17 +322,17 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
switch (scope) {
case UNIT_FILE_SYSTEM:
case LOOKUP_SCOPE_SYSTEM:
a = strdup(SYSTEM_CONFIG_UNIT_DIR);
b = strdup("/run/systemd/system");
break;
case UNIT_FILE_GLOBAL:
case LOOKUP_SCOPE_GLOBAL:
a = strdup(USER_CONFIG_UNIT_DIR);
b = strdup("/run/systemd/user");
break;
case UNIT_FILE_USER:
case LOOKUP_SCOPE_USER:
r = xdg_user_config_dir(&a, "/systemd/user");
if (r < 0 && r != -ENXIO)
return r;
@ -364,7 +364,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
return 0;
}
static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
static int acquire_control_dirs(LookupScope scope, char **persistent, char **runtime) {
_cleanup_free_ char *a = NULL;
int r;
@ -373,7 +373,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
switch (scope) {
case UNIT_FILE_SYSTEM: {
case LOOKUP_SCOPE_SYSTEM: {
_cleanup_free_ char *b = NULL;
a = strdup("/etc/systemd/system.control");
@ -389,7 +389,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
break;
}
case UNIT_FILE_USER:
case LOOKUP_SCOPE_USER:
r = xdg_user_config_dir(&a, "/systemd/user.control");
if (r < 0 && r != -ENXIO)
return r;
@ -406,7 +406,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
break;
case UNIT_FILE_GLOBAL:
case LOOKUP_SCOPE_GLOBAL:
return -EOPNOTSUPP;
default:
@ -419,7 +419,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
}
static int acquire_attached_dirs(
UnitFileScope scope,
LookupScope scope,
char **ret_persistent,
char **ret_runtime) {
@ -429,7 +429,7 @@ static int acquire_attached_dirs(
assert(ret_runtime);
/* Portable services are not available to regular users for now. */
if (scope != UNIT_FILE_SYSTEM)
if (scope != LOOKUP_SCOPE_SYSTEM)
return -EOPNOTSUPP;
a = strdup("/etc/systemd/system.attached");
@ -508,8 +508,8 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append)
}
int lookup_paths_init(
LookupPaths *p,
UnitFileScope scope,
LookupPaths *lp,
LookupScope scope,
LookupPathsFlags flags,
const char *root_dir) {
@ -526,16 +526,16 @@ int lookup_paths_init(
_cleanup_strv_free_ char **paths = NULL;
int r;
assert(p);
assert(lp);
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(scope < _LOOKUP_SCOPE_MAX);
#if HAVE_SPLIT_USR
flags |= LOOKUP_PATHS_SPLIT_USR;
#endif
if (!empty_or_root(root_dir)) {
if (scope == UNIT_FILE_USER)
if (scope == LOOKUP_SCOPE_USER)
return -EINVAL;
r = is_dir(root_dir, true);
@ -560,8 +560,8 @@ int lookup_paths_init(
if (r < 0)
return r;
if (scope == UNIT_FILE_USER) {
r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
if (scope == LOOKUP_SCOPE_USER) {
r = acquire_config_dirs(LOOKUP_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config);
if (r < 0)
return r;
}
@ -606,7 +606,7 @@ int lookup_paths_init(
switch (scope) {
case UNIT_FILE_SYSTEM:
case LOOKUP_SCOPE_SYSTEM:
add = strv_new(
/* If you modify this you also want to modify
* systemdsystemunitpath= in systemd.pc.in! */
@ -629,7 +629,7 @@ int lookup_paths_init(
STRV_IFNOTNULL(generator_late));
break;
case UNIT_FILE_GLOBAL:
case LOOKUP_SCOPE_GLOBAL:
add = strv_new(
/* If you modify this you also want to modify
* systemduserunitpath= in systemd.pc.in, and
@ -652,7 +652,7 @@ int lookup_paths_init(
STRV_IFNOTNULL(generator_late));
break;
case UNIT_FILE_USER:
case LOOKUP_SCOPE_USER:
add = user_dirs(persistent_config, runtime_config,
global_persistent_config, global_runtime_config,
generator, generator_early, generator_late,
@ -716,7 +716,7 @@ int lookup_paths_init(
if (r < 0)
return -ENOMEM;
*p = (LookupPaths) {
*lp = (LookupPaths) {
.search_path = strv_uniq(TAKE_PTR(paths)),
.persistent_config = TAKE_PTR(persistent_config),
@ -741,46 +741,56 @@ int lookup_paths_init(
return 0;
}
void lookup_paths_free(LookupPaths *p) {
if (!p)
return;
int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir) {
int r;
p->search_path = strv_free(p->search_path);
p->persistent_config = mfree(p->persistent_config);
p->runtime_config = mfree(p->runtime_config);
p->persistent_attached = mfree(p->persistent_attached);
p->runtime_attached = mfree(p->runtime_attached);
p->generator = mfree(p->generator);
p->generator_early = mfree(p->generator_early);
p->generator_late = mfree(p->generator_late);
p->transient = mfree(p->transient);
p->persistent_control = mfree(p->persistent_control);
p->runtime_control = mfree(p->runtime_control);
p->root_dir = mfree(p->root_dir);
p->temporary_dir = mfree(p->temporary_dir);
r = lookup_paths_init(lp, scope, flags, root_dir);
if (r < 0)
return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m",
isempty(root_dir) ? "" : " for root directory ", strempty(root_dir));
return r;
}
void lookup_paths_log(LookupPaths *p) {
assert(p);
void lookup_paths_free(LookupPaths *lp) {
if (!lp)
return;
if (strv_isempty(p->search_path)) {
lp->search_path = strv_free(lp->search_path);
lp->persistent_config = mfree(lp->persistent_config);
lp->runtime_config = mfree(lp->runtime_config);
lp->persistent_attached = mfree(lp->persistent_attached);
lp->runtime_attached = mfree(lp->runtime_attached);
lp->generator = mfree(lp->generator);
lp->generator_early = mfree(lp->generator_early);
lp->generator_late = mfree(lp->generator_late);
lp->transient = mfree(lp->transient);
lp->persistent_control = mfree(lp->persistent_control);
lp->runtime_control = mfree(lp->runtime_control);
lp->root_dir = mfree(lp->root_dir);
lp->temporary_dir = mfree(lp->temporary_dir);
}
void lookup_paths_log(LookupPaths *lp) {
assert(lp);
if (strv_isempty(lp->search_path)) {
log_debug("Ignoring unit files.");
p->search_path = strv_free(p->search_path);
lp->search_path = strv_free(lp->search_path);
} else {
_cleanup_free_ char *t = NULL;
t = strv_join(p->search_path, "\n\t");
t = strv_join(lp->search_path, "\n\t");
log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t));
}
}
char **generator_binary_paths(UnitFileScope scope) {
char **generator_binary_paths(LookupScope scope) {
bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
_cleanup_strv_free_ char **paths = NULL;
int r;
@ -795,15 +805,15 @@ char **generator_binary_paths(UnitFileScope scope) {
switch (scope) {
case UNIT_FILE_SYSTEM:
case LOOKUP_SCOPE_SYSTEM:
add = strv_new("/run/systemd/system-generators",
"/etc/systemd/system-generators",
"/usr/local/lib/systemd/system-generators",
SYSTEM_GENERATOR_DIR);
break;
case UNIT_FILE_GLOBAL:
case UNIT_FILE_USER:
case LOOKUP_SCOPE_GLOBAL:
case LOOKUP_SCOPE_USER:
add = strv_new("/run/systemd/user-generators",
"/etc/systemd/user-generators",
"/usr/local/lib/systemd/user-generators",

View File

@ -3,10 +3,7 @@
#include <stdbool.h>
typedef struct LookupPaths LookupPaths;
#include "def.h"
#include "unit-file.h"
#include "macro.h"
typedef enum LookupPathsFlags {
@ -15,7 +12,15 @@ typedef enum LookupPathsFlags {
LOOKUP_PATHS_SPLIT_USR = 1 << 2,
} LookupPathsFlags;
struct LookupPaths {
typedef enum LookupScope {
LOOKUP_SCOPE_SYSTEM,
LOOKUP_SCOPE_GLOBAL,
LOOKUP_SCOPE_USER,
_LOOKUP_SCOPE_MAX,
_LOOKUP_SCOPE_INVALID = -EINVAL,
} LookupScope;
typedef struct LookupPaths {
/* Where we look for unit files. This includes the individual special paths below, but also any vendor
* supplied, static unit file paths. */
char **search_path;
@ -52,9 +57,10 @@ struct LookupPaths {
/* A temporary directory when running in test mode, to be nuked */
char *temporary_dir;
};
} LookupPaths;
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
int lookup_paths_init(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir);
int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir);
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs);
int xdg_user_runtime_dir(char **ret, const char *suffix);
@ -67,7 +73,7 @@ bool path_is_user_config_dir(const char *path);
void lookup_paths_log(LookupPaths *p);
void lookup_paths_free(LookupPaths *p);
char **generator_binary_paths(UnitFileScope scope);
char **generator_binary_paths(LookupScope scope);
char **env_generator_binary_paths(bool is_system);
#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))

View File

@ -127,17 +127,22 @@ bool null_or_empty(struct stat *st) {
return false;
}
int null_or_empty_path(const char *fn) {
int null_or_empty_path_with_root(const char *fn, const char *root) {
struct stat st;
int r;
assert(fn);
/* If we have the path, let's do an easy text comparison first. */
if (path_equal(fn, "/dev/null"))
/* A symlink to /dev/null or an empty file?
* When looking under root_dir, we can't expect /dev/ to be mounted,
* so let's see if the path is a (possibly dangling) symlink to /dev/null. */
if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
return true;
if (stat(fn, &st) < 0)
return -errno;
r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
if (r < 0)
return r;
return null_or_empty(&st);
}

View File

@ -31,9 +31,13 @@ static inline int dir_is_populated(const char *path) {
}
bool null_or_empty(struct stat *st) _pure_;
int null_or_empty_path(const char *fn);
int null_or_empty_path_with_root(const char *fn, const char *root);
int null_or_empty_fd(int fd);
static inline int null_or_empty_path(const char *fn) {
return null_or_empty_path_with_root(fn, NULL);
}
int path_is_read_only_fs(const char *path);
int files_same(const char *filea, const char *fileb, int flags);

View File

@ -69,7 +69,7 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i
return 0;
}
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) {
int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target) {
const char *src, *dst;
_cleanup_free_ char *src_instance = NULL, *dst_instance = NULL;
UnitType src_unit_type, dst_unit_type;
@ -82,7 +82,8 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe
*
* -EINVAL is returned if the something is wrong with the source filename or the source unit type is
* not allowed to symlink,
* -EXDEV if the target filename is not a valid unit name or doesn't match the source.
* -EXDEV if the target filename is not a valid unit name or doesn't match the source,
* -ELOOP for an alias to self.
*/
src = basename(filename);
@ -92,51 +93,56 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe
src_name_type = unit_name_to_instance(src, &src_instance);
if (src_name_type < 0)
return log_notice_errno(src_name_type,
"%s: not a valid unit name \"%s\": %m", filename, src);
return log_full_errno(log_level, src_name_type,
"%s: not a valid unit name \"%s\": %m", filename, src);
src_unit_type = unit_name_to_type(src);
assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */
if (!unit_type_may_alias(src_unit_type))
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: symlinks are not allowed for units of this type, rejecting.",
filename);
return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL),
"%s: symlinks are not allowed for units of this type, rejecting.",
filename);
if (src_name_type != UNIT_NAME_PLAIN &&
!unit_type_may_template(src_unit_type))
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: templates not allowed for %s units, rejecting.",
filename, unit_type_to_string(src_unit_type));
return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL),
"%s: templates not allowed for %s units, rejecting.",
filename, unit_type_to_string(src_unit_type));
/* dst checks */
if (streq(src, dst))
return log_debug_errno(SYNTHETIC_ERRNO(ELOOP),
"%s: unit self-alias: %s → %s, ignoring.",
filename, src, dst);
dst_name_type = unit_name_to_instance(dst, &dst_instance);
if (dst_name_type < 0)
return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type,
"%s points to \"%s\" which is not a valid unit name: %m",
filename, dst);
return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type,
"%s points to \"%s\" which is not a valid unit name: %m",
filename, dst);
if (!(dst_name_type == src_name_type ||
(src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE)))
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
"%s: symlink target name type \"%s\" does not match source, rejecting.",
filename, dst);
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
"%s: symlink target name type \"%s\" does not match source, rejecting.",
filename, dst);
if (dst_name_type == UNIT_NAME_INSTANCE) {
assert(src_instance);
assert(dst_instance);
if (!streq(src_instance, dst_instance))
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
"%s: unit symlink target \"%s\" instance name doesn't match, rejecting.",
filename, dst);
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
"%s: unit symlink target \"%s\" instance name doesn't match, rejecting.",
filename, dst);
}
dst_unit_type = unit_name_to_type(dst);
if (dst_unit_type != src_unit_type)
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
"%s: symlink target \"%s\" has incompatible suffix, rejecting.",
filename, dst);
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
"%s: symlink target \"%s\" has incompatible suffix, rejecting.",
filename, dst);
return 0;
}
@ -259,6 +265,110 @@ static int directory_name_is_valid(const char *name) {
return false;
}
int unit_file_resolve_symlink(
const char *root_dir,
char **search_path,
const char *dir,
int dirfd,
const char *filename,
bool resolve_destination_target,
char **ret_destination) {
_cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL, *_dir = NULL, *_filename = NULL;
int r;
/* This can be called with either dir+dirfd valid and filename just a name,
* or !dir && dirfd==AT_FDCWD, and filename being a full path.
*
* If resolve_destination_target is true, an absolute path will be returned.
* If not, an absolute path is returned for linked unit files, and a relative
* path otherwise.
*
* Returns an error, false if this is an alias, true if it's a linked unit file. */
assert(filename);
assert(ret_destination);
assert(dir || path_is_absolute(filename));
assert(dirfd >= 0 || dirfd == AT_FDCWD);
r = readlinkat_malloc(dirfd, filename, &target);
if (r < 0)
return log_warning_errno(r, "Failed to read symlink %s%s%s: %m",
dir, dir ? "/" : "", filename);
if (!dir) {
r = path_extract_directory(filename, &_dir);
if (r < 0)
return r;
dir = _dir;
r = path_extract_filename(filename, &_filename);
if (r < 0)
return r;
if (r == O_DIRECTORY)
return log_warning_errno(SYNTHETIC_ERRNO(EISDIR),
"Unexpected path to a directory \"%s\", refusing.", filename);
filename = _filename;
}
bool is_abs = path_is_absolute(target);
if (root_dir || !is_abs) {
char *target_abs = path_join(is_abs ? root_dir : dir, target);
if (!target_abs)
return log_oom();
free_and_replace(target, target_abs);
}
/* Get rid of "." and ".." components in target path */
r = chase_symlinks(target, root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL);
if (r < 0)
return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m",
dir, filename, target);
assert(path_is_absolute(simplified));
/* Check if the symlink remain inside of of our search path.
* If yes, it is an alias. Verify that it is valid.
*
* If no, then this is a linked unit file or mask, and we don't care about the target name
* when loading units, and we return the link *source* (resolve_destination_target == false);
* When this is called for installation purposes, we want the final destination,
* so we return the *target*.
*/
const char *tail = path_startswith_strv(simplified, search_path);
if (tail) { /* An alias */
_cleanup_free_ char *target_name = NULL;
r = path_extract_filename(simplified, &target_name);
if (r < 0)
return r;
r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified);
if (r < 0)
return r;
if (is_path(tail))
log_warning("Suspicious symlink %s/%s→%s, treating as alias.",
dir, filename, simplified);
dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name);
} else {
log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified);
if (resolve_destination_target)
dst = TAKE_PTR(simplified);
else {
dst = path_join(dir, filename);
if (!dst)
return log_oom();
}
}
*ret_destination = TAKE_PTR(dst);
return !tail; /* true if linked unit file */
}
int unit_file_build_name_map(
const LookupPaths *lp,
uint64_t *cache_timestamp_hash,
@ -308,10 +418,9 @@ int unit_file_build_name_map(
FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
_unused_ _cleanup_free_ char *_filename_free = NULL;
_cleanup_free_ char *simplified = NULL;
bool symlink_to_dir = false;
const char *dst = NULL;
char *filename;
_cleanup_free_ char *dst = NULL;
bool symlink_to_dir = false;
/* We only care about valid units and dirs with certain suffixes, let's ignore the
* rest. */
@ -395,77 +504,35 @@ int unit_file_build_name_map(
/* We don't explicitly check for alias loops here. unit_ids_map_get() which
* limits the number of hops should be used to access the map. */
_cleanup_free_ char *target = NULL;
r = readlinkat_malloc(dirfd(d), de->d_name, &target);
if (r < 0) {
log_warning_errno(r, "Failed to read symlink %s/%s, ignoring: %m",
*dir, de->d_name);
r = unit_file_resolve_symlink(lp->root_dir, lp->search_path,
*dir, dirfd(d), de->d_name,
/* resolve_destination_target= */ false,
&dst);
if (r == -ENOMEM)
return r;
if (r < 0) /* we ignore other errors here */
continue;
}
const bool is_abs = path_is_absolute(target);
if (lp->root_dir || !is_abs) {
char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target);
if (!target_abs)
return log_oom();
free_and_replace(target, target_abs);
}
/* Get rid of "." and ".." components in target path */
r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m",
filename, target);
continue;
}
/* Check if the symlink goes outside of our search path.
* If yes, it's a linked unit file or mask, and we don't care about the target name.
* Let's just store the link source directly.
* If not, let's verify that it's a good symlink. */
char *tail = path_startswith_strv(simplified, lp->search_path);
if (!tail) {
log_debug("%s: linked unit file: %s → %s",
__func__, filename, simplified);
dst = filename;
} else {
bool self_alias;
dst = basename(simplified);
self_alias = streq(dst, de->d_name);
if (is_path(tail))
log_full(self_alias ? LOG_DEBUG : LOG_WARNING,
"Suspicious symlink %s→%s, treating as alias.",
filename, simplified);
r = unit_validate_alias_symlink_and_warn(filename, simplified);
if (r < 0)
continue;
if (self_alias) {
/* A self-alias that has no effect */
log_debug("%s: self-alias: %s/%s → %s, ignoring.",
__func__, *dir, de->d_name, dst);
continue;
}
log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst);
}
} else {
dst = filename;
dst = TAKE_PTR(_filename_free); /* Grab the copy we made previously, if available. */
if (!dst) {
dst = strdup(filename);
if (!dst)
return log_oom();
}
log_debug("%s: normal unit file: %s", __func__, dst);
}
r = hashmap_put_strdup(&ids, de->d_name, dst);
_cleanup_free_ char *key = strdup(de->d_name);
if (!key)
return log_oom();
r = hashmap_ensure_put(&ids, &string_hash_ops_free_free, key, dst);
if (r < 0)
return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m",
de->d_name, dst);
key = dst = NULL;
}
}

View File

@ -4,12 +4,11 @@
#include <stdbool.h>
#include "hashmap.h"
#include "path-lookup.h"
#include "time-util.h"
#include "unit-name.h"
typedef enum UnitFileState UnitFileState;
typedef enum UnitFileScope UnitFileScope;
typedef struct LookupPaths LookupPaths;
enum UnitFileState {
UNIT_FILE_ENABLED,
@ -29,21 +28,23 @@ enum UnitFileState {
_UNIT_FILE_STATE_INVALID = -EINVAL,
};
enum UnitFileScope {
UNIT_FILE_SYSTEM,
UNIT_FILE_GLOBAL,
UNIT_FILE_USER,
_UNIT_FILE_SCOPE_MAX,
_UNIT_FILE_SCOPE_INVALID = -EINVAL,
};
bool unit_type_may_alias(UnitType type) _const_;
bool unit_type_may_template(UnitType type) _const_;
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation);
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target);
int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target);
bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new);
int unit_file_resolve_symlink(
const char *root_dir,
char **search_path,
const char *dir,
int dirfd,
const char *filename,
bool resolve_destination_target,
char **ret_destination);
int unit_file_build_name_map(
const LookupPaths *lp,
uint64_t *cache_timestamp_hash,

View File

@ -2288,7 +2288,7 @@ fail:
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
bool carries_install_info,
sd_bus_error *error) {
@ -2352,7 +2352,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu
return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error);
}
static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) {
static int unit_file_preset_without_mode(LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) {
return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes);
}
@ -2412,7 +2412,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
static int method_disable_unit_files_generic(
sd_bus_message *message,
Manager *m,
int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
@ -2638,7 +2638,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s
flags = UNIT_FILE_DRY_RUN |
(runtime ? UNIT_FILE_RUNTIME : 0);
r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes);
if (r < 0)
return log_error_errno(r, "Failed to get file links for %s: %m", name);

View File

@ -62,7 +62,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (!getenv("SYSTEMD_LOG_LEVEL"))
log_set_max_level(LOG_CRIT);
assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0);
name = strjoina("a.", unit_type_to_string(t));
assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0);

View File

@ -2885,7 +2885,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
r = manager_new(arg_system ? LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER,
arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0,
&m);
if (r < 0) {

View File

@ -775,13 +775,13 @@ static int manager_setup_sigchld_event_source(Manager *m) {
return 0;
}
int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
_cleanup_(manager_freep) Manager *m = NULL;
const char *e;
int r;
assert(_m);
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER));
m = new(Manager, 1);
if (!m)
@ -1700,7 +1700,7 @@ static void manager_preset_all(Manager *m) {
return;
/* If this is the first boot, and we are in the host system, then preset everything */
r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
r = unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
if (r < 0)
log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
"Failed to populate /etc with preset unit settings, ignoring: %m");
@ -1751,11 +1751,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
/* If we are running in test mode, we still want to run the generators,
* but we should not touch the real generator directories. */
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope,
MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
root);
r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope,
MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
root);
if (r < 0)
return log_error_errno(r, "Failed to initialize path lookup table: %m");
return r;
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START));
r = manager_run_environment_generators(m);
@ -3343,9 +3343,9 @@ int manager_reload(Manager *m) {
m->uid_refs = hashmap_free(m->uid_refs);
m->gid_refs = hashmap_free(m->gid_refs);
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, 0, NULL);
if (r < 0)
log_warning_errno(r, "Failed to initialize path lookup table, ignoring: %m");
return r;
(void) manager_run_environment_generators(m);
(void) manager_run_generators(m);

View File

@ -235,7 +235,7 @@ struct Manager {
int user_lookup_fds[2];
sd_event_source *user_lookup_event_source;
UnitFileScope unit_file_scope;
LookupScope unit_file_scope;
LookupPaths lookup_paths;
Hashmap *unit_id_map;
Hashmap *unit_name_map;
@ -463,8 +463,8 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
return m->default_timeout_abort_set ? m->default_timeout_abort_usec : m->default_timeout_stop_usec;
}
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == LOOKUP_SCOPE_SYSTEM)
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != LOOKUP_SCOPE_SYSTEM)
#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
@ -475,7 +475,7 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
#define MANAGER_IS_TEST_RUN(m) ((m)->test_run_flags != 0)
int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **m);
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **m);
Manager* manager_free(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);

View File

@ -183,7 +183,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
COMMON_SYSTEM_SPECIFIERS,
COMMON_CREDS_SPECIFIERS,
COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope),
{}
};
@ -253,7 +253,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
COMMON_SYSTEM_SPECIFIERS,
COMMON_CREDS_SPECIFIERS,
COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope),
COMMON_TMP_SPECIFIERS,
{}

View File

@ -47,6 +47,27 @@ int device_add_property(sd_device *device, const char *key, const char *value) {
return 0;
}
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) {
_cleanup_free_ char *value = NULL;
va_list ap;
int r;
assert(device);
assert(key);
if (!format)
return device_add_property(device, key, NULL);
va_start(ap, format);
r = vasprintf(&value, format, ap);
va_end(ap);
if (r < 0)
return -ENOMEM;
return device_add_property(device, key, value);
}
void device_set_devlink_priority(sd_device *device, int priority) {
assert(device);

View File

@ -36,6 +36,7 @@ int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
int device_add_devlink(sd_device *device, const char *devlink);
bool device_has_devlink(sd_device *device, const char *devlink);
int device_add_property(sd_device *device, const char *property, const char *value);
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
int device_add_tag(sd_device *device, const char *tag, bool both);
void device_remove_tag(sd_device *device, const char *tag);
void device_cleanup_tags(sd_device *device);

View File

@ -601,8 +601,8 @@ static int get_search(uint64_t type, char ***list) {
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT:
case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: {
_cleanup_(lookup_paths_free) LookupPaths lp = {};
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
r = lookup_paths_init(&lp, scope, 0, NULL);
if (r < 0)
@ -615,8 +615,8 @@ static int get_search(uint64_t type, char ***list) {
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR:
case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: {
char **t;
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
t = generator_binary_paths(scope);
if (!t)

View File

@ -231,7 +231,7 @@ static int extract_now(
/* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
* discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as we mightbe
* compiled for a split-usr system but the image might be a legacy-usr one. */
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
if (r < 0)
return log_debug_errno(r, "Failed to acquire lookup paths: %m");
@ -1340,12 +1340,12 @@ int portable_attach(
strempty(extensions_joined));
}
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
if (r < 0)
return r;
HASHMAP_FOREACH(item, unit_files) {
r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name);
r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0)
@ -1539,7 +1539,7 @@ int portable_detach(
assert(name_or_path);
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
if (r < 0)
return r;
@ -1573,7 +1573,7 @@ int portable_detach(
if (r == 0)
continue;
r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state);
if (r < 0)
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_RUNTIME, UNIT_FILE_LINKED_RUNTIME))
@ -1717,7 +1717,7 @@ static int portable_get_state_internal(
assert(name_or_path);
assert(ret);
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
if (r < 0)
return r;
@ -1753,7 +1753,7 @@ static int portable_get_state_internal(
if (r == 0)
continue;
r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state);
if (r < 0)
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME))

View File

@ -785,7 +785,8 @@ static int condition_test_needs_update(Condition *c, char **env) {
if (r < 0) {
log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
return true;
} else if (r == 0) {
}
if (isempty(timestamp_str)) {
log_debug("No data in timestamp file '%s', using mtime.", p);
return true;
}

View File

@ -97,7 +97,11 @@ static int specifier_last_component(char specifier, const void *data, const char
return 0;
}
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
int install_name_printf(
LookupScope scope,
const UnitFileInstallInfo *info,
const char *format,
char **ret) {
/* This is similar to unit_name_printf() */
const Specifier table[] = {
@ -109,13 +113,13 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const
COMMON_SYSTEM_SPECIFIERS,
COMMON_CREDS_SPECIFIERS,
COMMON_CREDS_SPECIFIERS(scope),
{}
};
assert(i);
assert(info);
assert(format);
assert(ret);
return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret);
return specifier_printf(format, UNIT_NAME_MAX, table, info->root, info, ret);
}

View File

@ -4,4 +4,8 @@
#include "install.h"
#include "unit-name.h"
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret);
int install_name_printf(
LookupScope scope,
const UnitFileInstallInfo *info,
const char *format,
char **ret);

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@ typedef struct UnitFileInstallInfo UnitFileInstallInfo;
#include "macro.h"
#include "path-lookup.h"
#include "strv.h"
#include "unit-file.h"
#include "unit-name.h"
enum UnitFilePresetMode {
@ -70,7 +71,8 @@ struct UnitFileList {
enum UnitFileType {
UNIT_FILE_TYPE_REGULAR,
UNIT_FILE_TYPE_SYMLINK,
UNIT_FILE_TYPE_LINKED,
UNIT_FILE_TYPE_ALIAS,
UNIT_FILE_TYPE_MASKED,
_UNIT_FILE_TYPE_MAX,
_UNIT_FILE_TYPE_INVALID = -EINVAL,
@ -94,28 +96,28 @@ struct UnitFileInstallInfo {
};
int unit_file_enable(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_disable(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_reenable(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
char **names_or_paths,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_preset(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
@ -123,52 +125,52 @@ int unit_file_preset(
UnitFileChange **changes,
size_t *n_changes);
int unit_file_preset_all(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
UnitFilePresetMode mode,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_mask(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_unmask(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_link(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_revert(
UnitFileScope scope,
LookupScope scope,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_set_default(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
const char *file,
UnitFileChange **changes,
size_t *n_changes);
int unit_file_get_default(
UnitFileScope scope,
LookupScope scope,
const char *root_dir,
char **name);
int unit_file_add_dependency(
UnitFileScope scope,
LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
@ -178,22 +180,27 @@ int unit_file_add_dependency(
size_t *n_changes);
int unit_file_lookup_state(
UnitFileScope scope,
LookupScope scope,
const LookupPaths *paths,
const char *name,
UnitFileState *ret);
int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name);
int unit_file_get_state(LookupScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *name);
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
Hashmap* unit_file_list_free(Hashmap *h);
int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, size_t n_changes);
void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet);
int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst);
int unit_file_verify_alias(
const UnitFileInstallInfo *info,
const char *dst,
char **ret_dst,
UnitFileChange **changes,
size_t *n_changes);
typedef struct UnitFilePresetRule UnitFilePresetRule;
@ -204,7 +211,7 @@ typedef struct {
} UnitFilePresets;
void unit_file_presets_freep(UnitFilePresets *p);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
const char *unit_file_state_to_string(UnitFileState s) _const_;
UnitFileState unit_file_state_from_string(const char *s) _pure_;

View File

@ -18,6 +18,7 @@
#include "id128-util.h"
#include "macro.h"
#include "os-util.h"
#include "path-lookup.h"
#include "path-util.h"
#include "specifier.h"
#include "string-util.h"
@ -162,7 +163,8 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con
fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
if (fd < 0)
return fd;
/* Translate error for missing os-release file to EUNATCH. */
return fd == -ENOENT ? -EUNATCH : fd;
r = id128_read_fd(fd, ID128_PLAIN, &id);
} else
@ -269,44 +271,54 @@ int specifier_architecture(char specifier, const void *data, const char *root, c
}
/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid
* otherwise. We'll return an empty value or NULL in that case from the functions below. */
* otherwise. We'll return an empty value or NULL in that case from the functions below. But if the
* os-release file is missing, we'll return -EUNATCH. This means that something is seriously wrong with the
* installation. */
static int parse_os_release_specifier(const char *root, const char *id, char **ret) {
int r;
assert(ret);
/* Translate error for missing os-release file to EUNATCH. */
r = parse_os_release(root, id, ret);
return r == -ENOENT ? -EUNATCH : r;
}
int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "ID", ret);
return parse_os_release_specifier(root, "ID", ret);
}
int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "VERSION_ID", ret);
return parse_os_release_specifier(root, "VERSION_ID", ret);
}
int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "BUILD_ID", ret);
return parse_os_release_specifier(root, "BUILD_ID", ret);
}
int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "VARIANT_ID", ret);
return parse_os_release_specifier(root, "VARIANT_ID", ret);
}
int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "IMAGE_ID", ret);
return parse_os_release_specifier(root, "IMAGE_ID", ret);
}
int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
assert(ret);
return parse_os_release(root, "IMAGE_VERSION", ret);
return parse_os_release_specifier(root, "IMAGE_VERSION", ret);
}
int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
LookupScope scope = PTR_TO_INT(data);
char *t;
assert(ret);
t = gid_to_name(getgid());
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EINVAL;
t = gid_to_name(scope == LOOKUP_SCOPE_USER ? getgid() : 0);
if (!t)
return -ENOMEM;
@ -315,27 +327,42 @@ int specifier_group_name(char specifier, const void *data, const char *root, con
}
int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
LookupScope scope = PTR_TO_INT(data);
gid_t gid;
assert(ret);
if (asprintf(ret, UID_FMT, getgid()) < 0)
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EINVAL;
gid = scope == LOOKUP_SCOPE_USER ? getgid() : 0;
if (asprintf(ret, UID_FMT, gid) < 0)
return -ENOMEM;
return 0;
}
int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
LookupScope scope = PTR_TO_INT(data);
uid_t uid;
char *t;
assert(ret);
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
* to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EINVAL;
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
* specifer_user_id() below.
uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0;
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want
* to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain
* consistent with specifer_user_id() below.
*/
t = uid_to_name(getuid());
t = uid_to_name(uid);
if (!t)
return -ENOMEM;
@ -344,9 +371,17 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons
}
int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
LookupScope scope = PTR_TO_INT(data);
uid_t uid;
assert(ret);
if (asprintf(ret, UID_FMT, getuid()) < 0)
if (scope == LOOKUP_SCOPE_GLOBAL)
return -EINVAL;
uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0;
if (asprintf(ret, UID_FMT, uid) < 0)
return -ENOMEM;
return 0;

View File

@ -84,11 +84,11 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co
{ 'w', specifier_os_version_id, NULL }, \
{ 'W', specifier_os_variant_id, NULL }
#define COMMON_CREDS_SPECIFIERS \
{ 'g', specifier_group_name, NULL }, \
{ 'G', specifier_group_id, NULL }, \
{ 'u', specifier_user_name, NULL }, \
{ 'U', specifier_user_id, NULL }
#define COMMON_CREDS_SPECIFIERS(scope) \
{ 'g', specifier_group_name, INT_TO_PTR(scope) }, \
{ 'G', specifier_group_id, INT_TO_PTR(scope) }, \
{ 'u', specifier_user_name, INT_TO_PTR(scope) }, \
{ 'U', specifier_user_id, INT_TO_PTR(scope) }
#define COMMON_TMP_SPECIFIERS \
{ 'T', specifier_tmp_dir, NULL }, \

View File

@ -25,6 +25,7 @@
#include "cgroup-util.h"
#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
#include "namespace-util.h"
@ -33,6 +34,7 @@
#include "random-util.h"
#include "strv.h"
#include "tests.h"
#include "tmpfile-util.h"
char* setup_fake_runtime_dir(void) {
char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
@ -132,6 +134,23 @@ int log_tests_skipped_errno(int r, const char *message) {
return EXIT_TEST_SKIP;
}
int write_tmpfile(char *pattern, const char *contents) {
_cleanup_close_ int fd = -1;
assert(pattern);
assert(contents);
fd = mkostemp_safe(pattern);
if (fd < 0)
return fd;
ssize_t l = strlen(contents);
errno = 0;
if (write(fd, contents, l) != l)
return errno_or_else(EIO);
return 0;
}
bool have_namespaces(void) {
siginfo_t si = {};
pid_t pid;

View File

@ -30,6 +30,8 @@ void test_setup_logging(int level);
int log_tests_skipped(const char *message);
int log_tests_skipped_errno(int r, const char *message);
int write_tmpfile(char *pattern, const char *contents);
bool have_namespaces(void);
/* We use the small but non-trivial limit here */

View File

@ -37,9 +37,9 @@ int verb_cat(int argc, char *argv[], void *userdata) {
if (arg_transport != BUS_TRANSPORT_LOCAL)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
if (r < 0)
return log_error_errno(r, "Failed to determine unit paths: %m");
return r;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@ -99,7 +99,7 @@ int verb_cat(int argc, char *argv[], void *userdata) {
ansi_highlight_red(),
ansi_highlight_red(),
ansi_highlight_red(),
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user",
ansi_normal());
r = cat_files(fragment_path, dropin_paths, 0);
@ -406,8 +406,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
if (!path) {
if (!arg_force) {
log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.",
arg_scope == UNIT_FILE_GLOBAL ? " --global" :
arg_scope == UNIT_FILE_USER ? " --user" : "",
arg_scope == LOOKUP_SCOPE_GLOBAL ? " --global" :
arg_scope == LOOKUP_SCOPE_USER ? " --user" : "",
*name);
return -ENOENT;
}
@ -507,9 +507,9 @@ int verb_edit(int argc, char *argv[], void *userdata) {
if (arg_transport != BUS_TRANSPORT_LOCAL)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely.");
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
if (r < 0)
return log_error_errno(r, "Failed to determine unit paths: %m");
return r;
r = mac_selinux_init();
if (r < 0)

View File

@ -141,7 +141,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (STR_IN_SET(verb, "mask", "unmask")) {
_cleanup_(lookup_paths_free) LookupPaths lp = {};
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
if (r < 0)
return r;

View File

@ -18,7 +18,7 @@ static int show_installation_targets_client_side(const char *name) {
flags = UNIT_FILE_DRY_RUN |
(arg_runtime ? UNIT_FILE_RUNTIME : 0);
r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes);
if (r < 0)
return log_error_errno(r, "Failed to get file links for %s: %m", name);

View File

@ -762,7 +762,7 @@ static void print_status_info(
getuid(),
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
SD_JOURNAL_LOCAL_ONLY,
arg_scope == UNIT_FILE_SYSTEM,
arg_scope == LOOKUP_SCOPE_SYSTEM,
ellipsized);
if (i->need_daemon_reload)

View File

@ -246,10 +246,10 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
int verb_start_system_special(int argc, char *argv[], void *userdata) {
/* Like start_special above, but raises an error when running in user mode */
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad action for %s mode.",
arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
arg_scope == LOOKUP_SCOPE_GLOBAL ? "--global" : "--user");
return verb_start_special(argc, argv, userdata);
}

View File

@ -168,8 +168,8 @@ fail:
BUS_ERROR_UNIT_MASKED,
BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
log_error("See %s logs and 'systemctl%s status%s %s' for details.",
arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
arg_scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user",
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user",
name[0] == '-' ? " --" : "",
name);
@ -242,7 +242,7 @@ static const char** make_extra_args(const char *extra_args[static 4]) {
assert(extra_args);
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
extra_args[n++] = "--user";
if (arg_transport == BUS_TRANSPORT_REMOTE) {

View File

@ -116,7 +116,7 @@ int enable_sysv_units(const char *verb, char **args) {
/* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
return 0;
if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
@ -128,7 +128,7 @@ int enable_sysv_units(const char *verb, char **args) {
"is-enabled"))
return 0;
r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
r = lookup_paths_init_or_warn(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
if (r < 0)
return r;

View File

@ -46,7 +46,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) {
if (!buses[focus]) {
bool user;
user = arg_scope != UNIT_FILE_SYSTEM;
user = arg_scope != LOOKUP_SCOPE_SYSTEM;
if (focus == BUS_MANAGER)
r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
@ -73,7 +73,7 @@ void ask_password_agent_open_maybe(void) {
if (arg_dry_run)
return;
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
return;
ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
@ -82,7 +82,7 @@ void ask_password_agent_open_maybe(void) {
void polkit_agent_open_maybe(void) {
/* Open the polkit agent as a child process if necessary */
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
return;
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
@ -380,7 +380,7 @@ void warn_unit_file_changed(const char *unit) {
ansi_highlight_red(),
ansi_normal(),
unit,
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user");
}
int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
@ -814,7 +814,7 @@ bool install_client_side(void) {
if (!isempty(arg_root))
return true;
if (arg_scope == UNIT_FILE_GLOBAL)
if (arg_scope == LOOKUP_SCOPE_GLOBAL)
return true;
/* Unsupported environment variable, mostly for debugging purposes */

View File

@ -66,7 +66,7 @@ char **arg_properties = NULL;
bool arg_all = false;
enum dependency arg_dependency = DEPENDENCY_FORWARD;
const char *_arg_job_mode = NULL;
UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM;
bool arg_wait = false;
bool arg_no_block = false;
int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */
@ -616,15 +616,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_USER:
arg_scope = UNIT_FILE_USER;
arg_scope = LOOKUP_SCOPE_USER;
break;
case ARG_SYSTEM:
arg_scope = UNIT_FILE_SYSTEM;
arg_scope = LOOKUP_SCOPE_SYSTEM;
break;
case ARG_GLOBAL:
arg_scope = UNIT_FILE_GLOBAL;
arg_scope = LOOKUP_SCOPE_GLOBAL;
break;
case ARG_WAIT:
@ -924,10 +924,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
/* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system
* passwords */
if (arg_scope != UNIT_FILE_SYSTEM)
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
arg_ask_password = false;
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM)
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != LOOKUP_SCOPE_SYSTEM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot access user instance remotely.");

View File

@ -51,7 +51,7 @@ extern char **arg_properties;
extern bool arg_all;
extern enum dependency arg_dependency;
extern const char *_arg_job_mode;
extern UnitFileScope arg_scope;
extern LookupScope arg_scope;
extern bool arg_wait;
extern bool arg_no_block;
extern int arg_legend;

View File

@ -747,7 +747,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
if (hashmap_contains(all_services, name))
continue;
r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name);
r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, lp, name);
if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) {
log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
continue;
@ -891,9 +891,9 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
assert_se(arg_dest = dest_late);
r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
r = lookup_paths_init_or_warn(&lp, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
if (r < 0)
return log_error_errno(r, "Failed to find lookup paths: %m");
return r;
all_services = hashmap_new(&string_hash_ops);
if (!all_services)

View File

@ -97,7 +97,7 @@ int main(int argc, char *argv[]) {
/* The simple tests succeeded. Now let's try full unit-based use-case. */
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
assert_se(u = unit_new(m, sizeof(Service)));

View File

@ -301,7 +301,7 @@ int main(int argc, char *argv[]) {
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
assert_se(test_bpf_cgroup_programs(m,

View File

@ -90,7 +90,7 @@ int main(int argc, char *argv[]) {
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
/* We need to enable access to the filesystem where the binary is so we

View File

@ -42,7 +42,7 @@ TEST_RET(cgroup_mask, .sd_booted = true) {
assert_se(get_testdata_dir("units", &unit_dir) >= 0);
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (IN_SET(r, -EPERM, -EACCES)) {
log_error_errno(r, "manager_new: %m");
return log_tests_skipped("cannot create manager");

View File

@ -26,7 +26,7 @@ TEST_RET(default_memory_low, .sd_booted = true) {
assert_se(get_testdata_dir("units", &unit_dir) >= 0);
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (IN_SET(r, -EPERM, -EACCES)) {
log_error_errno(r, "manager_new: %m");
return log_tests_skipped("cannot create manager");

View File

@ -343,7 +343,8 @@ TEST_RET(copy_holes) {
assert_se(fstat(fd, &stat) >= 0);
blksz = stat.st_blksize;
buf = alloca0(blksz);
buf = alloca_safe(blksz);
memset(buf, 1, blksz);
/* We need to make sure to create hole in multiples of the block size, otherwise filesystems (btrfs)
* might silently truncate/extend the holes. */

View File

@ -93,7 +93,7 @@ int main(int argc, char *argv[]) {
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (manager_errno_skip_test(r))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);

View File

@ -9,7 +9,12 @@
#include "tests.h"
#include "tmpfile-util.h"
/* In case of repeating keys, later entries win. */
#define env_file_1 \
"a=a\n" \
"a=b\n" \
"a=b\n" \
"a=a\n" \
"b=b\\\n" \
"c\n" \
@ -55,18 +60,11 @@
TEST(load_env_file_1) {
_cleanup_strv_free_ char **data = NULL;
int r;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
assert_se(write_tmpfile(name, env_file_1) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(streq(data[0], "a=a"));
assert_se(streq(data[1], "b=bc"));
assert_se(streq(data[2], "d=de f"));
@ -77,50 +75,30 @@ TEST(load_env_file_1) {
}
TEST(load_env_file_2) {
_cleanup_strv_free_ char **data = NULL;
int r;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
assert_se(write_tmpfile(name, env_file_2) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(streq(data[0], "a=a"));
assert_se(data[1] == NULL);
}
TEST(load_env_file_3) {
_cleanup_strv_free_ char **data = NULL;
int r;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
assert_se(write_tmpfile(name, env_file_3) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(data == NULL);
}
TEST(load_env_file_4) {
_cleanup_strv_free_ char **data = NULL;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
int r;
assert_se(write_tmpfile(name, env_file_4) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
assert_se(streq(data[1], "MODULE_0=coretemp"));
assert_se(streq(data[2], "MODULE_1=f71882fg"));
@ -128,36 +106,22 @@ TEST(load_env_file_4) {
}
TEST(load_env_file_5) {
_cleanup_strv_free_ char **data = NULL;
int r;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
assert_se(write_tmpfile(name, env_file_5) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(streq(data[0], "a="));
assert_se(streq(data[1], "b="));
assert_se(data[2] == NULL);
}
TEST(load_env_file_6) {
_cleanup_strv_free_ char **data = NULL;
int r;
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
_cleanup_close_ int fd;
assert_se(write_tmpfile(name, env_file_6) == 0);
fd = mkostemp_safe(name);
assert_se(fd >= 0);
assert_se(write(fd, env_file_6, strlen(env_file_6)) == strlen(env_file_6));
r = load_env_file(NULL, name, &data);
assert_se(r == 0);
_cleanup_strv_free_ char **data = NULL;
assert_se(load_env_file(NULL, name, &data) == 0);
assert_se(streq(data[0], "a= n t x y '"));
assert_se(streq(data[1], "b=$'"));
assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n"));

View File

@ -1117,7 +1117,7 @@ typedef struct test_entry {
#define entry(x) {x, #x}
static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) {
static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@ -1239,11 +1239,11 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
if (r != 0)
return r;
r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
if (r != 0)
return r;
@ -1265,11 +1265,11 @@ int main(int argc, char *argv[]) {
can_unshare = false;
r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
if (r != 0)
return r;
return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
#else
return 0;
#endif

View File

@ -109,8 +109,7 @@ TEST(parse_env_file) {
"eleven", &eleven,
"twelve", &twelve,
"thirteen", &thirteen);
assert_se(r >= 0);
assert_se(r == 0);
log_info("one=[%s]", strna(one));
log_info("two=[%s]", strna(two));

File diff suppressed because it is too large Load Diff

View File

@ -32,13 +32,13 @@ int main(int argc, char* argv[]) {
test_setup_logging(LOG_DEBUG);
h = hashmap_new(&string_hash_ops);
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL);
assert_se(r == 0);
HASHMAP_FOREACH(p, h) {
UnitFileState s = _UNIT_FILE_STATE_INVALID;
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(p->path), &s);
assert_se((r < 0 && p->state == UNIT_FILE_BAD) ||
(p->state == s));
@ -52,18 +52,18 @@ int main(int argc, char* argv[]) {
log_info("/*** enable **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
log_info("/*** enable2 **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
@ -71,13 +71,13 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
@ -85,16 +85,16 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
log_info("/*** mask2 ***/");
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
@ -102,16 +102,16 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
log_info("/*** unmask2 ***/");
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
@ -119,13 +119,13 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
@ -133,16 +133,16 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
log_info("/*** disable2 ***/");
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
@ -150,13 +150,13 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
@ -164,13 +164,13 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
@ -178,26 +178,26 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
@ -205,26 +205,26 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
@ -232,13 +232,13 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
r = unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
@ -246,25 +246,25 @@ int main(int argc, char* argv[]) {
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
log_info("/*** preset files ***/");
changes = NULL;
n_changes = 0;
r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes);
r = unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes);
assert_se(r >= 0);
dump_changes(changes, n_changes);
unit_file_changes_free(changes, n_changes);
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state);
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files[0]), &state);
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);

View File

@ -42,7 +42,7 @@ TEST_RET(unit_file_get_set) {
h = hashmap_new(&string_hash_ops);
assert_se(h);
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL);
if (IN_SET(r, -EPERM, -EACCES))
return log_tests_skipped_errno(r, "unit_file_get_list");
@ -101,7 +101,7 @@ TEST(config_parse_exec) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(unit_freep) Unit *u = NULL;
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;
@ -445,7 +445,7 @@ TEST(config_parse_log_extra_fields) {
_cleanup_(unit_freep) Unit *u = NULL;
ExecContext c = {};
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;
@ -510,59 +510,74 @@ TEST(install_printf, .sd_booted = true) {
assert_se(user = uid_to_name(getuid()));
assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
#define expect(src, pattern, result) \
#define expect(scope, src, pattern, result) \
do { \
_cleanup_free_ char *t = NULL; \
_cleanup_free_ char \
*d1 = strdup(i.name), \
*d2 = strdup(i.path); \
assert_se(install_name_printf(&src, pattern, NULL, &t) >= 0 || !result); \
_cleanup_free_ char *t = NULL, \
*d1 = ASSERT_PTR(strdup(i.name)), \
*d2 = ASSERT_PTR(strdup(i.path)); \
int r = install_name_printf(scope, &src, pattern, &t); \
assert_se(result ? r >= 0 : r < 0); \
memzero(i.name, strlen(i.name)); \
memzero(i.path, strlen(i.path)); \
assert_se(d1 && d2); \
if (result) { \
printf("%s\n", t); \
assert_se(streq(t, result)); \
} else assert_se(t == NULL); \
} else \
assert_se(!t); \
strcpy(i.name, d1); \
strcpy(i.path, d2); \
} while (false)
expect(i, "%n", "name.service");
expect(i, "%N", "name");
expect(i, "%p", "name");
expect(i, "%i", "");
expect(i, "%j", "name");
expect(i, "%g", group);
expect(i, "%G", gid);
expect(i, "%u", user);
expect(i, "%U", uid);
expect(LOOKUP_SCOPE_SYSTEM, i, "%n", "name.service");
expect(LOOKUP_SCOPE_SYSTEM, i, "%N", "name");
expect(LOOKUP_SCOPE_SYSTEM, i, "%p", "name");
expect(LOOKUP_SCOPE_SYSTEM, i, "%i", "");
expect(LOOKUP_SCOPE_SYSTEM, i, "%j", "name");
expect(LOOKUP_SCOPE_SYSTEM, i, "%g", "root");
expect(LOOKUP_SCOPE_SYSTEM, i, "%G", "0");
expect(LOOKUP_SCOPE_SYSTEM, i, "%u", "root");
expect(LOOKUP_SCOPE_SYSTEM, i, "%U", "0");
expect(i, "%m", mid);
expect(i, "%b", bid);
expect(i, "%H", host);
expect(LOOKUP_SCOPE_SYSTEM, i, "%m", mid);
expect(LOOKUP_SCOPE_SYSTEM, i, "%b", bid);
expect(LOOKUP_SCOPE_SYSTEM, i, "%H", host);
expect(i2, "%g", group);
expect(i2, "%G", gid);
expect(i2, "%u", user);
expect(i2, "%U", uid);
expect(LOOKUP_SCOPE_SYSTEM, i2, "%g", "root");
expect(LOOKUP_SCOPE_SYSTEM, i2, "%G", "0");
expect(LOOKUP_SCOPE_SYSTEM, i2, "%u", "root");
expect(LOOKUP_SCOPE_SYSTEM, i2, "%U", "0");
expect(i3, "%n", "name@inst.service");
expect(i3, "%N", "name@inst");
expect(i3, "%p", "name");
expect(i3, "%g", group);
expect(i3, "%G", gid);
expect(i3, "%u", user);
expect(i3, "%U", uid);
expect(LOOKUP_SCOPE_USER, i2, "%g", group);
expect(LOOKUP_SCOPE_USER, i2, "%G", gid);
expect(LOOKUP_SCOPE_USER, i2, "%u", user);
expect(LOOKUP_SCOPE_USER, i2, "%U", uid);
expect(i3, "%m", mid);
expect(i3, "%b", bid);
expect(i3, "%H", host);
/* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called,
* even though the call is inside of a conditional where the pointer is checked. :( */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
expect(LOOKUP_SCOPE_GLOBAL, i2, "%g", NULL);
expect(LOOKUP_SCOPE_GLOBAL, i2, "%G", NULL);
expect(LOOKUP_SCOPE_GLOBAL, i2, "%u", NULL);
expect(LOOKUP_SCOPE_GLOBAL, i2, "%U", NULL);
#pragma GCC diagnostic pop
expect(i4, "%g", group);
expect(i4, "%G", gid);
expect(i4, "%u", user);
expect(i4, "%U", uid);
expect(LOOKUP_SCOPE_SYSTEM, i3, "%n", "name@inst.service");
expect(LOOKUP_SCOPE_SYSTEM, i3, "%N", "name@inst");
expect(LOOKUP_SCOPE_SYSTEM, i3, "%p", "name");
expect(LOOKUP_SCOPE_USER, i3, "%g", group);
expect(LOOKUP_SCOPE_USER, i3, "%G", gid);
expect(LOOKUP_SCOPE_USER, i3, "%u", user);
expect(LOOKUP_SCOPE_USER, i3, "%U", uid);
expect(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid);
expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid);
expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host);
expect(LOOKUP_SCOPE_USER, i4, "%g", group);
expect(LOOKUP_SCOPE_USER, i4, "%G", gid);
expect(LOOKUP_SCOPE_USER, i4, "%u", user);
expect(LOOKUP_SCOPE_USER, i4, "%U", uid);
}
static uint64_t make_cap(int cap) {
@ -791,7 +806,7 @@ TEST(config_parse_unit_env_file) {
_cleanup_strv_free_ char **files = NULL;
int r;
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;
@ -924,7 +939,7 @@ TEST(unit_is_recursive_template_dependency) {
Unit *u;
int r;
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;

View File

@ -2,8 +2,11 @@
#include <errno.h>
#include "fs-util.h"
#include "log.h"
#include "os-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
TEST(path_is_os_tree) {
@ -12,4 +15,61 @@ TEST(path_is_os_tree) {
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
TEST(parse_os_release) {
/* Let's assume that we're running in a valid system, so os-release is available */
_cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL;
assert_se(parse_os_release(NULL, "ID", &id) == 0);
log_info("ID: %s", id);
assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
assert_se(parse_os_release(NULL, "ID", &id2) == 0);
log_info("ID: %s", strnull(id2));
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
assert_se(write_tmpfile(tmpfile,
"ID=the-id \n"
"NAME=the-name") == 0);
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
_cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX";
assert_se(write_tmpfile(tmpfile2,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
"NAME='the-name'") == 0);
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0);
assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0);
log_info("FOOBAR: %s", strnull(foobar));
assert_se(foobar == NULL);
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
}
TEST(load_os_release_pairs) {
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
assert_se(write_tmpfile(tmpfile,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
"NAME='the-name'") == 0);
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
_cleanup_strv_free_ char **pairs = NULL;
assert_se(load_os_release_pairs(NULL, &pairs) == 0);
assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id",
"NAME", "the-name")));
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -11,7 +11,7 @@
#include "tests.h"
#include "tmpfile-util.h"
static void test_paths_one(UnitFileScope scope) {
static void test_paths_one(LookupScope scope) {
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
_cleanup_(lookup_paths_free) LookupPaths lp_without_env = {};
_cleanup_(lookup_paths_free) LookupPaths lp_with_env = {};
@ -34,9 +34,9 @@ static void test_paths_one(UnitFileScope scope) {
}
TEST(paths) {
test_paths_one(UNIT_FILE_SYSTEM);
test_paths_one(UNIT_FILE_USER);
test_paths_one(UNIT_FILE_GLOBAL);
test_paths_one(LOOKUP_SCOPE_SYSTEM);
test_paths_one(LOOKUP_SCOPE_USER);
test_paths_one(LOOKUP_SCOPE_GLOBAL);
}
TEST(user_and_global_paths) {
@ -48,8 +48,8 @@ TEST(user_and_global_paths) {
assert_se(unsetenv("XDG_DATA_DIRS") == 0);
assert_se(unsetenv("XDG_CONFIG_DIRS") == 0);
assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0);
assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0);
assert_se(lookup_paths_init(&lp_global, LOOKUP_SCOPE_GLOBAL, 0, NULL) == 0);
assert_se(lookup_paths_init(&lp_user, LOOKUP_SCOPE_USER, 0, NULL) == 0);
g = lp_global.search_path;
u = lp_user.search_path;
@ -70,7 +70,7 @@ TEST(user_and_global_paths) {
log_info("+ %s", *p);
}
static void test_generator_binary_paths_one(UnitFileScope scope) {
static void test_generator_binary_paths_one(LookupScope scope) {
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
_cleanup_strv_free_ char **gp_without_env = NULL;
_cleanup_strv_free_ char **env_gp_without_env = NULL;
@ -85,13 +85,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0);
gp_without_env = generator_binary_paths(scope);
env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
env_gp_without_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false);
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
STRV_FOREACH(dir, gp_without_env)
log_info(" %s", *dir);
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
STRV_FOREACH(dir, env_gp_without_env)
log_info(" %s", *dir);
@ -104,13 +104,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0);
gp_with_env = generator_binary_paths(scope);
env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
env_gp_with_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false);
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
STRV_FOREACH(dir, gp_with_env)
log_info(" %s", *dir);
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
STRV_FOREACH(dir, env_gp_with_env)
log_info(" %s", *dir);
@ -119,8 +119,8 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
}
TEST(generator_binary_paths) {
test_generator_binary_paths_one(UNIT_FILE_SYSTEM);
test_generator_binary_paths_one(UNIT_FILE_USER);
test_generator_binary_paths_one(LOOKUP_SCOPE_SYSTEM);
test_generator_binary_paths_one(LOOKUP_SCOPE_USER);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -33,7 +33,7 @@ static int setup_test(Manager **m) {
if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available");
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
if (manager_errno_skip_test(r))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);

View File

@ -30,7 +30,7 @@ int main(int argc, char *argv[]) {
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (manager_errno_skip_test(r))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);

View File

@ -135,7 +135,7 @@ int main(int argc, char *argv[]) {
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0);

View File

@ -228,17 +228,12 @@ TEST(passfd_read) {
if (r == 0) {
/* Child */
char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX";
_cleanup_close_ int tmpfd = -1;
pair[0] = safe_close(pair[0]);
tmpfd = mkostemp_safe(tmpfile);
assert_se(tmpfd >= 0);
assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents));
tmpfd = safe_close(tmpfd);
char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX";
assert_se(write_tmpfile(tmpfile, file_contents) == 0);
tmpfd = open(tmpfile, O_RDONLY);
_cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY);
assert_se(tmpfd >= 0);
assert_se(unlink(tmpfile) == 0);
@ -277,16 +272,12 @@ TEST(passfd_contents_read) {
/* Child */
struct iovec iov = IOVEC_INIT_STRING(wire_contents);
char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX";
_cleanup_close_ int tmpfd = -1;
pair[0] = safe_close(pair[0]);
tmpfd = mkostemp_safe(tmpfile);
assert_se(tmpfd >= 0);
assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents));
tmpfd = safe_close(tmpfd);
assert_se(write_tmpfile(tmpfile, file_contents) == 0);
tmpfd = open(tmpfile, O_RDONLY);
_cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY);
assert_se(tmpfd >= 0);
assert_se(unlink(tmpfile) == 0);

View File

@ -8,6 +8,7 @@
#include "string-util.h"
#include "strv.h"
#include "tests.h"
#include "unit-file.h"
static void test_specifier_escape_one(const char *a, const char *b) {
_cleanup_free_ char *x = NULL;
@ -46,7 +47,7 @@ TEST(specifier_escape_strv) {
static const Specifier specifier_table[] = {
COMMON_SYSTEM_SPECIFIERS,
COMMON_CREDS_SPECIFIERS,
COMMON_CREDS_SPECIFIERS(LOOKUP_SCOPE_USER),
{ 'h', specifier_user_home, NULL },
COMMON_TMP_SPECIFIERS,
@ -138,4 +139,18 @@ TEST(specifiers) {
}
}
TEST(specifiers_missing_data_ok) {
_cleanup_free_ char *resolved = NULL;
assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) >= 0);
assert_se(streq(resolved, "-----"));
assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0);
assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -EUNATCH);
assert_se(streq(resolved, "-----"));
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -18,6 +18,30 @@
#include "tests.h"
#include "tmpfile-util.h"
TEST(null_or_empty_path) {
assert_se(null_or_empty_path("/dev/null") == 1);
assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */
assert_se(null_or_empty_path("../../../../../../../../../../../../../../../../../../../../dev/null") == 1);
assert_se(null_or_empty_path("/proc/self/exe") == 0);
assert_se(null_or_empty_path("/nosuchfileordir") == -ENOENT);
}
TEST(null_or_empty_path_with_root) {
assert_se(null_or_empty_path_with_root("/dev/null", NULL) == 1);
assert_se(null_or_empty_path_with_root("/dev/null", "/") == 1);
assert_se(null_or_empty_path_with_root("/dev/null", "/.././../") == 1);
assert_se(null_or_empty_path_with_root("/dev/null", "/.././..") == 1);
assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", NULL) == 1);
assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", "/") == 1);
assert_se(null_or_empty_path_with_root("/proc/self/exe", NULL) == 0);
assert_se(null_or_empty_path_with_root("/proc/self/exe", "/") == 0);
assert_se(null_or_empty_path_with_root("/nosuchfileordir", NULL) == -ENOENT);
assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././../") == -ENOENT);
assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././..") == -ENOENT);
assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar") == 1);
assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar/") == 1);
}
TEST(files_same) {
_cleanup_close_ int fd = -1;
char name[] = "/tmp/test-files_same.XXXXXX";

View File

@ -8,20 +8,20 @@
#include "unit-file.h"
TEST(unit_validate_alias_symlink_and_warn) {
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0);
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL);
assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.service") == 0);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.foobar") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.service") == 0);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@YYY.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@XXX.service") == 0);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@.service") == 0);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b@.service") == -EXDEV);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.slice", "/other/b.slice") == -EINVAL);
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.slice", "/other/b.slice") == -EINVAL);
}
TEST(unit_file_build_name_map) {
@ -35,7 +35,7 @@ TEST(unit_file_build_name_map) {
ids = strv_skip(saved_argv, 1);
assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0);
assert_se(lookup_paths_init(&lp, LOOKUP_SCOPE_SYSTEM, 0, NULL) >= 0);
assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1);

View File

@ -228,7 +228,7 @@ TEST_RET(unit_printf, .sd_booted = true) {
assert_se(get_home_dir(&home) >= 0);
assert_se(get_shell(&shell) >= 0);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r == 0);

View File

@ -31,7 +31,7 @@ TEST(deserialize_exec_command) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;

View File

@ -26,7 +26,7 @@ int main(int argc, char *argv[]) {
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
assert_se(a = unit_new(m, sizeof(Service)));

View File

@ -204,31 +204,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret);
static int specifier_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret);
static const Specifier specifier_table[] = {
{ 'a', specifier_architecture, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'B', specifier_os_build_id, NULL },
{ 'H', specifier_host_name, NULL },
{ 'l', specifier_short_host_name, NULL },
{ 'm', specifier_machine_id_safe, NULL },
{ 'o', specifier_os_id, NULL },
{ 'v', specifier_kernel_release, NULL },
{ 'w', specifier_os_version_id, NULL },
{ 'W', specifier_os_variant_id, NULL },
{ 'h', specifier_user_home, NULL },
{ 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
{ 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
{ 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
{ 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
COMMON_CREDS_SPECIFIERS,
COMMON_TMP_SPECIFIERS,
{}
};
static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
int r;
@ -2737,7 +2712,7 @@ static bool should_include_path(const char *path) {
return false;
}
static int specifier_expansion_from_arg(Item *i) {
static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *i) {
int r;
assert(i);
@ -2944,6 +2919,30 @@ static int parse_line(
assert(line >= 1);
assert(buffer);
const Specifier specifier_table[] = {
{ 'a', specifier_architecture, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'B', specifier_os_build_id, NULL },
{ 'H', specifier_host_name, NULL },
{ 'l', specifier_short_host_name, NULL },
{ 'm', specifier_machine_id_safe, NULL },
{ 'o', specifier_os_id, NULL },
{ 'v', specifier_kernel_release, NULL },
{ 'w', specifier_os_version_id, NULL },
{ 'W', specifier_os_variant_id, NULL },
{ 'h', specifier_user_home, NULL },
{ 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
{ 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
{ 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
{ 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
COMMON_CREDS_SPECIFIERS(arg_user ? LOOKUP_SCOPE_USER : LOOKUP_SCOPE_SYSTEM),
COMMON_TMP_SPECIFIERS,
{}
};
r = extract_many_words(
&buffer,
NULL,
@ -3148,7 +3147,7 @@ static int parse_line(
if (!should_include_path(i.path))
return 0;
r = specifier_expansion_from_arg(&i);
r = specifier_expansion_from_arg(specifier_table, &i);
if (r == -ENXIO)
return log_unresolvable_specifier(fname, line);
if (r < 0) {

View File

@ -35,6 +35,7 @@
#include "device-monitor-private.h"
#include "device-private.h"
#include "device-util.h"
#include "errno-list.h"
#include "event-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -157,11 +158,15 @@ typedef struct Worker {
/* passed from worker to main process */
typedef enum EventResult {
EVENT_RESULT_SUCCESS,
EVENT_RESULT_FAILED,
EVENT_RESULT_TRY_AGAIN, /* when the block device is locked by another process. */
EVENT_RESULT_NERRNO_MIN = -ERRNO_MAX,
EVENT_RESULT_NERRNO_MAX = -1,
EVENT_RESULT_EXIT_STATUS_BASE = 0,
EVENT_RESULT_EXIT_STATUS_MAX = 255,
EVENT_RESULT_TRY_AGAIN = 256, /* when the block device is locked by another process. */
EVENT_RESULT_SIGNAL_BASE = 257,
EVENT_RESULT_SIGNAL_MAX = EVENT_RESULT_SIGNAL_BASE + _NSIG,
_EVENT_RESULT_MAX,
_EVENT_RESULT_INVALID = -EINVAL,
_EVENT_RESULT_INVALID = -EINVAL,
} EventResult;
static Event *event_free(Event *event) {
@ -356,7 +361,7 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda
return 1;
}
static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, int result) {
int r;
assert(dev);
@ -365,13 +370,40 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
if (!monitor)
return;
if (result != 0) {
(void) device_add_property(dev, "UDEV_WORKER_FAILED", "1");
switch (result) {
case EVENT_RESULT_NERRNO_MIN ... EVENT_RESULT_NERRNO_MAX:
(void) device_add_propertyf(dev, "UDEV_WORKER_ERRNO", "%i", -result);
(void) device_add_propertyf(dev, "UDEV_WORKER_ERRNO_NAME", "%s", strna(errno_to_name(result)));
break;
case EVENT_RESULT_EXIT_STATUS_BASE ... EVENT_RESULT_EXIT_STATUS_MAX:
(void) device_add_propertyf(dev, "UDEV_WORKER_EXIT_STATUS", "%i", result - EVENT_RESULT_EXIT_STATUS_BASE);
break;
case EVENT_RESULT_TRY_AGAIN:
assert_not_reached();
break;
case EVENT_RESULT_SIGNAL_BASE ... EVENT_RESULT_SIGNAL_MAX:
(void) device_add_propertyf(dev, "UDEV_WORKER_SIGNAL", "%i", result - EVENT_RESULT_SIGNAL_BASE);
(void) device_add_propertyf(dev, "UDEV_WORKER_SIGNAL_NAME", "%s", strna(signal_to_string(result - EVENT_RESULT_SIGNAL_BASE)));
break;
default:
log_device_warning(dev, "Unknown event result \"%i\", ignoring.", result);
}
}
r = device_monitor_send_device(monitor, NULL, dev);
if (r < 0)
log_device_warning_errno(dev, r,
"Failed to broadcast event to libudev listeners, ignoring: %m");
}
static int worker_send_result(Manager *manager, EventResult result) {
static int worker_send_result(Manager *manager, int result) {
assert(manager);
assert(manager->worker_watch[WRITE_END] >= 0);
@ -536,6 +568,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
*
* The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING */
r = worker_lock_block_device(dev, &fd_lock);
if (r == -EAGAIN)
return EVENT_RESULT_TRY_AGAIN;
if (r < 0)
return r;
@ -568,29 +602,25 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
Manager *manager = userdata;
EventResult result;
int r;
assert(dev);
assert(manager);
r = worker_process_device(manager, dev);
if (r == -EAGAIN) {
if (r == EVENT_RESULT_TRY_AGAIN)
/* if we couldn't acquire the flock(), then requeue the event */
result = EVENT_RESULT_TRY_AGAIN;
log_device_debug_errno(dev, r, "Block device is currently locked, requeueing the event.");
} else if (r < 0) {
result = EVENT_RESULT_FAILED;
log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m");
} else
result = EVENT_RESULT_SUCCESS;
log_device_debug(dev, "Block device is currently locked, requeueing the event.");
else {
if (r < 0)
log_device_warning_errno(dev, r, "Failed to process device, ignoring: %m");
if (result != EVENT_RESULT_TRY_AGAIN)
/* send processed event back to libudev listeners */
device_broadcast(monitor, dev);
device_broadcast(monitor, dev, r);
}
/* send udevd the result of the event execution */
r = worker_send_result(manager, result);
r = worker_send_result(manager, r);
if (r < 0)
log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m");
@ -1150,7 +1180,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
assert(manager);
for (;;) {
EventResult result;
int result;
struct iovec iovec = IOVEC_MAKE(&result, sizeof(result));
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
struct msghdr msghdr = {
@ -1174,7 +1204,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
cmsg_close_all(&msghdr);
if (size != sizeof(EventResult)) {
if (size != sizeof(result)) {
log_warning("Ignoring worker message with invalid size %zi bytes", size);
continue;
}
@ -1201,7 +1231,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
/* worker returned */
if (result == EVENT_RESULT_TRY_AGAIN &&
event_requeue(worker->event) < 0)
device_broadcast(manager->monitor, worker->event->dev);
device_broadcast(manager->monitor, worker->event->dev, -ETIMEDOUT);
/* When event_requeue() succeeds, worker->event is NULL, and event_free() handles NULL gracefully. */
event_free(worker->event);
@ -1543,7 +1573,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
device_tag_index(worker->event->dev, NULL, false);
/* Forward kernel event to libudev listeners */
device_broadcast(manager->monitor, worker->event->dev);
device_broadcast(manager->monitor, worker->event->dev,
WIFEXITED(status) ? EVENT_RESULT_EXIT_STATUS_BASE + WEXITSTATUS(status):
WIFSIGNALED(status) ? EVENT_RESULT_SIGNAL_BASE + WTERMSIG(status) : 0);
}
worker_free(worker);

View File

@ -88,6 +88,7 @@ endif
test_fstab_generator_sh = find_program('test-fstab-generator.sh')
test_network_generator_conversion_sh = find_program('test-network-generator-conversion.sh')
test_systemctl_enable_sh = find_program('test-systemctl-enable.sh')
test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py')
hwdb_test_sh = find_program('hwdb-test.sh')

View File

@ -0,0 +1,694 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -ex
# Silence warning from running_in_chroot_or_offline()
export SYSTEMD_IGNORE_CHROOT=1
systemctl=${1:-systemctl}
systemd_id128=${2:-systemd-id128}
unset root
cleanup() {
[ -n "$root" ] && rm -rf "$root"
}
trap cleanup exit
root=$(mktemp -d --tmpdir systemctl-test.XXXXXX)
islink() {
test -h "$1" || return 1
test "$(readlink "$1")" = "$2" || return 2
}
: '------enable nonexistent------------------------------------'
( ! "$systemctl" --root="$root" enable test1.service )
: '------basic enablement--------------------------------------'
mkdir -p "$root/etc/systemd/system"
cat >"$root/etc/systemd/system/test1.service" <<EOF
[Install]
WantedBy=default.target
RequiredBy=special.target
EOF
"$systemctl" --root="$root" enable test1.service
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" reenable test1.service
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" disable test1.service
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
: '------enable when link already exists-----------------------'
# We don't read the symlink target, so it's OK for the symlink to point
# to something else. We should just silently accept this.
mkdir -p "$root/etc/systemd/system/default.target.wants"
mkdir -p "$root/etc/systemd/system/special.target.requires"
ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/default.target.wants/test1.service"
ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" enable test1.service
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" reenable test1.service
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" disable test1.service
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
: '------suffix guessing---------------------------------------'
"$systemctl" --root="$root" enable test1
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" reenable test1
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
"$systemctl" --root="$root" disable test1
test ! -e "$root/etc/systemd/system/default.target.wants/test1.service"
test ! -e "$root/etc/systemd/system/special.target.requires/test1.service"
: '-------aliases----------------------------------------------'
cat >>"$root/etc/systemd/system/test1.service" <<EOF
Alias=test1-goodalias.service
Alias=test1@badalias.service
Alias=test1-badalias.target
Alias=test1-badalias.socket
# we have a series of good, bad, and then good again
Alias=test1-goodalias2.service
EOF
( ! "$systemctl" --root="$root" enable test1 )
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
test -e "$root/etc/systemd/system/test1-goodalias.service"
test -h "$root/etc/systemd/system/test1-goodalias.service"
test ! -h "$root/etc/systemd/system/test1@badalias.service"
test ! -h "$root/etc/systemd/system/test1-badalias.target"
test ! -h "$root/etc/systemd/system/test1-badalias.socket"
test -e "$root/etc/systemd/system/test1-goodalias2.service"
test -h "$root/etc/systemd/system/test1-goodalias2.service"
: '-------aliases in reeanble----------------------------------'
( ! "$systemctl" --root="$root" reenable test1 )
islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service"
islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service"
test ! -h "$root/etc/systemd/system/test1@badalias.service"
test ! -h "$root/etc/systemd/system/test1-badalias.target"
test ! -h "$root/etc/systemd/system/test1-badalias.socket"
"$systemctl" --root="$root" disable test1
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
test ! -h "$root/etc/systemd/system/test1-goodalias.service"
: '-------aliases when link already exists---------------------'
cat >"$root/etc/systemd/system/test1a.service" <<EOF
[Install]
Alias=test1a-alias.service
EOF
ln -s /usr/lib/systemd/system/test1a.service "$root/etc/systemd/system/test1a-alias.service"
"$systemctl" --root="$root" enable test1a.service
test -h "$root/etc/systemd/system/test1a-alias.service"
"$systemctl" --root="$root" disable test1a.service
test ! -h "$root/etc/systemd/system/test1a-alias.service"
: '-------also units-------------------------------------------'
cat >"$root/etc/systemd/system/test2.socket" <<EOF
[Install]
WantedBy=sockets.target
Also=test2.service
EOF
cat >"$root/etc/systemd/system/test2.service" <<EOF
[Install]
WantedBy=default.target
Also=test2.socket
EOF
"$systemctl" --root="$root" reenable test2.service
test -h "$root/etc/systemd/system/default.target.wants/test2.service"
test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
"$systemctl" --root="$root" reenable test2.socket
test -h "$root/etc/systemd/system/default.target.wants/test2.service"
test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
"$systemctl" --root="$root" disable test2.socket
test ! -e "$root/etc/systemd/system/default.target.wants/test2.service"
test ! -e "$root/etc/systemd/system/sockets.target.wants/test2.socket"
: '-------link-------------------------------------------------'
# File doesn't exist yet
test ! -e "$root/link1.path"
( ! "$systemctl" --root="$root" link '/link1.path' )
test ! -e "$root/etc/systemd/system/link1.path"
cat >"$root/link1.path" <<EOF
[Install]
WantedBy=paths.target
EOF
"$systemctl" --root="$root" link '/link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
: '-------link already linked same path------------------------'
SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" link '/link1.path' # this passes
islink "$root/etc/systemd/system/link1.path" "/link1.path"
: '-------link already linked different path-------------------'
mkdir "$root/subdir"
cp "$root/link1.path" "$root/subdir/"
( ! "$systemctl" --root="$root" link '/subdir/link1.path' )
islink "$root/etc/systemd/system/link1.path" "/link1.path"
: '-------link bad suffix--------------------------------------'
cp "$root/link1.path" "$root/subdir/link1.suffix"
( ! "$systemctl" --root="$root" link '/subdir/link1.suffix' )
test ! -e "$root/etc/systemd/system/link1.suffix"
: '-------unlink by unit name----------------------------------'
"$systemctl" --root="$root" disable 'link1.path'
test ! -e "$root/etc/systemd/system/link1.path"
: '-------unlink by path---------------------------------------'
"$systemctl" --root="$root" link '/link1.path'
test -h "$root/etc/systemd/system/link1.path"
"$systemctl" --root="$root" disable '/link1.path'
test ! -e "$root/etc/systemd/system/link1.path"
: '-------unlink by wrong path---------------------------------'
"$systemctl" --root="$root" link '/link1.path'
test -h "$root/etc/systemd/system/link1.path"
"$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name
test ! -e "$root/etc/systemd/system/link1.path"
: '-------link and enable--------------------------------------'
"$systemctl" --root="$root" enable '/link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
: '-------enable already linked same path----------------------'
"$systemctl" --root="$root" enable '/link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
: '-------enable already linked different path-----------------'
( ! "$systemctl" --root="$root" enable '/subdir/link1.path' )
islink "$root/etc/systemd/system/link1.path" "/link1.path"
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
: '-------enable bad suffix------------------------------------'
cp "$root/link1.path" "$root/subdir/link1.suffix"
( ! "$systemctl" --root="$root" enable '/subdir/link1.suffix' )
test ! -e "$root/etc/systemd/system/link1.suffix"
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix"
: '-------disable by unit name---------------------------------'
"$systemctl" --root="$root" disable 'link1.path'
test ! -e "$root/etc/systemd/system/link1.path"
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path"
: '-------disable by path--------------------------------------'
"$systemctl" --root="$root" enable '/link1.path'
test -h "$root/etc/systemd/system/link1.path"
test -h "$root/etc/systemd/system/paths.target.wants/link1.path"
"$systemctl" --root="$root" disable '/link1.path'
test ! -e "$root/etc/systemd/system/link1.path"
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path"
: '-------link and enable-------------------------------------'
"$systemctl" --root="$root" link '/link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path"
"$systemctl" --root="$root" enable 'link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
"$systemctl" --root="$root" reenable 'link1.path'
islink "$root/etc/systemd/system/link1.path" "/link1.path"
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
: '-------manual link------------------------------------------'
cat >"$root/link3.suffix" <<EOF
[Install]
WantedBy=services.target
EOF
# We wouldn't create such a link ourselves, but it should accept it when present.
ln -s "/link3.suffix" "$root/etc/systemd/system/link3.service"
SYSTEMD_LOG_LEVEL=debug SYSTEMD_LOG_LOCATION=1 "$systemctl" --root="$root" enable 'link3.service'
islink "$root/etc/systemd/system/link3.service" "/link3.suffix"
islink "$root/etc/systemd/system/services.target.wants/link3.service" "../link3.service"
SYSTEMD_LOG_LEVEL=debug SYSTEMD_LOG_LOCATION=1 "$systemctl" --root="$root" disable 'link3.service'
test ! -h "$root/etc/systemd/system/link3.service"
test ! -h "$root/etc/systemd/system/services.target.wants/link3.service"
: '-------enable on masked-------------------------------------'
ln -s "/dev/null" "$root/etc/systemd/system/masked.service"
( ! "$systemctl" --root="$root" enable 'masked.service' )
( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' )
: '-------enable on masked alias-------------------------------'
test -h "$root/etc/systemd/system/masked.service"
ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service"
( ! "$systemctl" --root="$root" enable 'masked-alias.service' )
( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' )
: '-------issue 22000: link in subdirectory--------------------'
mkdir -p "$root/etc/systemd/system/myown.d"
cat >"$root/etc/systemd/system/link5-also.service" <<EOF
[Install]
WantedBy=services.target
Also=link5.service
EOF
cat >"$root/etc/systemd/system/myown.d/link5.service" <<EOF
[Install]
WantedBy=services.target
Also=link5-also.service
EOF
( ! "$systemctl" --root="$root" enable 'link5.service' )
test ! -h "$root/etc/systemd/system/services.target.wants/link5.service"
test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service"
"$systemctl" --root="$root" enable 'link5-also.service'
test ! -h "$root/etc/systemd/system/services.target.wants/link5.service"
islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "../link5-also.service"
: '-------template enablement----------------------------------'
cat >"$root/etc/systemd/system/templ1@.service" <<EOF
[Install]
WantedBy=services.target
EOF
# No instance here — this can't succeed.
( ! "$systemctl" --root="$root" enable 'templ1@.service' )
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
"$systemctl" --root="$root" enable 'templ1@one.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
"$systemctl" --root="$root" enable 'templ1@two.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
"$systemctl" --root="$root" disable 'templ1@one.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
"$systemctl" --root="$root" disable 'templ1@two.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
: '-------template enablement w/ default instance--------------'
cat >"$root/etc/systemd/system/templ1@.service" <<EOF
[Install]
# check enablement with
WantedBy=services.target services.target
RequiredBy=other@templ1.target other@%p.target
DefaultInstance=333
EOF
"$systemctl" --root="$root" enable 'templ1@.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
"$systemctl" --root="$root" enable 'templ1@one.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
"$systemctl" --root="$root" enable 'templ1@two.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
"$systemctl" --root="$root" disable 'templ1@one.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service"
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
# disable remaining links here
"$systemctl" --root="$root" disable 'templ1@.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@333.service"
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service"
: '-------removal of relative enablement symlinks--------------'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service"
ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service"
ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service"
ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service"
ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service"
ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service"
ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
# this should remove all links
"$systemctl" --root="$root" disable 'templ1@.service'
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service"
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
: '-------template enablement for another template-------------'
cat >"$root/etc/systemd/system/templ2@.service" <<EOF
[Install]
RequiredBy=another-template@.target
EOF
"$systemctl" --root="$root" enable 'templ2@.service'
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
"$systemctl" --root="$root" enable 'templ2@two.service'
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
"$systemctl" --root="$root" disable 'templ2@other.service'
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
"$systemctl" --root="$root" disable 'templ2@two.service'
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service"
"$systemctl" --root="$root" disable 'templ2@.service'
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@.service"
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service"
: '-------aliases w/ and w/o instance--------------------------'
test ! -e "$root/etc/systemd/system/link4.service"
cat >"$root/etc/systemd/system/link4.service" <<EOF
[Install]
Alias=link4.service
Alias=link4@.service
Alias=link4@inst.service
Alias=link4alias.service
Alias=link4alias2.service
EOF
( ! "$systemctl" --root="$root" enable 'link4.service' )
test ! -h "$root/etc/systemd/system/link4.service" # this is our file
test ! -h "$root/etc/systemd/system/link4@.service"
test ! -h "$root/etc/systemd/system/link4@inst.service"
islink "$root/etc/systemd/system/link4alias.service" "link4.service"
islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
"$systemctl" --root="$root" disable 'link4.service'
test ! -h "$root/etc/systemd/system/link4.service"
test ! -h "$root/etc/systemd/system/link4@.service"
test ! -h "$root/etc/systemd/system/link4@inst.service"
test ! -h "$root/etc/systemd/system/link4alias.service"
test ! -h "$root/etc/systemd/system/link4alias2.service"
: '-------systemctl enable on path to unit file----------------'
cat >"$root/etc/systemd/system/link4.service" <<EOF
[Install]
Alias=link4alias.service
Alias=link4alias2.service
EOF
# Apparently this works. I'm not sure what to think.
"$systemctl" --root="$root" enable '/etc/systemd/system/link4.service'
test ! -h "$root/etc/systemd/system/link4.service" # this is our file
islink "$root/etc/systemd/system/link4alias.service" "link4.service"
islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
"$systemctl" --root="$root" disable '/etc/systemd/system/link4.service'
test ! -h "$root/etc/systemd/system/link4.service"
test ! -h "$root/etc/systemd/system/link4alias.service"
test ! -h "$root/etc/systemd/system/link4alias2.service"
: '-------issue 661: enable on unit file--------------'
test ! -e "$root/etc/systemd/system/link5.service"
cat >"$root/etc/systemd/system/link5.service" <<EOF
[Install]
Alias=link5.service
Alias=link5alias.service
Alias=link5alias2.service
EOF
"$systemctl" --root="$root" enable 'link5.service'
test ! -h "$root/etc/systemd/system/link5.service" # this is our file
islink "$root/etc/systemd/system/link5alias.service" "link5.service"
islink "$root/etc/systemd/system/link5alias2.service" "link5.service"
"$systemctl" --root="$root" disable 'link5.service'
test ! -h "$root/etc/systemd/system/link5alias.service"
test ! -h "$root/etc/systemd/system/link5alias2.service"
: '-------issue 661: link and enable on unit file--------------'
test ! -e "$root/etc/systemd/system/link5copy.service"
cat >"$root/link5copy.service" <<EOF
[Install]
Alias=link5copy.service
Alias=link5alias.service
Alias=link5alias2.service
EOF
test ! -e "$root/etc/systemd/system/link5copy.service"
"$systemctl" --root="$root" link '/link5copy.service'
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
test ! -h "$root/etc/systemd/system/link5alias.service"
test ! -h "$root/etc/systemd/system/link5alias2.service"
"$systemctl" --root="$root" disable 'link5copy.service'
test ! -h "$root/etc/systemd/system/link5copy.service"
test ! -h "$root/etc/systemd/system/link5alias.service"
test ! -h "$root/etc/systemd/system/link5alias2.service"
"$systemctl" --root="$root" enable '/link5copy.service'
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
islink "$root/etc/systemd/system/link5alias.service" 'link5copy.service'
islink "$root/etc/systemd/system/link5alias2.service" 'link5copy.service'
"$systemctl" --root="$root" disable 'link5copy.service'
test ! -h "$root/etc/systemd/system/link5copy.service"
test ! -h "$root/etc/systemd/system/link5alias.service"
test ! -h "$root/etc/systemd/system/link5alias2.service"
: '----issue 19437: plain templates in .wants/ or .requires/---'
test ! -e "$root/etc/systemd/system/link5@.path"
cat >"$root/etc/systemd/system/link5@.path" <<EOF
[Install]
WantedBy=target5@.target
RequiredBy=target5@.target
WantedBy=target5@inst.target
RequiredBy=target5@inst.target
EOF
"$systemctl" --root="$root" enable 'link5@.path'
test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
islink "$root/etc/systemd/system/target5@.target.wants/link5@.path" "../link5@.path"
islink "$root/etc/systemd/system/target5@.target.requires/link5@.path" "../link5@.path"
islink "$root/etc/systemd/system/target5@inst.target.wants/link5@.path" "../link5@.path"
islink "$root/etc/systemd/system/target5@inst.target.requires/link5@.path" "../link5@.path"
"$systemctl" --root="$root" disable 'link5@.path'
test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
test ! -h "$root/etc/systemd/system/target5@.target.wants/link5@.path"
test ! -h "$root/etc/systemd/system/target5@.target.requires/link5@.path"
test ! -h "$root/etc/systemd/system/target5@inst.target.wants/link5@.path"
test ! -h "$root/etc/systemd/system/target5@inst.target.requires/link5@.path"
: '-------removal of symlinks not listed in [Install]----------'
# c.f. 66a19d85a533b15ed32f4066ec880b5a8c06babd
test ! -e "$root/etc/systemd/system/multilink.mount"
cat >"$root/etc/systemd/system/multilink.mount" <<EOF
[Install]
WantedBy=multilink.target
EOF
mkdir -p "$root/etc/systemd/system/default.target.wants"
ln -s ../multilink.mount "$root/etc/systemd/system/default.target.wants/"
ln -s ../multilink.mount "$root/etc/systemd/system/multilink-alias.mount"
ln -s ../multilink.mount "$root/etc/systemd/system/multilink-badalias.service"
"$systemctl" --root="$root" disable 'multilink.mount'
test -e "$root/etc/systemd/system/multilink.mount" # this is our file
test ! -h "$root/etc/systemd/system/default.target.wants/"
test ! -h "$root/etc/systemd/system/multilink-alias.mount"
test ! -h "$root/etc/systemd/system/multilink-badalias.service"
: '-------merge 20017: specifiers in the unit file-------------'
test ! -e "$root/etc/systemd/system/some-some-link6@.socket"
# c.f. de61a04b188f81a85cdb5c64ddb4987dcd9d30d3
check_alias() {
: "------------------ %$1 -------------------------------------"
cat >"$root/etc/systemd/system/some-some-link6@.socket" <<EOF
[Install]
Alias=target@$1:%$1.socket
EOF
SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" enable 'some-some-link6@.socket' || return 1
islink "$root/etc/systemd/system/target@$1:$2.socket" "some-some-link6@.socket" || return 2
}
# TODO: our architecture names are different than what uname -m returns.
# Add something like 'systemd-detect-virt --print-architecture' and use it here.
check_alias a "$(uname -m | tr '_' '-')" || :
test ! -e "$root/etc/os-release"
test ! -e "$root/usr/lib/os-release"
( ! check_alias A '' )
( ! check_alias B '' )
( ! check_alias M '' )
( ! check_alias o '' )
( ! check_alias w '' )
( ! check_alias W '' )
cat >"$root/etc/os-release" <<EOF
# empty
EOF
check_alias A ''
check_alias B ''
check_alias M ''
check_alias o ''
check_alias w ''
check_alias W ''
cat >"$root/etc/os-release" <<EOF
ID='the-id'
VERSION_ID=39a
BUILD_ID=build-id
VARIANT_ID=wrong
VARIANT_ID=right
IMAGE_ID="foobar"
IMAGE_VERSION='1-2-3'
EOF
check_alias A '1-2-3'
check_alias B 'build-id'
check_alias M 'foobar'
check_alias o 'the-id'
check_alias w '39a'
check_alias W 'right'
check_alias b "$("$systemd_id128" boot-id)"
# Specifiers not available for [Install]
( ! check_alias C '' )
( ! check_alias E '' )
( ! check_alias f '' )
( ! check_alias h '' )
( ! check_alias I '' )
( ! check_alias J '' )
( ! check_alias L '' )
( ! check_alias P '' )
( ! check_alias s '' )
( ! check_alias S '' )
( ! check_alias t '' )
( ! check_alias T '' )
( ! check_alias V '' )
check_alias g root
check_alias G 0
check_alias u root
check_alias U 0
check_alias i ""
check_alias j 'link6'
check_alias l "$(uname -n | sed 's/\..*//')"
test ! -e "$root/etc/machine-id"
( ! check_alias m '' )
"$systemd_id128" new >"$root/etc/machine-id"
check_alias m "$(cat "$root/etc/machine-id")"
check_alias n 'some-some-link6@.socket'
check_alias N 'some-some-link6@'
check_alias p 'some-some-link6'
uname -r | grep -q '[^a-zA-Z0-9_.\\-]' || \
check_alias v "$(uname -r)"
# % is not legal in unit name
( ! check_alias % '%' )
# %z is not defined
( ! check_alias z 'z' )
: '-------specifiers in WantedBy-------------------------------'
# We don't need to repeat all the tests. Let's do a basic check that specifier
# expansion is performed.
cat >"$root/etc/systemd/system/some-some-link7.socket" <<EOF
[Install]
WantedBy=target@%p.target
WantedBy=another-target@.target
RequiredBy=target2@%p.target
RequiredBy=another-target2@.target
EOF
"$systemctl" --root="$root" enable 'some-some-link7.socket'
islink "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket" "../some-some-link7.socket"
islink "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket" "../some-some-link7.socket"
islink "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket" "../some-some-link7.socket"
islink "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket" "../some-some-link7.socket"
"$systemctl" --root="$root" disable 'some-some-link7.socket'
test ! -h "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket"
test ! -h "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket"
test ! -h "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket"
test ! -h "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket"
# TODO: repeat the tests above for presets
: '-------SYSTEMD_OS_RELEASE relative to root-------------------'
# check that os-release overwriting works as expected with root
test -e "$root/etc/os-release"
cat >"$root/etc/os-release2" <<EOF
ID='the-id2'
EOF
SYSTEMD_OS_RELEASE="$root/etc/os-release2" check_alias o 'the-id2'

View File

@ -98,13 +98,13 @@ def test_valid_specifiers(*, user):
test_content('f {} - - - - %b', '{}'.format(id128.get_boot().hex), user=user)
test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user)
test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user)
test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user)
test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user)
test_content('f {} - - - - %U', '{}'.format(os.getuid() if user else 0), user=user)
test_content('f {} - - - - %G', '{}'.format(os.getgid() if user else 0), user=user)
puser = pwd.getpwuid(os.getuid())
puser = pwd.getpwuid(os.getuid() if user else 0)
test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user)
pgroup = grp.getgrgid(os.getgid())
pgroup = grp.getgrgid(os.getgid() if user else 0)
test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user)
# Note that %h is the only specifier in which we look the environment,

View File

@ -3,6 +3,7 @@
set -ex
test_rule="/run/udev/rules.d/49-test.rules"
KILL_PID=
setup() {
mkdir -p "${test_rule%/*}"
@ -22,18 +23,37 @@ EOF
teardown() {
set +e
if [[ -n "$KILL_PID" ]]; then
kill "$KILL_PID"
fi
rm -rf "$TMPDIR"
mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf
rm -f "$test_rule"
systemctl restart systemd-udevd.service
}
run_test() {
local since
since="$(date '+%F %T')"
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX)
udevadm monitor --udev --property --subsystem-match=mem >"$TMPDIR"/monitor.txt &
KILL_PID="$!"
for _ in {1..20}; do
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --action add /dev/null
for _ in {1..40}; do
if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then
kill "$KILL_PID"
KILL_PID=
cat "$TMPDIR"/monitor.txt
grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt
grep -q 'UDEV_WORKER_SIGNAL=6' "$TMPDIR"/monitor.txt
grep -q 'UDEV_WORKER_SIGNAL_NAME=ABRT' "$TMPDIR"/monitor.txt
return 0
fi
sleep .5

View File

@ -3,7 +3,8 @@
set -eu
tag="$(git describe --abbrev=0 --match 'v[0-9][0-9][0-9]')"
git log --pretty=tformat:%aN --author=noreply@weblate.org --invert-grep -s "${tag}.." | \
git log --pretty=tformat:%aN -s "${tag}.." |
grep -v noreply@weblate.org |
sed 's/ / /g; s/--/-/g; s/.*/\0,/' |
sort -u | tr '\n' ' ' | sed -e "s/^/Contributions from: /g" -e "s/,\s*$/\n/g" | fold -w 72 -s | \
sort -u | tr '\n' ' ' | sed -e "s/^/Contributions from: /g" -e "s/,\s*$/\n/g" | fold -w 72 -s |
sed -e "s/^/ /g" -e "s/\s*$//g"