1
0
mirror of https://github.com/systemd/systemd synced 2026-03-11 23:54:46 +01:00

Compare commits

...

84 Commits

Author SHA1 Message Date
Luca Boccassi
907952bbc9 portabled: add --extension parameter for layered images support
Add an --extension parameter to portablectl, and new DBUS methods
to attach/detach/reattach/inspect.
Allows to append separate images on top of the root directory (os-release
will be searched in there) and mount the images using an overlay-like
setup (unit files will be searched in there) using the new ExtensionImages
service option.
2021-03-31 09:56:44 +01:00
Luca Boccassi
248b1e0aa4 gcrypt: do not ignore return values
Check the return code from gcrypt's functions. In some
cases just log, as it shoulnd't really happen.

Fixes various Coverity issues:

CID #1444702
CID #1444704
CID #1444706
CID #1444711
CID #1444712
CID #1444713
2021-03-31 10:51:35 +02:00
Zbigniew Jędrzejewski-Szmek
a59eb7d78f rpm: when disabling a unit, do not complain if systemd is not running
$ sudo dnf remove --installroot=/var/tmp/img1 systemd-networkd
...
  Running scriptlet: systemd-networkd-248~rc4-4.fc32.x86_64      1/1
Removed /etc/systemd/system/multi-user.target.wants/systemd-networkd.service.
Removed /etc/systemd/system/sockets.target.wants/systemd-networkd.socket.
Removed /etc/systemd/system/dbus-org.freedesktop.network1.service.
Removed /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service.
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

(Another option would be make --now do nothing if systemd is not running.
But I think that's not too good. 'disable --now' doing nothing would be OK,
since if systemd is not running, the service is not running either, so we are
in the desired state. But that argument doesn't work for 'enable --now'. And
accepting 'disable --now' but not 'enable --now' seems overly complex. So I
think it is better to make the scriptlet handle this case explicitly.)

Also, let's reindent the file to 4 spaces. Very deeply nested scriptlets are
harder to read, and the triggers file is indented to 4 spaces already.
2021-03-31 10:50:07 +02:00
Jan Janssen
a83ddc08d6 resolved.conf: Add hostnames for default DNS servers 2021-03-31 10:49:36 +02:00
Deepak Rawat
0d96caa5c0 logind: Add new flag for kexec reboot
Add new flag to allow kexec reboot if kernel is already loaded.
2021-03-31 10:48:48 +02:00
Zbigniew Jędrzejewski-Szmek
a93af34a40
Merge pull request #19109 from poettering/resolved-transaction-log-tweaks
resolved: minor tweaks to transaction logic and logging
2021-03-31 10:47:12 +02:00
Lennart Poettering
9a515f0a55 shared: add new IMAGE_VERSION=/IMAGE_ID= field to /etc/os-release
This specifes two new optional fields for /etc/os-release:
IMAGE_VERSION= and IMAGE_ID= that are supposed to identify the image of
the current booted system by name and version.

This is inspired by the versioning stuff in
https://github.com/systemd/mkosi/pull/683.

In environments where pre-built images are installed and updated as a
whole the existing os-release version/distro identifier are not
sufficient to describe the system's version, as they describe only the
distro an image is built from, but not the image itself, even if that
image is deployed many times on many systems, and even if that image
contains more resources than just the RPMs/DEBs.

In particular, "mkosi" is a tool for building disk images based on
distro RPMs with additional resources dropped in. The combination of all
of these together with their versions should also carry an identifier
and version, and that's what IMAGE_VERSION= and IMAGE_ID= is supposed to
be.
2021-03-31 10:46:22 +02:00
Zbigniew Jędrzejewski-Szmek
e872679629
Merge pull request #19064 from yuwata/resolve-fix-cache-19049
resolve: several trivial cleanups
2021-03-31 10:42:21 +02:00
gaoyi
f257a8fc13 udevd: don't kill worker in manager_kill_workers when it's running
If worker is running, kill worker may lead uevent unprocessed.
2021-03-31 10:41:44 +02:00
Zbigniew Jędrzejewski-Szmek
a2dc3adef2
Merge pull request #18990 from yuwata/network-dhcpv6-use-domains
network: also introduce UseDomains= for [DHCPv6] section
2021-03-31 10:38:37 +02:00
Lennart Poettering
16ede1d75a
Merge pull request #19101 from poettering/mount-util-fixes
Make recursive bind remounting handle failures gracefully
2021-03-31 10:37:49 +02:00
Lennart Poettering
27ec815eb4 dissect: make the --image= switch of our various tools honour Verity data
This adds simple Verity support to
mount_image_privately_interactively(): we dicover the verity metadata
and use it.
2021-03-31 10:36:14 +02:00
Zbigniew Jędrzejewski-Szmek
224e6c844d
Merge pull request #18989 from yuwata/ordered-set-put-strdup
ordered-set: make ordered_set_put_strdup() allocate OrderedSet object
2021-03-31 10:36:03 +02:00
Lennart Poettering
6020d00d7e repart: make sure CopyFiles= works with a / suffixed path
If we define a partition with CopyFiles=/efi/ this should just work.
However it previously didn't because basename() would return the
trailing slash.

Let's fix this by moving things to path_extract_{directory|filename}()
2021-03-31 10:35:45 +02:00
Lennart Poettering
e0b4bc239f machine-id-setup: support --image= mode 2021-03-31 10:35:31 +02:00
Lennart Poettering
f9d8325e69
Merge pull request #18971 from poettering/sysusers-creds
let's read LoadCredentials=/SetCredentials= style cred in sysusers/firstboot and when asking for passwords
2021-03-31 10:35:17 +02:00
Zbigniew Jędrzejewski-Szmek
4c31bfdf55
Merge pull request #18982 from keszybz/test-nss-users
Add a new test for user/group resolution in nss modules
2021-03-31 10:32:09 +02:00
Zbigniew Jędrzejewski-Szmek
b880ac2c15
Merge pull request #18958 from poettering/dissect-no-root
dissect-image: support images without rootfs but with /usr partition + support simple partition versioning via strverscmp() on part label
2021-03-31 10:31:32 +02:00
Luca Boccassi
834bab01f9 compress: support streaming lz4 without full input mmap
The advantage of stream compression is keeping a low memory profile,
but the lz4 stream compressor usage mmaps the whole file in memory.

Change it to read bits by bits, like the other stream compression
helpers.
2021-03-31 10:29:36 +02:00
Zbigniew Jędrzejewski-Szmek
bcceabcfc2
Merge pull request #18886 from anitazha/shutdownconsole
logging shutdown to /dev/console
2021-03-31 10:28:26 +02:00
Zbigniew Jędrzejewski-Szmek
87f9300d71
Merge pull request #18850 from yuwata/sd-device-monitor-cleanups
sd-device-monitor: trivial cleanups
2021-03-31 10:27:06 +02:00
Henri Chain
cb0e818f7c Introduce ExitType 2021-03-31 10:26:07 +02:00
Zbigniew Jędrzejewski-Szmek
82a335db83
Merge pull request #18777 from yuwata/network-set-ifname-to-engines
network: set ifname to dhcp4 client or friends
2021-03-31 10:25:23 +02:00
Lennart Poettering
9f17a03ae8 update TODO 2021-03-26 12:22:17 +01:00
Lennart Poettering
8806bb4bc7 ask-password: when querying for a password, try to read from credential store first
This adds generic support for the SetCredential=/LoadCredential= logic
to our password querying infrastructure: if a password is requested by a
program that has a credential store configured via
$CREDENTIALS_DIRECTORY we'll look in it for a password.

The "systemd-ask-password" tool is updated with an option to specify the
credential to look for.
2021-03-26 12:21:56 +01:00
Lennart Poettering
f6ab6199a2 man: document in nspawn docs how to make use of the new firstboot/sysusers features 2021-03-26 12:21:37 +01:00
Lennart Poettering
416f7b3a11 firstboot: allow provisioning of firstboot params via creds too 2021-03-26 12:21:18 +01:00
Lennart Poettering
f8fd093001 firstboot: slightly reorder variable declaration
Let's put the locale fields which we process together next to each
other.
2021-03-26 12:21:14 +01:00
Lennart Poettering
361662f434 units: make sure to query console settings before we apply them 2021-03-26 12:21:11 +01:00
Lennart Poettering
99e9f896fb sysusers: read passwords from the credentials logic
Let's make use of our own credentials infrastructure in our tools: let's
hook up systemd-sysusers with the credentials logic, so that the root
password can be provisioned this way. This is really useful when working
with stateless systems, in particular nspawn's "--volatile=yes" switch,
as this works now:

 # systemd-nspawn -i foo.raw --volatile=yes --set-credential=passwd.plaintext-password:foo

For the first time we have a nice, non-interactive way to provision the
root password for a fully stateless system from the container manager.
Yay!
2021-03-26 12:20:52 +01:00
Lennart Poettering
fc682be261 core: when inheriting credentials from manager to service, make missing creds graceful
Let's be a bit less strict when setting up credentials: if the service
manager didn't receieve a cred, and we shall propagate it down via
LoadCredentials= don't fail. Fail on all other errors though, as before,
and on explicitly listed paths.
2021-03-26 12:20:48 +01:00
Lennart Poettering
8a29862e32 core: allow omitting second part of LoadCredentials= argument
This allows "LoadCredentials=foo" to be used as shortcut for
"LoadCredentials=foo:foo", i.e. it's a very short way to inherit a
credential under its original name from the service manager into a
service.
2021-03-26 12:20:29 +01:00
Lennart Poettering
786d19fd1b util: add creds-util.[ch] with helpers for dealing with credentials 2021-03-26 12:19:31 +01:00
Lennart Poettering
67d22a3665 test: add explicit test for bind_remount_one_with_mountinfo() 2021-03-26 11:51:26 +01:00
Lennart Poettering
10cdbb8372 test: add test for bind_remount_recursive() 2021-03-26 11:51:26 +01:00
Lennart Poettering
0338df47cf mount-util: generate failure if bind_remount_one_with_mountinfo() is called on non-existing path 2021-03-26 11:51:26 +01:00
Lennart Poettering
b23c6a6411 mount-util: handle remount failures gracefully if flags already match
In bind_remount_one_with_mountinfo() let's handle mount failures
gracefully if the flags already match anyway. This isn't perfect, since
it mixes up superblock and mount point flags, but it's close enough.
2021-03-26 11:51:26 +01:00
Lennart Poettering
2c5ff8ea76 mount-util: fold what we need from get_mount_flags() bind_remount_one_with_mountinfo()
And get rid of get_mount_flags() altogether.

(This drops the statvfs() fallback that get_mount_flags() did. That
fallback was incomplete however, and mostly hid errors. Our primary
avenue to get mount flags is /proc/self/mountinfo and we should trust
it, and fix bugs we might encounter with it, but not tape over it.
Dropping the fallback is relevant in particular as it actually returned
mount flags for any path, not just mount points, which was very icky.)
2021-03-26 11:51:26 +01:00
Lennart Poettering
ba8dced2a6 mount-util: store mount flags in "todo" list in + handle submounts gracefully
This replaces the "todo" set with a "todo" hash map that stores the
mount flags we found. This makes an explicit call to get_mount_flags()
unncessary, since we have the flags handy right-away, and lowers our
work from O(n^2) to O(n). Nice!

The "done" set is also improved slightly: we'll use more modern ways to
allocate it, via set_ensure_consume(), and freeing-via-hash_ops.

Finally, failures on submount remounts are now handled gracefully,
there are just too many reasons why they might fail, given NFS, autofs,
FUSE which weird access controls, where even root might lack the privs
to do something.

Fixes: #16156
2021-03-26 11:51:26 +01:00
Lennart Poettering
4b6ef52756 mount-util: extend comment a bit, mention that we aren't atomic in behaviour 2021-03-26 11:39:37 +01:00
Lennart Poettering
5c5753b9ea mount-util: shortcut things after generating top-level bind mount
Instead of marking the bind mount read-only right-away, let's just
restart the loop, so that we'll pick it up like any other mount and then
remount like that.
2021-03-26 11:39:37 +01:00
Lennart Poettering
d6bfab118d mount-util: reorder a few things
Let's always query one property, check it, and then query the next,
preferring "cheap" ones over "slow" ones (i.e. cheap are the ones we can
check directly, and slow are the ones we need to check with some loop of
some kind).
2021-03-26 11:39:37 +01:00
Lennart Poettering
c6111b85f7 path: drop simplification of path in bind_remount_recursive_with_mountinfo()
We only use path-aware comparisons and hashops, hence no need to
simplify, we can use the path as it is.
2021-03-26 11:39:37 +01:00
Lennart Poettering
670e8efd60 mount-until: make sure we'll exit bind_remount_recursive_with_mountinfo() loop eventually
Just some robustness given that /proc/self/mountinfo was previously
broken in the kernel.
2021-03-26 11:39:37 +01:00
Lennart Poettering
9d0619dee7 mountpoint-util: rebreak some comments 2021-03-26 11:39:37 +01:00
Lennart Poettering
b898474fec mountpoint-util: a symlink is never a mount point
The various flavours of stat() basically tell us for free if something
is a symlink. If it is, then it's definitely not a mount point. Use
that.

All other inode types can be mount point, just symlinks cannot.
2021-03-26 11:39:37 +01:00
Lennart Poettering
981318d2b5 test-namespace: drop spurious double new line 2021-03-26 11:39:37 +01:00
Lennart Poettering
6d660692f2 resolved: use sd_event_add_time_relative() where appropriate 2021-03-26 11:38:04 +01:00
Lennart Poettering
213cb4f7e4 resolved: reset initial_jitter_elapsed properly
This fixes resetting of initial_jitter_elapsed: the first time the timer
hits after initial_jitter_scheduled is set we need to mark things as
elapsed.

(Also improve log messages around this while we are at it)
2021-03-26 11:38:01 +01:00
Lennart Poettering
2f9c3b2ab4 resolved: mention transaction ID in jitter log message 2021-03-26 11:37:57 +01:00
Lennart Poettering
9ee18bf473 resolved: use random_u64_range() for randomizing initial transaction jitter 2021-03-26 11:37:54 +01:00
Lennart Poettering
ca55fb8840 resolved: don't mention confusing server switch on server-less protocols 2021-03-26 11:37:49 +01:00
Zbigniew Jędrzejewski-Szmek
f0cb09bb0f test-nss-hosts: make buffer size configurable too and document it 2021-03-23 14:14:08 +01:00
Zbigniew Jędrzejewski-Szmek
e2aa384bcd test-nss-hosts: use _cleanup_, fix return value, assert on allocations 2021-03-23 14:14:08 +01:00
Zbigniew Jędrzejewski-Szmek
f0d1266821 test-nss-users: add new nss test that resolves users and groups
Inspired by https://bugzilla.redhat.com/show_bug.cgi?id=1929936.
This is similar to test-nss-hosts, but does users, groups, uid, gids.

Functions tested are:
_nss_*_getpwnam_r
_nss_*_getgrnam_r
_nss_*_getpwgid_r
_nss_*_getgrgid_r

Other entry points should be tested too, but it's not relevant to the bug
I was investigating, so I'm leaving that for later ;)
2021-03-23 14:14:08 +01:00
Yu Watanabe
9fffe0a912 resolve: dns_answer_contains() does not return negative errno 2021-03-23 21:30:23 +09:00
Yu Watanabe
06939d3b0c resolve: use dns_answer_size() and dns_answer_isempty() 2021-03-23 21:30:23 +09:00
Yu Watanabe
ae526a5ea5 resolve: rename function argument in prototype to match its declaration 2021-03-23 21:30:23 +09:00
Yu Watanabe
160f3145db resolve: drop doubled white space 2021-03-23 21:30:23 +09:00
Yu Watanabe
8e95506a22 resolve: drop meaningless bitfield specifier
This also rearrange the members to remove holes in the struct.
2021-03-23 21:30:23 +09:00
Lennart Poettering
e6ba912a1a update TODO 2021-03-16 14:58:00 +01:00
Lennart Poettering
df27f1dbca doc: mention that choosing root/usr partitions by strverscmp() on the partition label is OK 2021-03-16 14:57:56 +01:00
Lennart Poettering
1474d7ac2d dissect: show partition label in table
We nowadays pick up the partition label while dissecting, let's show it
if we have it.
2021-03-16 14:57:53 +01:00
Lennart Poettering
166ff7316e dissect: don't insist on a root/usr partition when just inspecting
Let's relax rules here a bit, taking benefit of the fact that
DISSECT_IMAGE_REQUIRE_ROOT + DISSECT_IMAGE_GENERIC_ROOT are now separate
flags.
2021-03-16 14:57:49 +01:00
Lennart Poettering
9cb1709b72 execute: drop DissectImageFlags parameter from namespace_setup()
The function already has a ridiculous amount of paramaters, let's drop
one that is either not used at all or has a constant value and let's
pick it internally.
2021-03-16 14:57:45 +01:00
Lennart Poettering
4b5de5dd6c dissect-image: split DISSECT_IMAGE_REQUIRE_ROOT in two
Previously, the flag did two things at once: enable support for using
generic partitions as root fs if there were only one/allow use of
partition-table-less images as root fs. And secondly, insist that there
was a rootfs, and fail if not. Let's split these two in two separate
options so that they can be used independently of each other.

There are cases where one wants to use one without the other (i.e. when
inspecting things with systemd-dissect tool it should be OK to do so
even if image has no root fs), and it's cleaner anyway.
2021-03-16 14:57:40 +01:00
Lennart Poettering
2679f40735 dissect-image: extend comment on returned errors a bit 2021-03-16 14:57:36 +01:00
Lennart Poettering
08fe0a5386 dissect-image: do an strverscmp() on the partition label of root/usr if multiple exist
Let's add a very simple mechanism for doing A/B updating of disk images:
for root + /usr and their verity partitions let's ue strverscmp() on the
label to determine which one to use when dissecting a disk image. That
way, if the root partition label contains a string such as "foo-0.15"
and another one "foo-0.16", the latter wins.

For other partition types let's stick to the logic of "first partition
found" win, as before. Versioning makes sense for partitions that
typically and primarily may carry software packages, but the other
partition types usuall don't.
2021-03-16 14:57:31 +01:00
Lennart Poettering
d04faa4e19 tree-wide: make use of DISSECT_IMAGE_USR_NO_ROOT in various tools
Let's make use of the new dissection in all tools where this makes
sense, which are all tools that dissect images, except for those which
inherently operate on state/configuraiton and thus where an image
without state nor configuration is useless (e.g.
systemd-tmpfiles/systemd-firstboot/… --image= switch).
2021-03-16 14:57:27 +01:00
Lennart Poettering
7cf660302f dissect-image: support images without rootfs but with /usr/
Let's add support for images that include an /usr/ file system but no
root fs. Mount a tmpfs as root for images like this, all controlled by a
new flag DISSECT_IMAGE_USR_NO_ROOT.

This is useful for entirely stateless images, that come up pristine on
every single boot.
2021-03-16 14:56:48 +01:00
Yu Watanabe
6e4571f0c2 network: use string_hash_ops_free 2021-03-14 00:39:10 +09:00
Yu Watanabe
cf45350745 ordered-set: make ordered_set_put_strdup() allocate OrderedSet object
For consistency with set_put_strdup().
2021-03-14 00:39:05 +09:00
Yu Watanabe
f225a338c3 network: also introduce UseDomains= for [DHCPv6] section
When we split [DHCP] section into [DHCPv4] and [DHCPv6], UseDomains=
setting was forgot to be introduced in [DHCPv6] section.
2021-03-14 00:28:19 +09:00
Yu Watanabe
5b7f0aaf69 network: use userdata instead data in conf parsers
These takes no offset, so should not change any behavior.
2021-03-14 00:24:48 +09:00
Zbigniew Jędrzejewski-Szmek
3f9721fef0 Rename test-nss to test-nss-hosts 2021-03-12 14:37:36 +01:00
Anita Zhang
016f36ae72 shutdown: log on container exit 2021-03-04 20:08:26 -08:00
Anita Zhang
f975f1cc74 shutdown: set always_reopen_console
Back in v232 systemd-shutdown would log to /dev/console. However after
the addition of always_reopen_console (v233) it would log to STDERR.
This caused some debugging issues as container systemd-shutdown logs
weren't being logged to console as the arg `--log-target=console` suggested.

Since it appears that always_reopen_console was intended for pid1, set
it in systemd-shutdown as well so logs will go to /dev/console.
2021-03-04 20:08:00 -08:00
Yu Watanabe
30e2c8c7e8 sd-device-enumerator: add comments why trivial_hash_ops_free_free is used
Follow-up for a0887abbd8bd9f1a9a975af08e6b4a43960bb3e2.
2021-03-05 06:39:33 +09:00
Yu Watanabe
7117842657 sd-device-monitor: use hashmap_put_strdup_full() 2021-03-05 06:37:30 +09:00
Yu Watanabe
0fa28efea6 sd-device-monitor: use UINT64_C() macro 2021-03-05 06:35:24 +09:00
Yu Watanabe
79c397a12e sd-device-monitor: use assert() in non-public functions 2021-03-05 06:35:24 +09:00
Yu Watanabe
a7d757ec29 dhcp6: tighten T1 and T2 value check
Only when T1 and T2 are both 0, they are adjusted later based on
address or prefix T1 and T2. So the first check must be changed.
2021-03-04 05:51:56 +09:00
Yu Watanabe
353887831b libsystemd-network: make log_dhcp_client() or friends include interface name 2021-03-04 05:51:28 +09:00
Yu Watanabe
61a9fa8f0c libsystemd-network: introduce sd_xxx_{set,get}_ifname() 2021-03-04 05:24:54 +09:00
162 changed files with 3417 additions and 1204 deletions

14
TODO
View File

@ -61,11 +61,6 @@ Features:
With all that in place if nspawn host and container payload are up-to-date
enough we have a very simple way to make host users available in containers.
* systemd-sysusers: pick up passwords from credentials logic, so that users can
easily set root user pw. enable cred inheriting for root user from PID 1, so
that for containers we can configure the root pw automatically via nspawn's
--set-credential= switch. (Also do this for systemd-firstboot)
* whenever we receive fds via SCM_RIGHTS make sure none got dropped due to the
reception limit the kernel silently enforces.
@ -321,12 +316,6 @@ Features:
* busctl: maybe expose a verb "ping" for pinging a dbus service to see if it
exists and responds.
* when systemd-nspawn and suchlike dissect an OS image, and there are multiple
root partitions, do an strverscmp() on the partition label and boot
first. That is inspired how sd-boot figures out which kernel to boot, and
thus allows defining OS images which can be A/B updated and we default to the
newest version automatically, both in nspawn and in sd-boot
* systemd-gpt-auto should probably set x-systemd.growfs on the mounts it
creates
@ -848,9 +837,6 @@ Features:
* journalctl: make sure -f ends when the container indicated by -M terminates
* mount: automatically search for "main" partition of an image has multiple
partitions
* in nss-systemd, if we run inside of RootDirectory= with PrivateUsers= set,
find a way to map the User=/Group= of the service to the right name. This way
a user/group for a service only has to exist on the host for the right

View File

@ -162,7 +162,14 @@ partition is listed in `/etc/fstab` or with `root=` on the kernel command line,
it _must_ take precedence over automatically discovered partitions. If a
`/home/`, `/usr/`, `/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/`
directory is found to be populated already in the root partition, the automatic
discovery _must not_ mount any discovered file system over it.
discovery _must not_ mount any discovered file system over it. Optionally, in
case of the root, `/usr/` and their Verity partitions instead of strictly
mounting the first suitable partition an OS might choose to mount the partition
whose label compares the highest according to `strverscmp()` or a similar
logic, in order to implement a simple partition-based A/B versioning
scheme. The precise rules are left for the implementation to decide, but when
in doubt earlier partitions (by their index) should always win over later
partitions if the label comparison is inconclusive.
A *container* *manager* should automatically discover and mount the root,
`/usr/`, `/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container

View File

@ -198,11 +198,6 @@ All tools:
prefixed with `:` in which case the kernel command line option takes
precedence, if it is specified as well.
installed systemd tests:
* `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if
a test executable is moved to an arbitrary location.
`nss-systemd`:
* `$SYSTEMD_NSS_BYPASS_SYNTHETIC=1` — if set, `nss-systemd` won't synthesize
@ -302,6 +297,14 @@ installed systemd tests:
* `$SYSTEMD_SYSVRCND_PATH` — Controls where `systemd-sysv-generator` looks for
SysV init script runlevel link farms.
systemd tests:
* `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if
a test executable is moved to an arbitrary location.
* `$SYSTEMD_TEST_NSS_BUFSIZE` — size of scratch buffers for "reentrant"
functions exported by the nss modules.
fuzzers:
* `$SYSTEMD_FUZZ_OUTPUT` — A boolean that specifies whether to write output to

View File

@ -303,6 +303,7 @@ Most service unit settings are available for transient units.
✓ ExecStartPre=
✓ ExecStop=
✓ ExecStopPost=
✓ ExitType=
✓ FileDescriptorStoreMax=
✓ GuessMainPID=
✓ NonBlocking=

View File

@ -555,10 +555,13 @@ node /org/freedesktop/login1 {
extendability, defined as follows:</para>
<programlisting>
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) &lt;&lt; 0)
#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) &lt;&lt; 1)
</programlisting>
<para> When the <varname>flags</varname> is 0 then these methods behave just like the versions
without flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active
inhibitors are honoured for privileged users too.</para>
inhibitors are honoured for privileged users too. When <constant>SD_LOGIND_KEXEC_REBOOT</constant>
(0x02) is set, then <function>RebootWithFlags()</function> perform kexec reboot if kexec
kernel is loaded.</para>
<para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation.
See the description of <command>reboot</command> in

View File

@ -48,6 +48,13 @@ node /org/freedesktop/portable1 {
out s image,
out ay os_release,
out a{say} units);
GetImageMetadataWithExtensions(in s image,
in as extensions,
in as matches,
in t flags,
out s image,
out ay os_release,
out a{say} units);
GetImageState(in s image,
out s state);
AttachImage(in s image,
@ -56,9 +63,20 @@ node /org/freedesktop/portable1 {
in b runtime,
in s copy_mode,
out a(sss) changes);
AttachImageWithExtensions(in s image,
in as extensions,
in as matches,
in s profile,
in s copy_mode,
in t flags,
out a(sss) changes);
DetachImage(in s image,
in b runtime,
out a(sss) changes);
DetachImageWithExtensions(in s image,
in as extensions,
in t flags,
out a(sss) changes);
ReattachImage(in s image,
in as matches,
in s profile,
@ -66,6 +84,14 @@ node /org/freedesktop/portable1 {
in s copy_mode,
out a(sss) changes_removed,
out a(sss) changes_updated);
ReattachImageWithExtensions(in s image,
in as extensions,
in as matches,
in s profile,
in s copy_mode,
in t flags,
out a(sss) changes_removed,
out a(sss) changes_updated);
RemoveImage(in s image);
MarkImageReadOnly(in s image,
in b read_only);
@ -102,14 +128,22 @@ node /org/freedesktop/portable1 {
<variablelist class="dbus-method" generated="True" extra-ref="GetImageMetadata()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetImageMetadataWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetImageState()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachImage()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachImageWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DetachImage()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DetachImageWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="ReattachImage()"/>
<variablelist class="dbus-method" generated="True" extra-ref="ReattachImageWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="RemoveImage()"/>
<variablelist class="dbus-method" generated="True" extra-ref="MarkImageReadOnly()"/>
@ -149,6 +183,12 @@ node /org/freedesktop/portable1 {
and a list of portable units contained in the image, in the form of a string (unit name) and
an array of bytes with the content.</para>
<para><function>GetImageMetadataWithExtensions()</function> retrieves metadata associated with an image.
This method is a superset of <function>GetImageMetadata()</function> with the addition of
a list of extensions as input parameter, which were overlayed on top of the main
image via <function>AttachImageWithExtensions()</function>.
The <varname>flag</varname> parameter is currently unused and reserved for future purposes.</para>
<para><function>GetImageState()</function> retrieves the image state as one of the following
strings:
<itemizedlist>
@ -197,6 +237,16 @@ node /org/freedesktop/portable1 {
Note that an image cannot be attached if a unit that it contains is already present
on the system.</para>
<para><function>AttachImageWithExtensions()</function> attaches a portable image to the system.
This method is a superset of <function>AttachImage()</function> with the addition of
a list of extensions as input parameter, which will be overlayed on top of the main
image. When this method is used, detaching must be done by passing the same arguments via the
<function>DetachImageWithExtensions()</function> method. For more details on this functionality,
see the <varname>MountImages=</varname> entry on
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
The <varname>flag</varname> parameter is currently unused and reserved for future purposes.</para>
<para><function>DetachImage()</function> detaches a portable image from the system.
This method takes an image path or name, and a boolean indicating whether the image to
detach was attached only for the current boot session or persistently. This method
@ -209,6 +259,12 @@ node /org/freedesktop/portable1 {
</itemizedlist>
Note that an image cannot be detached if a unit that it contains is running.</para>
<para><function>DetachImageWithExtensions()</function> detaches a portable image from the system.
This method is a superset of <function>DetachImage()</function> with the addition of
a list of extensions as input parameter, which were overlayed on top of the main
image via <function>AttachImageWithExtensions()</function>.
The <varname>flag</varname> parameter is currently unused and reserved for future purposes.</para>
<para><function>ReattachImage()</function> combines the effects of the
<function>AttachImage()</function> method and the <function>DetachImage()</function> method.
The difference is that it is allowed to reattach an image while one or more of its units
@ -218,6 +274,14 @@ node /org/freedesktop/portable1 {
<function>DetachImage()</function> method (first array, units that were removed) and the
<function>AttachImage()</function> method (second array, units that were updated or added).</para>
<para><function>ReattachImageWithExtensions()</function> reattaches a portable image to the system.
This method is a superset of <function>ReattachImage()</function> with the addition of
a list of extensions as input parameter, which will be overlayed on top of the main
image. For more details on this functionality, see the <varname>MountImages=</varname> entry on
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
The <varname>flag</varname> parameter is currently unused and reserved for future purposes</para>
<para><function>RemoveImage()</function> removes the image with the specified name.</para>
<para><function>MarkImageReadOnly()</function> toggles the read-only flag of an image.</para>
@ -225,6 +289,15 @@ node /org/freedesktop/portable1 {
<para><function>SetPoolLimit()</function> sets an overall quota limit on the pool of images.</para>
<para><function>SetImageLimit()</function> sets a per-image quota limit.</para>
<para>The <function>AttachImageWithExtensions()</function>,
<function>DetachImageWithExtensions()</function> and
<function>ReattachImageWithExtensions()</function> methods take in options as flags instead of
booleans to allow for extendability, defined as follows:</para>
<programlisting>
#define SD_SYSTEMD_PORTABLE_RUNTIME (UINT64_C(1) &lt;&lt; 0)
</programlisting>
</refsect2>
<refsect2>
@ -254,20 +327,42 @@ node /org/freedesktop/portable1 {
out s image,
out ay os_release,
out a{say} units);
GetMetadataWithExtensions(in as extensions,
in as matches,
in t flags,
out s image,
out ay os_release,
out a{say} units);
GetState(out s UNNAMED);
Attach(in as matches,
in s profile,
in b runtime,
in s copy_mode,
out a(sss) changes);
AttachWithExtensions(in as extensions,
in as matches,
in s profile,
in s copy_mode,
in t flags,
out a(sss) changes);
Detach(in b runtime,
out a(sss) changes);
DetachWithExtensions(in as extensions,
in t flags,
out a(sss) changes);
Reattach(in as matches,
in s profile,
in b runtime,
in s copy_mode,
out a(sss) changes_removed,
out a(sss) changes_updated);
ReattacheWithExtensions(in as extensions,
in as matches,
in s profile,
in s copy_mode,
in t flags,
out a(sss) changes_removed,
out a(sss) changes_updated);
Remove();
MarkReadOnly(in b read_only);
SetLimit(in t limit);
@ -303,14 +398,22 @@ node /org/freedesktop/portable1 {
<!--method GetMetadata is not documented!-->
<!--method GetMetadataWithExtensions is not documented!-->
<!--method GetState is not documented!-->
<!--method Attach is not documented!-->
<!--method AttachWithExtensions is not documented!-->
<!--method Detach is not documented!-->
<!--method DetachWithExtensions is not documented!-->
<!--method Reattach is not documented!-->
<!--method ReattacheWithExtensions is not documented!-->
<!--method Remove is not documented!-->
<!--method MarkReadOnly is not documented!-->
@ -327,14 +430,22 @@ node /org/freedesktop/portable1 {
<variablelist class="dbus-method" generated="True" extra-ref="GetMetadata()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetMetadataWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetState()"/>
<variablelist class="dbus-method" generated="True" extra-ref="Attach()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="Detach()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DetachWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="Reattach()"/>
<variablelist class="dbus-method" generated="True" extra-ref="ReattacheWithExtensions()"/>
<variablelist class="dbus-method" generated="True" extra-ref="Remove()"/>
<variablelist class="dbus-method" generated="True" extra-ref="MarkReadOnly()"/>
@ -377,14 +488,22 @@ node /org/freedesktop/portable1 {
<listitem><para>GetMetadata()</para></listitem>
<listitem><para>GetMetadataWithExtensions()</para></listitem>
<listitem><para>GetState()</para></listitem>
<listitem><para>Attach()</para></listitem>
<listitem><para>AttachWithExtensions()</para></listitem>
<listitem><para>Detach()</para></listitem>
<listitem><para>DetachWithExtensions()</para></listitem>
<listitem><para>Reattach()</para></listitem>
<listitem><para>ReattacheWithExtensions()</para></listitem>
<listitem><para>Remove()</para></listitem>
<listitem><para>MarkReadOnly()</para></listitem>

View File

@ -2250,6 +2250,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Type = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ExitType = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Restart = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s PIDFile = '...';
@ -2808,6 +2810,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property Type is not documented!-->
<!--property ExitType is not documented!-->
<!--property Restart is not documented!-->
<!--property PIDFile is not documented!-->
@ -3320,6 +3324,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="Type"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExitType"/>
<variablelist class="dbus-property" generated="True" extra-ref="Restart"/>
<variablelist class="dbus-property" generated="True" extra-ref="PIDFile"/>

View File

@ -346,6 +346,28 @@
<literal>SYSEXT_LEVEL=15.14</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_ID=</varname></term>
<listitem><para> A lower-case string (no spaces or other characters outside of 09, az, ".", "_" and
"-"), identifying a specific image of the operating system. This is supposed to be used for
environments where OS images are prepared, built, shipped and updated as comprehensive, consistent OS
images. This field is optional and may not be implemented on all systems, in particulary not on those
that are not managed via images but put together and updated from individual packages and on the
local system. Examples: <literal>IMAGE_ID=vendorx-cashier-system</literal>,
<literal>IMAGE_ID=netbook-image</literal> </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_VERSION=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the OS image version. This is supposed to be used together with
<varname>IMAGE_ID</varname> described above, to discern different versions of the same
image. Examples: <literal>IMAGE_VERSION=33</literal>,
<literal>IMAGE_VERSION=47.1rc1</literal> </para></listitem>
</varlistentry>
</variablelist>
<para>If you are reading this file from C code or a shell script

View File

@ -352,6 +352,19 @@
<listitem><para>Don't block waiting for attach --now to complete.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--extension=</option><replaceable>PATH</replaceable></term>
<listitem><para>Add an additional image <replaceable>PATH</replaceable> as an overlay on
top of <replaceable>IMAGE</replaceable> when attaching/detaching. This argument can be specified
multiple times, in which case the order in which images are laid down follows the rules specified in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for the <varname>ExtensionImages=</varname> directive.</para>
<para>Note that the same extensions have to be specified, in the same order, when attaching
and detaching.</para></listitem>
</varlistentry>
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />

View File

@ -543,11 +543,13 @@
</thead>
<tbody>
<xi:include href="standard-specifiers.xml" xpointer="a"/>
<xi:include href="standard-specifiers.xml" xpointer="A"/>
<xi:include href="standard-specifiers.xml" xpointer="b"/>
<xi:include href="standard-specifiers.xml" xpointer="B"/>
<xi:include href="standard-specifiers.xml" xpointer="H"/>
<xi:include href="standard-specifiers.xml" xpointer="l"/>
<xi:include href="standard-specifiers.xml" xpointer="m"/>
<xi:include href="standard-specifiers.xml" xpointer="M"/>
<xi:include href="standard-specifiers.xml" xpointer="o"/>
<xi:include href="standard-specifiers.xml" xpointer="v"/>
<xi:include href="standard-specifiers.xml" xpointer="w"/>

View File

@ -4,16 +4,21 @@
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<tbody>
<row id='b'>
<entry><literal>%b</literal></entry>
<entry>Boot ID</entry>
<entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
</row>
<row id='a'>
<entry><literal>%a</literal></entry>
<entry>Architecture</entry>
<entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for a full list.</entry>
</row>
<row id='A'>
<entry><literal>%A</literal></entry>
<entry>Operating system image version</entry>
<entry>The operating system image version identifier of the running system, as read from the <varname>IMAGE_VERSION=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
</row>
<row id='b'>
<entry><literal>%b</literal></entry>
<entry>Boot ID</entry>
<entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
</row>
<row id='B'>
<entry><literal>%B</literal></entry>
<entry>Operating system build ID</entry>
@ -34,6 +39,11 @@
<entry>Machine ID</entry>
<entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
</row>
<row id='M'>
<entry><literal>%M</literal></entry>
<entry>Operating system image identifier</entry>
<entry>The operating system image identifier of the running system, as read from the <varname>IMAGE_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
</row>
<row id='o'>
<entry><literal>%o</literal></entry>
<entry>Operating system ID</entry>

View File

@ -138,6 +138,17 @@
directly. Example: <literal>--keyname=cryptsetup</literal></para></listitem>
</varlistentry>
<varlistentry>
<term><option>--credential=</option></term>
<listitem><para>Configure a credential to read the password from if it exists. This may be used in
conjunction with the <varname>LoadCredential=</varname> and <varname>SetCredential=</varname>
settings in unit files. See
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. If not specified, defaults to <literal>password</literal>. This option has no effect if no
credentials directory is passed to the program (i.e. <varname>$CREDENTIALS_DIRECTORY</varname> is not
set) or if the no credential of the specified name exists.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--timeout=</option></term>

View File

@ -283,7 +283,69 @@
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1>
<title>Credentials</title>
<para><command>systemd-firstboot</command> supports the service credentials logic as implemented by
<varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<varlistentry>
<term><literal>passwd.hashed-password.root</literal></term>
<term><literal>passwd.plaintext-password.root</literal></term>
<listitem><para>A hashed or plaintext version of the root password to use, in place of prompting the
user. These credentials are equivalent to the same ones defined for the
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
service.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>passwd.shell.root</literal></term>
<listitem><para>Specifies the shell binary to use for the the specified account when creating
it. Equivalent to the credential of the same name defined for the
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
service.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>firstboot.locale</literal></term>
<term><literal>firstboot.locale-messages</literal></term>
<listitem><para>These credentials specify the locale settings to set during first boot, in place of
prompting the user.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>firstboot.keymap</literal></term>
<listitem><para>This credential specifies the keyboard setting to set during first boot, in place of
prompting the user.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>firstboot.timezone</literal></term>
<listitem><para>This credential specifies the system timezone setting to set during first boot, in
place of prompting the user.</para></listitem>
</varlistentry>
</variablelist>
<para>Note that by default the <filename>systemd-firstboot.service</filename> unit file is set up to
inherit the listed credentials
from the service manager. Thus, when invoking a container with an unpopulated <filename>/etc/</filename>
for the first time it is possible to configure the root user's password to be <literal>systemd</literal>
like this:</para>
<para><programlisting># systemd-nspawn --image=… --set-credential=firstboot.locale:de_DE.UTF-8 …</programlisting></para>
<para>Note that these credentials are only read and applied during the first boot process. Once they are
applied they remain applied for subsequent boots, and the credentials are not considered anymore.</para>
</refsect1>
<refsect1>

View File

@ -82,13 +82,19 @@
<variablelist>
<varlistentry>
<term><option>--root=<replaceable>root</replaceable></option></term>
<listitem><para>Takes a directory path as argument. All paths
operated will be prefixed with the given alternate
<replaceable>root</replaceable> path, including the path for
<term><option>--root=<replaceable>path</replaceable></option></term>
<listitem><para>Takes a directory path as argument. All paths operated on will be prefixed with the
given alternate <replaceable>root</replaceable> path, including the path for
<filename>/etc/machine-id</filename> itself.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--image=<replaceable>path</replaceable></option></term>
<listitem><para>Takes a path to a device node or refular file as argument. This is similar to
<option>--root=</option> as described above, but operates on a disk image instead of a directory
tree.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--commit</option></term>
<listitem><para>Commit a transient machine ID to disk. This

View File

@ -1487,7 +1487,31 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
<para>In order to embed binary data into the credential data for <option>--set-credential=</option>
use C-style escaping (i.e. <literal>\n</literal> to embed a newline, or <literal>\x00</literal> to
embed a <constant>NUL</constant> byte. Note that the invoking shell might already apply unescaping
once, hence this might require double escaping!).</para></listitem>
once, hence this might require double escaping!).</para>
<para>The
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
services read credentials configured this way for the purpose of configuring the container's root
user's password and shell, as well as system locale, keymap and timezone during the first boot
process of the container. This is particularly useful in combination with
<option>--volatile=yes</option> where every single boot appears as first boot, since configuration
applied to <filename>/etc/</filename> is lost on container reboot cycles. See the respective man
pages for details. Example:</para>
<programlisting># systemd-nspawn -i image.raw \
--volatile=yes \
--set-credential=firstboot.locale:de_DE.UTF-8 \
--set-credential=passwd.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' \
-b</programlisting>
<para>The above command line will invoke the specified image file <filename>image.raw</filename> in
volatile mode, i.e with an empty <filename>/etc/</filename> and <filename>/var/</filename>, so that
the container's payload recognizes this as first boot condition, and will invoke
<filename>systemd-firstboot.service</filename>, which then read the two passed credentials to
configure the system's initial locale and root password.</para>
</listitem>
</varlistentry>
</variablelist>

View File

@ -126,7 +126,60 @@
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1>
<title>Credentials</title>
<para><command>systemd-sysusers</command> supports the service credentials logic as implemented by
<varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<varlistentry>
<term><literal>passwd.hashed-password.<replaceable>user</replaceable></literal></term>
<listitem><para>A UNIX hashed password string to use for the specified user, when creating an entry
for it. This is particularly useful for the <literal>root</literal> user as it allows provisioning
the default root password to use via a unit file drop-in or from a container manager passing in this
credential. Note that setting this credential has no effect if the specified user account already
exists. This credential is hence primarily useful in first boot scenarios or systems that are fully
stateless and come up with an empty <filename>/etc/</filename> on every boot.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>passwd.plaintext-password.<replaceable>user</replaceable></literal></term>
<listitem><para>Similar to <literal>passwd.hashed-password.<replaceable>user</replaceable></literal>
but expect a literal, plaintext password, which is then automatically hashed before used for the user
account. If both the hashed and the plaintext credential are specified for the same user the
former takes precedence. It's generally recommended to specify the hashed version; however in test
environments with weaker requirements on security it might be easier to pass passwords in plaintext
instead.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>passwd.shell.<replaceable>user</replaceable></literal></term>
<listitem><para>Specifies the shell binary to use for the the specified account when creating it.</para></listitem>
</varlistentry>
</variablelist>
<para>Note that by default the <filename>systemd-sysusers.service</filename> unit file is set up to
inherit the <literal>passwd.hashed-password.root</literal>,
<literal>passwd.plaintext-password.root</literal> and <literal>passwd.shell.root</literal> credentials
from the service manager. Thus, when invoking a container with an unpopulated <filename>/etc/</filename>
for the first time it is possible to configure the root user's password to be <literal>systemd</literal>
like this:</para>
<para><programlisting># systemd-nspawn --image=… --set-credential=password.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' …</programlisting></para>
<para>Note again that the data specified in these credentials is consulted only when creating an account
for the first time, it may not be used for changing the password or shell of an account that already
exists.</para>
<para>Use <citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for generating UNIX password hashes from the command line.</para>
</refsect1>
<refsect1>
@ -141,7 +194,9 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<ulink url="https://systemd.io/UIDS-GIDS">Users, Groups, UIDs and GIDs on systemd systems</ulink>
<ulink url="https://systemd.io/UIDS-GIDS">Users, Groups, UIDs and GIDs on systemd systems</ulink>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -90,10 +90,12 @@
</thead>
<tbody>
<xi:include href="standard-specifiers.xml" xpointer="a"/>
<xi:include href="standard-specifiers.xml" xpointer="A"/>
<xi:include href="standard-specifiers.xml" xpointer="b"/>
<xi:include href="standard-specifiers.xml" xpointer="B"/>
<xi:include href="standard-specifiers.xml" xpointer="H"/>
<xi:include href="standard-specifiers.xml" xpointer="m"/>
<xi:include href="standard-specifiers.xml" xpointer="M"/>
<xi:include href="standard-specifiers.xml" xpointer="o"/>
<xi:include href="standard-specifiers.xml" xpointer="v"/>
<xi:include href="standard-specifiers.xml" xpointer="w"/>

View File

@ -2821,7 +2821,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<variablelist class='unit-directives'>
<varlistentry>
<term><varname>LoadCredential=</varname><replaceable>ID</replaceable>:<replaceable>PATH</replaceable></term>
<term><varname>LoadCredential=</varname><replaceable>ID</replaceable><optional>:<replaceable>PATH</replaceable></optional></term>
<listitem><para>Pass a credential to the unit. Credentials are limited-size binary or textual objects
that may be passed to unit processes. They are primarily used for passing cryptographic keys (both
@ -2834,19 +2834,21 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
environment variable to the unit's processes.</para>
<para>The <varname>LoadCredential=</varname> setting takes a textual ID to use as name for a
credential plus a file system path. The ID must be a short ASCII string suitable as filename in the
filesystem, and may be chosen freely by the user. If the specified path is absolute it is opened as
regular file and the credential data is read from it. If the absolute path refers to an
<constant>AF_UNIX</constant> stream socket in the file system a connection is made to it (only once
at unit start-up) and the credential data read from the connection, providing an easy IPC integration
point for dynamically providing credentials from other services. If the specified path is not
absolute and itself qualifies as valid credential identifier it is understood to refer to a
credential that the service manager itself received via the <varname>$CREDENTIALS_DIRECTORY</varname>
environment variable, which may be used to propagate credentials from an invoking environment (e.g. a
container manager that invoked the service manager) into a service. The contents of the file/socket
may be arbitrary binary or textual data, including newline characters and <constant>NUL</constant>
bytes. This option may be used multiple times, each time defining an additional credential to pass to
the unit.</para>
credential plus a file system path, separated by a colon. The ID must be a short ASCII string
suitable as filename in the filesystem, and may be chosen freely by the user. If the specified path
is absolute it is opened as regular file and the credential data is read from it. If the absolute
path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is made
to it (only once at unit start-up) and the credential data read from the connection, providing an
easy IPC integration point for dynamically providing credentials from other services. If the
specified path is not absolute and itself qualifies as valid credential identifier it is understood
to refer to a credential that the service manager itself received via the
<varname>$CREDENTIALS_DIRECTORY</varname> environment variable, which may be used to propagate
credentials from an invoking environment (e.g. a container manager that invoked the service manager)
into a service. The contents of the file/socket may be arbitrary binary or textual data, including
newline characters and <constant>NUL</constant> bytes. If the file system path is omitted it is
chosen identical to the credential name, i.e. this is a terse way do declare credentials to inherit
from the service manager into a service. This option may be used multiple times, each time defining
an additional credential to pass to the unit.</para>
<para>The credential files/IPC sockets must be accessible to the service manager, but don't have to
be directly accessible to the unit's processes: the credential data is read and copied into separate,

View File

@ -1961,6 +1961,7 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<term><varname>UseDNS=</varname></term>
<term><varname>UseNTP=</varname></term>
<term><varname>UseHostname=</varname></term>
<term><varname>UseDomains=</varname></term>
<listitem>
<para>As in the [DHCPv4] section.</para>
</listitem>

View File

@ -255,6 +255,31 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ExitType=</varname></term>
<listitem>
<para>Configures the process exit type for this service unit. One of <option>main</option> or
<option>cgroup</option>:</para>
<itemizedlist>
<listitem><para>If set to <option>main</option> (the default), the service manager
will consider the unit stopped when the main process, which is determined according to the `Type`, exits.
</para></listitem>
<listitem><para>The <option>cgroup</option> exit type is meant for applications whose forking model is not
known ahead of time and which might not have a specific main process. The service will stay running as long
as at least one process in the cgroup is running. The exit status of the service is that of the last
process in the cgroup to exit.</para></listitem>
</itemizedlist>
<para>It is generally recommended to use <varname>ExitType=</varname><option>main</option> when a service has
a known forking model and a main process can reliably be determined. <varname>ExitType=</varname>
<option>cgroup</option> is well suited for transient or automatically generated services, such as graphical
applications inside of a desktop environment.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RemainAfterExit=</varname></term>

View File

@ -1872,6 +1872,7 @@
<entry>Architecture</entry>
<entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> above for a full list.</entry>
</row>
<xi:include href="standard-specifiers.xml" xpointer="A"/>
<xi:include href="standard-specifiers.xml" xpointer="b"/>
<xi:include href="standard-specifiers.xml" xpointer="B"/>
<row>
@ -1944,6 +1945,7 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
<entry>This is either <filename>/var/log</filename> (for the system manager) or the path <literal>$XDG_CONFIG_HOME</literal> resolves to with <filename index="false">/log</filename> appended (for user managers).</entry>
</row>
<xi:include href="standard-specifiers.xml" xpointer="m"/>
<xi:include href="standard-specifiers.xml" xpointer="M"/>
<row>
<entry><literal>%n</literal></entry>
<entry>Full unit name</entry>

View File

@ -259,11 +259,13 @@ r - 500-900
</thead>
<tbody>
<xi:include href="standard-specifiers.xml" xpointer="a"/>
<xi:include href="standard-specifiers.xml" xpointer="A"/>
<xi:include href="standard-specifiers.xml" xpointer="b"/>
<xi:include href="standard-specifiers.xml" xpointer="B"/>
<xi:include href="standard-specifiers.xml" xpointer="H"/>
<xi:include href="standard-specifiers.xml" xpointer="l"/>
<xi:include href="standard-specifiers.xml" xpointer="m"/>
<xi:include href="standard-specifiers.xml" xpointer="M"/>
<xi:include href="standard-specifiers.xml" xpointer="o"/>
<xi:include href="standard-specifiers.xml" xpointer="T"/>
<xi:include href="standard-specifiers.xml" xpointer="v"/>

View File

@ -635,6 +635,7 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
</thead>
<tbody>
<xi:include href="standard-specifiers.xml" xpointer="a"/>
<xi:include href="standard-specifiers.xml" xpointer="A"/>
<xi:include href="standard-specifiers.xml" xpointer="b"/>
<xi:include href="standard-specifiers.xml" xpointer="B"/>
<row>
@ -665,6 +666,7 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
<entry>In <option>--user</option> mode, this is the same as <varname>$XDG_CONFIG_HOME</varname> with <filename index="false">/log</filename> appended, and <filename>/var/log</filename> otherwise.</entry>
</row>
<xi:include href="standard-specifiers.xml" xpointer="m"/>
<xi:include href="standard-specifiers.xml" xpointer="M"/>
<xi:include href="standard-specifiers.xml" xpointer="o"/>
<row>
<entry><literal>%S</literal></entry>

View File

@ -269,7 +269,7 @@ option('dns-over-tls', type : 'combo', choices : ['auto', 'gnutls', 'openssl', '
description : 'DNS-over-TLS support')
option('dns-servers', type : 'string',
description : 'space-separated list of default DNS servers',
value : '1.1.1.1 8.8.8.8 1.0.0.1 8.8.4.4 2606:4700:4700::1111 2001:4860:4860::8888 2606:4700:4700::1001 2001:4860:4860::8844')
value : '1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google 1.0.0.1#cloudflare-dns.com 8.8.4.4#dns.google 2606:4700:4700::1111#cloudflare-dns.com 2001:4860:4860::8888#dns.google 2606:4700:4700::1001#cloudflare-dns.com 2001:4860:4860::8844#dns.google')
option('ntp-servers', type : 'string',
description : 'space-separated list of default NTP servers',
value : 'time1.google.com time2.google.com time3.google.com time4.google.com')

View File

@ -78,7 +78,7 @@ _systemd_run() {
-p|--property)
local comps='CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP=
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group=
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth=
DevicePolicy= KillMode= ExitType= DeviceAllow= BlockIOReadBandwidth=
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment=
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=

View File

@ -45,7 +45,7 @@ _arguments \
{-p+,--property=}'[Set unit property]:NAME=VALUE:(( \
CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP= \
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
DevicePolicy= KillMode= ExitType= DeviceAllow= BlockIOReadBandwidth= \
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \

View File

@ -12,10 +12,12 @@
#include "main-func.h"
#include "pretty-print.h"
#include "strv.h"
#include "terminal-util.h"
static const char *arg_icon = NULL;
static const char *arg_id = NULL;
static const char *arg_keyname = NULL;
static const char *arg_id = NULL; /* identifier for 'ask-password' protocol */
static const char *arg_key_name = NULL; /* name in kernel keyring */
static const char *arg_credential_name = NULL; /* name in $CREDENTIALS_DIRECTORY directory */
static char *arg_message = NULL;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
static bool arg_multiple = false;
@ -32,21 +34,26 @@ static int help(void) {
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] MESSAGE\n\n"
"Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
printf("%1$s [OPTIONS...] MESSAGE\n\n"
"%3$sQuery the user for a system passphrase, via the TTY or an UI agent.%4$s\n\n"
" -h --help Show this help\n"
" --icon=NAME Icon name\n"
" --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
" --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
" --credential=NAME\n"
" Credential name for LoadCredential=/SetCredential=\n"
" credentials\n"
" --timeout=SEC Timeout in seconds\n"
" --echo Do not mask input (useful for usernames)\n"
" --no-tty Ask question via agent even on TTY\n"
" --accept-cached Accept cached passwords\n"
" --multiple List multiple passwords if available\n"
" --no-output Do not print password to standard output\n"
"\nSee the %s for details.\n",
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link);
link,
ansi_highlight(),
ansi_normal());
return 0;
}
@ -64,6 +71,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_KEYNAME,
ARG_NO_OUTPUT,
ARG_VERSION,
ARG_CREDENTIAL,
};
static const struct option options[] = {
@ -78,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "id", required_argument, NULL, ARG_ID },
{ "keyname", required_argument, NULL, ARG_KEYNAME },
{ "no-output", no_argument, NULL, ARG_NO_OUTPUT },
{ "credential", required_argument, NULL, ARG_CREDENTIAL },
{}
};
@ -128,13 +137,17 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_KEYNAME:
arg_keyname = optarg;
arg_key_name = optarg;
break;
case ARG_NO_OUTPUT:
arg_no_output = true;
break;
case ARG_CREDENTIAL:
arg_credential_name = optarg;
break;
case '?':
return -EINVAL;
@ -170,7 +183,7 @@ static int run(int argc, char *argv[]) {
else
timeout = 0;
r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l);
r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", timeout, arg_flags, &l);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");

54
src/basic/creds-util.c Normal file
View File

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "creds-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "path-util.h"
bool credential_name_valid(const char *s) {
/* We want that credential names are both valid in filenames (since that's our primary way to pass
* them around) and as fdnames (which is how we might want to pass them around eventually) */
return filename_is_valid(s) && fdname_is_valid(s);
}
int get_credentials_dir(const char **ret) {
const char *e;
assert(ret);
e = secure_getenv("CREDENTIALS_DIRECTORY");
if (!e)
return -ENXIO;
if (!path_is_absolute(e) || !path_is_normalized(e))
return -EINVAL;
*ret = e;
return 0;
}
int read_credential(const char *name, void **ret, size_t *ret_size) {
_cleanup_free_ char *fn = NULL;
const char *d;
int r;
assert(ret);
if (!credential_name_valid(name))
return -EINVAL;
r = get_credentials_dir(&d);
if (r < 0)
return r;
fn = path_join(d, name);
if (!fn)
return -ENOMEM;
return read_full_file_full(
AT_FDCWD, fn,
UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE,
NULL,
(char**) ret, ret_size);
}

12
src/basic/creds-util.h Normal file
View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <sys/types.h>
bool credential_name_valid(const char *s);
int get_credentials_dir(const char **ret);
int read_credential(const char *name, void **ret, size_t *ret_size);

View File

@ -20,6 +20,7 @@ void initialize_libgcrypt(bool secmem) {
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
gcry_error_t err;
size_t hash_size;
void *hash;
char *enc;
@ -29,8 +30,8 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
gcry_md_open(&md, md_algorithm, 0);
if (!md)
err = gcry_md_open(&md, md_algorithm, 0);
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
return -EIO;
gcry_md_write(md, s, len);

View File

@ -5,12 +5,13 @@
#include <unistd.h>
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0)
#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1)
/* For internal use only */
#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63)
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS)
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE)
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_KEXEC_REBOOT)
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE)
bool session_id_valid(const char *id);

View File

@ -35,6 +35,8 @@ basic_sources = files('''
conf-files.h
copy.c
copy.h
creds-util.c
creds-util.h
def.h
device-nodes.c
device-nodes.h

View File

@ -196,13 +196,15 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
if (statx(fd, filename, (FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW) |
(flags & AT_EMPTY_PATH) |
AT_NO_AUTOMOUNT, 0, &sx) < 0) {
AT_NO_AUTOMOUNT, STATX_TYPE, &sx) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
/* If statx() is not available or forbidden, fall back to name_to_handle_at() below */
} else if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */
return FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
else if (FLAGS_SET(sx.stx_mask, STATX_TYPE) && S_ISLNK(sx.stx_mode))
return false; /* symlinks are never mount points */
r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
@ -231,16 +233,13 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
} else if (r < 0)
return r;
/* The parent can do name_to_handle_at() but the
* directory we are interested in can't? If so, it
* must be a mount point. */
/* The parent can do name_to_handle_at() but the directory we are interested in can't? If so, it must
* be a mount point. */
if (nosupp)
return 1;
/* If the file handle for the directory we are
* interested in and its parent are identical, we
* assume this is the root directory, which is a mount
* point. */
/* If the file handle for the directory we are interested in and its parent are identical, we assume
* this is the root directory, which is a mount point. */
if (h->handle_bytes == h_parent->handle_bytes &&
h->handle_type == h_parent->handle_type &&
@ -263,23 +262,22 @@ fallback_fdinfo:
if (mount_id != mount_id_parent)
return 1;
/* Hmm, so, the mount ids are the same. This leaves one
* special case though for the root file system. For that,
* let's see if the parent directory has the same inode as we
* are interested in. Hence, let's also do fstat() checks now,
* too, but avoid the st_dev comparisons, since they aren't
* that useful on unionfs mounts. */
/* Hmm, so, the mount ids are the same. This leaves one special case though for the root file
* system. For that, let's see if the parent directory has the same inode as we are interested
* in. Hence, let's also do fstat() checks now, too, but avoid the st_dev comparisons, since they
* aren't that useful on unionfs mounts. */
check_st_dev = false;
fallback_fstat:
/* yay for fstatat() taking a different set of flags than the other
* _at() above */
/* yay for fstatat() taking a different set of flags than the other _at() above */
if (flags & AT_SYMLINK_FOLLOW)
flags &= ~AT_SYMLINK_FOLLOW;
else
flags |= AT_SYMLINK_NOFOLLOW;
if (fstatat(fd, filename, &a, flags) < 0)
return -errno;
if (S_ISLNK(a.st_mode)) /* Symlinks are never mount points */
return false;
if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
return -errno;

View File

@ -213,3 +213,25 @@ typedef enum nss_status (*_nss_gethostbyaddr_r_t)(
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop);
typedef enum nss_status (*_nss_getpwnam_r_t)(
const char *name,
struct passwd *pwd,
char *buffer, size_t buflen,
int *errnop);
typedef enum nss_status (*_nss_getpwuid_r_t)(
uid_t uid,
struct passwd *pwd,
char *buffer, size_t buflen,
int *errnop);
typedef enum nss_status (*_nss_getgrnam_r_t)(
const char *name,
struct group *gr,
char *buffer, size_t buflen,
int *errnop);
typedef enum nss_status (*_nss_getgrgid_r_t)(
gid_t gid,
struct group *gr,
char *buffer, size_t buflen,
int *errnop);

View File

@ -35,30 +35,33 @@ int ordered_set_consume(OrderedSet *s, void *p) {
return r;
}
int ordered_set_put_strdup(OrderedSet *s, const char *p) {
int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS) {
char *c;
int r;
assert(s);
assert(p);
r = _ordered_set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
if (ordered_set_contains(*s, p))
return 0;
c = strdup(p);
if (!c)
return -ENOMEM;
r = ordered_set_consume(s, c);
if (r == -EEXIST)
return 0;
return r;
return ordered_set_consume(*s, c);
}
int ordered_set_put_strdupv(OrderedSet *s, char **l) {
int _ordered_set_put_strdupv(OrderedSet **s, char **l HASHMAP_DEBUG_PARAMS) {
int n = 0, r;
char **i;
STRV_FOREACH(i, l) {
r = ordered_set_put_strdup(s, *i);
r = _ordered_set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@ -68,7 +71,7 @@ int ordered_set_put_strdupv(OrderedSet *s, char **l) {
return n;
}
int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l) {
int ordered_set_put_string_set(OrderedSet **s, OrderedSet *l) {
int n = 0, r;
char *p;

View File

@ -26,6 +26,10 @@ static inline OrderedSet* ordered_set_free_free(OrderedSet *s) {
return (OrderedSet*) ordered_hashmap_free_free((OrderedHashmap*) s);
}
static inline int ordered_set_contains(OrderedSet *s, const void *p) {
return ordered_hashmap_contains((OrderedHashmap*) s, p);
}
static inline int ordered_set_put(OrderedSet *s, void *p) {
return ordered_hashmap_put((OrderedHashmap*) s, p, p);
}
@ -59,9 +63,11 @@ static inline char** ordered_set_get_strv(OrderedSet *s) {
}
int ordered_set_consume(OrderedSet *s, void *p);
int ordered_set_put_strdup(OrderedSet *s, const char *p);
int ordered_set_put_strdupv(OrderedSet *s, char **l);
int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l);
int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS);
#define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
int _ordered_set_put_strdupv(OrderedSet **s, char **l HASHMAP_DEBUG_PARAMS);
#define ordered_set_put_strdupv(s, l) _ordered_set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS)
int ordered_set_put_string_set(OrderedSet **s, OrderedSet *l);
void ordered_set_print(FILE *f, const char *field, OrderedSet *s);
#define _ORDERED_SET_FOREACH(e, s, i) \

View File

@ -1190,9 +1190,3 @@ bool prefixed_path_strv_contains(char **l, const char *path) {
return false;
}
bool credential_name_valid(const char *s) {
/* We want that credential names are both valid in filenames (since that's our primary way to pass
* them around) and as fdnames (which is how we might want to pass them around eventually) */
return filename_is_valid(s) && fdname_is_valid(s);
}

View File

@ -183,5 +183,3 @@ static inline const char *empty_to_root(const char *path) {
bool path_strv_contains(char **l, const char *path);
bool prefixed_path_strv_contains(char **l, const char *path);
bool credential_name_valid(const char *s);

View File

@ -13,6 +13,7 @@
#include "cap-list.h"
#include "capability-util.h"
#include "cpu-set-util.h"
#include "creds-util.h"
#include "dbus-execute.h"
#include "dbus-util.h"
#include "env-util.h"

View File

@ -27,6 +27,7 @@
#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exit_type, service_exit_type, ServiceExitType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
@ -192,6 +193,7 @@ int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_b
const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ExitType", "s", property_get_exit_type, offsetof(Service, exit_type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), SD_BUS_VTABLE_PROPERTY_CONST),
@ -377,6 +379,7 @@ static int bus_set_transient_std_fd(
}
static BUS_DEFINE_SET_TRANSIENT_PARSE(notify_access, NotifyAccess, notify_access_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_exit_type, ServiceExitType, service_exit_type_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
@ -414,6 +417,9 @@ static int bus_service_set_transient_property(
if (streq(name, "Type"))
return bus_set_transient_service_type(u, name, &s->type, message, flags, error);
if (streq(name, "ExitType"))
return bus_set_transient_service_exit_type(u, name, &s->exit_type, message, flags, error);
if (streq(name, "OOMPolicy"))
return bus_set_transient_oom_policy(u, name, &s->oom_policy, message, flags, error);

View File

@ -2564,6 +2564,7 @@ static int acquire_credentials(
ReadFullFileFlags flags = READ_FULL_FILE_SECURE;
_cleanup_(erase_and_freep) char *data = NULL;
_cleanup_free_ char *j = NULL, *bindname = NULL;
bool missing_ok = true;
const char *source;
size_t size, add;
@ -2577,6 +2578,8 @@ static int acquire_credentials(
if (asprintf(&bindname, "@%" PRIx64"/unit/%s/%s", random_u64(), unit, *id) < 0)
return -ENOMEM;
missing_ok = false;
} else if (params->received_credentials) {
/* If this is a relative path, take it relative to the credentials we received
* ourselves. We don't support the AF_UNIX stuff in this mode, since we are operating
@ -2589,16 +2592,23 @@ static int acquire_credentials(
} else
source = NULL;
if (source)
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
else
r = -ENOENT;
if (r == -ENOENT &&
faccessat(dfd, *id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) /* If the source file doesn't exist, but we already acquired the key otherwise, then don't fail */
if (r == -ENOENT && (missing_ok || faccessat(dfd, *id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)) {
/* Make a missing inherited credential non-fatal, let's just continue. After all apps
* will get clear errors if we don't pass such a missing credential on as they
* themselves will get ENOENT when trying to read them, which should not be much
* worse than when we handle the error here and make it fatal.
*
* Also, if the source file doesn't exist, but we already acquired the key otherwise,
* then don't fail either. */
log_debug_errno(r, "Couldn't read inherited credential '%s', skipping: %m", *fn);
continue;
}
if (r < 0)
return r;
return log_debug_errno(r, "Failed to read credential '%s': %m", *fn);
add = strlen(*id) + size;
if (add > left)
@ -3247,7 +3257,6 @@ static int apply_mount_namespace(
propagate_dir,
incoming_dir,
root_dir || root_image ? params->notify_socket : NULL,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
error_path);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports

View File

@ -359,6 +359,7 @@ Service.StartLimitAction, config_parse_emergency_action,
Service.FailureAction, config_parse_emergency_action, 0, offsetof(Unit, failure_action)
Service.RebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, reboot_arg)
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.ExitType, config_parse_service_exit_type, 0, offsetof(Service, exit_type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only)

View File

@ -16,8 +16,8 @@
#include "sd-messages.h"
#include "af-list.h"
#include "alloc-util.h"
#include "all-units.h"
#include "alloc-util.h"
#include "bpf-firewall.h"
#include "bus-error.h"
#include "bus-internal.h"
@ -28,6 +28,7 @@
#include "conf-parser.h"
#include "core-varlink.h"
#include "cpu-set-util.h"
#include "creds-util.h"
#include "env-util.h"
#include "errno-list.h"
#include "escape.h"
@ -130,6 +131,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "
DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
@ -4606,6 +4608,14 @@ int config_parse_load_credential(
log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", k);
return 0;
}
if (isempty(p)) {
/* If only one field field is specified take it as shortcut for inheriting a credential named
* the same way from our parent */
q = strdup(k);
if (!q)
return log_oom();
} else {
r = unit_full_printf(u, p, &q);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", p);
@ -4615,6 +4625,7 @@ int config_parse_load_credential(
log_syntax(unit, LOG_WARNING, filename, line, r, "Credential source \"%s\" not valid, ignoring.", q);
return 0;
}
}
r = strv_consume_pair(&context->load_credentials, TAKE_PTR(k), TAKE_PTR(q));
if (r < 0)
@ -5748,6 +5759,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_exit_type, "SERVICEEXITTYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
{ config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
{ config_parse_kill_mode, "KILLMODE" },

View File

@ -32,6 +32,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_exit_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_output);

View File

@ -30,6 +30,7 @@
#include "clean-ipc.h"
#include "clock-util.h"
#include "core-varlink.h"
#include "creds-util.h"
#include "dbus-job.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
@ -49,8 +50,8 @@
#include "install.h"
#include "io-util.h"
#include "label.h"
#include "locale-setup.h"
#include "load-fragment.h"
#include "locale-setup.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
@ -852,8 +853,8 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
if (r < 0)
return r;
e = secure_getenv("CREDENTIALS_DIRECTORY");
if (e) {
r = get_credentials_dir(&e);
if (r >= 0) {
m->received_credentials = strdup(e);
if (!m->received_credentials)
return -ENOMEM;

View File

@ -1802,7 +1802,6 @@ int setup_namespace(
const char *propagate_dir,
const char *incoming_dir,
const char *notify_socket,
DissectImageFlags dissect_image_flags,
char **error_path) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
@ -1813,6 +1812,13 @@ int setup_namespace(
MountEntry *m = NULL, *mounts = NULL;
bool require_prefix = false, setup_propagate = false;
const char *root, *extension_dir = "/run/systemd/unit-extensions";
DissectImageFlags dissect_image_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_USR_NO_ROOT;
size_t n_mounts;
int r;
@ -1825,8 +1831,6 @@ int setup_namespace(
mount_flags = MS_SHARED;
if (root_image) {
dissect_image_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
/* Make the whole image read-only if we can determine that we only access it in a read-only fashion. */
if (root_read_only(read_only_paths,
ns_info->protect_system) &&

View File

@ -143,7 +143,6 @@ int setup_namespace(
const char *propagate_dir,
const char *incoming_dir,
const char *notify_socket,
DissectImageFlags dissected_image_flags,
char **error_path);
#define RUN_SYSTEMD_EMPTY "/run/systemd/empty"

View File

@ -1621,18 +1621,25 @@ static int control_pid_good(Service *s) {
return s->control_pid > 0;
}
static int cgroup_good(Service *s) {
int r;
static int cgroup_empty(Service *s) {
assert(s);
/* Returns 0 if the cgroup is empty or doesn't exist, > 0 if it is exists and is populated, < 0 if we can't
* figure it out */
/* Returns 0 if there is no cgroup, > 0 if is empty or doesn't exist, < 0 if we can't figure it out */
if (!UNIT(s)->cgroup_path)
return 0;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path);
return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path);
}
static int cgroup_good(Service *s) {
int r;
/* Returns 0 if the cgroup is empty or doesn't exist, > 0 if it is exists and is populated, < 0 if we can't
* figure it out */
r = cgroup_empty(s);
if (r < 0)
return r;
@ -3398,7 +3405,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown code");
if (s->main_pid == pid) {
/* Services with ExitType=cgroup ignore the main PID for purposes of exit status */
if (s->exit_type == SERVICE_EXIT_CGROUP && s->main_pid == pid) {
service_unwatch_main_pid(s);
s->main_pid_known = false;
}
if ((s->exit_type == SERVICE_EXIT_MAIN && s->main_pid == pid) ||
(s->exit_type == SERVICE_EXIT_CGROUP && cgroup_empty(s) && !control_pid_good(s))) {
/* Forking services may occasionally move to a new PID.
* As long as they update the PID file before exiting the old
* PID, they're fine. */
@ -3431,7 +3445,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
unit_log_process_exit(
u,
"Main process",
s->exit_type == SERVICE_EXIT_CGROUP ? "Last process" : "Main process",
service_exec_command_to_string(SERVICE_EXEC_START),
f == SERVICE_SUCCESS,
code, status);
@ -4448,6 +4462,13 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
static const char* const service_exit_type_table[_SERVICE_EXIT_TYPE_MAX] = {
[SERVICE_EXIT_MAIN] = "main",
[SERVICE_EXIT_CGROUP] = "cgroup",
};
DEFINE_STRING_TABLE_LOOKUP(service_exit_type, ServiceExitType);
static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
[SERVICE_EXEC_CONDITION] = "ExecCondition",
[SERVICE_EXEC_START_PRE] = "ExecStartPre",

View File

@ -35,6 +35,13 @@ typedef enum ServiceType {
_SERVICE_TYPE_INVALID = -EINVAL,
} ServiceType;
typedef enum ServiceExitType {
SERVICE_EXIT_MAIN, /* we consider the main PID when deciding if the service exited */
SERVICE_EXIT_CGROUP, /* we wait for the last process in the cgroup to exit */
_SERVICE_EXIT_TYPE_MAX,
_SERVICE_EXIT_TYPE_INVALID = -EINVAL,
} ServiceExitType;
typedef enum ServiceExecCommand {
SERVICE_EXEC_CONDITION,
SERVICE_EXEC_START_PRE,
@ -97,6 +104,7 @@ struct Service {
Unit meta;
ServiceType type;
ServiceExitType exit_type;
ServiceRestart restart;
ExitStatusSet restart_prevent_status;
ExitStatusSet restart_force_status;
@ -226,6 +234,9 @@ ServiceRestart service_restart_from_string(const char *s) _pure_;
const char* service_type_to_string(ServiceType i) _const_;
ServiceType service_type_from_string(const char *s) _pure_;
const char* service_exit_type_to_string(ServiceExitType i) _const_;
ServiceExitType service_exit_type_from_string(const char *s) _pure_;
const char* service_exec_command_to_string(ServiceExecCommand i) _const_;
ServiceExecCommand service_exec_command_from_string(const char *s) _pure_;

View File

@ -57,7 +57,7 @@ int enroll_password(
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords);
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
@ -68,7 +68,7 @@ int enroll_password(
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords2);
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");

View File

@ -417,7 +417,7 @@ static int prepare_luks(
"Too many attempts, giving up:");
r = ask_password_auto(
question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY,
question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY,
ask_password_flags,
&passwords);
if (r < 0)

View File

@ -88,7 +88,7 @@ int acquire_fido2_key(
pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", until, flags, &pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
if (r < 0)
return log_error_errno(r, "Failed to ask for user password: %m");

View File

@ -70,6 +70,7 @@ static int pkcs11_callback(
data->friendly_name,
"drive-harddisk",
"pkcs11-pin",
"cryptsetup.pkcs11-pin",
data->until,
NULL);
if (r < 0)

View File

@ -545,7 +545,7 @@ static int get_password(
id = strjoina("cryptsetup:", disk_path);
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until,
ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
&passwords);
if (r < 0)
@ -561,7 +561,7 @@ static int get_password(
id = strjoina("cryptsetup-verification:", disk_path);
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query verification password: %m");

View File

@ -44,7 +44,12 @@ static const char *arg_image = NULL;
static const char *arg_path = NULL;
static const char *arg_source = NULL;
static const char *arg_target = NULL;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
static DissectImageFlags arg_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_USR_NO_ROOT;
static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
@ -293,6 +298,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_image = argv[optind];
arg_path = argv[optind + 1];
arg_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
break;
case ACTION_COPY_FROM:
@ -304,7 +310,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_source = argv[optind + 1];
arg_target = argc > optind + 2 ? argv[optind + 2] : "-" /* this means stdout */ ;
arg_flags |= DISSECT_IMAGE_READ_ONLY;
arg_flags |= DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_REQUIRE_ROOT;
break;
case ACTION_COPY_TO:
@ -322,6 +328,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_target = argv[optind + 1];
}
arg_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
break;
default:
@ -460,7 +467,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
return log_oom();
}
t = table_new("rw", "designator", "partition uuid", "fstype", "architecture", "verity", "node", "partno");
t = table_new("rw", "designator", "partition uuid", "partition label", "fstype", "architecture", "verity", "node", "partno");
if (!t)
return log_oom();
@ -489,6 +496,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
r = table_add_many(
t,
TABLE_STRING, p->label,
TABLE_STRING, p->fstype,
TABLE_STRING, architecture_to_string(p->architecture));
if (r < 0)

View File

@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "copy.h"
#include "creds-util.h"
#include "dissect-image.h"
#include "env-file.h"
#include "fd-util.h"
@ -43,8 +44,8 @@
static char *arg_root = NULL;
static char *arg_image = NULL;
static char *arg_locale = NULL; /* $LANG */
static char *arg_keymap = NULL;
static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
static char *arg_keymap = NULL;
static char *arg_timezone = NULL;
static char *arg_hostname = NULL;
static sd_id128_t arg_machine_id = {};
@ -232,11 +233,29 @@ static bool locale_is_ok(const char *name) {
static int prompt_locale(void) {
_cleanup_strv_free_ char **locales = NULL;
bool acquired_from_creds = false;
int r;
if (arg_locale || arg_locale_messages)
return 0;
r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
if (r < 0)
log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
else
acquired_from_creds = true;
r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
if (r < 0)
log_debug_errno(r, "Failed to read credential firstboot.locale-message, ignoring: %m");
else
acquired_from_creds = true;
if (acquired_from_creds) {
log_debug("Acquired locale from credentials.");
return 0;
}
if (!arg_prompt_locale)
return 0;
@ -336,6 +355,14 @@ static int prompt_keymap(void) {
if (arg_keymap)
return 0;
r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
if (r < 0)
log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
else {
log_debug("Acquired keymap from credential.");
return 0;
}
if (!arg_prompt_keymap)
return 0;
@ -407,6 +434,14 @@ static int prompt_timezone(void) {
if (arg_timezone)
return 0;
r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
if (r < 0)
log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
else {
log_debug("Acquired timezone from credential.");
return 0;
}
if (!arg_prompt_timezone)
return 0;
@ -558,6 +593,22 @@ static int prompt_root_password(void) {
if (arg_root_password)
return 0;
r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
if (r == -ENOENT) {
r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
if (r < 0)
log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
else {
arg_root_password_is_hashed = false;
return 0;
}
} else if (r < 0)
log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
else {
arg_root_password_is_hashed = true;
return 0;
}
if (!arg_prompt_root_password)
return 0;
@ -631,7 +682,18 @@ static int find_shell(const char *path, const char *root) {
static int prompt_root_shell(void) {
int r;
if (arg_root_shell || !arg_prompt_root_shell)
if (arg_root_shell)
return 0;
r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
if (r < 0)
log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
else {
log_debug("Acquired root shell from credential.");
return 0;
}
if (!arg_prompt_root_shell)
return 0;
print_welcome();
@ -1291,7 +1353,11 @@ static int run(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
&unlink_dir,
&loop_device,
&decrypted_image);

View File

@ -665,7 +665,13 @@ static int enumerate_partitions(dev_t devnum) {
if (r <= 0)
return r;
r = dissect_image(fd, NULL, NULL, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
r = dissect_image(
fd,
NULL, NULL,
DISSECT_IMAGE_GPT_ONLY|
DISSECT_IMAGE_NO_UDEV|
DISSECT_IMAGE_USR_NO_ROOT,
&m);
if (r == -ENOPKG) {
log_debug_errno(r, "No suitable partition table found, ignoring.");
return 0;

View File

@ -221,7 +221,7 @@ static int acquire_existing_password(const char *user_name, UserRecord *hr, bool
user_name) < 0)
return log_oom();
r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password);
r = ask_password_auto(question, "user-home", NULL, "home-password", "home.password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");
@ -257,7 +257,7 @@ static int acquire_token_pin(const char *user_name, UserRecord *hr) {
return log_oom();
/* We never cache or use cached PINs, since usually there are only very few attempts allowed before the PIN is blocked */
r = ask_password_auto(question, "user-home", NULL, "token-pin", USEC_INFINITY, 0, &pin);
r = ask_password_auto(question, "user-home", NULL, "token-pin", "home.token-pin", USEC_INFINITY, 0, &pin);
if (r < 0)
return log_error_errno(r, "Failed to acquire security token PIN: %m");
@ -1010,7 +1010,7 @@ static int acquire_new_password(
if (asprintf(&question, "Please enter new password for user %s:", user_name) < 0)
return log_oom();
r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &first);
r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &first);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");
@ -1018,7 +1018,7 @@ static int acquire_new_password(
if (asprintf(&question, "Please enter new password for user %s (repeat):", user_name) < 0)
return log_oom();
r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &second);
r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &second);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");

View File

@ -2150,7 +2150,10 @@ int main(int argc, char *argv[]) {
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK : DISSECT_IMAGE_READ_ONLY),
&unlink_dir,
&loop_device,

View File

@ -12,6 +12,7 @@
#include "sd-dhcp-client.h"
#include "dhcp-protocol.h"
#include "log-link.h"
#include "socket-util.h"
typedef struct sd_dhcp_option {
@ -65,5 +66,15 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui
#define DHCP_CLIENT_DONT_DESTROY(client) \
_cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
#define log_dhcp_client_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
#define log_dhcp_client(client, fmt, ...) log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__)
#define log_dhcp_client_errno(client, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_dhcp_client_get_ifname(client), \
LOG_DEBUG, _e, "DHCPv4 client: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_dhcp_client(client, fmt, ...) \
log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__)

View File

@ -10,7 +10,7 @@
#include "dhcp-internal.h"
#include "ordered-set.h"
#include "log.h"
#include "log-link.h"
#include "time-util.h"
typedef enum DHCPRawOption {
@ -48,6 +48,7 @@ struct sd_dhcp_server {
int fd_raw;
int ifindex;
char *ifname;
be32_t address;
be32_t netmask;
be32_t subnet;
@ -85,9 +86,6 @@ typedef struct DHCPRequest {
uint32_t lifetime;
} DHCPRequest;
#define log_dhcp_server(client, fmt, ...) log_internal(LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__)
#define log_dhcp_server_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__)
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length);
int dhcp_server_send_packet(sd_dhcp_server *server,
@ -96,3 +94,16 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
void client_id_hash_func(const DHCPClientId *p, struct siphash *state);
int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b);
#define log_dhcp_server_errno(server, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_dhcp_server_get_ifname(server), \
LOG_DEBUG, _e, "DHCPv4 server: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_dhcp_server(server, fmt, ...) \
log_dhcp_server_errno(server, 0, fmt, ##__VA_ARGS__)

View File

@ -9,9 +9,11 @@
#include <netinet/in.h>
#include "sd-event.h"
#include "sd-dhcp6-client.h"
#include "list.h"
#include "hashmap.h"
#include "list.h"
#include "log-link.h"
#include "macro.h"
#include "sparse-endian.h"
@ -78,7 +80,7 @@ struct ia_ta {
be32_t id;
} _packed_;
struct DHCP6IA {
typedef struct DHCP6IA {
uint16_t type;
union {
struct ia_na ia_na;
@ -87,12 +89,7 @@ struct DHCP6IA {
};
LIST_HEAD(DHCP6Address, addresses);
};
typedef struct DHCP6IA DHCP6IA;
#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
#define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, fmt, ##__VA_ARGS__)
} DHCP6IA;
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
@ -105,7 +102,7 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHash
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code);
int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code);
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count,
size_t *allocated);
@ -121,3 +118,16 @@ const char *dhcp6_message_type_to_string(int s) _const_;
int dhcp6_message_type_from_string(const char *s) _pure_;
const char *dhcp6_message_status_to_string(int s) _const_;
int dhcp6_message_status_from_string(const char *s) _pure_;
#define log_dhcp6_client_errno(client, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_dhcp6_client_get_ifname(client), \
LOG_DEBUG, _e, "DHCPv6 client: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_dhcp6_client(client, fmt, ...) \
log_dhcp6_client_errno(client, 0, fmt, ##__VA_ARGS__)

View File

@ -425,7 +425,7 @@ int dhcp6_option_parse_status(DHCP6Option *option, size_t len) {
return be16toh(statusopt->status);
}
static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
static int dhcp6_option_parse_address(sd_dhcp6_client *client, DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option;
DHCP6Address *addr;
uint32_t lt_valid, lt_pref;
@ -437,23 +437,20 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t
lt_valid = be32toh(addr_option->iaaddr.lifetime_valid);
lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid) {
log_dhcp6_client(client,
if (lt_valid == 0 || lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Valid lifetime of an IA address is zero or "
"preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
return -EINVAL;
}
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option));
if (r < 0)
return r;
if (r > 0) {
log_dhcp6_client(client, "Non-zero status code '%s' for address is received",
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Non-zero status code '%s' for address is received",
dhcp6_message_status_to_string(r));
return -EINVAL;
}
}
addr = new0(DHCP6Address, 1);
@ -470,7 +467,7 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t
return 0;
}
static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
static int dhcp6_option_parse_pdprefix(sd_dhcp6_client *client, DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option;
DHCP6Address *prefix;
uint32_t lt_valid, lt_pref;
@ -482,23 +479,20 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_
lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid);
lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid) {
log_dhcp6_client(client,
if (lt_valid == 0 || lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Valid lifetieme of a PD prefix is zero or "
"preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
return -EINVAL;
}
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option));
if (r < 0)
return r;
if (r > 0) {
log_dhcp6_client(client, "Non-zero status code '%s' for PD prefix is received",
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Non-zero status code '%s' for PD prefix is received",
dhcp6_message_status_to_string(r));
return -EINVAL;
}
}
prefix = new0(DHCP6Address, 1);
@ -515,7 +509,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_
return 0;
}
int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code) {
int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code) {
uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
uint16_t iatype, optlen;
size_t iaaddr_offset;
@ -541,10 +535,10 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
lt_t1 = be32toh(ia->ia_na.lifetime_t1);
lt_t2 = be32toh(ia->ia_na.lifetime_t2);
if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
log_dhcp6_client(client, "IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2);
return -EINVAL;
}
if (lt_t1 > lt_t2)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec",
lt_t1, lt_t2);
break;
@ -559,10 +553,10 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
lt_t1 = be32toh(ia->ia_pd.lifetime_t1);
lt_t2 = be32toh(ia->ia_pd.lifetime_t2);
if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
log_dhcp6_client(client, "IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2);
return -EINVAL;
}
if (lt_t1 > lt_t2)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec",
lt_t1, lt_t2);
break;
@ -594,12 +588,11 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
switch (opt) {
case SD_DHCP6_OPTION_IAADDR:
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA)) {
log_dhcp6_client(client, "IA Address option not in IA NA or TA option");
return -EINVAL;
}
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA))
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA Address option not in IA NA or TA option");
r = dhcp6_option_parse_address(option, ia, &lt_valid);
r = dhcp6_option_parse_address(client, option, ia, &lt_valid);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0 && lt_valid < lt_min)
@ -609,12 +602,11 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
case SD_DHCP6_OPTION_IA_PD_PREFIX:
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD)) {
log_dhcp6_client(client, "IA PD Prefix option not in IA PD option");
return -EINVAL;
}
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD))
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA PD Prefix option not in IA PD option");
r = dhcp6_option_parse_pdprefix(option, ia, &lt_valid);
r = dhcp6_option_parse_pdprefix(client, option, ia, &lt_valid);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0 && lt_valid < lt_min)
@ -650,7 +642,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
switch(iatype) {
case SD_DHCP6_OPTION_IA_NA:
if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2 && lt_min != UINT32_MAX) {
if (ia->ia_na.lifetime_t1 == 0 && ia->ia_na.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_na.lifetime_t1 = htobe32(lt_t1);
@ -663,7 +655,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
break;
case SD_DHCP6_OPTION_IA_PD:
if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2 && lt_min != UINT32_MAX) {
if (ia->ia_pd.lifetime_t1 == 0 && ia->ia_pd.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_pd.lifetime_t1 = htobe32(lt_t1);

View File

@ -5,13 +5,14 @@
#include "sd-lldp.h"
#include "hashmap.h"
#include "log.h"
#include "log-link.h"
#include "prioq.h"
struct sd_lldp {
unsigned n_ref;
int ifindex;
char *ifname;
int fd;
sd_event *event;
@ -32,8 +33,18 @@ struct sd_lldp {
struct ether_addr filter_address;
};
#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
const char* lldp_event_to_string(sd_lldp_event_t e) _const_;
sd_lldp_event_t lldp_event_from_string(const char *s) _pure_;
#define log_lldp_errno(lldp, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_lldp_get_ifname(lldp), \
LOG_DEBUG, _e, "LLDP: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_lldp(lldp, fmt, ...) \
log_lldp_errno(lldp, 0, fmt, ##__VA_ARGS__)

View File

@ -112,7 +112,7 @@ sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
return n;
}
static int parse_string(char **s, const void *q, size_t n) {
static int parse_string(sd_lldp *lldp, char **s, const void *q, size_t n) {
const char *p = q;
char *k;
@ -120,7 +120,7 @@ static int parse_string(char **s, const void *q, size_t n) {
assert(p || n == 0);
if (*s) {
log_lldp("Found duplicate string, ignoring field.");
log_lldp(lldp, "Found duplicate string, ignoring field.");
return 0;
}
@ -133,14 +133,14 @@ static int parse_string(char **s, const void *q, size_t n) {
/* Look for inner NULs */
if (memchr(p, 0, n)) {
log_lldp("Found inner NUL in string, ignoring field.");
log_lldp(lldp, "Found inner NUL in string, ignoring field.");
return 0;
}
/* Let's escape weird chars, for security reasons */
k = cescape_length(p, n);
if (!k)
return -ENOMEM;
return log_oom_debug();
free(*s);
*s = k;
@ -156,27 +156,24 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
assert(n);
if (n->raw_size < sizeof(struct ether_header)) {
log_lldp("Received truncated packet, ignoring.");
return -EBADMSG;
}
if (n->raw_size < sizeof(struct ether_header))
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Received truncated packet, ignoring.");
memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
if (h.ether_type != htobe16(ETHERTYPE_LLDP)) {
log_lldp("Received packet with wrong type, ignoring.");
return -EBADMSG;
}
if (h.ether_type != htobe16(ETHERTYPE_LLDP))
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Received packet with wrong type, ignoring.");
if (h.ether_dhost[0] != 0x01 ||
h.ether_dhost[1] != 0x80 ||
h.ether_dhost[2] != 0xc2 ||
h.ether_dhost[3] != 0x00 ||
h.ether_dhost[4] != 0x00 ||
!IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) {
log_lldp("Received packet with wrong destination address, ignoring.");
return -EBADMSG;
}
!IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e))
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Received packet with wrong destination address, ignoring.");
memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
@ -188,27 +185,24 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
uint8_t type;
uint16_t length;
if (left < 2) {
log_lldp("TLV lacks header, ignoring.");
return -EBADMSG;
}
if (left < 2)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"TLV lacks header, ignoring.");
type = p[0] >> 1;
length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
p += 2, left -= 2;
if (left < length) {
log_lldp("TLV truncated, ignoring datagram.");
return -EBADMSG;
}
if (left < length)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"TLV truncated, ignoring datagram.");
switch (type) {
case SD_LLDP_TYPE_END:
if (length != 0) {
log_lldp("End marker TLV not zero-sized, ignoring datagram.");
return -EBADMSG;
}
if (length != 0)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"End marker TLV not zero-sized, ignoring datagram.");
/* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
* as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
@ -216,98 +210,93 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
goto end_marker;
case SD_LLDP_TYPE_CHASSIS_ID:
if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */
log_lldp("Chassis ID field size out of range, ignoring datagram.");
return -EBADMSG;
}
if (n->id.chassis_id) {
log_lldp("Duplicate chassis ID field, ignoring datagram.");
return -EBADMSG;
}
if (length < 2 || length > 256)
/* includes the chassis subtype, hence one extra byte */
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Chassis ID field size out of range, ignoring datagram.");
if (n->id.chassis_id)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Duplicate chassis ID field, ignoring datagram.");
n->id.chassis_id = memdup(p, length);
if (!n->id.chassis_id)
return -ENOMEM;
return log_oom_debug();
n->id.chassis_id_size = length;
break;
case SD_LLDP_TYPE_PORT_ID:
if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */
log_lldp("Port ID field size out of range, ignoring datagram.");
return -EBADMSG;
}
if (n->id.port_id) {
log_lldp("Duplicate port ID field, ignoring datagram.");
return -EBADMSG;
}
if (length < 2 || length > 256)
/* includes the port subtype, hence one extra byte */
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Port ID field size out of range, ignoring datagram.");
if (n->id.port_id)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Duplicate port ID field, ignoring datagram.");
n->id.port_id = memdup(p, length);
if (!n->id.port_id)
return -ENOMEM;
return log_oom_debug();
n->id.port_id_size = length;
break;
case SD_LLDP_TYPE_TTL:
if (length != 2) {
log_lldp("TTL field has wrong size, ignoring datagram.");
return -EBADMSG;
}
if (length != 2)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"TTL field has wrong size, ignoring datagram.");
if (n->has_ttl) {
log_lldp("Duplicate TTL field, ignoring datagram.");
return -EBADMSG;
}
if (n->has_ttl)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Duplicate TTL field, ignoring datagram.");
n->ttl = unaligned_read_be16(p);
n->has_ttl = true;
break;
case SD_LLDP_TYPE_PORT_DESCRIPTION:
r = parse_string(&n->port_description, p, length);
r = parse_string(n->lldp, &n->port_description, p, length);
if (r < 0)
return r;
break;
case SD_LLDP_TYPE_SYSTEM_NAME:
r = parse_string(&n->system_name, p, length);
r = parse_string(n->lldp, &n->system_name, p, length);
if (r < 0)
return r;
break;
case SD_LLDP_TYPE_SYSTEM_DESCRIPTION:
r = parse_string(&n->system_description, p, length);
r = parse_string(n->lldp, &n->system_description, p, length);
if (r < 0)
return r;
break;
case SD_LLDP_TYPE_SYSTEM_CAPABILITIES:
if (length != 4)
log_lldp("System capabilities field has wrong size, ignoring.");
else {
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"System capabilities field has wrong size.");
n->system_capabilities = unaligned_read_be16(p);
n->enabled_capabilities = unaligned_read_be16(p + 2);
n->has_capabilities = true;
}
break;
case SD_LLDP_TYPE_PRIVATE: {
case SD_LLDP_TYPE_PRIVATE:
if (length < 4)
log_lldp("Found private TLV that is too short, ignoring.");
else {
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"Found private TLV that is too short, ignoring.");
/* RFC 8520: MUD URL */
if (memcmp(p, SD_LLDP_OUI_MUD, sizeof(SD_LLDP_OUI_MUD)) == 0 &&
p[sizeof(SD_LLDP_OUI_MUD)] == SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION) {
r = parse_string(&n->mud_url, p + sizeof(SD_LLDP_OUI_MUD) + 1,
r = parse_string(n->lldp, &n->mud_url, p + sizeof(SD_LLDP_OUI_MUD) + 1,
length - 1 - sizeof(SD_LLDP_OUI_MUD));
if (r < 0)
return r;
}
}
}
break;
}
@ -315,11 +304,9 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
}
end_marker:
if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) {
log_lldp("One or more mandatory TLV missing in datagram. Ignoring.");
return -EBADMSG;
}
if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl)
return log_lldp_errno(n->lldp, SYNTHETIC_ERRNO(EBADMSG),
"One or more mandatory TLV missing in datagram. Ignoring.");
n->rindex = sizeof(struct ether_header);

View File

@ -16,6 +16,8 @@ sources = files('''
sd-ipv4acd.c
arp-util.h
arp-util.c
network-common.c
network-common.h
network-internal.c
network-internal.h
sd-ndisc.c

View File

@ -5,11 +5,11 @@
Copyright © 2014 Intel Corporation. All rights reserved.
***/
#include "log.h"
#include "time-util.h"
#include "sd-ndisc.h"
#include "log-link.h"
#include "time-util.h"
#define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC)
#define NDISC_MAX_ROUTER_SOLICITATION_INTERVAL (3600U * USEC_PER_SEC)
#define NDISC_MAX_ROUTER_SOLICITATIONS 3U
@ -18,6 +18,7 @@ struct sd_ndisc {
unsigned n_ref;
int ifindex;
char *ifname;
int fd;
sd_event *event;
@ -37,8 +38,18 @@ struct sd_ndisc {
void *userdata;
};
#define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__)
#define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__)
const char* ndisc_event_to_string(sd_ndisc_event_t e) _const_;
sd_ndisc_event_t ndisc_event_from_string(const char *s) _pure_;
#define log_ndisc_errno(ndisc, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_ndisc_get_ifname(ndisc), \
LOG_DEBUG, _e, "NDISC: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_ndisc(ndisc, fmt, ...) \
log_ndisc_errno(ndisc, 0, fmt, ##__VA_ARGS__)

View File

@ -43,7 +43,7 @@ _public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, si
return -ENOMEM;
memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size);
r = ndisc_router_parse(rt);
r = ndisc_router_parse(NULL, rt);
if (r < 0)
return r;
@ -87,7 +87,7 @@ _public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size
return 0;
}
int ndisc_router_parse(sd_ndisc_router *rt) {
int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
struct nd_router_advert *a;
const uint8_t *p;
bool has_mtu = false, has_flag_extension = false;
@ -95,23 +95,20 @@ int ndisc_router_parse(sd_ndisc_router *rt) {
assert(rt);
if (rt->raw_size < sizeof(struct nd_router_advert)) {
log_ndisc("Too small to be a router advertisement, ignoring.");
return -EBADMSG;
}
if (rt->raw_size < sizeof(struct nd_router_advert))
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Too small to be a router advertisement, ignoring.");
/* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
a = NDISC_ROUTER_RAW(rt);
if (a->nd_ra_type != ND_ROUTER_ADVERT) {
log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
return -EBADMSG;
}
if (a->nd_ra_type != ND_ROUTER_ADVERT)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Received ND packet that is not a router advertisement, ignoring.");
if (a->nd_ra_code != 0) {
log_ndisc("Received ND packet with wrong RA code, ignoring.");
return -EBADMSG;
}
if (a->nd_ra_code != 0)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Received ND packet with wrong RA code, ignoring.");
rt->hop_limit = a->nd_ra_curhoplimit;
rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */
@ -131,36 +128,31 @@ int ndisc_router_parse(sd_ndisc_router *rt) {
if (left == 0)
break;
if (left < 2) {
log_ndisc("Option lacks header, ignoring datagram.");
return -EBADMSG;
}
if (left < 2)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Option lacks header, ignoring datagram.");
type = p[0];
length = p[1] * 8;
if (length == 0) {
log_ndisc("Zero-length option, ignoring datagram.");
return -EBADMSG;
}
if (left < length) {
log_ndisc("Option truncated, ignoring datagram.");
return -EBADMSG;
}
if (length == 0)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Zero-length option, ignoring datagram.");
if (left < length)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Option truncated, ignoring datagram.");
switch (type) {
case SD_NDISC_OPTION_PREFIX_INFORMATION:
if (length != 4*8) {
log_ndisc("Prefix option of invalid size, ignoring datagram.");
return -EBADMSG;
}
if (length != 4*8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Prefix option of invalid size, ignoring datagram.");
if (p[2] > 128) {
log_ndisc("Bad prefix length, ignoring datagram.");
return -EBADMSG;
}
if (p[2] > 128)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Bad prefix length, ignoring datagram.");
break;
@ -168,14 +160,13 @@ int ndisc_router_parse(sd_ndisc_router *rt) {
uint32_t m;
if (has_mtu) {
log_ndisc("MTU option specified twice, ignoring.");
log_ndisc(nd, "MTU option specified twice, ignoring.");
break;
}
if (length != 8) {
log_ndisc("MTU option of invalid size, ignoring datagram.");
return -EBADMSG;
}
if (length != 8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"MTU option of invalid size, ignoring datagram.");
m = be32toh(*(uint32_t*) (p + 4));
if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
@ -186,37 +177,32 @@ int ndisc_router_parse(sd_ndisc_router *rt) {
}
case SD_NDISC_OPTION_ROUTE_INFORMATION:
if (length < 1*8 || length > 3*8) {
log_ndisc("Route information option of invalid size, ignoring datagram.");
return -EBADMSG;
}
if (length < 1*8 || length > 3*8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Route information option of invalid size, ignoring datagram.");
if (p[2] > 128) {
log_ndisc("Bad route prefix length, ignoring datagram.");
return -EBADMSG;
}
if (p[2] > 128)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Bad route prefix length, ignoring datagram.");
break;
case SD_NDISC_OPTION_RDNSS:
if (length < 3*8 || (length % (2*8)) != 1*8) {
log_ndisc("RDNSS option has invalid size.");
return -EBADMSG;
}
if (length < 3*8 || (length % (2*8)) != 1*8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG), "RDNSS option has invalid size.");
break;
case SD_NDISC_OPTION_FLAGS_EXTENSION:
if (has_flag_extension) {
log_ndisc("Flags extension option specified twice, ignoring.");
log_ndisc(nd, "Flags extension option specified twice, ignoring.");
break;
}
if (length < 1*8) {
log_ndisc("Flags extension option has invalid size.");
return -EBADMSG;
}
if (length < 1*8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Flags extension option has invalid size.");
/* Add in the additional flags bits */
rt->flags |=
@ -231,10 +217,9 @@ int ndisc_router_parse(sd_ndisc_router *rt) {
break;
case SD_NDISC_OPTION_DNSSL:
if (length < 2*8) {
log_ndisc("DNSSL option has invalid size.");
return -EBADMSG;
}
if (length < 2*8)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"DNSSL option has invalid size.");
break;
}
@ -437,7 +422,7 @@ _public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret)
flags = pi->nd_opt_pi_flags_reserved;
if ((flags & ND_OPT_PI_FLAG_AUTO) && (pi->nd_opt_pi_prefix_len != 64)) {
log_ndisc("Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
log_ndisc(NULL, "Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
flags &= ~ND_OPT_PI_FLAG_AUTO;
}

View File

@ -45,4 +45,4 @@ static inline size_t NDISC_ROUTER_OPTION_LENGTH(const sd_ndisc_router *rt) {
}
sd_ndisc_router *ndisc_router_new(size_t raw_size);
int ndisc_router_parse(sd_ndisc_router *rt);
int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt);

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "format-util.h"
#include "network-common.h"
#include "string-util.h"
const char *get_ifname(int ifindex, char **ifname) {
char buf[IF_NAMESIZE + 1];
assert(ifname);
/* This sets ifname only when it is not set yet. */
if (*ifname)
return *ifname;
if (ifindex <= 0)
return NULL;
if (!format_ifname(ifindex, buf))
return NULL;
return *ifname = strdup(buf);
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
const char *get_ifname(int ifindex, char **ifname);

View File

@ -7,7 +7,7 @@
#include "sd-radv.h"
#include "log.h"
#include "log-link.h"
#include "list.h"
#include "sparse-endian.h"
@ -41,6 +41,7 @@ struct sd_radv {
RAdvState state;
int ifindex;
char *ifname;
sd_event *event;
int event_priority;
@ -124,6 +125,15 @@ struct sd_radv_route_prefix {
LIST_FIELDS(struct sd_radv_route_prefix, prefix);
};
#define log_radv_full(level, error, fmt, ...) log_internal(level, error, PROJECT_FILE, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__)
#define log_radv_errno(error, fmt, ...) log_radv_full(LOG_DEBUG, error, fmt, ##__VA_ARGS__)
#define log_radv(fmt, ...) log_radv_errno(0, fmt, ##__VA_ARGS__)
#define log_radv_errno(radv, error, fmt, ...) \
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_radv_get_ifname(radv), \
LOG_DEBUG, _e, "RADV: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_radv(radv, fmt, ...) \
log_radv_errno(radv, 0, fmt, ##__VA_ARGS__)

View File

@ -24,6 +24,7 @@
#include "hostname-util.h"
#include "io-util.h"
#include "memory-util.h"
#include "network-common.h"
#include "random-util.h"
#include "set.h"
#include "sort-util.h"
@ -76,6 +77,7 @@ struct sd_dhcp_client {
int event_priority;
sd_event_source *timeout_resend;
int ifindex;
char *ifname;
int fd;
uint16_t port;
union sockaddr_union link;
@ -282,6 +284,23 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
return 0;
}
int sd_dhcp_client_set_ifname(sd_dhcp_client *client, const char *ifname) {
assert_return(client, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&client->ifname, ifname);
}
const char *sd_dhcp_client_get_ifname(sd_dhcp_client *client) {
if (!client)
return NULL;
return get_ifname(client->ifindex, &client->ifname);
}
int sd_dhcp_client_set_mac(
sd_dhcp_client *client,
const uint8_t *addr,
@ -2205,6 +2224,7 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
client->user_class = strv_free(client->user_class);
ordered_hashmap_free(client->extra_options);
ordered_hashmap_free(client->vendor_options);
free(client->ifname);
return mfree(client);
}

View File

@ -15,6 +15,7 @@
#include "fd-util.h"
#include "in-addr-util.h"
#include "io-util.h"
#include "network-common.h"
#include "ordered-set.h"
#include "siphash24.h"
#include "string-util.h"
@ -158,6 +159,8 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
ordered_set_free(server->vendor_options);
free(server->bound_leases);
free(server->ifname);
return mfree(server);
}
@ -169,29 +172,47 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
assert_return(ret, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
server = new0(sd_dhcp_server, 1);
server = new(sd_dhcp_server, 1);
if (!server)
return -ENOMEM;
server->n_ref = 1;
server->fd_raw = -1;
server->fd = -1;
server->address = htobe32(INADDR_ANY);
server->netmask = htobe32(INADDR_ANY);
server->ifindex = ifindex;
*server = (sd_dhcp_server) {
.n_ref = 1,
.fd_raw = -1,
.fd = -1,
.address = htobe32(INADDR_ANY),
.netmask = htobe32(INADDR_ANY),
.ifindex = ifindex,
.default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC),
.max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC),
};
server->leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops);
if (!server->leases_by_client_id)
return -ENOMEM;
server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC);
server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC);
*ret = TAKE_PTR(server);
return 0;
}
int sd_dhcp_server_set_ifname(sd_dhcp_server *server, const char *ifname) {
assert_return(server, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&server->ifname, ifname);
}
const char *sd_dhcp_server_get_ifname(sd_dhcp_server *server) {
if (!server)
return NULL;
return get_ifname(server->ifindex, &server->ifname);
}
int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
int r;

View File

@ -21,6 +21,7 @@
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "network-common.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-table.h"
@ -47,6 +48,7 @@ struct sd_dhcp6_client {
sd_event *event;
int event_priority;
int ifindex;
char *ifname;
DHCP6Address hint_pd_prefix;
struct in6_addr local_address;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
@ -165,6 +167,23 @@ int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
return 0;
}
int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname) {
assert_return(client, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&client->ifname, ifname);
}
const char *sd_dhcp6_client_get_ifname(sd_dhcp6_client *client) {
if (!client)
return NULL;
return get_ifname(client->ifindex, &client->ifname);
}
int sd_dhcp6_client_set_local_address(
sd_dhcp6_client *client,
const struct in6_addr *local_address) {
@ -1172,7 +1191,7 @@ static int client_parse_message(
break;
}
r = dhcp6_option_parse_ia(option, &lease->ia, &ia_na_status);
r = dhcp6_option_parse_ia(client, option, &lease->ia, &ia_na_status);
if (r < 0 && r != -ENOMSG)
return r;
@ -1205,7 +1224,7 @@ static int client_parse_message(
break;
}
r = dhcp6_option_parse_ia(option, &lease->pd, &ia_pd_status);
r = dhcp6_option_parse_ia(client, option, &lease->pd, &ia_pd_status);
if (r < 0 && r != -ENOMSG)
return r;
@ -1787,6 +1806,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
ordered_hashmap_free(client->extra_options);
strv_free(client->user_class);
strv_free(client->vendor_class);
free(client->ifname);
return mfree(client);
}

View File

@ -206,7 +206,7 @@ int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
lease->dns_count,
&lease->dns_allocated);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Invalid DNS server option: %m");
return r;
lease->dns_count = r;
@ -321,19 +321,16 @@ int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen)
if (!optlen)
return 0;
if (lease->ntp || lease->ntp_fqdn) {
log_dhcp6_client(client, "NTP information already provided");
if (lease->ntp || lease->ntp_fqdn)
return -EEXIST;
return 0;
}
log_dhcp6_client(client, "Using deprecated SNTP information");
/* Using deprecated SNTP information */
r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
lease->ntp_count,
&lease->ntp_allocated);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Invalid SNTP server option: %m");
return r;
lease->ntp_count = r;

View File

@ -16,9 +16,9 @@
#include "ether-addr-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "in-addr-util.h"
#include "log-link.h"
#include "network-common.h"
#include "random-util.h"
#include "siphash24.h"
#include "string-table.h"
@ -56,7 +56,7 @@ struct sd_ipv4acd {
int ifindex;
int fd;
char ifname[IF_NAMESIZE + 1];
char *ifname;
unsigned n_iteration;
unsigned n_conflict;
@ -76,7 +76,15 @@ struct sd_ipv4acd {
};
#define log_ipv4acd_errno(acd, error, fmt, ...) \
log_interface_full_errno(sd_ipv4acd_get_ifname(acd), LOG_DEBUG, error, "IPV4ACD: " fmt, ##__VA_ARGS__)
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_ipv4acd_get_ifname(acd), \
LOG_DEBUG, _e, "IPv4ACD: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_ipv4acd(acd, fmt, ...) \
log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
@ -125,7 +133,7 @@ static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
ipv4acd_reset(acd);
sd_ipv4acd_detach_event(acd);
free(acd->ifname);
return mfree(acd);
}
@ -398,16 +406,10 @@ fail:
}
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
char ifname[IF_NAMESIZE + 1];
assert_return(acd, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
if (!format_ifname(ifindex, ifname))
return -ENODEV;
strcpy(acd->ifname, ifname);
acd->ifindex = ifindex;
return 0;
@ -420,11 +422,21 @@ int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) {
return acd->ifindex;
}
int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *ifname) {
assert_return(acd, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&acd->ifname, ifname);
}
const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) {
if (!acd)
return NULL;
return empty_to_null(acd->ifname);
return get_ifname(acd->ifindex, &acd->ifname);
}
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {

View File

@ -50,7 +50,15 @@ struct sd_ipv4ll {
};
#define log_ipv4ll_errno(ll, error, fmt, ...) \
log_interface_full_errno(sd_ipv4ll_get_ifname(ll), LOG_DEBUG, error, "IPV4LL: " fmt, ##__VA_ARGS__)
({ \
int _e = (error); \
if (DEBUG_LOGGING) \
log_interface_full_errno( \
sd_ipv4ll_get_ifname(ll), \
LOG_DEBUG, _e, "IPv4LL: " fmt, \
##__VA_ARGS__); \
-ERRNO_VALUE(_e); \
})
#define log_ipv4ll(ll, fmt, ...) \
log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__)
@ -112,6 +120,13 @@ int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) {
return sd_ipv4acd_get_ifindex(ll->acd);
}
int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *ifname) {
assert_return(ll, -EINVAL);
assert_return(ifname, -EINVAL);
return sd_ipv4acd_set_ifname(ll->acd, ifname);
}
const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) {
if (!ll)
return NULL;

View File

@ -14,6 +14,7 @@
#include "lldp-neighbor.h"
#include "lldp-network.h"
#include "memory-util.h"
#include "network-common.h"
#include "socket-util.h"
#include "sort-util.h"
#include "string-table.h"
@ -39,12 +40,10 @@ static void lldp_callback(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor
assert(lldp);
assert(event >= 0 && event < _SD_LLDP_EVENT_MAX);
if (!lldp->callback) {
log_lldp("Received '%s' event.", lldp_event_to_string(event));
return;
}
if (!lldp->callback)
return (void) log_lldp(lldp, "Received '%s' event.", lldp_event_to_string(event));
log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event));
log_lldp(lldp, "Invoking callback for '%s' event.", lldp_event_to_string(event));
lldp->callback(lldp, event, n, lldp->userdata);
}
@ -186,11 +185,11 @@ static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) {
r = lldp_add_neighbor(lldp, n);
if (r < 0) {
log_lldp_errno(r, "Failed to add datagram. Ignoring.");
log_lldp_errno(lldp, r, "Failed to add datagram. Ignoring.");
return 0;
}
log_lldp("Successfully processed LLDP datagram.");
log_lldp(lldp, "Successfully processed LLDP datagram.");
return 0;
}
@ -204,8 +203,10 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
assert(lldp);
space = next_datagram_size_fd(fd);
if (space < 0)
return log_lldp_errno(space, "Failed to determine datagram size to read: %m");
if (space < 0) {
log_lldp_errno(lldp, space, "Failed to determine datagram size to read, ignoring: %m");
return 0;
}
n = lldp_neighbor_new(space);
if (!n)
@ -216,12 +217,13 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
log_lldp_errno(lldp, errno, "Failed to read LLDP datagram, ignoring: %m");
return 0;
}
if ((size_t) length != n->raw_size) {
log_lldp("Packet size mismatch.");
return -EINVAL;
log_lldp(lldp, "Packet size mismatch, ignoring");
return 0;
}
/* Try to get the timestamp of this packet if it is known */
@ -267,7 +269,7 @@ _public_ int sd_lldp_start(sd_lldp *lldp) {
(void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
log_lldp("Started LLDP client");
log_lldp(lldp, "Started LLDP client");
return 1;
fail:
@ -282,7 +284,7 @@ _public_ int sd_lldp_stop(sd_lldp *lldp) {
if (lldp->fd < 0)
return 0;
log_lldp("Stopping LLDP client");
log_lldp(lldp, "Stopping LLDP client");
lldp_reset(lldp);
lldp_flush_neighbors(lldp);
@ -343,6 +345,23 @@ _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
return 0;
}
int sd_lldp_set_ifname(sd_lldp *lldp, const char *ifname) {
assert_return(lldp, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&lldp->ifname, ifname);
}
const char *sd_lldp_get_ifname(sd_lldp *lldp) {
if (!lldp)
return NULL;
return get_ifname(lldp->ifindex, &lldp->ifname);
}
static sd_lldp* lldp_free(sd_lldp *lldp) {
assert(lldp);
@ -354,6 +373,7 @@ static sd_lldp* lldp_free(sd_lldp *lldp) {
hashmap_free(lldp->neighbor_by_id);
prioq_free(lldp->neighbor_by_expiry);
free(lldp->ifname);
return mfree(lldp);
}
@ -398,12 +418,16 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
int r;
r = lldp_make_space(lldp, 0);
if (r < 0)
return log_lldp_errno(r, "Failed to make space: %m");
if (r < 0) {
log_lldp_errno(lldp, r, "Failed to make space, ignoring: %m");
return 0;
}
r = lldp_start_timer(lldp, NULL);
if (r < 0)
return log_lldp_errno(r, "Failed to restart timer: %m");
if (r < 0) {
log_lldp_errno(lldp, r, "Failed to restart timer, ignoring: %m");
return 0;
}
return 0;
}

View File

@ -16,6 +16,7 @@
#include "memory-util.h"
#include "ndisc-internal.h"
#include "ndisc-router.h"
#include "network-common.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-table.h"
@ -34,12 +35,10 @@ static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, sd_ndisc_rou
assert(ndisc);
assert(event >= 0 && event < _SD_NDISC_EVENT_MAX);
if (!ndisc->callback) {
log_ndisc("Received '%s' event.", ndisc_event_to_string(event));
return;
}
if (!ndisc->callback)
return (void) log_ndisc(ndisc, "Received '%s' event.", ndisc_event_to_string(event));
log_ndisc("Invoking callback for '%s' event.", ndisc_event_to_string(event));
log_ndisc(ndisc, "Invoking callback for '%s' event.", ndisc_event_to_string(event));
ndisc->callback(ndisc, event, rt, ndisc->userdata);
}
@ -65,6 +64,23 @@ _public_ int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) {
return 0;
}
int sd_ndisc_set_ifname(sd_ndisc *nd, const char *ifname) {
assert_return(nd, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&nd->ifname, ifname);
}
const char *sd_ndisc_get_ifname(sd_ndisc *nd) {
if (!nd)
return NULL;
return get_ifname(nd->ifindex, &nd->ifname);
}
_public_ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
assert_return(nd, -EINVAL);
@ -129,6 +145,7 @@ static sd_ndisc *ndisc_free(sd_ndisc *nd) {
ndisc_reset(nd);
sd_ndisc_detach_event(nd);
free(nd->ifname);
return mfree(nd);
}
@ -181,7 +198,7 @@ static int ndisc_handle_datagram(sd_ndisc *nd, sd_ndisc_router *rt) {
assert(nd);
assert(rt);
r = ndisc_router_parse(rt);
r = ndisc_router_parse(nd, rt);
if (r == -EBADMSG) /* Bad packet */
return 0;
if (r < 0)
@ -193,7 +210,7 @@ static int ndisc_handle_datagram(sd_ndisc *nd, sd_ndisc_router *rt) {
if (rt->hop_limit > 0)
nd->hop_limit = rt->hop_limit;
log_ndisc("Received Router Advertisement: flags %s preference %s lifetime %" PRIu16 " sec",
log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %" PRIu16 " sec",
rt->flags & ND_RA_FLAG_MANAGED ? "MANAGED" : rt->flags & ND_RA_FLAG_OTHER ? "OTHER" : "none",
rt->preference == SD_NDISC_PREFERENCE_HIGH ? "high" : rt->preference == SD_NDISC_PREFERENCE_LOW ? "low" : "medium",
rt->lifetime);
@ -214,8 +231,10 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda
assert(nd->event);
buflen = next_datagram_size_fd(fd);
if (buflen < 0)
return log_ndisc_errno(buflen, "Failed to determine datagram size to read: %m");
if (buflen < 0) {
log_ndisc_errno(nd, buflen, "Failed to determine datagram size to read, ignoring: %m");
return 0;
}
rt = ndisc_router_new(buflen);
if (!rt)
@ -226,22 +245,22 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda
switch (r) {
case -EADDRNOTAVAIL:
(void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &rt->address, &addr);
log_ndisc("Received RA from non-link-local address %s. Ignoring", addr);
log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring", addr);
break;
case -EMULTIHOP:
log_ndisc("Received RA with invalid hop limit. Ignoring.");
log_ndisc(nd, "Received RA with invalid hop limit. Ignoring.");
break;
case -EPFNOSUPPORT:
log_ndisc("Received invalid source address from ICMPv6 socket. Ignoring.");
log_ndisc(nd, "Received invalid source address from ICMPv6 socket. Ignoring.");
break;
case -EAGAIN: /* ignore spurious wakeups */
break;
default:
log_ndisc_errno(r, "Unexpected error while reading from ICMPv6, ignoring: %m");
log_ndisc_errno(nd, r, "Unexpected error while reading from ICMPv6, ignoring: %m");
break;
}
@ -290,11 +309,11 @@ static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
if (r < 0) {
log_ndisc_errno(r, "Error sending Router Solicitation: %m");
log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m");
goto fail;
}
log_ndisc("Sent Router Solicitation, next solicitation in %s",
log_ndisc(nd, "Sent Router Solicitation, next solicitation in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
nd->retransmit_time, USEC_PER_SEC));
@ -311,7 +330,7 @@ static int ndisc_timeout_no_ra(sd_event_source *s, uint64_t usec, void *userdata
assert(s);
assert(nd);
log_ndisc("No RA received before link confirmation timeout");
log_ndisc(nd, "No RA received before link confirmation timeout");
(void) event_source_disable(nd->timeout_no_ra);
ndisc_callback(nd, SD_NDISC_EVENT_TIMEOUT, NULL);
@ -326,7 +345,7 @@ _public_ int sd_ndisc_stop(sd_ndisc *nd) {
if (nd->fd < 0)
return 0;
log_ndisc("Stopping IPv6 Router Solicitation client");
log_ndisc(nd, "Stopping IPv6 Router Solicitation client");
ndisc_reset(nd);
return 1;
@ -379,7 +398,7 @@ _public_ int sd_ndisc_start(sd_ndisc *nd) {
if (r < 0)
goto fail;
log_ndisc("Started IPv6 Router Solicitation client");
log_ndisc(nd, "Started IPv6 Router Solicitation client");
return 1;
fail:

View File

@ -19,6 +19,7 @@
#include "io-util.h"
#include "macro.h"
#include "memory-util.h"
#include "network-common.h"
#include "radv-internal.h"
#include "random-util.h"
#include "socket-util.h"
@ -122,6 +123,7 @@ static sd_radv *radv_free(sd_radv *ra) {
sd_radv_detach_event(ra);
ra->fd = safe_close(ra->fd);
free(ra->ifname);
return mfree(ra);
}
@ -245,22 +247,22 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
switch (r) {
case -EADDRNOTAVAIL:
(void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr);
log_radv("Received RS from non-link-local address %s. Ignoring", addr);
log_radv(ra, "Received RS from non-link-local address %s. Ignoring", addr);
break;
case -EMULTIHOP:
log_radv("Received RS with invalid hop limit. Ignoring.");
log_radv(ra, "Received RS with invalid hop limit. Ignoring.");
break;
case -EPFNOSUPPORT:
log_radv("Received invalid source address from ICMPv6 socket. Ignoring.");
log_radv(ra, "Received invalid source address from ICMPv6 socket. Ignoring.");
break;
case -EAGAIN: /* ignore spurious wakeups */
break;
default:
log_radv_errno(r, "Unexpected error receiving from ICMPv6 socket: %m");
log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, Ignoring: %m");
break;
}
@ -268,7 +270,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
}
if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
log_radv("Too short packet received");
log_radv(ra, "Too short packet received, ignoring");
return 0;
}
@ -276,9 +278,9 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
r = radv_send(ra, &src, ra->lifetime);
if (r < 0)
log_radv_errno(r, "Unable to send solicited Router Advertisement to %s: %m", strnull(addr));
log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", strnull(addr));
else
log_radv("Sent solicited Router Advertisement to %s", strnull(addr));
log_radv(ra, "Sent solicited Router Advertisement to %s", strnull(addr));
return 0;
}
@ -311,7 +313,7 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
r = radv_send(ra, NULL, ra->lifetime);
if (r < 0)
log_radv_errno(r, "Unable to send Router Advertisement: %m");
log_radv_errno(ra, r, "Unable to send Router Advertisement: %m");
/* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
@ -328,7 +330,7 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
timeout = radv_compute_timeout(min_timeout, max_timeout);
log_radv("Next Router Advertisement in %s",
log_radv(ra, "Next Router Advertisement in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
timeout, USEC_PER_SEC));
@ -359,13 +361,13 @@ _public_ int sd_radv_stop(sd_radv *ra) {
if (ra->state == SD_RADV_STATE_IDLE)
return 0;
log_radv("Stopping IPv6 Router Advertisement daemon");
log_radv(ra, "Stopping IPv6 Router Advertisement daemon");
/* RFC 4861, Section 6.2.5, send at least one Router Advertisement
with zero lifetime */
r = radv_send(ra, NULL, 0);
if (r < 0)
log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
log_radv_errno(ra, r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
radv_reset(ra);
ra->fd = safe_close(ra->fd);
@ -410,7 +412,7 @@ _public_ int sd_radv_start(sd_radv *ra) {
ra->state = SD_RADV_STATE_ADVERTISING;
log_radv("Started IPv6 Router Advertisement daemon");
log_radv(ra, "Started IPv6 Router Advertisement daemon");
return 0;
@ -432,6 +434,23 @@ _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
return 0;
}
int sd_radv_set_ifname(sd_radv *ra, const char *ifname) {
assert_return(ra, -EINVAL);
assert_return(ifname, -EINVAL);
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
return -EINVAL;
return free_and_strdup(&ra->ifname, ifname);
}
const char *sd_radv_get_ifname(sd_radv *ra) {
if (!ra)
return NULL;
return get_ifname(ra->ifindex, &ra->ifname);
}
_public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
assert_return(ra, -EINVAL);
@ -562,10 +581,9 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
(void) in_addr_prefix_to_string(AF_INET6,
(const union in_addr_union*) &cur->opt.in6_addr,
cur->opt.prefixlen, &addr_cur);
log_radv("IPv6 prefix %s already configured, ignoring %s",
return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
"IPv6 prefix %s already configured, ignoring %s",
strna(addr_cur), strna(addr_p));
return -EEXIST;
}
p = sd_radv_prefix_ref(p);
@ -575,7 +593,7 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
ra->n_prefixes++;
if (!dynamic) {
log_radv("Added prefix %s", strna(addr_p));
log_radv(ra, "Added prefix %s", strna(addr_p));
return 0;
}
@ -585,9 +603,9 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
if (ra->ra_sent > 0) {
r = radv_send(ra, NULL, ra->lifetime);
if (r < 0)
log_radv_errno(r, "Unable to send Router Advertisement for added prefix: %m");
log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix: %m");
else
log_radv("Sent Router Advertisement for added prefix");
log_radv(ra, "Sent Router Advertisement for added prefix");
}
update:
@ -608,7 +626,7 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
cur->valid_until = valid_until;
cur->preferred_until = preferred_until;
log_radv("Updated prefix %s preferred %s valid %s",
log_radv(ra, "Updated prefix %s preferred %s valid %s",
strna(addr_p),
format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
preferred, USEC_PER_SEC),
@ -678,10 +696,9 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int
(void) in_addr_prefix_to_string(AF_INET6,
(const union in_addr_union*) &cur->opt.in6_addr,
cur->opt.prefixlen, &addr);
log_radv("IPv6 route prefix %s already configured, ignoring %s",
return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
"IPv6 route prefix %s already configured, ignoring %s",
strna(addr), strna(pretty));
return -EEXIST;
}
p = sd_radv_route_prefix_ref(p);
@ -690,7 +707,7 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int
ra->n_route_prefixes++;
if (!dynamic) {
log_radv("Added prefix %s", strna(pretty));
log_radv(ra, "Added prefix %s", strna(pretty));
return 0;
}
@ -698,9 +715,9 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int
if (ra->ra_sent > 0) {
r = radv_send(ra, NULL, ra->lifetime);
if (r < 0)
log_radv_errno(r, "Unable to send Router Advertisement for added route prefix: %m");
log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix: %m");
else
log_radv("Sent Router Advertisement for added route prefix");
log_radv(ra, "Sent Router Advertisement for added route prefix");
}
update:
@ -713,7 +730,7 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int
if (valid_until == USEC_INFINITY)
return -EOVERFLOW;
log_radv("Updated route prefix %s valid %s",
log_radv(ra, "Updated route prefix %s valid %s",
strna(pretty),
format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, valid, USEC_PER_SEC));
@ -842,7 +859,7 @@ _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr
if (prefixlen > 64)
/* unusual but allowed, log it */
log_radv("Unusual prefix length %d greater than 64", prefixlen);
log_radv(NULL, "Unusual prefix length %d greater than 64", prefixlen);
p->opt.in6_addr = *in6_addr;
p->opt.prefixlen = prefixlen;
@ -932,7 +949,7 @@ _public_ int sd_radv_prefix_set_route_prefix(sd_radv_route_prefix *p, const stru
if (prefixlen > 64)
/* unusual but allowed, log it */
log_radv("Unusual prefix length %u greater than 64", prefixlen);
log_radv(NULL, "Unusual prefix length %u greater than 64", prefixlen);
p->opt.in6_addr = *in6_addr;
p->opt.prefixlen = prefixlen;

View File

@ -295,17 +295,17 @@ static int test_option_status(sd_event *e) {
option = (DHCP6Option *)option1;
assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(option, &ia, NULL);
r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
assert_se(r == 0);
assert_se(ia.addresses == NULL);
option->len = htobe16(17);
r = dhcp6_option_parse_ia(option, &ia, NULL);
r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option->len = htobe16(sizeof(DHCP6Option));
r = dhcp6_option_parse_ia(option, &ia, NULL);
r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
@ -313,7 +313,7 @@ static int test_option_status(sd_event *e) {
option = (DHCP6Option *)option2;
assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(option, &ia, NULL);
r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses == NULL);
@ -321,7 +321,7 @@ static int test_option_status(sd_event *e) {
option = (DHCP6Option *)option3;
assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(option, &ia, NULL);
r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses != NULL);
dhcp6_lease_free_ia(&ia);
@ -330,7 +330,7 @@ static int test_option_status(sd_event *e) {
option = (DHCP6Option *)option4;
assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(option, &pd, NULL);
r = dhcp6_option_parse_ia(NULL, option, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses != NULL);
assert_se(memcmp(&pd.ia_pd.id, &option4[4], 4) == 0);
@ -342,7 +342,7 @@ static int test_option_status(sd_event *e) {
option = (DHCP6Option *)option5;
assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(option, &pd, NULL);
r = dhcp6_option_parse_ia(NULL, option, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses != NULL);
dhcp6_lease_free_ia(&pd);
@ -461,7 +461,7 @@ static int test_advertise_option(sd_event *e) {
val = htobe32(120);
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
assert_se(dhcp6_option_parse_ia(option, &lease->ia, NULL) >= 0);
assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
break;
@ -658,7 +658,7 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) {
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
/* Then, this should refuse all addresses. */
assert_se(dhcp6_option_parse_ia(option, &lease->ia, NULL) >= 0);
assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
break;

View File

@ -116,6 +116,8 @@ _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumer
else
hashmap = &enumerator->nomatch_sysattr;
/* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
* multiple times with the same sysattr but different value. */
r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
if (r <= 0)
return r;
@ -131,6 +133,8 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
assert_return(enumerator, -EINVAL);
assert_return(property, -EINVAL);
/* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
* multiple times with the same property but different value. */
r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
if (r <= 0)
return r;

View File

@ -83,8 +83,8 @@ static int monitor_set_nl_address(sd_device_monitor *m) {
}
int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender) {
assert_return(m, -EINVAL);
assert_return(sender, -EINVAL);
assert(m);
assert(sender);
m->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
return 0;
@ -104,7 +104,7 @@ int device_monitor_disconnect(sd_device_monitor *m) {
}
int device_monitor_get_fd(sd_device_monitor *m) {
assert_return(m, -EINVAL);
assert(m);
return m->sock;
}
@ -114,8 +114,8 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
_cleanup_close_ int sock = -1;
int r;
assert(group >= 0 && group < _MONITOR_NETLINK_GROUP_MAX);
assert_return(ret, -EINVAL);
assert_return(group >= 0 && group < _MONITOR_NETLINK_GROUP_MAX, -EINVAL);
if (group == MONITOR_GROUP_UDEV &&
access("/run/udev/control", F_OK) < 0 &&
@ -304,7 +304,7 @@ _public_ sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *
int device_monitor_enable_receiving(sd_device_monitor *m) {
int r;
assert_return(m, -EINVAL);
assert(m);
r = sd_device_monitor_filter_update(m);
if (r < 0)
@ -334,8 +334,8 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
(void) sd_device_monitor_detach_event(m);
hashmap_free_free_free(m->subsystem_filter);
set_free_free(m->tag_filter);
hashmap_free(m->subsystem_filter);
set_free(m->tag_filter);
return mfree(m);
}
@ -346,8 +346,8 @@ static int passes_filter(sd_device_monitor *m, sd_device *device) {
const char *tag, *subsystem, *devtype, *s, *d = NULL;
int r;
assert_return(m, -EINVAL);
assert_return(device, -EINVAL);
assert(m);
assert(device);
if (hashmap_isempty(m->subsystem_filter))
goto tag;
@ -413,6 +413,7 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
bool is_initialized = false;
int r;
assert(m);
assert(ret);
buflen = recvmsg(m->sock, &smsg, 0);
@ -507,10 +508,10 @@ static uint64_t string_bloom64(const char *str) {
uint64_t bits = 0;
uint32_t hash = string_hash32(str);
bits |= 1LLU << (hash & 63);
bits |= 1LLU << ((hash >> 6) & 63);
bits |= 1LLU << ((hash >> 12) & 63);
bits |= 1LLU << ((hash >> 18) & 63);
bits |= UINT64_C(1) << (hash & 63);
bits |= UINT64_C(1) << ((hash >> 6) & 63);
bits |= UINT64_C(1) << ((hash >> 12) & 63);
bits |= UINT64_C(1) << ((hash >> 18) & 63);
return bits;
}
@ -717,40 +718,31 @@ _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) {
}
_public_ int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype) {
_cleanup_free_ char *s = NULL, *d = NULL;
int r;
assert_return(m, -EINVAL);
assert_return(subsystem, -EINVAL);
s = strdup(subsystem);
if (!s)
return -ENOMEM;
if (devtype) {
d = strdup(devtype);
if (!d)
return -ENOMEM;
}
r = hashmap_ensure_put(&m->subsystem_filter, NULL, s, d);
if (r < 0)
/* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
* multiple times with the same subsystem but different devtypes. */
r = hashmap_put_strdup_full(&m->subsystem_filter, &trivial_hash_ops_free_free, subsystem, devtype);
if (r <= 0)
return r;
TAKE_PTR(s);
TAKE_PTR(d);
m->filter_uptodate = false;
return 0;
return r;
}
_public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag) {
int r;
assert_return(m, -EINVAL);
assert_return(tag, -EINVAL);
int r = set_put_strdup(&m->tag_filter, tag);
if (r > 0)
r = set_put_strdup(&m->tag_filter, tag);
if (r <= 0)
return r;
m->filter_uptodate = false;
return r;
}
@ -760,8 +752,8 @@ _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
assert_return(m, -EINVAL);
m->subsystem_filter = hashmap_free_free_free(m->subsystem_filter);
m->tag_filter = set_free_free(m->tag_filter);
m->subsystem_filter = hashmap_free(m->subsystem_filter);
m->tag_filter = set_free(m->tag_filter);
if (setsockopt(m->sock, SOL_SOCKET, SO_DETACH_FILTER, &filter, sizeof(filter)) < 0)
return -errno;

View File

@ -614,14 +614,10 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
#if HAVE_LZ4
LZ4F_errorCode_t c;
_cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
_cleanup_free_ char *buf = NULL;
char *src = NULL;
size_t size, n, total_in = 0, total_out, offset = 0, frame_size;
struct stat st;
_cleanup_free_ void *in_buff = NULL;
_cleanup_free_ char *out_buff = NULL;
size_t out_allocsize, n, total_in = 0, total_out, offset = 0, frame_size;
int r;
static const LZ4F_compressOptions_t options = {
.stableSrc = 1,
};
static const LZ4F_preferences_t preferences = {
.frameInfo.blockSizeID = 5,
};
@ -630,74 +626,66 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
if (LZ4F_isError(c))
return -ENOMEM;
if (fstat(fdf, &st) < 0)
return log_debug_errno(errno, "fstat() failed: %m");
frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences);
size = frame_size + 64*1024; /* add some space for header and trailer */
buf = malloc(size);
if (!buf)
out_allocsize = frame_size + 64*1024; /* add some space for header and trailer */
out_buff = malloc(out_allocsize);
if (!out_buff)
return -ENOMEM;
n = offset = total_out = LZ4F_compressBegin(ctx, buf, size, &preferences);
in_buff = malloc(LZ4_BUFSIZE);
if (!in_buff)
return -ENOMEM;
n = offset = total_out = LZ4F_compressBegin(ctx, out_buff, out_allocsize, &preferences);
if (LZ4F_isError(n))
return -EINVAL;
src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0);
if (src == MAP_FAILED)
return -errno;
log_debug("Buffer size is %zu bytes, header size %zu bytes.", out_allocsize, n);
log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n);
while (total_in < (size_t) st.st_size) {
for (;;) {
ssize_t k;
k = MIN(LZ4_BUFSIZE, st.st_size - total_in);
n = LZ4F_compressUpdate(ctx, buf + offset, size - offset,
src + total_in, k, &options);
if (LZ4F_isError(n)) {
r = -ENOTRECOVERABLE;
goto cleanup;
}
k = loop_read(fdf, in_buff, LZ4_BUFSIZE, true);
if (k < 0)
return k;
if (k == 0)
break;
n = LZ4F_compressUpdate(ctx, out_buff + offset, out_allocsize - offset,
in_buff, k, NULL);
if (LZ4F_isError(n))
return -ENOTRECOVERABLE;
total_in += k;
offset += n;
total_out += n;
if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes) {
r = log_debug_errno(SYNTHETIC_ERRNO(EFBIG),
if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes)
return log_debug_errno(SYNTHETIC_ERRNO(EFBIG),
"Compressed stream longer than %" PRIu64 " bytes", max_bytes);
goto cleanup;
}
if (size - offset < frame_size + 4) {
k = loop_write(fdt, buf, offset, false);
if (k < 0) {
r = k;
goto cleanup;
}
if (out_allocsize - offset < frame_size + 4) {
k = loop_write(fdt, out_buff, offset, false);
if (k < 0)
return k;
offset = 0;
}
}
n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options);
if (LZ4F_isError(n)) {
r = -ENOTRECOVERABLE;
goto cleanup;
}
n = LZ4F_compressEnd(ctx, out_buff + offset, out_allocsize - offset, NULL);
if (LZ4F_isError(n))
return -ENOTRECOVERABLE;
offset += n;
total_out += n;
r = loop_write(fdt, buf, offset, false);
r = loop_write(fdt, out_buff, offset, false);
if (r < 0)
goto cleanup;
return r;
log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
total_in, total_out,
(double) total_out / total_in * 100);
cleanup:
munmap(src, st.st_size);
return r;
return 0;
#else
return -EPROTONOSUPPORT;
#endif

View File

@ -99,10 +99,12 @@ _pure_ static uint64_t uint64_import(const void *buf, size_t buflen) {
static void det_randomize(void *buf, size_t buflen, const void *seed, size_t seedlen, uint32_t idx) {
gcry_md_hd_t hd, hd2;
size_t olen, cpylen;
gcry_error_t err;
uint32_t ctr;
olen = gcry_md_get_algo_dlen(RND_HASH);
gcry_md_open(&hd, RND_HASH, 0);
err = gcry_md_open(&hd, RND_HASH, 0);
assert_se(gcry_err_code(err) == GPG_ERR_NO_ERROR); /* This shouldn't happen */
gcry_md_write(hd, seed, seedlen);
gcry_md_putc(hd, (idx >> 24) & 0xff);
gcry_md_putc(hd, (idx >> 16) & 0xff);
@ -110,7 +112,8 @@ static void det_randomize(void *buf, size_t buflen, const void *seed, size_t see
gcry_md_putc(hd, (idx >> 0) & 0xff);
for (ctr = 0; buflen; ctr++) {
gcry_md_copy(&hd2, hd);
err = gcry_md_copy(&hd2, hd);
assert_se(gcry_err_code(err) == GPG_ERR_NO_ERROR); /* This shouldn't happen */
gcry_md_putc(hd2, (ctr >> 24) & 0xff);
gcry_md_putc(hd2, (ctr >> 16) & 0xff);
gcry_md_putc(hd2, (ctr >> 8) & 0xff);

View File

@ -65,6 +65,8 @@ int journal_file_append_tag(JournalFile *f) {
int journal_file_hmac_start(JournalFile *f) {
uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
gcry_error_t err;
assert(f);
if (!f->seal)
@ -76,7 +78,11 @@ int journal_file_hmac_start(JournalFile *f) {
/* Prepare HMAC for next cycle */
gcry_md_reset(f->hmac);
FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
gcry_md_setkey(f->hmac, key, sizeof(key));
err = gcry_md_setkey(f->hmac, key, sizeof(key));
if (gcry_err_code(err) != GPG_ERR_NO_ERROR)
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"gcry_md_setkey() failed with error code: %d",
gcry_err_code(err));
f->hmac_running = true;

View File

@ -1880,6 +1880,8 @@ static int method_do_shutdown_or_sleep(
return r;
if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_KEXEC_REBOOT))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
} else {
/* Old style method: no flags parameter, but interactive bool passed as boolean in
* payload. Let's convert this argument to the new-style flags parameter for our internal
@ -1893,6 +1895,9 @@ static int method_do_shutdown_or_sleep(
flags = interactive ? SD_LOGIND_INTERACTIVE : 0;
}
if ((flags & SD_LOGIND_KEXEC_REBOOT) && kexec_loaded())
unit_name = SPECIAL_KEXEC_TARGET;
/* Don't allow multiple jobs being executed at the same time */
if (m->action_what > 0)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,

View File

@ -6,20 +6,25 @@
#include <stdlib.h>
#include "alloc-util.h"
#include "dissect-image.h"
#include "id128-util.h"
#include "log.h"
#include "machine-id-setup.h"
#include "main-func.h"
#include "mount-util.h"
#include "parse-argument.h"
#include "path-util.h"
#include "pretty-print.h"
#include "terminal-util.h"
#include "util.h"
static char *arg_root = NULL;
static char *arg_image = NULL;
static bool arg_commit = false;
static bool arg_print = false;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
@ -29,15 +34,18 @@ static int help(void) {
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n\n"
"Initialize /etc/machine-id from a random source.\n\n"
printf("%s [OPTIONS...]\n"
"\n%sInitialize /etc/machine-id from a random source.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --root=ROOT Filesystem root\n"
" --root=PATH Operate relative to root path\n"
" --image=PATH Operate relative to image file\n"
" --commit Commit transient ID\n"
" --print Print used machine ID\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
return 0;
@ -48,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_ROOT,
ARG_IMAGE,
ARG_COMMIT,
ARG_PRINT,
};
@ -56,6 +65,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
{ "image", required_argument, NULL, ARG_IMAGE },
{ "commit", no_argument, NULL, ARG_COMMIT },
{ "print", no_argument, NULL, ARG_PRINT },
{}
@ -82,6 +92,12 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
case ARG_IMAGE:
r = parse_path_argument(optarg, false, &arg_image);
if (r < 0)
return r;
break;
case ARG_COMMIT:
arg_commit = true;
break;
@ -101,10 +117,16 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Extraneous arguments");
if (arg_image && arg_root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
return 1;
}
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
char buf[SD_ID128_STRING_MAX];
sd_id128_t id;
int r;
@ -116,6 +138,26 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
if (arg_image) {
assert(!arg_root);
r = mount_image_privately_interactively(
arg_image,
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK,
&unlink_dir,
&loop_device,
&decrypted_image);
if (r < 0)
return r;
arg_root = strdup(unlink_dir);
if (!arg_root)
return log_oom();
}
if (arg_commit) {
const char *etc_machine_id;

View File

@ -311,7 +311,7 @@ int config_parse_dhcp_route_metric(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
uint32_t metric;
int r;
@ -355,7 +355,7 @@ int config_parse_dhcp_use_dns(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
int r;
assert(filename);
@ -386,6 +386,49 @@ int config_parse_dhcp_use_dns(
return 0;
}
int config_parse_dhcp_use_domains(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
DHCPUseDomains d;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
d = dhcp_use_domains_from_string(rvalue);
if (d < 0) {
log_syntax(unit, LOG_WARNING, filename, line, d,
"Failed to parse %s=%s, ignoring assignment: %m", lvalue, rvalue);
return 0;
}
if (streq_ptr(section, "DHCPv4")) {
network->dhcp_use_domains = d;
network->dhcp_use_domains_set = true;
} else if (streq_ptr(section, "DHCPv6")) {
network->dhcp6_use_domains = d;
network->dhcp6_use_domains_set = true;
} else { /* [DHCP] section */
if (!network->dhcp_use_domains_set)
network->dhcp_use_domains = d;
if (!network->dhcp6_use_domains_set)
network->dhcp6_use_domains = d;
}
return 0;
}
int config_parse_dhcp_use_ntp(
const char* unit,
const char *filename,
@ -398,7 +441,7 @@ int config_parse_dhcp_use_ntp(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
int r;
assert(filename);
@ -441,7 +484,7 @@ int config_parse_section_route_table(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
uint32_t rt;
int r;
@ -478,7 +521,7 @@ int config_parse_iaid(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
uint32_t iaid;
int r;
@ -807,7 +850,7 @@ int config_parse_dhcp_request_options(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
int r;
assert(filename);
@ -861,9 +904,6 @@ int config_parse_dhcp_request_options(
}
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse DHCP use domains setting");
static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
[DHCP_USE_DOMAINS_NO] = "no",
[DHCP_USE_DOMAINS_ROUTE] = "route",

View File

@ -178,7 +178,7 @@ int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata,
}
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL;
_cleanup_ordered_set_free_ OrderedSet *search_domains = NULL, *route_domains = NULL;
Link *l = userdata;
int r;
@ -218,15 +218,15 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
domains = route_only ? &route_domains : &search_domains;
r = ordered_set_ensure_allocated(domains, &string_hash_ops);
r = ordered_set_ensure_allocated(domains, &string_hash_ops_free);
if (r < 0)
return r;
r = ordered_set_put(*domains, str);
r = ordered_set_consume(*domains, TAKE_PTR(str));
if (r == -EEXIST)
continue;
if (r < 0)
return r;
TAKE_PTR(str);
}
r = sd_bus_message_exit_container(message);
@ -242,8 +242,8 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
if (r == 0)
return 1; /* Polkit will call us back */
ordered_set_free_free(l->search_domains);
ordered_set_free_free(l->route_domains);
ordered_set_free(l->search_domains);
ordered_set_free(l->route_domains);
l->search_domains = TAKE_PTR(search_domains);
l->route_domains = TAKE_PTR(route_domains);

View File

@ -478,8 +478,8 @@ void link_dns_settings_clear(Link *link) {
link->dns = mfree(link->dns);
link->n_dns = UINT_MAX;
link->search_domains = ordered_set_free_free(link->search_domains);
link->route_domains = ordered_set_free_free(link->route_domains);
link->search_domains = ordered_set_free(link->search_domains);
link->route_domains = ordered_set_free(link->route_domains);
link->dns_default_route = -1;
link->llmnr = _RESOLVE_SUPPORT_INVALID;

View File

@ -1555,8 +1555,10 @@ int config_parse_address_generation_type(
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse UseDomains= setting");
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
"Failed to parse DHCPv6Client= setting")
"Failed to parse DHCPv6Client= setting");
static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",

View File

@ -79,6 +79,7 @@ void ndisc_flush(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_address_filter);
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_use_domains);
const char* ipv6_accept_ra_start_dhcp6_client_to_string(IPv6AcceptRAStartDHCP6Client i) _const_;
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client_from_string(const char *s) _pure_;

View File

@ -199,7 +199,7 @@ DHCPv4.UseNTP, config_parse_dhcp_use_ntp,
DHCPv4.UseSIP, config_parse_bool, 0, offsetof(Network, dhcp_use_sip)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, 0
DHCPv4.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCPv4.UseGateway, config_parse_tristate, 0, offsetof(Network, dhcp_use_gateway)
DHCPv4.RequestOptions, config_parse_dhcp_request_options, AF_INET, 0
@ -230,6 +230,7 @@ DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_li
DHCPv6.UseAddress, config_parse_bool, 0, offsetof(Network, dhcp6_use_address)
DHCPv6.UseDNS, config_parse_dhcp_use_dns, 0, 0
DHCPv6.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp6_use_hostname)
DHCPv6.UseDomains, config_parse_dhcp_use_domains, 0, 0
DHCPv6.UseNTP, config_parse_dhcp_use_ntp, 0, 0
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit)
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
@ -245,7 +246,7 @@ DHCPv6.RouteMetric, config_parse_dhcp_route_metric,
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
IPv6AcceptRA.RouterAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_router)
@ -466,8 +467,8 @@ DHCP.UseDNS, config_parse_dhcp_use_dns,
DHCP.UseNTP, config_parse_dhcp_use_ntp, 0, 0
DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCP.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCP.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCP.UseDomains, config_parse_dhcp_use_domains, 0, 0
DHCP.UseDomainName, config_parse_dhcp_use_domains, 0, 0
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCP.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
@ -485,7 +486,7 @@ DHCP.IAID, config_parse_iaid,
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit)
DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, 0
DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
IPv6AcceptRA.DenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.BlackList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)

View File

@ -896,11 +896,9 @@ int config_parse_domains(
}
OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
r = ordered_set_ensure_allocated(set, &string_hash_ops_free);
if (r < 0)
return log_oom();
r = ordered_set_put_strdup(*set, domain);
r = ordered_set_put_strdup(set, domain);
if (r == -EEXIST)
continue;
if (r < 0)
return log_oom();
}

View File

@ -151,6 +151,7 @@ struct Network {
bool dhcp_send_release;
bool dhcp_send_decline;
DHCPUseDomains dhcp_use_domains;
bool dhcp_use_domains_set;
Set *dhcp_deny_listed_ip;
Set *dhcp_allow_listed_ip;
Set *dhcp_request_options;
@ -165,6 +166,8 @@ struct Network {
bool dhcp6_use_ntp;
bool dhcp6_use_ntp_set;
bool dhcp6_rapid_commit;
DHCPUseDomains dhcp6_use_domains;
bool dhcp6_use_domains_set;
uint8_t dhcp6_pd_length;
uint32_t dhcp6_route_metric;
bool dhcp6_route_metric_set;

View File

@ -19,7 +19,7 @@
#include "strv.h"
#include "tmpfile-util.h"
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
const char *p;
int r;
@ -40,7 +40,7 @@ static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr
return r;
}
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
assert(s);
@ -57,8 +57,8 @@ static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_add
return c;
}
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
_cleanup_free_ char *p = NULL;
int r;
assert(s);
@ -68,7 +68,11 @@ static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address
if (r < 0)
return r;
r = ordered_set_consume(s, p);
r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
if (r < 0)
return r;
r = ordered_set_consume(*s, TAKE_PTR(p));
if (r == -EEXIST)
return 0;
@ -76,7 +80,7 @@ static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address
}
static int ordered_set_put_in4_addrv(
OrderedSet *s,
OrderedSet **s,
const struct in_addr *addresses,
size_t n,
bool (*predicate)(const struct in_addr *addr)) {
@ -100,7 +104,7 @@ static int ordered_set_put_in4_addrv(
}
int manager_save(Manager *m) {
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
_cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
const char *operstate_str, *carrier_state_str, *address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
@ -114,27 +118,6 @@ int manager_save(Manager *m) {
assert(m);
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
sip = ordered_set_new(&string_hash_ops);
if (!sip)
return -ENOMEM;
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
route_domains = ordered_set_new(&dns_name_hash_ops);
if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links) {
const struct in_addr *addresses;
@ -155,21 +138,21 @@ int manager_save(Manager *m) {
/* First add the static configured entries */
if (link->n_dns != UINT_MAX)
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
else
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
if (r < 0)
return r;
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
if (r < 0)
return r;
@ -180,7 +163,7 @@ int manager_save(Manager *m) {
if (link->network->dhcp_use_dns) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
@ -190,7 +173,7 @@ int manager_save(Manager *m) {
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
@ -200,7 +183,7 @@ int manager_save(Manager *m) {
if (link->network->dhcp_use_sip) {
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
@ -208,10 +191,11 @@ int manager_save(Manager *m) {
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
OrderedSet **target_domains;
const char *domainname;
char **domains = NULL;
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? &search_domains : &route_domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(target_domains, domainname);
@ -504,14 +488,12 @@ int link_save(Link *link) {
/************************************************************/
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease) {
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO && link->dhcp_lease) {
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
}
if (link->dhcp6_lease)
if (link->network->dhcp6_use_domains != DHCP_USE_DOMAINS_NO && link->dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
}
fputs("DOMAINS=", f);
space = false;

View File

@ -35,6 +35,7 @@
#include "cgroup-util.h"
#include "copy.h"
#include "cpu-set-util.h"
#include "creds-util.h"
#include "dev-setup.h"
#include "discover-image.h"
#include "dissect-image.h"
@ -1592,9 +1593,9 @@ static int parse_argv(int argc, char *argv[]) {
else {
const char *e;
e = getenv("CREDENTIALS_DIRECTORY");
if (!e)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential not available (no credentials passed at all): %s", word);
r = get_credentials_dir(&e);
if (r < 0)
return log_error_errno(r, "Credential not available (no credentials passed at all): %s", word);
j = path_join(e, p);
if (!j)
@ -3581,8 +3582,12 @@ static int outer_child(
* makes sure ESP partitions and userns are compatible. */
r = dissected_image_mount_and_warn(
dissected_image, directory, arg_uid_shift,
DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|
dissected_image,
directory,
arg_uid_shift,
DISSECT_IMAGE_MOUNT_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK)|
(arg_start_mode == START_BOOT ? DISSECT_IMAGE_VALIDATE_OS : 0));
if (r < 0)
@ -3669,8 +3674,14 @@ static int outer_child(
if (dissected_image) {
/* Now we know the uid shift, let's now mount everything else that might be in the image. */
r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK));
r = dissected_image_mount(
dissected_image,
directory,
arg_uid_shift,
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK));
if (r == -EUCLEAN)
return log_error_errno(r, "File system check for image failed: %m");
if (r < 0)
@ -5378,7 +5389,11 @@ static int run(int argc, char *argv[]) {
}
} else {
DissectImageFlags dissect_image_flags = DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK;
DissectImageFlags dissect_image_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_USR_NO_ROOT;
assert(arg_image);
assert(!arg_template);

View File

@ -2655,11 +2655,15 @@ static int do_copy_files(Partition *p, const char *fs) {
STRV_FOREACH_PAIR(source, target, p->copy_files) {
_cleanup_close_ int sfd = -1, pfd = -1, tfd = -1;
_cleanup_free_ char *dn = NULL;
_cleanup_free_ char *dn = NULL, *fn = NULL;
dn = dirname_malloc(*target);
if (!dn)
return log_oom();
r = path_extract_directory(*target, &dn);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = path_extract_filename(*target, &fn);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from '%s': %m", *target);
sfd = chase_symlinks_and_open(*source, arg_root, CHASE_PREFIX_ROOT|CHASE_WARN, O_CLOEXEC|O_NOCTTY, NULL);
if (sfd < 0)
@ -2686,7 +2690,7 @@ static int do_copy_files(Partition *p, const char *fs) {
r = copy_tree_at(
sfd, ".",
pfd, basename(*target),
pfd, fn,
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
} else

Some files were not shown because too many files have changed in this diff Show More