]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25513 from brauner/pivot_root.nspawn
authorLuca Boccassi <bluca@debian.org>
Tue, 6 Dec 2022 00:51:51 +0000 (01:51 +0100)
committerGitHub <noreply@github.com>
Tue, 6 Dec 2022 00:51:51 +0000 (01:51 +0100)
nspawn: support pivot_root()

155 files changed:
.github/workflows/cifuzz.yml
.github/workflows/codeql.yml
.github/workflows/development_freeze.yml
.github/workflows/differential-shellcheck.yml
.github/workflows/issue_labeler.yml
.github/workflows/requirements.txt
.github/workflows/scorecards.yml
NEWS
TODO
docs/CONTRIBUTING.md
hwdb.d/60-evdev.hwdb
hwdb.d/60-keyboard.hwdb
hwdb.d/70-av-production.hwdb
man/crypttab.xml
man/kernel-install.xml
man/org.freedesktop.systemd1.xml
man/repart.d.xml
man/resolvectl.xml
man/rules/meson.build
man/systemctl.xml
man/systemd-detect-virt.xml
man/systemd-repart.xml
man/systemd-resolved.service.xml
man/systemd.network.xml
man/systemd.resource-control.xml
man/systemd.unit.xml
meson.build
mkosi.conf.d/10-systemd.conf
po/id.po
src/basic/chase-symlinks.c
src/basic/constants.h
src/basic/dirent-util.c
src/basic/dirent-util.h
src/basic/fd-util.c
src/basic/fd-util.h
src/basic/hostname-util.h
src/basic/recurse-dir.c
src/basic/terminal-util.c
src/basic/virt.c
src/basic/virt.h
src/boot/efi/boot.c
src/boot/efi/console.c
src/boot/efi/cpio.c
src/boot/efi/efi-string.c
src/boot/efi/efi-string.h
src/boot/efi/linux.c
src/boot/efi/linux.h
src/boot/efi/linux_x86.c
src/boot/efi/measure.c
src/boot/efi/missing_efi.h
src/boot/efi/part-discovery.c
src/boot/efi/splash.c
src/boot/efi/stub.c
src/boot/efi/test-efi-string.c
src/boot/efi/util.c
src/boot/efi/util.h
src/boot/efi/vmm.c
src/cgtop/cgtop.c
src/core/dbus-manager.c
src/core/dbus-scope.c
src/core/device.c
src/core/device.h
src/core/main.c
src/core/namespace.c
src/core/scope.c
src/core/scope.h
src/core/service.c
src/dissect/dissect.c
src/gpt-auto-generator/gpt-auto-generator.c
src/home/homed-manager.h
src/home/homework-luks.c
src/journal/journald-audit.c
src/journal/journald-context.c
src/journal/journald-kmsg.c
src/journal/journald-native.c
src/journal/journald-server.c
src/journal/journald-server.h
src/journal/journald-stream.c
src/journal/journald-syslog.c
src/kernel-install/90-uki-copy.install [new file with mode: 0755]
src/kernel-install/meson.build
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-journal/journal-file.c
src/libsystemd/sd-journal/journal-internal.h
src/libsystemd/sd-journal/journal-vacuum.c
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/sd-netlink.c
src/login/logind-dbus.c
src/login/logind.c
src/mount/mount-tool.c
src/network/networkd-address.c
src/network/networkd-ndisc.c
src/network/networkd-util.h
src/nspawn/nspawn.c
src/nss-myhostname/nss-myhostname.c
src/oom/oomd-util.c
src/oom/oomd-util.h
src/oom/test-oomd-util.c
src/partition/repart.c
src/portable/portable.c
src/pstore/pstore.c
src/resolve/fuzz-resource-record.c [new file with mode: 0644]
src/resolve/meson.build
src/resolve/resolvectl.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-synthesize.c
src/resolve/resolved-dns-synthesize.h
src/rpm/systemd-update-helper.in
src/shared/acl-util.c
src/shared/acl-util.h
src/shared/blkid-util.h
src/shared/blockdev-util.c
src/shared/bootspec.c
src/shared/btrfs-util.c
src/shared/bus-unit-util.c
src/shared/copy.c
src/shared/copy.h
src/shared/cryptsetup-util.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/fdisk-util.c [new file with mode: 0644]
src/shared/fdisk-util.h
src/shared/find-esp.c
src/shared/install.c
src/shared/meson.build
src/shared/mkfs-util.c
src/shared/resolve-util.h
src/sysext/sysext.c
src/systemctl/fuzz-systemctl-parse-argv.c
src/systemctl/systemctl-enable.c
src/systemctl/systemctl-start-special.c
src/systemctl/systemctl.c
src/systemctl/systemctl.h
src/sysupdate/sysupdate-partition.c
src/test/test-fd-util.c
src/test/test-loop-block.c
src/tmpfiles/tmpfiles.c
src/udev/udev-builtin-blkid.c
test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120 [new file with mode: 0644]
test/fuzz/fuzz-resource-record/crash-type-bitmap-to-json [new file with mode: 0644]
test/fuzz/fuzz-resource-record/ub-zero-length-rdata [new file with mode: 0644]
test/test-shutdown.py
test/units/testsuite-58.sh
test/units/testsuite-64.sh
test/units/testsuite-70.sh
test/units/testsuite-74.cgtop.sh
test/units/testsuite-74.firstboot.sh
test/units/testsuite-75.sh
units/systemd-boot-system-token.service
units/systemd-networkd-wait-online.service.in
units/systemd-networkd-wait-online@.service.in

index 25731abc5a5aa7708f38a3a167c110ab3b5bcf58..d783abba3b07cc7f8549f5b1e8e3778d6e813427 100644 (file)
@@ -55,7 +55,7 @@ jobs:
           dry-run: false
           sanitizer: ${{ matrix.sanitizer }}
       - name: Upload Crash
-        uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8
+        uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb
         if: failure() && steps.build.outcome == 'success'
         with:
           name: ${{ matrix.sanitizer }}-${{ matrix.architecture }}-artifacts
index 8b21b5da46084c9c38beb570559433ee702d8e83..fc60df264ed9de63f6564ff8e4cdcd2f2c5ef293 100644 (file)
@@ -26,6 +26,7 @@ permissions:
 jobs:
   analyze:
     name: Analyze
+    if: github.repository != 'systemd/systemd-security'
     runs-on: ubuntu-22.04
     concurrency:
       group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
index 7932373e86b9f4bd44428eed49c1bd68d5ffc5e1..5124d85ac8d2a27ac46960ba050c9b8d99cefb70 100644 (file)
@@ -13,6 +13,7 @@ permissions:
 jobs:
   freezer:
     runs-on: ubuntu-22.04
+    if: github.repository == 'systemd/systemd'
 
     permissions:
       pull-requests: write
index 20ce6816326cb5b79783f53bd3cd7b32b689cde7..ff554b63c19d2bdea61435c2753f0ce08517e334 100644 (file)
@@ -26,6 +26,6 @@ jobs:
           fetch-depth: 0
 
       - name: Differential ShellCheck
-        uses: redhat-plumbers-in-action/differential-shellcheck@1b1b75e42f0694c1012228513b21617a748c866e
+        uses: redhat-plumbers-in-action/differential-shellcheck@f3cd08fcf12680861615270b29494d2b87c3e1cc
         with:
           token: ${{ secrets.GITHUB_TOKEN }}
index 0a97bf4a969d5719361e7987b072a4ff6b5991c8..275dbbb84ee450b3a03a7b405b93432c346ca876 100644 (file)
@@ -29,7 +29,7 @@ jobs:
           template-path: .github/ISSUE_TEMPLATE/${{ matrix.template }}
 
       - name: Set labels based on component field
-        uses: redhat-plumbers-in-action/advanced-issue-labeler@fe9c43b7d77bd8bd7fbe86c2c217e74ebeea71f2
+        uses: redhat-plumbers-in-action/advanced-issue-labeler@88209aef583c66312529c515d41ea6a710a4baba
         with:
           issue-form: ${{ steps.issue-parser.outputs.jsonString }}
           template: ${{ matrix.template }}
index 57839c7f80794b8c7e5b40c45df78554c7d5df9c..00cd6579b467580a5601c72fab235d9b98070786 100644 (file)
@@ -1,18 +1,20 @@
-meson==0.63.3 \
-    --hash=sha256:519c0932e1a8b208741f0fdce90aa5c0b528dd297cf337009bf63539846ac056 \
-    --hash=sha256:d677b809c4895dcbaac9bf6c43703fcb3609a4b24c6057c78f828590049cf43a
-ninja==1.10.2.4 \
-    --hash=sha256:24e3bc4713667a9a1d15484ad2bb77bbaedb1e6d45254cb03f7964b8b497231a \
-    --hash=sha256:251fb21cd6691accd0d95e28721ad8a50a6ec0ace97f9a8de3976f39301686f6 \
-    --hash=sha256:327c319176c5a4af21908b727b776e9f5caf275680403da632821ba071fd6296 \
-    --hash=sha256:3300f3f37d62dcc7bdd19284dff9eaed7d629f4ed2725019a6ce3291c655fb83 \
-    --hash=sha256:34c8e44f6e2e35ff9444994bfc7bf451c8d4bf15e31ad1e3ef7b06f78647b35b \
-    --hash=sha256:3fa6e69838613815c80abcaca34681c5b7cf15bf921543e518f5c918d7098bb7 \
-    --hash=sha256:5b973b1ce7075e9091db290adbbf93ba9066a94f97c369d0ff631251c633e81b \
-    --hash=sha256:685daebd1bc21480256351000a01dfb520636832fa65efc9f121474ff640e3df \
-    --hash=sha256:b0350784b37c5080223ec1bedc507153cc714b502c17dd5a64552e930b0dca25 \
-    --hash=sha256:b12cfed6382e510a597b3d08d7eec96664f7c8b8ee436eef645736c453d1c135 \
-    --hash=sha256:b264085e409533aecb57040c5e90fbfb64db91a61575c7e637411780446412fa \
-    --hash=sha256:b86a4e4ba2ed999d8b10f2b3f2ed56d7457ff647268f4098dd0b63dd145ede32 \
-    --hash=sha256:da7a6d9b2ed2018165fbf90068e2c64da08f2568c700fdb8abea07a245dc4664 \
-    --hash=sha256:ea245943a9849e5b1ebd74c1a4c1edd2c9801b62c0386165c7ac47623e353627
+meson==0.64.1 \
+    --hash=sha256:3a8e030c2334f782085f81627062cc6d4a6771edf31e055ffe374f9e6b089ab9 \
+    --hash=sha256:8cf376d3b8640d8957d335eb4b61f2e30412c4aea3fa2affe72ae4c98145d51d
+ninja==1.11.1 \
+    --hash=sha256:1c474326e11fba3f8c2582715d79216292e327d3335367c0e87e9647a002cc4a \
+    --hash=sha256:3329b4b7c1694730772522a3ba0ba40fd15c012476ed3e1c9f0fd9e76190394e \
+    --hash=sha256:34753459493543782d87267e4cad63dd4639b07f8394ffe6d4417e9eda05c8a8 \
+    --hash=sha256:3b28b595ed580752240ade7821b6cb7a5a4c6a604c865dc474bd38f06e2eb7f5 \
+    --hash=sha256:4e547bc759c570773d83d110c41fd5ca9a94c0a9a8388f5a3ea37bdf97d002b0 \
+    --hash=sha256:60179bb4f22c88279c53a5402bb5fe81c97c627a28d93c737d1fa067d892115d \
+    --hash=sha256:642cb64d859276998f14972724850e0c5b7febbc1bce3d2065b7e0cb7d3a0b79 \
+    --hash=sha256:6f6465a7efe6473a2a34edab83633594de19d59406a727316e1367ebcc528908 \
+    --hash=sha256:779f228e407c54a8b6e4cbf8f835489998dd250f67bf1b9bd7b8a8ab6bdcdc7b \
+    --hash=sha256:817e2aee2a4d28a708a67bcfba1817ae502c32c6d8ef80e50d63b0f23adf3a08 \
+    --hash=sha256:a7a564fe755ddfbdbccb07b0b758e3f8460e5f8ba1adaab40a5eaa2f8c01ce68 \
+    --hash=sha256:ba50a32424912e5f3ee40d791b506a160dc0eeda7de5ad8faebe7aa8006244dc \
+    --hash=sha256:c833a47d39b2d1eee3f9ca886fa1581efd5be6068b82734ac229961ee8748f90 \
+    --hash=sha256:df11b8afea0501883e33faeb1c43d2ef67f466d5f4bd85f9c376e9a93a43a277 \
+    --hash=sha256:edec1053e141253076b2df7ec03a246ff581e9270aa1ca9759397b21e2760e57 \
+    --hash=sha256:f48c3c6eea204062f6bbf089dfc63e1ad41a08640e1da46ef2b30fa426f7ce23
index c363c8e6198c7e0f2d64a58749406d04e2b14e8e..4b6c5f8eed0f5a792048536f686f13e53e8509ac 100644 (file)
@@ -56,7 +56,7 @@ jobs:
       # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
       # format to the repository Actions tab.
       - name: Upload artifact
-        uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # tag=v3.0.0
+        uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3.0.0
         with:
           name: SARIF file
           path: results.sarif
diff --git a/NEWS b/NEWS
index db5d84c47dbf933d128c2bb4a2556d2cc2ec8d72..a295a8ebe2accff4c83cd39a093b131e6017a198 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -32,6 +32,11 @@ CHANGES WITH 253 in spe:
          virtualized ones, and is activated in the case that the system token
          is missing from either sd-boot and sd-stub booted systems.
 
+        Changes in systemctl:
+
+    * systemctl reboot has dropped support for accepting a positional argument
+      as the argument to reboot(2) syscall. Please use --reboot-argument instead.
+
 CHANGES WITH 252 🎃:
 
         Announcements of Future Feature Removals:
diff --git a/TODO b/TODO
index 0c785220ec005f5939cf37003e66aefef24f3851..1d4b484f7f99f246a9a5d55859eae744baeb7744 100644 (file)
--- a/TODO
+++ b/TODO
@@ -125,6 +125,22 @@ Deprecations and removals:
 
 Features:
 
+* systemd-dissect: maybe add "--attach" and "--detach" verbs which
+  synchronously attach a DDI to a loopback device but not actually mount them.
+
+* gpt-auto-generator: generate device names via /dev/disk/by-diskseq/ to pin
+  the medium
+
+* pam_systemd_home: add module parameter to control whether to only accept
+  only password or only pcks11/fido2 auth, and then use this to hook nicely
+  into two of the three PAM stacks gdm provides.
+  See discussion at https://github.com/authselect/authselect/pull/311
+
+* sd-boot: make boot loader spec type #1 accept http urls in "linux"
+  lines. THen, do the uefi http dance to download kernels and boot them. This
+  is then useful for network boot, by embdedding a cpio with type #1 snippets
+  in sd-boot, which reference remote kernels.
+
 * fix systemd-gpt-auto-generator in case a UKI is spawned from XBOOTLDR without
   sd-boot. In that case LoaderDevicePartUUID will point to the XBOOTLDR, and we
   should then derive the root disk from that, and then the ESP/XBOOTLDR from
@@ -143,6 +159,8 @@ Features:
   to make a parser for this reasonably robust. use same path structures as in
   the ESP. Similar add one for signature key drop-ins.
 
+* sd-boot: also allow passing in the cpio as in the previous item via SMBIOS
+
 * add a new EFI tool "sd-fetch" or so. It looks in a PE section ".url" for an
   URL, then downloads the file from it using UEFI HTTP APIs, and executes it.
   Usecase: provide a minimal ESP with sd-boot and a couple of these sd-fetch
@@ -158,6 +176,7 @@ Features:
   encrypted/verity root fs in UKI.
 
 * sd-stub: add ".bootcfg" section for kernel bootconfig data (as per
+  https://docs.kernel.org/admin-guide/bootconfig.html)
 
 * tpm2: add (optional) support for generating a local signing key from PCR 15
   state. use private key part to sign PCR 7+14 policies. stash signatures for
@@ -190,9 +209,6 @@ Features:
   xattr set, check bpf table to find dirs with hashes for other prior DDIs and
   try to use inode from there.
 
-* dissect too: add --with switch that will invoke a command with the image
-  mounted, and as current working directory. Terminate once done.
-
 * extend the verity signature partition to permit multiple signatures for the
   same root hash, so that people can sign a single image with multiple keys.
 
@@ -396,12 +412,6 @@ Features:
   ID from it securely. This would then allow us to bind secrets a specific
   system securely.
 
-* nspawn: maybe allow TPM passthrough, backed by swtpm, and measure --image=
-  hash into its PCR 11, so that nspawn instances can be TPM enabled, and
-  partake in measurements/remote attestation and such. swtpm would run outside
-  of control of container, and ideally would itself bind its encryption keys to
-  host TPM.
-
 * tree-wide: convert as much as possible over to use sd_event_set_signal_exit(), instead
   of manually hooking into SIGINT/SIGTERM
 
@@ -463,7 +473,7 @@ Features:
 * Add support for extra verity configuration options to systemd-repart (FEC,
   hash type, etc)
 
-* chase_symlinks(): take inspiraton from path_extract_filename() and return
+* chase_symlinks(): take inspiration from path_extract_filename() and return
   O_DIRECTORY if input path contains trailing slash.
 
 * chase_symlinks(): refuse resolution if trailing slash is specified on input,
@@ -814,11 +824,6 @@ Features:
   multiple versions are around of the same resource, show which ones. (in other
   words: show partition labels).
 
-* systemd-nspawn: make boot assessment do something sensible in a
-  container. i.e send an sd_notify() from payload to container manager once
-  boot-up is completed successfully, and use that in nspawn for dealing with
-  boot counting, implemented in the partition table labels and directory names.
-
 * maybe add a generator that reads /proc/cmdline, looks for
   systemd.pull-raw-portable=, systemd-pull-raw-sysext= and similar switches
   that take an URL as parameter. It then generates service units for
@@ -875,8 +880,6 @@ Features:
 * add linker script that implicitly adds symbol for build ID and new coredump
   json package metadata, and use that when logging
 
-* systemd-dissect: show GPT disk UUID in output
-
 * Enable RestrictFileSystems= for all our long-running services (similar:
   RestrictNetworkInterfaces=)
 
@@ -886,9 +889,6 @@ Features:
 * cryptsetup/homed: implement TOTP authentication backed by TPM2 and its
   internal clock.
 
-* nspawn: optionally set up nftables/iptables routes that forward UDP/TCP
-  traffic on port 53 to resolved stub 127.0.0.54
-
 * man: rework os-release(5), and clearly separate our extension-release.d/ and
   initrd-release parts, i.e. list explicitly which fields are about what.
 
@@ -963,6 +963,10 @@ Features:
   records would be stripped of all meta info, except the basic UID/name
   info. Then use this in portabled environments that do not use PrivateUsers=1.
 
+* portabled: when extracting unit files and copying to system.attached, if a
+  .p7s is available in the image, use it to protect the system.attached copy
+  with fs-verity, so that it cannot be tampered with
+
 * logind introduce two types of sessions: "heavy" and "light". The former would
   be our current sessions. But the latter would be a new type of session that
   is mostly the same but does not pull in user@.service or wait for it. Then,
@@ -992,10 +996,6 @@ Features:
   for /home/, and similar. Similar add --image-dissect-policy= to tools that
   take --image= that take the same short string.
 
-* nspawn: maybe optionally insert .nspawn file as GPT partition into images, so
-  that such container images are entirely stand-alone and can be updated as
-  one.
-
 * we probably should extend the root verity hash of the root fs into some PCR
   on boot. (i.e. maybe add a veritytab option tpm2-measure=12 or so to measure
   it into PCR 12); Similar: we probably should extend the LUKS volume key of
@@ -1198,11 +1198,6 @@ Features:
 * systemd-path: add ESP and XBOOTLDR path. Add "private" runtime/state/cache dir enum,
   mapping to $RUNTIME_DIRECTORY, $STATE_DIRECTORY and such
 
-* All tools that support --root= should also learn --image= so that they can
-  operate on disk images directly. Specifically: systemctl, coredumpctl.
-  (Already done: bootctl, systemd-nspawn, systemd-firstboot,
-  systemd-repart, systemd-tmpfiles, systemd-sysusers, journalctl)
-
 * seccomp: by default mask x32 ABI system wide on x86-64. it's on its way out
 
 * seccomp: don't install filters for ABIs that are masked anyway for the
@@ -2214,13 +2209,39 @@ Features:
     PID 1...
   - optionally automatically add FORWARD rules to iptables whenever nspawn is
     running, remove them when shut down.
-
-* nspawn: add support for sysext extensions, too. i.e. a new --extension=
-  switch that takes one or more arguments, and applies the extensions already
-  during startup.
-
-* when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or
-  so, freeze the payload too.
+  - add support for sysext extensions, too. i.e. a new --extension= switch that
+    takes one or more arguments, and applies the extensions already during
+    startup.
+  - when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU
+    or so, freeze the payload too.
+  - support time namespaces
+  - on cgroupsv1 issue cgroup empty handler process based on host events, so
+    that we make cgroup agent logic safe
+  - add API to invoke binary in container, then use that as fallback in
+    "machinectl shell"
+  - make nspawn suitable for shell pipelines: instead of triggering a hangup
+    when input is finished, send ^D, which synthesizes an EOF. Then wait for
+    hangup or ^D before passing on the EOF.
+  - greater control over selinux label?
+  - support that /proc, /sys/, /dev are pre-mounted
+  - maybe allow TPM passthrough, backed by swtpm, and measure --image= hash
+    into its PCR 11, so that nspawn instances can be TPM enabled, and partake
+    in measurements/remote attestation and such. swtpm would run outside of
+    control of container, and ideally would itself bind its encryption keys to
+    host TPM.
+  - make boot assessment do something sensible in a container. i.e send an
+    sd_notify() from payload to container manager once boot-up is completed
+    successfully, and use that in nspawn for dealing with boot counting,
+    implemented in the partition table labels and directory names.
+  - optionally set up nftables/iptables routes that forward UDP/TCP traffic on
+    port 53 to resolved stub 127.0.0.54
+  - maybe optionally insert .nspawn file as GPT partition into images, so that
+    such container images are entirely stand-alone and can be updated as one.
+  - The subreaper logic we currently have seems overly complex. We should
+    investigate whether creating the inner child with CLONE_PARENT isn't better.
+  - Reduce the number of sockets that are currently in use and just rely on one
+    or two sockets.
+  - Support running nspawn as an unprivileged user.
 
 * machined: add API to acquire UID range. add API to mount/dissect loopback
   file. Both protected by PK. Then make nspawn use these APIs to run
@@ -2228,22 +2249,6 @@ Features:
   so that the client side can remain entirely unprivileged, with SUID or
   anything like that.
 
-* nspawn: support time namespaces
-
-* nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
-  so that we make cgroup agent logic safe
-
-* nspawn/machined: add API to invoke binary in container, then use that as
-  fallback in "machinectl shell"
-
-* nspawn: make nspawn suitable for shell pipelines: instead of triggering a
-  hangup when input is finished, send ^D, which synthesizes an EOF. Then wait
-  for hangup or ^D before passing on the EOF.
-
-* nspawn: greater control over selinux label?
-
-* nspawn: support that /proc, /sys/, /dev are pre-mounted
-
 * machined:
   - add an API so that libvirt-lxc can inform us about network interfaces being
     removed or added to an existing machine
index c106c4354446919c8b224b4c6d21da66714d528b..1db99ad41a7b1e17c9442440855511326612d197 100644 (file)
@@ -20,9 +20,11 @@ We welcome contributions from everyone. However, please follow the following gui
 Following these guidelines makes it easier for us to process your issue, and ensures we won't close your issue right-away for being misfiled.
 
 ### Older downstream versions
+
 For older versions that are still supported by your distribution please use respective downstream tracker:
+
 * **Fedora** - [bugzilla](https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=systemd)
-* **RHEL/CentOS** - [bugzilla](https://bugzilla.redhat.com/) or [systemd-rhel github](https://github.com/systemd-rhel/)
+* **RHEL/CentOS stream** - [bugzilla](https://bugzilla.redhat.com/) or [systemd-rhel GitHub](https://github.com/redhat-plumbers)
 * **Debian** - [bugs.debian.org](https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=systemd)
 
 ## Security vulnerability reports
@@ -45,12 +47,12 @@ See [reporting of security vulnerabilities](SECURITY.md).
 * See [filtered list of pull requests](https://github.com/systemd/systemd/pulls?q=is%3Aopen+is%3Apr+-label%3A%22reviewed%2Fneeds-rework+%F0%9F%94%A8%22+-label%3Aneeds-rebase+-label%3Agood-to-merge%2Fwith-minor-suggestions+-label%3A%22good-to-merge%2Fwaiting-for-ci+%F0%9F%91%8D%22+-label%3Apostponed+-label%3A%22needs-reporter-feedback+%E2%9D%93%22+-label%3A%22dont-merge+%F0%9F%92%A3%22+-label%3A%22ci-fails%2Fneeds-rework+%F0%9F%94%A5%22+sort%3Aupdated-desc) for requests that are ready for review.
 * After performing a review, set
 
-    * `reviewed/needs-rework` if the pull request needs significant changes
-    * `ci-fails/needs-rework` if the automatic tests fail and the failure is relevant to the pull request
-    * `ci-failure-appears-unrelated` if the test failures seem irrelevant
-    * `needs-rebase` if the pull request needs a rebase because of conflicts
-    * `good-to-merge/waiting-for-ci` if the pull request should be merged without further review
-    * `good-to-merge/with-minor-suggestions` if the pull request should be merged after an update without going through another round of reviews
+  * `reviewed/needs-rework` if the pull request needs significant changes
+  * `ci-fails/needs-rework` if the automatic tests fail and the failure is relevant to the pull request
+  * `ci-failure-appears-unrelated` if the test failures seem irrelevant
+  * `needs-rebase` if the pull request needs a rebase because of conflicts
+  * `good-to-merge/waiting-for-ci` if the pull request should be merged without further review
+  * `good-to-merge/with-minor-suggestions` if the pull request should be merged after an update without going through another round of reviews
 
 Unfortunately only members of the `systemd` organization on github can change labels.
 If your pull request is mislabeled, make a comment in the pull request and somebody will fix it.
index 47e06737ba75892fd96c6bf1408b1bc13bc2f915..8902b8b163cf564aca6c24f0424a1fd129d6bfbe 100644 (file)
@@ -237,6 +237,13 @@ evdev:name:Synaptics TM2382-001:dmi:*svnDellInc.:pnInspiron3537:*
  EVDEV_ABS_35=::24
  EVDEV_ABS_36=::34
 
+# Dell Inspiron N4010
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN4010:*
+ EVDEV_ABS_00=1188:5797:49
+ EVDEV_ABS_01=893:4894:80
+ EVDEV_ABS_35=1188:5797:49
+ EVDEV_ABS_36=893:4894:80
+
 # Dell Inspiron N5040
 evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040:*
  EVDEV_ABS_00=25:2000:22
index 498a4c5f5ec2024b3a7308845c1c779b124948a1..9707132beecaea6ec8b8d8272efe97d2a8b0b2bd 100644 (file)
@@ -278,6 +278,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNotebook:pnW65_67SZ:*
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
 
+evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNS50_70MU:*
+evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNV4XMB,ME,MZ:*
+evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNS5x_NS7xPU:*
+evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNV4xPZ:*
+ KEYBOARD_KEY_f7=f21                                    # Touchpad Toggle
+ KEYBOARD_KEY_f8=f21                                    # Touchpad Toggle
+
 ###########################################################
 # Compal
 ###########################################################
index 5df128f07e654ae0e825b20f0536d063467e0624..f89f26eb6f7bba867ecada62d40d6e0f72707bca 100644 (file)
@@ -52,6 +52,10 @@ usb:v0FD9p006D*
 usb:v0FD9p0080*
  ID_AV_PRODUCTION_CONTROLLER=1
 
+# Stream Deck Pedal
+usb:v0FD9p0086*
+ ID_AV_PRODUCTION_CONTROLLER=1
+
 #############################
 # Hercules (Guillemot Corp)
 #############################
index cbbb8ab2a96ab6dfc2da340f7d734ad65c1707e5..896a62358d0b23502f9f9d4c1f7380cf223cbaa7 100644 (file)
     and use this to determine which key to send, allowing a single listening socket to serve keys for
     multiple volumes. If the PKCS#11 logic is used (see above), the socket source name is picked in similar
     fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used. And similarly for
-    FIDO2 (<literal>/cryptsetup-fido2/</literal>) and TPM2 (<literal>/cryptsetup-tpm2/</literal>). A diffent
+    FIDO2 (<literal>/cryptsetup-fido2/</literal>) and TPM2 (<literal>/cryptsetup-tpm2/</literal>). A different
     path component is used so that services providing key material know that the secret key was not requested
     directly, but instead an encrypted key that will be decrypted via the PKCS#11/FIDO2/TPM2 logic to acquire
     the final secret key.</para>
index 29b0d8eb54f8af9c98d7dafba6a54e857fed23ed..f3fdc961f4def15e89d581c92349e23712944d19 100644 (file)
             is missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para>
 
             <para>If <varname>$KERNEL_INSTALL_LAYOUT</varname> is not "bls", this plugin does nothing.</para></listitem>
+
+            <listitem><para><filename>90-uki-copy.install</filename> copies a file
+            <filename>uki.efi</filename> from <varname>$KERNEL_INSTALL_STAGING_AREA</varname> or if it does
+            not exist the <replaceable>KERNEL-IMAGE</replaceable> argument, iff it has a
+            <literal>.efi</literal> extension, to
+            <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.efi</filename>.</para>
+
+            <para>If <varname>$KERNEL_INSTALL_LAYOUT</varname> is not "uki", this plugin does nothing.</para></listitem>
           </itemizedlist>
         </listitem>
       </varlistentry>
 
             <listitem><para><filename>90-loaderentry.install</filename> removes the file
             <filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
+
+            <listitem><para><filename>90-uki-copy.install</filename> removes the file
+            <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.efi</filename>.</para></listitem>
           </itemizedlist>
         </listitem>
       </varlistentry>
       (EFI System Partition) are mounted, and also conceptually referred to as <varname>$BOOT</varname>. Can
       be overridden by setting <varname>$BOOT_ROOT</varname> (see below).</para>
 
-      <para><varname>$KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the
+      <para><varname>$KERNEL_INSTALL_LAYOUT=bls|uki|other|...</varname> is set for the plugins to specify the
       installation layout. Defaults to <option>bls</option> if
       <filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable></filename> exists, or <option>other</option>
       otherwise. Additional layout names may be defined by convention. If a plugin uses a special layout,
             <para>Implemented by <filename>90-loaderentry.install</filename>.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term>uki</term>
+          <listitem>
+            <para>Standard <ulink
+            url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
+            Specification</ulink> Type #2 layout, compatible with
+            <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>:
+            unified kernel images under <filename>$BOOT/EFI/Linux</filename> as
+            <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>[+<replaceable>TRIES</replaceable>].efi</filename>.</para>
+            <para>Implemented by <filename>90-uki-copy.install</filename>.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term>other</term>
           <listitem>
           <filename>/etc/kernel/tries</filename>
         </term>
           <listitem>
-            <para>Read by <filename>90-loaderentry.install</filename>. If this file exists a numeric value is read from
-            it and the naming of the generated entry file is slightly altered to include it as
-            <filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>. This
+            <para>Read by <filename>90-loaderentry.install</filename> and
+            <filename>90-uki-copy.install</filename>. If this file exists a numeric value is read from it
+            and the naming of the generated entry file or UKI is slightly altered to include it as
+            <filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>
+            or
+            <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>, respectively. This
             is useful for boot loaders such as
-            <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> which
-            implement boot attempt counting with a counter embedded in the entry file name.
+            <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+            which implement boot attempt counting with a counter embedded in the entry file name.
             <varname>$KERNEL_INSTALL_CONF_ROOT</varname> may be used to override the path.</para>
           </listitem>
       </varlistentry>
index 758f52fe4432c90272356dddc2d6f0ccf301cfb4..4f8936e86671ba7b19a427b66e6ea440a2399248 100644 (file)
@@ -209,6 +209,10 @@ node /org/freedesktop/systemd1 {
       DisableUnitFilesWithFlags(in  as files,
                                 in  t flags,
                                 out a(sss) changes);
+      DisableUnitFilesWithFlagsAndInstallInfo(in  as files,
+                                              in  t flags,
+                                              out b carries_install_info,
+                                              out a(sss) changes);
       ReenableUnitFiles(in  as files,
                         in  b runtime,
                         in  b force,
@@ -916,6 +920,8 @@ node /org/freedesktop/systemd1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlags()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlagsAndInstallInfo()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="ReenableUnitFiles()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="LinkUnitFiles()"/>
@@ -1417,7 +1423,7 @@ node /org/freedesktop/systemd1 {
       enabled for runtime only (true, <filename>/run/</filename>), or persistently (false,
       <filename>/etc/</filename>). The second one controls whether symlinks pointing to other units shall be
       replaced if necessary. This method returns one boolean and an array of the changes made. The boolean
-      signals whether the unit files contained any enablement information (i.e. an [Install]) section. The
+      signals whether the unit files contained any enablement information (i.e. an [Install] section). The
       changes array consists of structures with three strings: the type of the change (one of
       <literal>symlink</literal> or <literal>unlink</literal>), the file name of the symlink and the
       destination of the symlink. Note that most of the following calls return a changes list in the same
@@ -1440,6 +1446,11 @@ node /org/freedesktop/systemd1 {
       replaced if necessary. <varname>SD_SYSTEMD_UNIT_PORTABLE</varname> will add or remove the symlinks in
       <filename>/etc/systemd/system.attached</filename> and <filename>/run/systemd/system.attached</filename>.</para>
 
+      <para><function>DisableUnitFilesWithFlagsAndInstallInfo()</function> is similar to
+      <function>DisableUnitFilesWithFlags()</function> and takes the same arguments, but returns
+      a boolean to indicate whether the unit files contain any enablement information, like
+      <function>EnableUnitFiles()</function>. The changes made are still returned in an array.</para>
+
       <para>Similarly, <function>ReenableUnitFiles()</function> applies the changes to one or more units that
       would result from disabling and enabling the unit quickly one after the other in an atomic
       fashion. This is useful to apply updated [Install] information contained in unit files.</para>
@@ -10169,6 +10180,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
       readonly t RuntimeMaxUSec = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t RuntimeRandomizedExtraUSec = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s OOMPolicy = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s Slice = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
@@ -10345,6 +10358,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--property RuntimeRandomizedExtraUSec is not documented!-->
 
+    <!--property OOMPolicy is not documented!-->
+
     <!--property Slice is not documented!-->
 
     <!--property ControlGroupId is not documented!-->
@@ -10529,6 +10544,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RuntimeRandomizedExtraUSec"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="OOMPolicy"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Slice"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ControlGroup"/>
index 7e19ab7e0ccd0d5561312e04969b71a82e0103d4..fe3de8d58a4678bd3be9a5816c735c45b840c497 100644 (file)
         <para>The copy operation is executed before the file system is registered in the partition table,
         thus ensuring that a file system populated this way only ever exists fully initialized.</para>
 
+        <para>Note that <varname>CopyFiles=</varname> will skip copying files that aren't supported by the
+        target filesystem (e.g symlinks, fifos, sockets and devices on vfat). When an unsupported file type
+        is encountered, repart will skip copying this file and write a log message about it.</para>
+
         <para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
 
         <para>When <command>systemd-repart</command> is invoked with the <option>--image=</option> or
index 2cb855c360ffb3eb6ccdc3e5da95ff49d79bef45..c966ca67bd28cd157db46b8c56454d7e3b886814 100644 (file)
 
         <listitem><para>Takes a boolean parameter; used in conjunction with <command>query</command>. If true
         (the default), select domains are resolved on the local system, among them
-        <literal>localhost</literal>, <literal>_gateway</literal> and <literal>_outbound</literal>, or
-        entries from <filename>/etc/hosts</filename>. If false these domains are not resolved locally, and
-        either fail (in case of <literal>localhost</literal>, <literal>_gateway</literal> or
-        <literal>_outbound</literal> and suchlike) or go to the network via regular DNS/mDNS/LLMNR lookups
-        (in case of <filename>/etc/hosts</filename> entries).</para></listitem>
+        <literal>localhost</literal>, <literal>_gateway</literal>, <literal>_outbound</literal>,
+        <literal>_localdnsstub</literal> and <literal>_localdnsproxy</literal> or entries from
+        <filename>/etc/hosts</filename>. If false these domains are not resolved locally, and either fail (in
+        case of <literal>localhost</literal>, <literal>_gateway</literal> or <literal>_outbound</literal> and
+        suchlike) or go to the network via regular DNS/mDNS/LLMNR lookups (in case of
+        <filename>/etc/hosts</filename> entries).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index bb7799036d8f968cb5b3b7a75b21f2d78a2535c0..ac4196e548e48f12f139a7e5caf613284c231d49 100644 (file)
@@ -248,6 +248,8 @@ manpages = [
    'sd_bus_emit_object_removed',
    'sd_bus_emit_properties_changed',
    'sd_bus_emit_properties_changed_strv',
+   'sd_bus_emit_signal_to',
+   'sd_bus_emit_signal_tov',
    'sd_bus_emit_signalv'],
   ''],
  ['sd_bus_enqueue_for_read', '3', [], ''],
@@ -348,7 +350,7 @@ manpages = [
    'sd_bus_message_new_method_errnof',
    'sd_bus_message_new_method_errorf'],
   ''],
- ['sd_bus_message_new_signal', '3', [], ''],
+ ['sd_bus_message_new_signal', '3', ['sd_bus_message_new_signal_to'], ''],
  ['sd_bus_message_open_container',
   '3',
   ['sd_bus_message_close_container',
index 1d91c8a726298c4965394502f2e06f21cc47902c..d6deb6d78a0daaea7f048b583e64519756e1febd 100644 (file)
@@ -771,6 +771,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             account.
             </para>
 
+            <para>When using this operation on units without install information, a warning about it is shown.
+            <option>--no-warn</option> can be used to suppress the warning.</para>
+
             <para>Enabling units should not be confused with starting (activating) units, as done by the
             <command>start</command> command. Enabling and starting units is orthogonal: units may be enabled without
             being started and started without being enabled. Enabling simply hooks the unit into various suggested
@@ -814,8 +817,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             executed. This output may be suppressed by passing <option>--quiet</option>.
             </para>
 
-            <para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option>
-            and <option>--global</option> in a similar way as <command>enable</command>.</para>
+            <para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option>,
+            <option>--global</option> and <option>--no-warn</option> in a similar way as <command>enable</command>.</para>
           </listitem>
         </varlistentry>
 
@@ -1997,6 +2000,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--no-warn</option></term>
+
+        <listitem>
+          <para>Don't generate the warning shown by default when using
+          <command>enable</command> or <command>disable</command> on units
+          without install information (i.e. don't have or have an empty
+          [Install] section).</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--no-block</option></term>
 
index a8c089d0b515ed6b7678dfbd00ec35ff216b55b4..a92d83fe298bcb37b2379ce26a10843bf97d6284 100644 (file)
@@ -62,7 +62,7 @@
         </thead>
         <tbody>
           <row>
-            <entry valign="top" morerows="15">VM</entry>
+            <entry valign="top" morerows="16">VM</entry>
             <entry><varname>qemu</varname></entry>
             <entry>QEMU software virtualization, without KVM</entry>
           </row>
             <entry><ulink url="https://developer.apple.com/documentation/virtualization">Apple Virtualization.framework</ulink></entry>
           </row>
 
+          <row>
+            <entry><varname>sre</varname></entry>
+            <entry><ulink url="https://www.lockheedmartin.com/en-us/products/Hardened-Security-for-Intel-Processors.html">LMHS SRE hypervisor</ulink></entry>
+          </row>
+
           <row>
             <entry valign="top" morerows="9">Container</entry>
             <entry><varname>openvz</varname></entry>
index 6559fceedb47c1465be1a3f88d19f29829bad880..2c74afbe0fa347dffe7103419156c14e61eb1cc2 100644 (file)
         are excluded. If <option>--exclude-partitions=</option> is used, all partitions that are specified
         are excluded. Both options take a comma separated list of GPT partition type UUIDs or identifiers
         (see <varname>Type=</varname> in
-        <citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>). All
-        partitions that are excluded using these options are still taken into account when calculating the
-        sizes and offsets of other partitions, but aren't actually written to the disk image. The net effect
-        of this option is that if you run <command>systemd-repart</command> again without these options, the
-        missing partitions will be added as if they had not been excluded the first time
+        <citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--skip-partitions=</option><arg rep="repeat">PARTITION</arg></term>
+
+        <listitem><para>This option specifies which partition types <command>systemd-repart</command> should
+        skip. All partitions that are skipped using this option are still taken into account when calculating
+        the sizes and offsets of other partitions, but aren't actually written to the disk image. The net
+        effect of this option is that if you run <command>systemd-repart</command> again without these
+        options, the missing partitions will be added as if they had not been skipped the first time
         <command>systemd-repart</command> was executed.</para></listitem>
       </varlistentry>
 
index 7f30fa6536275daf10aeb62b5ce5727d2c9f9354..c006c03b534f3991cbd29942e073e44632a9d012 100644 (file)
       local default gateway configured. This assigns a stable hostname to the local outbound IP addresses,
       useful for referencing them independently of the current network configuration state.</para></listitem>
 
+      <listitem><para>The hostname <literal>_localdnsstub</literal> is resolved to the IP address 127.0.0.53,
+      i.e. the address the local DNS stub (see above) is listening on.</para></listitem>
+
+      <listitem><para>The hostname <literal>_localdnsproxy</literal> is resolved to the IP address 127.0.0.54,
+      i.e. the address the local DNS proxy (see above) is listening on.</para></listitem>
+
       <listitem><para>The mappings defined in <filename>/etc/hosts</filename> are resolved to their
       configured addresses and back, but they will not affect lookups for non-address types (like MX).
       Support for <filename>/etc/hosts</filename> may be disabled with <varname>ReadEtcHosts=no</varname>,
index 6a7ab696a38e1df86ddbb9581fb115af1daa1ea3..7b30bd2e78c97566a0740a5b6a28f12b77021bcb 100644 (file)
@@ -2335,7 +2335,7 @@ allow my_server_t localnet_peer_t:peer recv;</programlisting>
         <listitem>
           <para>Takes a boolean. Specifies whether to add an address from the delegated prefixes which
           are received from the WAN interface by the DHCPv6 Prefix Delegation. When true (on LAN
-          interfce), the EUI-64 algorithm will be used by default to form an interface identifier from
+          interface), the EUI-64 algorithm will be used by default to form an interface identifier from
           the delegated prefixes. See also <varname>Token=</varname> setting below. Defaults to yes.
           </para>
         </listitem>
index fe875a81c3dde3eb042e233512f4e48ad0fefa41..1142ad7758f0bb29a0e1cdc8ab9984db8b2d002b 100644 (file)
@@ -1101,10 +1101,10 @@ DeviceAllow=/dev/loop-control
           only respect these extended attributes if the unit's cgroup is owned by root.</para>
 
           <para>When calculating candidates to relieve memory pressure, <command>systemd-oomd</command>
-          will only respect these extended attributes if the unit's cgroup owner, and the
-          owner of the monitored ancestor cgroup are the same. For example, if <command>systemd-oomd</command>
-          is calculating candidates for <filename>-.slice</filename>, then extended attributes set
-          on descendants of <filename>/user.slice/user-1000.slice/user@1000.service/</filename>
+          will only respect these extended attributes if the unit's cgroup is owned by root, or if the
+          unit's cgroup owner, and the owner of the monitored ancestor cgroup are the same. For example,
+          if <command>systemd-oomd</command> is calculating candidates for <filename>-.slice</filename>,
+          then extended attributes set on descendants of <filename>/user.slice/user-1000.slice/user@1000.service/</filename>
           will be ignored because the descendants are owned by UID 1000, and <filename>-.slice</filename>
           is owned by UID 0. But, if calculating candidates for
           <filename>/user.slice/user-1000.slice/user@1000.service/</filename>, then extended attributes set
index 8e1a3464dfbeeff577da6e09cf3f96007b3c15c8..0c17d918148d97dfcd8b73113c5b60c4b7878488 100644 (file)
           <literal>bhyve</literal>,
           <literal>qnx</literal>,
           <literal>apple</literal>,
+          <literal>sre</literal>,
           <literal>openvz</literal>,
           <literal>lxc</literal>,
           <literal>lxc-libvirt</literal>,
index 37d46dfae2a9aa16981e7956c891462595b41e65..504644bca8a6c6953eac0a13ca7d716e1592eca8 100644 (file)
@@ -510,6 +510,10 @@ conf.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
 conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
 conf.set('SIZEOF_TIMEX_MEMBER', cc.sizeof('typeof(((struct timex *)0)->freq)', prefix : '#include <sys/timex.h>'))
 
+long_max = cc.compute_int('LONG_MAX', prefix : '#include <limits.h>')
+assert(long_max > 100000)
+conf.set_quoted('LONG_MAX_STR', '@0@'.format(long_max))
+
 decl_headers = '''
 #include <uchar.h>
 #include <sys/mount.h>
@@ -2752,7 +2756,8 @@ if conf.get('ENABLE_HOMED') == 1
                 'systemd-homework',
                 systemd_homework_sources,
                 include_directories : includes,
-                link_with : [libshared],
+                link_with : [libshared,
+                             libshared_fdisk],
                 dependencies : [threads,
                                 libblkid,
                                 libcrypt,
@@ -3331,7 +3336,8 @@ if conf.get('ENABLE_SYSUPDATE') == 1
                 'systemd-sysupdate',
                 systemd_sysupdate_sources,
                 include_directories : includes,
-                link_with : [libshared],
+                link_with : [libshared,
+                             libshared_fdisk],
                 dependencies : [threads,
                                 libblkid,
                                 libfdisk,
@@ -3807,7 +3813,8 @@ if conf.get('ENABLE_REPART') == 1
                 'systemd-repart',
                 systemd_repart_sources,
                 include_directories : includes,
-                link_with : [libshared],
+                link_with : [libshared,
+                             libshared_fdisk],
                 dependencies : [threads,
                                 libblkid,
                                 libfdisk,
@@ -3827,7 +3834,8 @@ if conf.get('ENABLE_REPART') == 1
                         link_with : [libshared_static,
                                      libbasic,
                                      libbasic_gcrypt,
-                                     libsystemd_static],
+                                     libsystemd_static,
+                                     libshared_fdisk],
                         dependencies : [threads,
                                         libblkid,
                                         libfdisk,
@@ -4170,19 +4178,19 @@ alias_target('fuzzers', fuzzer_exes)
 
 ############################################################
 
+subdir('docs/sysvinit')
+subdir('docs/var-log')
+subdir('hwdb.d')
+subdir('man')
 subdir('modprobe.d')
+subdir('network')
+subdir('presets')
+subdir('shell-completion/bash')
+subdir('shell-completion/zsh')
 subdir('sysctl.d')
 subdir('sysusers.d')
 subdir('tmpfiles.d')
-subdir('hwdb.d')
 subdir('units')
-subdir('presets')
-subdir('network')
-subdir('man')
-subdir('shell-completion/bash')
-subdir('shell-completion/zsh')
-subdir('docs/sysvinit')
-subdir('docs/var-log')
 
 install_subdir('factory/etc',
                install_dir : factorydir)
index f9e4d086160ed3a3c2bef1b3b24b7d93b7df720c..a91378da971b7255b70e734a73462f65f5f4a971 100644 (file)
@@ -3,9 +3,7 @@
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
 
 [Output]
-Format=gpt_btrfs
 Bootable=yes
-HostonlyInitrd=yes
 # Prevent ASAN warnings when building the image
 Environment=ASAN_OPTIONS=verify_asan_link_order=false
 OutputDirectory=mkosi.output
index 47b5e35c75a9c0e57cdbf1c9874506ebfefd4053..fd63f2ba00427d6b5782847281155ff5f53052f6 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -1,12 +1,12 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 #
 # Indonesian translation for systemd.
-# Andika Triwidada <andika@gmail.com>, 2014, 2021.
+# Andika Triwidada <andika@gmail.com>, 2014, 2021, 2022.
 msgid ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-10-20 10:35+0200\n"
-"PO-Revision-Date: 2021-09-24 11:05+0000\n"
+"PO-Revision-Date: 2022-11-25 08:19+0000\n"
 "Last-Translator: Andika Triwidada <andika@gmail.com>\n"
 "Language-Team: Indonesian <https://translate.fedoraproject.org/projects/"
 "systemd/master/id/>\n"
@@ -15,7 +15,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.8\n"
+"X-Generator: Weblate 4.14.2\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -157,22 +157,19 @@ msgstr "Otentikasi diperlukan untuk mendapatkan UUID produk."
 
 #: src/hostname/org.freedesktop.hostname1.policy:61
 msgid "Get hardware serial number"
-msgstr ""
+msgstr "Dapatkan nomor seri perangkat keras"
 
 #: src/hostname/org.freedesktop.hostname1.policy:62
-#, fuzzy
 msgid "Authentication is required to get hardware serial number."
-msgstr "Otentikasi diperlukan untuk menyetel waktu sistem."
+msgstr "Otentikasi diperlukan untuk mendapatkan nomor seri perangkat keras."
 
 #: src/hostname/org.freedesktop.hostname1.policy:71
-#, fuzzy
 msgid "Get system description"
-msgstr "Setel zona waktu sistem"
+msgstr "Dapatkan deskripsi sistem"
 
 #: src/hostname/org.freedesktop.hostname1.policy:72
-#, fuzzy
 msgid "Authentication is required to get system description."
-msgstr "Otentikasi diperlukan untuk menyetel zona waktu sistem."
+msgstr "Otentikasi diperlukan untuk mendapatkan deskripsi sistem."
 
 #: src/import/org.freedesktop.import1.policy:22
 msgid "Import a VM or container image"
@@ -495,7 +492,7 @@ msgstr "Otentikasi diperlukan untuk menghibernasi sistem."
 
 #: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while other users are logged in"
-msgstr "Hibernasikan sistem ketika pengguna lain sedang log masuk."
+msgstr "Hibernasikan sistem ketika pengguna lain sedang log masuk"
 
 #: src/login/org.freedesktop.login1.policy:311
 msgid ""
@@ -507,7 +504,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:321
 msgid "Hibernate the system while an application is inhibiting this"
-msgstr "Hibernasikan sistem ketika sebuah aplikasi meminta untuk mencegahnya."
+msgstr "Hibernasikan sistem ketika sebuah aplikasi meminta untuk mencegahnya"
 
 #: src/login/org.freedesktop.login1.policy:322
 msgid ""
index 0bb07000bad8922b10e83a4793cb6bd059997df0..fc6e26d2f206cab8b28d90da20eb22425e493ae5 100644 (file)
@@ -466,8 +466,10 @@ int chase_symlinks(
                         return -errno;
 
                 flags |= CHASE_AT_RESOLVE_IN_ROOT;
-        } else
+        } else {
+                path = absolute;
                 fd = AT_FDCWD;
+        }
 
         r = chase_symlinks_at(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL);
         if (r < 0)
index 54021911ab31a35b0858490fcafc5e5caf9f9923..4a24ba9c8cba162afe60937513f81d4df4a1916d 100644 (file)
@@ -43,7 +43,7 @@
 #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
 
 /* The default value for the net.unix.max_dgram_qlen sysctl */
-#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512
 
 #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
 #define SIGNALS_IGNORE SIGPIPE
index 2eea228c20a01e3c5790b69e29d1f6b74ef7bbdb..17df6a24c907683dba9480f0251c9adf5bb1704d 100644 (file)
@@ -8,11 +8,11 @@
 #include "stat-util.h"
 #include "string-util.h"
 
-static int dirent_ensure_type(DIR *d, struct dirent *de) {
+int dirent_ensure_type(int dir_fd, struct dirent *de) {
         STRUCT_STATX_DEFINE(sx);
         int r;
 
-        assert(d);
+        assert(dir_fd >= 0);
         assert(de);
 
         if (de->d_type != DT_UNKNOWN)
@@ -24,7 +24,7 @@ static int dirent_ensure_type(DIR *d, struct dirent *de) {
         }
 
         /* Let's ask only for the type, nothing else. */
-        r = statx_fallback(dirfd(d), de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx);
+        r = statx_fallback(dir_fd, de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx);
         if (r < 0)
                 return r;
 
@@ -80,7 +80,7 @@ struct dirent *readdir_ensure_type(DIR *d) {
                 if (!de)
                         return NULL;
 
-                r = dirent_ensure_type(d, de);
+                r = dirent_ensure_type(dirfd(d), de);
                 if (r >= 0)
                         return de;
                 if (r != -ENOENT) {
index 5fde9043a30abd4478ca25c9ae908f647156578c..0f1fb231190a891a21978f43e4a40f4e0c9d3ee8 100644 (file)
@@ -10,6 +10,7 @@
 
 bool dirent_is_file(const struct dirent *de) _pure_;
 bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
+int dirent_ensure_type(int dir_fd, struct dirent *de);
 
 struct dirent *readdir_ensure_type(DIR *d);
 struct dirent *readdir_no_dot(DIR *dirp);
index ec33a61588e9f8cb6eca7236c38e5a88fe4bdb89..01a45e4384daacc7b8efd5b05a0f0d21cb1c1a66 100644 (file)
@@ -780,6 +780,37 @@ int fd_reopen(int fd, int flags) {
         return new_fd;
 }
 
+int fd_reopen_condition(
+                int fd,
+                int flags,
+                int mask,
+                int *ret_new_fd) {
+
+        int r, new_fd;
+
+        assert(fd >= 0);
+
+        /* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
+         * flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
+         * needed, but only then. */
+
+        r = fcntl(fd, F_GETFL);
+        if (r < 0)
+                return -errno;
+
+        if ((r & mask) == (flags & mask)) {
+                *ret_new_fd = -1;
+                return fd;
+        }
+
+        new_fd = fd_reopen(fd, flags);
+        if (new_fd < 0)
+                return new_fd;
+
+        *ret_new_fd = new_fd;
+        return new_fd;
+}
+
 int read_nr_open(void) {
         _cleanup_free_ char *nr_open = NULL;
         int r;
index 29c7d86f27ddbb6b0f17ae1426cff33825fb3499..fbaa45861342fa51a5119f658bd5ec6c3a28a5a9 100644 (file)
@@ -108,6 +108,7 @@ static inline int make_null_stdio(void) {
         })
 
 int fd_reopen(int fd, int flags);
+int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
 int read_nr_open(void);
 int fd_get_diskseq(int fd, uint64_t *ret);
 
index a00b852395d6e8655ac773f3c2fb2a20e78cfc48..bcac3d9fb067a6d7fcd055b37528d55779d421ec 100644 (file)
@@ -60,4 +60,12 @@ static inline bool is_outbound_hostname(const char *hostname) {
         return STRCASE_IN_SET(hostname, "_outbound", "_outbound.");
 }
 
+static inline bool is_dns_stub_hostname(const char *hostname) {
+        return STRCASE_IN_SET(hostname, "_localdnsstub", "_localdnsstub.");
+}
+
+static inline bool is_dns_proxy_stub_hostname(const char *hostname) {
+        return STRCASE_IN_SET(hostname, "_localdnsproxy", "_localdnsproxy.");
+}
+
 int get_pretty_hostname(char **ret);
index 908e833501efbf30644844dea45a88116af3afa3..fe18b98d5b8672ff0357e675b618b046237e91e7 100644 (file)
@@ -33,6 +33,7 @@ int readdir_all(int dir_fd,
         struct dirent *entry;
         DirectoryEntries *nde;
         size_t add, sz, j;
+        int r;
 
         assert(dir_fd >= 0);
 
@@ -84,6 +85,15 @@ int readdir_all(int dir_fd,
                 if (ignore_dirent(entry, flags))
                         continue;
 
+                if (FLAGS_SET(flags, RECURSE_DIR_ENSURE_TYPE)) {
+                        r = dirent_ensure_type(dir_fd, entry);
+                        if (r == -ENOENT)
+                                /* dentry gone by now? no problem, let's just suppress it */
+                                continue;
+                        if (r < 0)
+                                return r;
+                }
+
                 de->n_entries++;
         }
 
@@ -104,8 +114,14 @@ int readdir_all(int dir_fd,
                 if (ignore_dirent(entry, flags))
                         continue;
 
+                /* If d_type == DT_UNKNOWN that means we failed to ensure the type in the earlier loop and
+                 * didn't include the dentry in de->n_entries and as such should skip it here as well. */
+                if (FLAGS_SET(flags, RECURSE_DIR_ENSURE_TYPE) && entry->d_type == DT_UNKNOWN)
+                        continue;
+
                 de->entries[j++] = entry;
         }
+        assert(j == de->n_entries);
 
         if (FLAGS_SET(flags, RECURSE_DIR_SORT))
                 typesafe_qsort(de->entries, de->n_entries, sort_func);
@@ -160,7 +176,8 @@ int recurse_dir(
                         return r;
         }
 
-        r = readdir_all(dir_fd, flags, &de);
+        /* Mask out RECURSE_DIR_ENSURE_TYPE so we can do it ourselves and avoid an extra statx() call. */
+        r = readdir_all(dir_fd, flags & ~RECURSE_DIR_ENSURE_TYPE, &de);
         if (r < 0)
                 return r;
 
index 8fa9986a768a4083be630510977d66646637f280..7bc2f71bcfd3624bda1b2d1ba503d5802138dab2 100644 (file)
@@ -268,7 +268,7 @@ int reset_terminal_fd(int fd, bool switch_to_text) {
 
         termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
         termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
-        termios.c_oflag |= ONLCR;
+        termios.c_oflag |= ONLCR | OPOST;
         termios.c_cflag |= CREAD;
         termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
 
index 9a0b5a28d19ee84085945f9fdc91893c5a07c585..7c238613e6df3516efc66f379376d232b581eed6 100644 (file)
@@ -50,6 +50,8 @@ static Virtualization detect_vm_cpuid(void) {
                 { "QNXQVMBSQG",   VIRTUALIZATION_QNX       },
                 /* https://projectacrn.org */
                 { "ACRNACRNACRN", VIRTUALIZATION_ACRN      },
+                /* https://www.lockheedmartin.com/en-us/products/Hardened-Security-for-Intel-Processors.html */
+                { "SRESRESRESRE", VIRTUALIZATION_SRE       },
         };
 
         uint32_t eax, ebx, ecx, edx;
@@ -1036,6 +1038,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_ACRN]            = "acrn",
         [VIRTUALIZATION_POWERVM]         = "powervm",
         [VIRTUALIZATION_APPLE]           = "apple",
+        [VIRTUALIZATION_SRE]             = "sre",
         [VIRTUALIZATION_VM_OTHER]        = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN]  = "systemd-nspawn",
index e19a238939869e1e5bf76e26840d0e4ba071f3d6..d49f3237e816f98b1ef25dda6897ca5ee3aeef51 100644 (file)
@@ -26,6 +26,7 @@ typedef enum Virtualization {
         VIRTUALIZATION_ACRN,
         VIRTUALIZATION_POWERVM,
         VIRTUALIZATION_APPLE,
+        VIRTUALIZATION_SRE,
         VIRTUALIZATION_VM_OTHER,
         VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
 
index 85e936b866d9488b8f06a44fcfe1c85a9f49d78f..9a562dcf223d05da007c5a74132cf0f3a036d1f8 100644 (file)
@@ -1204,7 +1204,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
                                 continue;
                         }
                         free(config->entry_default_config);
-                        config->entry_default_config = xstra_to_str(value);
+                        config->entry_default_config = xstr8_to_16(value);
                         continue;
                 }
 
@@ -1418,32 +1418,32 @@ static void config_entry_add_type1(
         while ((line = line_get_key_value(content, " \t", &pos, &key, &value))) {
                 if (streq8(key, "title")) {
                         free(entry->title);
-                        entry->title = xstra_to_str(value);
+                        entry->title = xstr8_to_16(value);
                         continue;
                 }
 
                 if (streq8(key, "sort-key")) {
                         free(entry->sort_key);
-                        entry->sort_key = xstra_to_str(value);
+                        entry->sort_key = xstr8_to_16(value);
                         continue;
                 }
 
                 if (streq8(key, "version")) {
                         free(entry->version);
-                        entry->version = xstra_to_str(value);
+                        entry->version = xstr8_to_16(value);
                         continue;
                 }
 
                 if (streq8(key, "machine-id")) {
                         free(entry->machine_id);
-                        entry->machine_id = xstra_to_str(value);
+                        entry->machine_id = xstr8_to_16(value);
                         continue;
                 }
 
                 if (streq8(key, "linux")) {
                         free(entry->loader);
                         entry->type = LOADER_LINUX;
-                        entry->loader = xstra_to_path(value);
+                        entry->loader = xstr8_to_path(value);
                         entry->key = 'l';
                         continue;
                 }
@@ -1451,7 +1451,7 @@ static void config_entry_add_type1(
                 if (streq8(key, "efi")) {
                         entry->type = LOADER_EFI;
                         free(entry->loader);
-                        entry->loader = xstra_to_path(value);
+                        entry->loader = xstr8_to_path(value);
 
                         /* do not add an entry for ourselves */
                         if (strcaseeq16(entry->loader, loaded_image_path)) {
@@ -1472,7 +1472,7 @@ static void config_entry_add_type1(
 
                 if (streq8(key, "devicetree")) {
                         free(entry->devicetree);
-                        entry->devicetree = xstra_to_path(value);
+                        entry->devicetree = xstr8_to_path(value);
                         continue;
                 }
 
@@ -1481,7 +1481,7 @@ static void config_entry_add_type1(
                                 entry->initrd,
                                 n_initrd == 0 ? 0 : (n_initrd + 1) * sizeof(uint16_t *),
                                 (n_initrd + 2) * sizeof(uint16_t *));
-                        entry->initrd[n_initrd++] = xstra_to_path(value);
+                        entry->initrd[n_initrd++] = xstr8_to_path(value);
                         entry->initrd[n_initrd] = NULL;
                         continue;
                 }
@@ -1489,7 +1489,7 @@ static void config_entry_add_type1(
                 if (streq8(key, "options")) {
                         _cleanup_free_ char16_t *new = NULL;
 
-                        new = xstra_to_str(value);
+                        new = xstr8_to_16(value);
                         if (entry->options) {
                                 char16_t *s = xpool_print(L"%s %s", entry->options, new);
                                 free(entry->options);
@@ -2134,49 +2134,49 @@ static void config_entry_add_unified(
                 while ((line = line_get_key_value(content, "=", &pos, &key, &value))) {
                         if (streq8(key, "PRETTY_NAME")) {
                                 free(os_pretty_name);
-                                os_pretty_name = xstra_to_str(value);
+                                os_pretty_name = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "IMAGE_ID")) {
                                 free(os_image_id);
-                                os_image_id = xstra_to_str(value);
+                                os_image_id = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "NAME")) {
                                 free(os_name);
-                                os_name = xstra_to_str(value);
+                                os_name = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "ID")) {
                                 free(os_id);
-                                os_id = xstra_to_str(value);
+                                os_id = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "IMAGE_VERSION")) {
                                 free(os_image_version);
-                                os_image_version = xstra_to_str(value);
+                                os_image_version = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "VERSION")) {
                                 free(os_version);
-                                os_version = xstra_to_str(value);
+                                os_version = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "VERSION_ID")) {
                                 free(os_version_id);
-                                os_version_id = xstra_to_str(value);
+                                os_version_id = xstr8_to_16(value);
                                 continue;
                         }
 
                         if (streq8(key, "BUILD_ID")) {
                                 free(os_build_id);
-                                os_build_id = xstra_to_str(value);
+                                os_build_id = xstr8_to_16(value);
                                 continue;
                         }
                 }
@@ -2219,13 +2219,11 @@ static void config_entry_add_unified(
                 content = mfree(content);
 
                 /* read the embedded cmdline file */
-                err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, NULL);
+                size_t cmdline_len;
+                err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, &cmdline_len);
                 if (err == EFI_SUCCESS) {
-                        /* chomp the newline */
-                        if (content[szs[SECTION_CMDLINE] - 1] == '\n')
-                                content[szs[SECTION_CMDLINE] - 1] = '\0';
-
-                        entry->options = xstra_to_str(content);
+                        entry->options = xstrn8_to_16(content, cmdline_len);
+                        mangle_stub_cmdline(entry->options);
                 }
         }
 }
@@ -2640,12 +2638,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         /* Uncomment the next line if you need to wait for debugger. */
         // debug_break();
 
-        /* The firmware may skip initializing some devices for the sake of a faster boot. This is especially
-         * true for fastboot enabled firmwares. But this means that things we use like input devices or the
-         * xbootldr partition may not be available yet. Reconnect all drivers should hopefully make the
-         * firmware initialize everything we need. */
-        (void) reconnect_all_drivers();
-
         err = BS->OpenProtocol(image,
                         &LoadedImageProtocol,
                         (void **)&loaded_image,
index 14c0008afb47bf751a5d8644c196160a67cf5dd8..cd980fd535f8d417e84659778146909c06b002a5 100644 (file)
 #define VERTICAL_MAX_OK 1080
 #define VIEWPORT_RATIO 10
 
+static EFI_STATUS console_connect(void) {
+        EFI_BOOT_MANAGER_POLICY_PROTOCOL *boot_policy;
+        EFI_STATUS err;
+
+        /* This should make console devices appear/fully initialize on fastboot firmware. */
+
+        err = BS->LocateProtocol(
+                        &(EFI_GUID) EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID, NULL, (void **) &boot_policy);
+        if (err != EFI_SUCCESS)
+                return err;
+
+        return boot_policy->ConnectDeviceClass(boot_policy, &(EFI_GUID) EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID);
+}
+
 static inline void event_closep(EFI_EVENT *event) {
         if (!*event)
                 return;
@@ -47,6 +61,8 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
         assert(key);
 
         if (!checked) {
+                console_connect();
+
                 /* Get the *first* TextInputEx device.*/
                 err = BS->LocateProtocol(&SimpleTextInputExProtocol, NULL, (void **) &extraInEx);
                 if (err != EFI_SUCCESS || BS->CheckEvent(extraInEx->WaitForKeyEx) == EFI_INVALID_PARAMETER)
index 648f9f000f4ac3326c7ff810876559df3ba2c136..76e2cd7f4e0a48c8b386086636a71844cea5f51c 100644 (file)
@@ -359,24 +359,7 @@ static char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
         if (device_path_to_str(file_path, &file_path_str) != EFI_SUCCESS)
                 return NULL;
 
-        for (char16_t *i = file_path_str, *fixed = i;; i++) {
-                if (*i == '\0') {
-                        *fixed = '\0';
-                        break;
-                }
-
-                /* Fix device path node separator. */
-                if (*i == '/')
-                        *i = '\\';
-
-                /* Double '\' is not allowed in EFI file paths. */
-                if (fixed != file_path_str && fixed[-1] == '\\' && *i == '\\')
-                        continue;
-
-                *fixed = *i;
-                fixed++;
-        }
-
+        convert_efi_path(file_path_str);
         return xpool_print(u"%s.extra.d", file_path_str);
 }
 
index b877c6f224b010a4d2cd1e9796b53f9a6aaab941..2ba15673c9316c3227ba168238e5e704e6b95dae 100644 (file)
@@ -9,7 +9,8 @@
 #  include "util.h"
 #else
 #  include <stdlib.h>
-#  include "macro.h"
+#  include "alloc-util.h"
+#  define xnew(t, n) ASSERT_SE_PTR(new(t, n))
 #  define xmalloc(n) ASSERT_SE_PTR(malloc(n))
 #endif
 
@@ -138,6 +139,81 @@ DEFINE_STRCHR(char16_t, strchr16);
 DEFINE_STRNDUP(char, xstrndup8, strnlen8);
 DEFINE_STRNDUP(char16_t, xstrndup16, strnlen16);
 
+static unsigned utf8_to_unichar(const char *utf8, size_t n, char32_t *c) {
+        char32_t unichar;
+        unsigned len;
+
+        assert(utf8);
+        assert(c);
+
+        if (!(utf8[0] & 0x80)) {
+                *c = utf8[0];
+                return 1;
+        } else if ((utf8[0] & 0xe0) == 0xc0) {
+                len = 2;
+                unichar = utf8[0] & 0x1f;
+        } else if ((utf8[0] & 0xf0) == 0xe0) {
+                len = 3;
+                unichar = utf8[0] & 0x0f;
+        } else if ((utf8[0] & 0xf8) == 0xf0) {
+                len = 4;
+                unichar = utf8[0] & 0x07;
+        } else if ((utf8[0] & 0xfc) == 0xf8) {
+                len = 5;
+                unichar = utf8[0] & 0x03;
+        } else if ((utf8[0] & 0xfe) == 0xfc) {
+                len = 6;
+                unichar = utf8[0] & 0x01;
+        } else {
+                *c = UINT32_MAX;
+                return 1;
+        }
+
+        if (len > n) {
+                *c = UINT32_MAX;
+                return len;
+        }
+
+        for (unsigned i = 1; i < len; i++) {
+                if ((utf8[i] & 0xc0) != 0x80) {
+                        *c = UINT32_MAX;
+                        return len;
+                }
+                unichar <<= 6;
+                unichar |= utf8[i] & 0x3f;
+        }
+
+        *c = unichar;
+        return len;
+}
+
+/* Convert UTF-8 to UCS-2, skipping any invalid or short byte sequences. */
+char16_t *xstrn8_to_16(const char *str8, size_t n) {
+        if (!str8 || n == 0)
+                return NULL;
+
+        size_t i = 0;
+        char16_t *str16 = xnew(char16_t, n + 1);
+
+        while (n > 0 && *str8 != '\0') {
+                char32_t unichar;
+
+                size_t utf8len = utf8_to_unichar(str8, n, &unichar);
+                str8 += utf8len;
+                n = LESS_BY(n, utf8len);
+
+                switch (unichar) {
+                case 0 ... 0xd7ffU:
+                case 0xe000U ... 0xffffU:
+                        str16[i++] = unichar;
+                        break;
+                }
+        }
+
+        str16[i] = '\0';
+        return str16;
+}
+
 static bool efi_fnmatch_prefix(const char16_t *p, const char16_t *h, const char16_t **ret_p, const char16_t **ret_h) {
         assert(p);
         assert(h);
index d4d76a7c18875a087c4687683b8bd0ead6387737..e12add0b19908b6cca1ac2157e3db95b3404a9f3 100644 (file)
@@ -99,6 +99,11 @@ static inline char16_t *xstrdup16(const char16_t *s) {
         return xstrndup16(s, SIZE_MAX);
 }
 
+char16_t *xstrn8_to_16(const char *str8, size_t n);
+static inline char16_t *xstr8_to_16(const char *str8) {
+        return xstrn8_to_16(str8, strlen8(str8));
+}
+
 bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
 
 bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
index dd7eb48c8c832a365dc679da1dce59d3bb7aef20..48801f9dd8695632a6ef93a25df4f3162c0b57ac 100644 (file)
@@ -93,15 +93,16 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
 
 EFI_STATUS linux_exec(
                 EFI_HANDLE parent,
-                const char *cmdline, UINTN cmdline_len,
-                const void *linux_buffer, UINTN linux_length,
-                const void *initrd_buffer, UINTN initrd_length) {
+                const char16_t *cmdline,
+                const void *linux_buffer,
+                size_t linux_length,
+                const void *initrd_buffer,
+                size_t initrd_length) {
 
         uint32_t compat_address;
         EFI_STATUS err;
 
         assert(parent);
-        assert(cmdline || cmdline_len == 0);
         assert(linux_buffer && linux_length > 0);
         assert(initrd_buffer || initrd_length == 0);
 
@@ -113,7 +114,6 @@ EFI_STATUS linux_exec(
                 return linux_exec_efi_handover(
                                 parent,
                                 cmdline,
-                                cmdline_len,
                                 linux_buffer,
                                 linux_length,
                                 initrd_buffer,
@@ -133,7 +133,7 @@ EFI_STATUS linux_exec(
                 return log_error_status_stall(err, u"Error getting kernel loaded image protocol: %r", err);
 
         if (cmdline) {
-                loaded_image->LoadOptions = xstra_to_str(cmdline);
+                loaded_image->LoadOptions = (void *) cmdline;
                 loaded_image->LoadOptionsSize = strsize16(loaded_image->LoadOptions);
         }
 
index 19e5f5c4a8180192b4926b60363cb8ddd76fca46..f0a6a37ed1bd514d5eedf7f0cc563ba8d45f8182 100644 (file)
@@ -2,14 +2,19 @@
 #pragma once
 
 #include <efi.h>
+#include <uchar.h>
 
 EFI_STATUS linux_exec(
                 EFI_HANDLE parent,
-                const char *cmdline, UINTN cmdline_len,
-                const void *linux_buffer, UINTN linux_length,
-                const void *initrd_buffer, UINTN initrd_length);
+                const char16_t *cmdline,
+                const void *linux_buffer,
+                size_t linux_length,
+                const void *initrd_buffer,
+                size_t initrd_length);
 EFI_STATUS linux_exec_efi_handover(
                 EFI_HANDLE parent,
-                const char *cmdline, UINTN cmdline_len,
-                const void *linux_buffer, UINTN linux_length,
-                const void *initrd_buffer, UINTN initrd_length);
+                const char16_t *cmdline,
+                const void *linux_buffer,
+                size_t linux_length,
+                const void *initrd_buffer,
+                size_t initrd_length);
index 64336ce348eedbca5c12bb33f024561a3ef0a2bf..6a5e4311079d116e2960e06824ce7adf2064dcd6 100644 (file)
@@ -126,12 +126,13 @@ static void linux_efi_handover(EFI_HANDLE parent, uintptr_t kernel, BootParams *
 
 EFI_STATUS linux_exec_efi_handover(
                 EFI_HANDLE parent,
-                const char *cmdline, UINTN cmdline_len,
-                const void *linux_buffer, UINTN linux_length,
-                const void *initrd_buffer, UINTN initrd_length) {
+                const char16_t *cmdline,
+                const void *linux_buffer,
+                size_t linux_length,
+                const void *initrd_buffer,
+                size_t initrd_length) {
 
         assert(parent);
-        assert(cmdline || cmdline_len == 0);
         assert(linux_buffer);
         assert(initrd_buffer || initrd_length == 0);
 
@@ -185,14 +186,20 @@ EFI_STATUS linux_exec_efi_handover(
 
         _cleanup_pages_ Pages cmdline_pages = {};
         if (cmdline) {
+                size_t len = MIN(strlen16(cmdline), image_params->hdr.cmdline_size);
+
                 cmdline_pages = xmalloc_pages(
                                 can_4g ? AllocateAnyPages : AllocateMaxAddress,
                                 EfiLoaderData,
-                                EFI_SIZE_TO_PAGES(cmdline_len + 1),
+                                EFI_SIZE_TO_PAGES(len + 1),
                                 CMDLINE_PTR_MAX);
 
-                memcpy(PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr), cmdline, cmdline_len);
-                ((char *) PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr))[cmdline_len] = 0;
+                /* Convert cmdline to ASCII. */
+                char *cmdline8 = PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr);
+                for (size_t i = 0; i < len; i++)
+                        cmdline8[i] = cmdline[i] <= 0x7E ? cmdline[i] : ' ';
+                cmdline8[len] = '\0';
+
                 boot_params->hdr.cmd_line_ptr = (uint32_t) cmdline_pages.addr;
                 boot_params->ext_cmd_line_ptr = cmdline_pages.addr >> 32;
                 assert(can_4g || cmdline_pages.addr <= CMDLINE_PTR_MAX);
index 9a16920787bf3f41d11a616368fae23d6f2f2c39..6da07d917e4cd824d1253cb93b97f9d3e3172e4f 100644 (file)
@@ -187,7 +187,7 @@ EFI_STATUS tpm_log_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, U
         _cleanup_free_ char16_t *c = NULL;
 
         if (description)
-                c = xstra_to_str(description);
+                c = xstr8_to_16(description);
 
         return tpm_log_event(pcrindex, buffer, buffer_size, c, ret_measured);
 }
index f9169248ec4db323e516418ebc5815e8eb16b8c0..b446e0399f053426334a6e1a48088966072a70fe 100644 (file)
@@ -385,3 +385,35 @@ typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
         { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0,  0xe, 0x67, 0x65, 0x6f }}
 
 #endif
+
+#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID
+#  define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \
+        { 0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } }
+
+typedef struct {
+        CHAR16 **Argv;
+        UINTN Argc;
+        void *StdIn;
+        void *StdOut;
+        void *StdErr;
+} EFI_SHELL_PARAMETERS_PROTOCOL;
+#endif
+
+#ifndef EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID
+#define EFI_BOOT_MANAGER_POLICY_PROTOCOL_GUID \
+        { 0xFEDF8E0C, 0xE147, 0x11E3, { 0x99, 0x03, 0xB8, 0xE8, 0x56, 0x2C, 0xBA, 0xFA } }
+#define EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID \
+        { 0xCAB0E94C, 0xE15F, 0x11E3, { 0x91, 0x8D, 0xB8, 0xE8, 0x56, 0x2C, 0xBA, 0xFA } }
+
+typedef struct EFI_BOOT_MANAGER_POLICY_PROTOCOL EFI_BOOT_MANAGER_POLICY_PROTOCOL;
+struct EFI_BOOT_MANAGER_POLICY_PROTOCOL {
+        UINT64 Revision;
+        EFI_STATUS (EFIAPI *ConnectDevicePath)(
+                EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
+                EFI_DEVICE_PATH *DevicePath,
+                BOOLEAN Recursive);
+        EFI_STATUS (EFIAPI *ConnectDeviceClass)(
+                EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
+                EFI_GUID *Class);
+};
+#endif
index de6d6112a13280cc1d24c7db64f5e071c9ee6cb8..14479c06eaee937ec2d48755da910cf938c36784 100644 (file)
@@ -202,6 +202,10 @@ static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVI
         if (err != EFI_SUCCESS)
                 return err;
 
+        /* The drivers for other partitions on this drive may not be initialized on fastboot firmware, so we
+         * have to ask the firmware to do just that. */
+        (void) BS->ConnectController(disk_handle, NULL, NULL, true);
+
         err = BS->HandleProtocol(disk_handle, &BlockIoProtocol, (void **)&block_io);
         if (err != EFI_SUCCESS)
                 return err;
index 5bc1084e6265db2da64db7085b6dd89ca90c1148..25df97eb21e1b395903fe9ab41e15fb78a0263cb 100644 (file)
@@ -39,16 +39,11 @@ struct bmp_map {
 
 static EFI_STATUS bmp_parse_header(
                 const uint8_t *bmp,
-                UINTN size,
+                size_t size,
                 struct bmp_dib **ret_dib,
                 struct bmp_map **ret_map,
                 const uint8_t **pixmap) {
 
-        struct bmp_file *file;
-        struct bmp_dib *dib;
-        struct bmp_map *map;
-        UINTN row_size;
-
         assert(bmp);
         assert(ret_dib);
         assert(ret_map);
@@ -58,7 +53,7 @@ static EFI_STATUS bmp_parse_header(
                 return EFI_INVALID_PARAMETER;
 
         /* check file header */
-        file = (struct bmp_file *)bmp;
+        struct bmp_file *file = (struct bmp_file *) bmp;
         if (file->signature[0] != 'B' || file->signature[1] != 'M')
                 return EFI_INVALID_PARAMETER;
         if (file->size != size)
@@ -67,7 +62,7 @@ static EFI_STATUS bmp_parse_header(
                 return EFI_INVALID_PARAMETER;
 
         /*  check device-independent bitmap */
-        dib = (struct bmp_dib *)(bmp + sizeof(struct bmp_file));
+        struct bmp_dib *dib = (struct bmp_dib *) (bmp + sizeof(struct bmp_file));
         if (dib->size < sizeof(struct bmp_dib))
                 return EFI_UNSUPPORTED;
 
@@ -92,38 +87,26 @@ static EFI_STATUS bmp_parse_header(
                 return EFI_UNSUPPORTED;
         }
 
-        row_size = ((UINTN) dib->depth * dib->x + 31) / 32 * 4;
+        size_t row_size = ((size_t) dib->depth * dib->x + 31) / 32 * 4;
         if (file->size - file->offset <  dib->y * row_size)
                 return EFI_INVALID_PARAMETER;
         if (row_size * dib->y > 64 * 1024 * 1024)
                 return EFI_INVALID_PARAMETER;
 
         /* check color table */
-        map = (struct bmp_map *)(bmp + sizeof(struct bmp_file) + dib->size);
+        struct bmp_map *map = (struct bmp_map *) (bmp + sizeof(struct bmp_file) + dib->size);
         if (file->offset < sizeof(struct bmp_file) + dib->size)
                 return EFI_INVALID_PARAMETER;
 
         if (file->offset > sizeof(struct bmp_file) + dib->size) {
-                uint32_t map_count;
-                UINTN map_size;
+                uint32_t map_count = 0;
 
                 if (dib->colors_used)
                         map_count = dib->colors_used;
-                else {
-                        switch (dib->depth) {
-                        case 1:
-                        case 4:
-                        case 8:
-                                map_count = 1 << dib->depth;
-                                break;
+                else if (IN_SET(dib->depth, 1, 4, 8))
+                        map_count = 1 << dib->depth;
 
-                        default:
-                                map_count = 0;
-                                break;
-                        }
-                }
-
-                map_size = file->offset - (sizeof(struct bmp_file) + dib->size);
+                size_t map_size = file->offset - (sizeof(struct bmp_file) + dib->size);
                 if (map_size != sizeof(struct bmp_map) * map_count)
                         return EFI_INVALID_PARAMETER;
         }
@@ -135,28 +118,51 @@ static EFI_STATUS bmp_parse_header(
         return EFI_SUCCESS;
 }
 
-static void pixel_blend(uint32_t *dst, const uint32_t source) {
-        uint32_t alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g;
-
-        assert(dst);
-
-        alpha = (source & 0xff);
-
-        /* convert src from RGBA to XRGB */
-        src = source >> 8;
+enum Channels { R, G, B, A, _CHANNELS_MAX };
+static void read_channel_maks(
+                const struct bmp_dib *dib,
+                uint32_t channel_mask[static _CHANNELS_MAX],
+                uint8_t channel_shift[static _CHANNELS_MAX],
+                uint8_t channel_scale[static _CHANNELS_MAX]) {
 
-        /* decompose into RB and G components */
-        src_rb = (src & 0xff00ff);
-        src_g  = (src & 0x00ff00);
-
-        dst_rb = (*dst & 0xff00ff);
-        dst_g  = (*dst & 0x00ff00);
-
-        /* blend */
-        rb = ((((src_rb - dst_rb) * alpha + 0x800080) >> 8) + dst_rb) & 0xff00ff;
-        g  = ((((src_g  -  dst_g) * alpha + 0x008000) >> 8) +  dst_g) & 0x00ff00;
+        assert(dib);
 
-        *dst = (rb | g);
+        if (IN_SET(dib->depth, 16, 32) && dib->size >= sizeof(*dib) + 3 * sizeof(uint32_t)) {
+                uint32_t *mask = (uint32_t *) ((uint8_t *) dib + sizeof(*dib));
+                channel_mask[R] = mask[R];
+                channel_mask[G] = mask[G];
+                channel_mask[B] = mask[B];
+                channel_shift[R] = __builtin_ctz(mask[R]);
+                channel_shift[G] = __builtin_ctz(mask[G]);
+                channel_shift[B] = __builtin_ctz(mask[B]);
+                channel_scale[R] = 0xff / ((1 << __builtin_popcount(mask[R])) - 1);
+                channel_scale[G] = 0xff / ((1 << __builtin_popcount(mask[G])) - 1);
+                channel_scale[B] = 0xff / ((1 << __builtin_popcount(mask[B])) - 1);
+
+                if (dib->size >= sizeof(*dib) + 4 * sizeof(uint32_t) && mask[A] != 0) {
+                        channel_mask[A] = mask[A];
+                        channel_shift[A] = __builtin_ctz(mask[A]);
+                        channel_scale[A] = 0xff / ((1 << __builtin_popcount(mask[A])) - 1);
+                } else {
+                        channel_mask[A] = 0;
+                        channel_shift[A] = 0;
+                        channel_scale[A] = 0;
+                }
+        } else {
+                bool bpp16 = dib->depth == 16;
+                channel_mask[R] = bpp16 ? 0x7C00 : 0xFF0000;
+                channel_mask[G] = bpp16 ? 0x03E0 : 0x00FF00;
+                channel_mask[B] = bpp16 ? 0x001F : 0x0000FF;
+                channel_mask[A] = bpp16 ? 0x0000 : 0x000000;
+                channel_shift[R] = bpp16 ? 0xA : 0x10;
+                channel_shift[G] = bpp16 ? 0x5 : 0x08;
+                channel_shift[B] = bpp16 ? 0x0 : 0x00;
+                channel_shift[A] = bpp16 ? 0x0 : 0x00;
+                channel_scale[R] = bpp16 ? 0x08 : 0x1;
+                channel_scale[G] = bpp16 ? 0x08 : 0x1;
+                channel_scale[B] = bpp16 ? 0x08 : 0x1;
+                channel_scale[A] = bpp16 ? 0x00 : 0x0;
+        }
 }
 
 static EFI_STATUS bmp_to_blt(
@@ -172,17 +178,19 @@ static EFI_STATUS bmp_to_blt(
         assert(map);
         assert(pixmap);
 
+        uint32_t channel_mask[_CHANNELS_MAX];
+        uint8_t channel_shift[_CHANNELS_MAX], channel_scale[_CHANNELS_MAX];
+        read_channel_maks(dib, channel_mask, channel_shift, channel_scale);
+
         /* transform and copy pixels */
         in = pixmap;
-        for (UINTN y = 0; y < dib->y; y++) {
-                EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out;
-                UINTN row_size;
+        for (uint32_t y = 0; y < dib->y; y++) {
+                EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out = &buf[(dib->y - y - 1) * dib->x];
 
-                out = &buf[(dib->y - y - 1) * dib->x];
-                for (UINTN x = 0; x < dib->x; x++, in++, out++) {
+                for (uint32_t x = 0; x < dib->x; x++, in++, out++) {
                         switch (dib->depth) {
                         case 1: {
-                                for (UINTN i = 0; i < 8 && x < dib->x; i++) {
+                                for (unsigned i = 0; i < 8 && x < dib->x; i++) {
                                         out->Red = map[((*in) >> (7 - i)) & 1].red;
                                         out->Green = map[((*in) >> (7 - i)) & 1].green;
                                         out->Blue = map[((*in) >> (7 - i)) & 1].blue;
@@ -195,9 +203,7 @@ static EFI_STATUS bmp_to_blt(
                         }
 
                         case 4: {
-                                UINTN i;
-
-                                i = (*in) >> 4;
+                                unsigned i = (*in) >> 4;
                                 out->Red = map[i].red;
                                 out->Green = map[i].green;
                                 out->Blue = map[i].blue;
@@ -218,16 +224,6 @@ static EFI_STATUS bmp_to_blt(
                                 out->Blue = map[*in].blue;
                                 break;
 
-                        case 16: {
-                                uint16_t i = *(uint16_t *) in;
-
-                                out->Red = (i & 0x7c00) >> 7;
-                                out->Green = (i & 0x3e0) >> 2;
-                                out->Blue = (i & 0x1f) << 3;
-                                in += 1;
-                                break;
-                        }
-
                         case 24:
                                 out->Red = in[2];
                                 out->Green = in[1];
@@ -235,34 +231,42 @@ static EFI_STATUS bmp_to_blt(
                                 in += 2;
                                 break;
 
+                        case 16:
                         case 32: {
-                                uint32_t i = *(uint32_t *) in;
+                                uint32_t i = dib->depth == 16 ? *(uint16_t *) in : *(uint32_t *) in;
+
+                                uint8_t r = ((i & channel_mask[R]) >> channel_shift[R]) * channel_scale[R],
+                                        g = ((i & channel_mask[G]) >> channel_shift[G]) * channel_scale[G],
+                                        b = ((i & channel_mask[B]) >> channel_shift[B]) * channel_scale[B],
+                                        a = 0xFFu;
+                                if (channel_mask[A] != 0)
+                                        a = ((i & channel_mask[A]) >> channel_shift[A]) * channel_scale[A];
 
-                                pixel_blend((uint32_t *)out, i);
+                                out->Red = (out->Red * (0xFFu - a) + r * a) >> 8;
+                                out->Green = (out->Green * (0xFFu - a) + g * a) >> 8;
+                                out->Blue = (out->Blue * (0xFFu - a) + b * a) >> 8;
 
-                                in += 3;
+                                in += dib->depth == 16 ? 1 : 3;
                                 break;
                         }
                         }
                 }
 
                 /* add row padding; new lines always start at 32 bit boundary */
-                row_size = in - pixmap;
+                size_t row_size = in - pixmap;
                 in += ((row_size + 3) & ~3) - row_size;
         }
 
         return EFI_SUCCESS;
 }
 
-EFI_STATUS graphics_splash(const uint8_t *content, UINTN len) {
+EFI_STATUS graphics_splash(const uint8_t *content, size_t len) {
         EFI_GRAPHICS_OUTPUT_BLT_PIXEL background = {};
         EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
         struct bmp_dib *dib;
         struct bmp_map *map;
         const uint8_t *pixmap;
-        _cleanup_free_ void *blt = NULL;
-        UINTN x_pos = 0;
-        UINTN y_pos = 0;
+        size_t x_pos = 0, y_pos = 0;
         EFI_STATUS err;
 
         if (len == 0)
@@ -297,9 +301,9 @@ EFI_STATUS graphics_splash(const uint8_t *content, UINTN len) {
         if (err != EFI_SUCCESS)
                 return err;
 
-        /* EFI buffer */
-        blt = xnew(EFI_GRAPHICS_OUTPUT_BLT_PIXEL, dib->x * dib->y);
-
+        /* Read in current screen content to perform proper alpha blending. */
+        _cleanup_free_ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *blt = xnew(
+                        EFI_GRAPHICS_OUTPUT_BLT_PIXEL, dib->x * dib->y);
         err = GraphicsOutput->Blt(
                         GraphicsOutput, blt,
                         EfiBltVideoToBltBuffer, x_pos, y_pos, 0, 0,
index 6ece3cf7334cb0c4aaf7ac3927d01de3ad9e83f1..023f8ae25586c87824c1921d4afbea788a94240a 100644 (file)
@@ -133,16 +133,62 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
         (void) efivar_set_uint64_le(LOADER_GUID, L"StubFeatures", stub_features, 0);
 }
 
+static bool use_load_options(
+                EFI_HANDLE stub_image,
+                EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
+                bool have_cmdline,
+                char16_t **ret) {
+
+        assert(stub_image);
+        assert(loaded_image);
+        assert(ret);
+
+        /* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
+         * the stub image. */
+        if (secure_boot_enabled() && have_cmdline)
+                return false;
+
+        /* We also do a superficial check whether first character of passed command line
+         * is printable character (for compat with some Dell systems which fill in garbage?). */
+        if (loaded_image->LoadOptionsSize < sizeof(char16_t) || ((char16_t *) loaded_image->LoadOptions)[0] <= 0x1F)
+                return false;
+
+        /* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that
+         * LoadOptions starts with the stub binary path which we want to strip off. */
+        EFI_SHELL_PARAMETERS_PROTOCOL *shell;
+        if (BS->HandleProtocol(stub_image, &(EFI_GUID) EFI_SHELL_PARAMETERS_PROTOCOL_GUID, (void **) &shell)
+            != EFI_SUCCESS) {
+                /* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so
+                 * it could be anything! */
+                *ret = xstrndup16(loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t));
+                mangle_stub_cmdline(*ret);
+                return true;
+        }
+
+        if (shell->Argc < 2)
+                /* No arguments were provided? Then we fall back to built-in cmdline. */
+                return false;
+
+        /* Assemble the command line ourselves without our stub path. */
+        *ret = xstrdup16(shell->Argv[1]);
+        for (size_t i = 2; i < shell->Argc; i++) {
+                _cleanup_free_ char16_t *old = *ret;
+                *ret = xpool_print(u"%s %s", old, shell->Argv[i]);
+        }
+
+        mangle_stub_cmdline(*ret);
+        return true;
+}
+
 EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
-        UINTN credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
-        UINTN cmdline_len = 0, linux_size, initrd_size, dt_size;
+        size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
+        size_t linux_size, initrd_size, dt_size;
         EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
         _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
         EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
-        UINTN addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
-        char *cmdline = NULL;
-        _cleanup_free_ char *cmdline_owned = NULL;
+        size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
+        _cleanup_free_ char16_t *cmdline = NULL;
         int sections_measured = -1, parameters_measured = -1;
         bool sysext_measured = false, m;
         uint64_t loader_features = 0;
@@ -221,32 +267,19 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         /* Show splash screen as early as possible */
         graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
 
-        if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
-                cmdline = (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE];
-                cmdline_len = szs[UNIFIED_SECTION_CMDLINE];
-        }
-
-        /* if we are not in secure boot mode, or none was provided, accept a custom command line and replace
-         * the built-in one. We also do a superficial check whether first character of passed command line
-         * is printable character (for compat with some Dell systems which fill in garbage?). */
-        if ((!secure_boot_enabled() || cmdline_len == 0) &&
-            loaded_image->LoadOptionsSize > 0 &&
-            ((char16_t *) loaded_image->LoadOptions)[0] > 0x1F) {
-                cmdline_len = (loaded_image->LoadOptionsSize / sizeof(char16_t)) * sizeof(char);
-                cmdline = cmdline_owned = xnew(char, cmdline_len);
-
-                for (UINTN i = 0; i < cmdline_len; i++) {
-                        char16_t c = ((char16_t *) loaded_image->LoadOptions)[i];
-                        cmdline[i] = c > 0x1F && c < 0x7F ? c : ' '; /* convert non-printable and non_ASCII characters to spaces. */
-                }
-
+        if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
                 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
                  * duplicates what we already did in the boot menu, if that was already used. However, since
                  * we want the boot menu to support an EFI binary, and want to this stub to be usable from
                  * any boot menu, let's measure things anyway. */
                 m = false;
-                (void) tpm_log_load_options(loaded_image->LoadOptions, &m);
+                (void) tpm_log_load_options(cmdline, &m);
                 parameters_measured = m;
+        } else if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
+                cmdline = xstrn8_to_16(
+                                (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
+                                szs[UNIFIED_SECTION_CMDLINE]);
+                mangle_stub_cmdline(cmdline);
         }
 
         export_variables(loaded_image);
@@ -387,7 +420,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
                         log_error_stall(L"Error loading embedded devicetree: %r", err);
         }
 
-        err = linux_exec(image, cmdline, cmdline_len,
+        err = linux_exec(image, cmdline,
                          PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
                          PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
         graphics_mode(false);
index 2b2359fe5c6e329224ed463dd567ce9f25afc3eb..7b43e1d629ea89c175691d93eb6149ffc851445d 100644 (file)
@@ -324,6 +324,33 @@ TEST(xstrdup16) {
         free(s);
 }
 
+TEST(xstrn8_to_16) {
+        char16_t *s = NULL;
+
+        assert_se(xstrn8_to_16(NULL, 1) == NULL);
+        assert_se(xstrn8_to_16("a", 0) == NULL);
+
+        assert_se(s = xstrn8_to_16("", 1));
+        assert_se(streq16(s, u""));
+        free(s);
+
+        assert_se(s = xstrn8_to_16("1", 1));
+        assert_se(streq16(s, u"1"));
+        free(s);
+
+        assert_se(s = xstr8_to_16("abcxyzABCXYZ09 .,-_#*!\"§$%&/()=?`~"));
+        assert_se(streq16(s, u"abcxyzABCXYZ09 .,-_#*!\"§$%&/()=?`~"));
+        free(s);
+
+        assert_se(s = xstr8_to_16("ÿⱿ𝇉 😺"));
+        assert_se(streq16(s, u"ÿⱿ "));
+        free(s);
+
+        assert_se(s = xstrn8_to_16("¶¶", 3));
+        assert_se(streq16(s, u"¶"));
+        free(s);
+}
+
 #define TEST_FNMATCH_ONE(pattern, haystack, expect)                                     \
         ({                                                                              \
                 assert_se(fnmatch(pattern, haystack, 0) == (expect ? 0 : FNM_NOMATCH)); \
index 57436dbf0cada22b0cc9801abd223aefc1ac6a54..f9aeeb483310b54d98499888ac946cb79c44c65c 100644 (file)
@@ -244,127 +244,36 @@ void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t
         efivar_set(vendor, name, str, 0);
 }
 
-static int utf8_to_16(const char *stra, char16_t *c) {
-        char16_t unichar;
-        UINTN len;
-
-        assert(stra);
-        assert(c);
-
-        if (!(stra[0] & 0x80))
-                len = 1;
-        else if ((stra[0] & 0xe0) == 0xc0)
-                len = 2;
-        else if ((stra[0] & 0xf0) == 0xe0)
-                len = 3;
-        else if ((stra[0] & 0xf8) == 0xf0)
-                len = 4;
-        else if ((stra[0] & 0xfc) == 0xf8)
-                len = 5;
-        else if ((stra[0] & 0xfe) == 0xfc)
-                len = 6;
-        else
-                return -1;
-
-        switch (len) {
-        case 1:
-                unichar = stra[0];
-                break;
-        case 2:
-                unichar = stra[0] & 0x1f;
-                break;
-        case 3:
-                unichar = stra[0] & 0x0f;
-                break;
-        case 4:
-                unichar = stra[0] & 0x07;
-                break;
-        case 5:
-                unichar = stra[0] & 0x03;
-                break;
-        case 6:
-                unichar = stra[0] & 0x01;
-                break;
-        }
-
-        for (UINTN i = 1; i < len; i++) {
-                if ((stra[i] & 0xc0) != 0x80)
-                        return -1;
-                unichar <<= 6;
-                unichar |= stra[i] & 0x3f;
-        }
-
-        *c = unichar;
-        return len;
-}
-
-char16_t *xstra_to_str(const char *stra) {
-        UINTN strlen;
-        UINTN len;
-        UINTN i;
-        char16_t *str;
+void convert_efi_path(char16_t *path) {
+        assert(path);
 
-        assert(stra);
+        for (size_t i = 0, fixed = 0;; i++) {
+                /* Fix device path node separator. */
+                path[fixed] = (path[i] == '/') ? '\\' : path[i];
 
-        len = strlen8(stra);
-        str = xnew(char16_t, len + 1);
-
-        strlen = 0;
-        i = 0;
-        while (i < len) {
-                int utf8len;
-
-                utf8len = utf8_to_16(stra + i, str + strlen);
-                if (utf8len <= 0) {
-                        /* invalid utf8 sequence, skip the garbage */
-                        i++;
+                /* Double '\' is not allowed in EFI file paths. */
+                if (fixed > 0 && path[fixed - 1] == '\\' && path[fixed] == '\\')
                         continue;
-                }
 
-                strlen++;
-                i += utf8len;
+                if (path[i] == '\0')
+                        break;
+
+                fixed++;
         }
-        str[strlen] = '\0';
-        return str;
 }
 
-char16_t *xstra_to_path(const char *stra) {
-        char16_t *str;
-        UINTN strlen;
-        UINTN len;
-        UINTN i;
-
-        assert(stra);
-
-        len = strlen8(stra);
-        str = xnew(char16_t, len + 2);
-
-        str[0] = '\\';
-        strlen = 1;
-        i = 0;
-        while (i < len) {
-                int utf8len;
-
-                utf8len = utf8_to_16(stra + i, str + strlen);
-                if (utf8len <= 0) {
-                        /* invalid utf8 sequence, skip the garbage */
-                        i++;
-                        continue;
-                }
-
-                if (str[strlen] == '/')
-                        str[strlen] = '\\';
-                if (str[strlen] == '\\' && str[strlen-1] == '\\') {
-                        /* skip double slashes */
-                        i += utf8len;
-                        continue;
-                }
+char16_t *xstr8_to_path(const char *str8) {
+        assert(str8);
+        char16_t *path = xstr8_to_16(str8);
+        convert_efi_path(path);
+        return path;
+}
 
-                strlen++;
-                i += utf8len;
-        }
-        str[strlen] = '\0';
-        return str;
+void mangle_stub_cmdline(char16_t *cmdline) {
+        for (; *cmdline != '\0'; cmdline++)
+                /* Convert ASCII control characters to spaces. */
+                if (*cmdline <= 0x1F)
+                        *cmdline = ' ';
 }
 
 EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **ret, UINTN *ret_size) {
index 4c5b6cab13b2c6f3c7db5bb7be770bd38ffa78f9..08f732f484e163a78b1cbe6b88d93d9d30e8a4f5 100644 (file)
@@ -137,8 +137,9 @@ EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, ui
 EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
 EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
 
-char16_t *xstra_to_path(const char *stra);
-char16_t *xstra_to_str(const char *stra);
+void convert_efi_path(char16_t *path);
+char16_t *xstr8_to_path(const char *stra);
+void mangle_stub_cmdline(char16_t *cmdline);
 
 EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **content, UINTN *content_size);
 
index b1bfd778fc490ed6733d5fd8607779843742785a..2260b217b79b318cdf09cfb3d2f7f453ee1b73fa 100644 (file)
@@ -83,6 +83,10 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
         assert(ret_vmm_dev);
         assert(ret_vmm_dir);
 
+        /* Make sure all file systems have been initialized. Only do this in VMs as this is slow
+         * on some real firmwares. */
+        (void) reconnect_all_drivers();
+
         /* find all file system handles */
         err = BS->LocateHandleBuffer(ByProtocol, &FileSystemProtocol, NULL, &n_handles, &handles);
         if (err != EFI_SUCCESS)
index cf51024dcbeff8e2677a20399ab55caf3ee7b275..5d82d656bcad145770180a193c6f2f8d67ecb530 100644 (file)
@@ -56,6 +56,13 @@ typedef struct Group {
         uint64_t io_input_bps, io_output_bps;
 } Group;
 
+/* Counted objects, enum order matters */
+typedef enum PidsCount {
+        COUNT_USERSPACE_PROCESSES,      /* least */
+        COUNT_ALL_PROCESSES,
+        COUNT_PIDS,                     /* most, requires pids controller */
+} PidsCount;
+
 static unsigned arg_depth = 3;
 static unsigned arg_iterations = UINT_MAX;
 static bool arg_batch = false;
@@ -66,11 +73,7 @@ static char* arg_root = NULL;
 static bool arg_recursive = true;
 static bool arg_recursive_unset = false;
 
-static enum {
-        COUNT_PIDS,
-        COUNT_USERSPACE_PROCESSES,
-        COUNT_ALL_PROCESSES,
-} arg_count = COUNT_PIDS;
+static PidsCount arg_count = COUNT_PIDS;
 
 static enum {
         ORDER_PATH,
@@ -916,6 +919,7 @@ static int run(int argc, char *argv[]) {
         usec_t last_refresh = 0;
         bool quit = false, immediate_refresh = false;
         _cleanup_free_ char *root = NULL;
+        PidsCount possible_count;
         CGroupMask mask;
         int r;
 
@@ -929,7 +933,9 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Failed to determine supported controllers: %m");
 
-        arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES;
+        /* honor user selection unless pids controller is unavailable */
+        possible_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_ALL_PROCESSES;
+        arg_count = MIN(possible_count, arg_count);
 
         if (arg_recursive_unset && arg_count == COUNT_PIDS)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
index ab2617153a6ccec674e4ec3b9c8531263f77815c..d2e73726065e3c0178820ed531e08b1a26b3571b 100644 (file)
@@ -2425,6 +2425,7 @@ static int method_disable_unit_files_generic(
                 sd_bus_message *message,
                 Manager *m,
                 int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], InstallChange **changes, size_t *n_changes),
+                bool carries_install_info,
                 sd_bus_error *error) {
 
         _cleanup_strv_free_ char **l = NULL;
@@ -2440,7 +2441,8 @@ static int method_disable_unit_files_generic(
         if (r < 0)
                 return r;
 
-        if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags")) {
+        if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags") ||
+            sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlagsAndInstallInfo")) {
                 uint64_t raw_flags;
 
                 r = sd_bus_message_read(message, "t", &raw_flags);
@@ -2469,19 +2471,23 @@ static int method_disable_unit_files_generic(
         if (r < 0)
                 return install_error(error, r, changes, n_changes);
 
-        return reply_install_changes_and_free(m, message, -1, changes, n_changes, error);
+        return reply_install_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes, error);
 }
 
 static int method_disable_unit_files_with_flags(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
+}
+
+static int method_disable_unit_files_with_flags_and_install_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ true, error);
 }
 
 static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
 }
 
 static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error);
+        return method_disable_unit_files_generic(message, userdata, unit_file_unmask, /* carries_install_info = */ false, error);
 }
 
 static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -3194,6 +3200,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
                                 SD_BUS_RESULT("a(sss)", changes),
                                 method_disable_unit_files_with_flags,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DisableUnitFilesWithFlagsAndInstallInfo",
+                                SD_BUS_ARGS("as", files, "t", flags),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_disable_unit_files_with_flags_and_install_info,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("ReenableUnitFiles",
                                 SD_BUS_ARGS("as", files, "b", runtime, "b", force),
                                 SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
index 7d2ceb0765db8b206e3a51c4b38858d3497a13ac..7b07bb8bb9c2cb77a32ea7206164c89256c46ab1 100644 (file)
@@ -5,6 +5,7 @@
 #include "bus-get-properties.h"
 #include "dbus-cgroup.h"
 #include "dbus-kill.h"
+#include "dbus-manager.h"
 #include "dbus-scope.h"
 #include "dbus-unit.h"
 #include "dbus-util.h"
@@ -39,6 +40,7 @@ int bus_scope_method_abandon(sd_bus_message *message, void *userdata, sd_bus_err
 }
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
 
 const sd_bus_vtable bus_scope_vtable[] = {
         SD_BUS_VTABLE_START(0),
@@ -47,6 +49,7 @@ const sd_bus_vtable bus_scope_vtable[] = {
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RuntimeRandomizedExtraUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_rand_extra_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("OOMPolicy", "s", bus_property_get_oom_policy, offsetof(Scope, oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_SIGNAL("RequestStop", NULL, 0),
         SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_method_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END
@@ -77,6 +80,9 @@ static int bus_scope_set_transient_property(
         if (streq(name, "RuntimeRandomizedExtraUSec"))
                 return bus_set_transient_usec(u, name, &s->runtime_rand_extra_usec, message, flags, error);
 
+        if (streq(name, "OOMPolicy"))
+                return bus_set_transient_oom_policy(u, name, &s->oom_policy, message, flags, error);
+
         if (streq(name, "PIDs")) {
                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
                 unsigned n = 0;
index 224fc908355ae4ebde18231bf90d760bde8aa5f2..6e07f2745b4d754e1653b06496a6e22305487b39 100644 (file)
@@ -135,6 +135,7 @@ static void device_done(Unit *u) {
         assert(d);
 
         device_unset_sysfs(d);
+        d->deserialized_sysfs = mfree(d->deserialized_sysfs);
         d->wants_property = strv_free(d->wants_property);
         d->path = mfree(d->path);
 }
@@ -267,7 +268,7 @@ static int device_coldplug(Unit *u) {
          * 1. MANAGER_IS_RUNNING() == false
          * 2. enumerate devices: manager_enumerate() -> device_enumerate()
          *    Device.enumerated_found is set.
-         * 3. deserialize devices: manager_deserialize() -> device_deserialize()
+         * 3. deserialize devices: manager_deserialize() -> device_deserialize_item()
          *    Device.deserialize_state and Device.deserialized_found are set.
          * 4. coldplug devices: manager_coldplug() -> device_coldplug()
          *    deserialized properties are copied to the main properties.
@@ -282,23 +283,41 @@ static int device_coldplug(Unit *u) {
          *
          * - On switch-root, the udev database may be cleared, except for devices with sticky bit, i.e.
          *   OPTIONS="db_persist". Hence, almost no devices are enumerated in the step 2. However, in
-         *   general, we have several serialized devices. So, DEVICE_FOUND_UDEV bit in the deserialized_found
-         *   must be ignored, as udev rules in initrd and the main system are often different. If the
-         *   deserialized state is DEVICE_PLUGGED, we need to downgrade it to DEVICE_TENTATIVE. Unlike the
-         *   other starting mode, MANAGER_IS_SWITCHING_ROOT() is true when device_coldplug() and
-         *   device_catchup() are called.  Hence, let's conditionalize the operations by using the
-         *   flag. After switch-root, systemd-udevd will (re-)process all devices, and the Device.found and
-         *   Device.state will be adjusted.
+         *   general, we have several serialized devices. So, DEVICE_FOUND_UDEV bit in the
+         *   Device.deserialized_found must be ignored, as udev rules in initrd and the main system are often
+         *   different. If the deserialized state is DEVICE_PLUGGED, we need to downgrade it to
+         *   DEVICE_TENTATIVE. Unlike the other starting mode, MANAGER_IS_SWITCHING_ROOT() is true when
+         *   device_coldplug() and device_catchup() are called. Hence, let's conditionalize the operations by
+         *   using the flag. After switch-root, systemd-udevd will (re-)process all devices, and the
+         *   Device.found and Device.state will be adjusted.
          *
-         * - On reload or reexecute, we can trust enumerated_found, deserialized_found, and deserialized_state.
-         *   Of course, deserialized parameters may be outdated, but the unit state can be adjusted later by
-         *   device_catchup() or uevents. */
+         * - On reload or reexecute, we can trust Device.enumerated_found, Device.deserialized_found, and
+         *   Device.deserialized_state. Of course, deserialized parameters may be outdated, but the unit
+         *   state can be adjusted later by device_catchup() or uevents. */
 
         if (MANAGER_IS_SWITCHING_ROOT(m) &&
             !FLAGS_SET(d->enumerated_found, DEVICE_FOUND_UDEV)) {
-                found &= ~DEVICE_FOUND_UDEV; /* ignore DEVICE_FOUND_UDEV bit */
+
+                /* The device has not been enumerated. On switching-root, such situation is natural. See the
+                 * above comment. To prevent problematic state transition active → dead → active, let's
+                 * drop the DEVICE_FOUND_UDEV flag and downgrade state to DEVICE_TENTATIVE(activating). See
+                 * issue #12953 and #23208. */
+                found &= ~DEVICE_FOUND_UDEV;
                 if (state == DEVICE_PLUGGED)
-                        state = DEVICE_TENTATIVE; /* downgrade state */
+                        state = DEVICE_TENTATIVE;
+
+                /* Also check the validity of the device syspath. Without this check, if the device was
+                 * removed while switching root, it would never go to inactive state, as both Device.found
+                 * and Device.enumerated_found do not have the DEVICE_FOUND_UDEV flag, so device_catchup() in
+                 * device_update_found_one() does nothing in most cases. See issue #25106. Note that the
+                 * syspath field is only serialized when systemd is sufficiently new and the device has been
+                 * already processed by udevd. */
+                if (d->deserialized_sysfs) {
+                        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+
+                        if (sd_device_new_from_syspath(&dev, d->deserialized_sysfs) < 0)
+                                state = DEVICE_DEAD;
+                }
         }
 
         if (d->found == found && d->state == state)
@@ -387,6 +406,9 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
         assert(f);
         assert(fds);
 
+        if (d->sysfs)
+                (void) serialize_item(f, "sysfs", d->sysfs);
+
         if (d->path)
                 (void) serialize_item(f, "path", d->path);
 
@@ -408,7 +430,14 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
         assert(value);
         assert(fds);
 
-        if (streq(key, "path")) {
+        if (streq(key, "sysfs")) {
+                if (!d->deserialized_sysfs) {
+                        d->deserialized_sysfs = strdup(value);
+                        if (!d->deserialized_sysfs)
+                                log_oom_debug();
+                }
+
+        } else if (streq(key, "path")) {
                 if (!d->path) {
                         d->path = strdup(value);
                         if (!d->path)
index 7584bc70c4f609b9d7ca331404fad635dd594c2f..9dd6fb57c234738a48d464815abf4c9c46b695ec 100644 (file)
@@ -20,7 +20,7 @@ typedef enum DeviceFound {
 struct Device {
         Unit meta;
 
-        char *sysfs;
+        char *sysfs, *deserialized_sysfs;
         char *path; /* syspath, device node, alias, or devlink */
 
         /* In order to be able to distinguish dependencies on different device nodes we might end up creating multiple
index 119c518664ff78877bebd87a4a055ae11e2d7971..9c1de3624cb94d719a3564e9624de5107a1ea2e9 100644 (file)
@@ -1184,9 +1184,10 @@ static void bump_file_max_and_nr_open(void) {
 #if BUMP_PROC_SYS_FS_FILE_MAX
         /* The maximum the kernel allows for this since 5.2 is LONG_MAX, use that. (Previously things were
          * different, but the operation would fail silently.) */
-        r = sysctl_writef("fs/file-max", "%li\n", LONG_MAX);
+        r = sysctl_write("fs/file-max", LONG_MAX_STR);
         if (r < 0)
-                log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to bump fs.file-max, ignoring: %m");
+                log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING,
+                               r, "Failed to bump fs.file-max, ignoring: %m");
 #endif
 
 #if BUMP_PROC_SYS_FS_NR_OPEN
@@ -1218,7 +1219,7 @@ static void bump_file_max_and_nr_open(void) {
                         break;
                 }
 
-                r = sysctl_writef("fs/nr_open", "%i\n", v);
+                r = sysctl_writef("fs/nr_open", "%i", v);
                 if (r == -EINVAL) {
                         log_debug("Couldn't write fs.nr_open as %i, halving it.", v);
                         v /= 2;
@@ -1404,8 +1405,7 @@ static int bump_unix_max_dgram_qlen(void) {
         if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
                 return 0;
 
-        r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", WRITE_STRING_FILE_DISABLE_BUFFER,
-                               "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN);
+        r = sysctl_write("net/unix/max_dgram_qlen", STRINGIFY(DEFAULT_UNIX_MAX_DGRAM_QLEN));
         if (r < 0)
                 return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
                                       "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
index c9c2132b8ad3796af3320bba866378979adcba3b..4920716f3487536271996a955e961f205f0abe49 100644 (file)
@@ -2051,7 +2051,9 @@ int setup_namespace(
                 DISSECT_IMAGE_RELAX_VAR_CHECK |
                 DISSECT_IMAGE_FSCK |
                 DISSECT_IMAGE_USR_NO_ROOT |
-                DISSECT_IMAGE_GROWFS;
+                DISSECT_IMAGE_GROWFS |
+                DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                DISSECT_IMAGE_PIN_PARTITION_DEVICES;
         size_t n_mounts;
         int r;
 
index 54a6cc63e4b4a9d55c4fde55ed20264311a1ab3f..e2fc4cc995ef8f1f52e3db9b7b44f7a62adc8234 100644 (file)
@@ -43,6 +43,7 @@ static void scope_init(Unit *u) {
         s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
         u->ignore_on_isolate = true;
         s->user = s->group = NULL;
+        s->oom_policy = _OOM_POLICY_INVALID;
 }
 
 static void scope_done(Unit *u) {
@@ -194,6 +195,11 @@ static int scope_add_extras(Scope *s) {
         if (r < 0)
                 return r;
 
+        if (s->oom_policy < 0)
+                s->oom_policy = s->cgroup_context.delegate ? OOM_CONTINUE : UNIT(s)->manager->default_oom_policy;
+
+        s->cgroup_context.memory_oom_group = s->oom_policy == OOM_KILL;
+
         return scope_add_default_dependencies(s);
 }
 
@@ -286,11 +292,13 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sScope State: %s\n"
                 "%sResult: %s\n"
                 "%sRuntimeMaxSec: %s\n"
-                "%sRuntimeRandomizedExtraSec: %s\n",
+                "%sRuntimeRandomizedExtraSec: %s\n"
+                "%sOOMPolicy: %s\n",
                 prefix, scope_state_to_string(s->state),
                 prefix, scope_result_to_string(s->result),
                 prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
-                prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC));
+                prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
+                prefix, oom_policy_to_string(s->oom_policy));
 
         cgroup_context_dump(UNIT(s), f, prefix);
         kill_context_dump(&s->kill_context, f, prefix);
@@ -635,11 +643,16 @@ static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
         else
                 log_unit_debug(u, "Process of control group was killed by the OOM killer.");
 
-        /* This will probably need to be modified when scope units get an oom-policy */
+        if (s->oom_policy == OOM_CONTINUE)
+                return;
+
         switch (s->state) {
 
         case SCOPE_START_CHOWN:
         case SCOPE_RUNNING:
+                scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_FAILURE_OOM_KILL);
+                break;
+
         case SCOPE_STOP_SIGTERM:
                 scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_OOM_KILL);
                 break;
index 6a228f1177d027d96370eb5a0faf03505275b9b2..c9574a32c2abc9e98724baf9e1ac109e91e5f346 100644 (file)
@@ -38,6 +38,8 @@ struct Scope {
 
         char *user;
         char *group;
+
+        OOMPolicy oom_policy;
 };
 
 extern const UnitVTable scope_vtable;
index 2c734eb0966e217bf3f8f73dfd7b1167d4e66e11..bb190b1e8aa2159ae0ce2bd062525815bb56ab33 100644 (file)
@@ -2421,7 +2421,7 @@ static void service_enter_reload(Service *s) {
                 r = service_spawn(s,
                                   s->control_command,
                                   s->timeout_start_usec,
-                                  EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP|EXEC_WRITE_CREDENTIALS,
+                                  EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
                                   &s->control_pid);
                 if (r < 0)
                         goto fail;
index 4ff86ba1dedc0aadaff0493f3a252f687dfac531..3892bfb208b48fd3fb1beff54c2ba569dc6787fb 100644 (file)
@@ -67,7 +67,9 @@ static DissectImageFlags arg_flags =
         DISSECT_IMAGE_RELAX_VAR_CHECK |
         DISSECT_IMAGE_FSCK |
         DISSECT_IMAGE_USR_NO_ROOT |
-        DISSECT_IMAGE_GROWFS;
+        DISSECT_IMAGE_GROWFS |
+        DISSECT_IMAGE_PIN_PARTITION_DEVICES |
+        DISSECT_IMAGE_ADD_PARTITION_DEVICES;
 static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT;
 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
 static PagerFlags arg_pager_flags = 0;
@@ -1174,9 +1176,9 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
 
 static int action_umount(const char *path) {
         _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *canonical = NULL, *devname = NULL;
+        _cleanup_free_ char *canonical = NULL;
         _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
-        dev_t devno;
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
         int r;
 
         fd = chase_symlinks_and_open(path, NULL, 0, O_DIRECTORY, &canonical);
@@ -1191,18 +1193,26 @@ static int action_umount(const char *path) {
         if (r < 0)
                 return log_error_errno(r, "Failed to determine whether '%s' is a mount point: %m", canonical);
 
-        r = fd_get_whole_disk(fd, /*backing=*/ true, &devno);
-        if (r < 0)
-                return log_error_errno(r, "Failed to find backing block device for '%s': %m", canonical);
+        r = block_device_new_from_fd(fd, BLOCK_DEVICE_LOOKUP_WHOLE_DISK | BLOCK_DEVICE_LOOKUP_BACKING, &dev);
+        if (r < 0) {
+                _cleanup_close_ int usr_fd = -1;
+
+                /* The command `systemd-dissect --mount` expects that the image at least has the root or /usr
+                 * partition. If it does not have the root partition, then we mount the /usr partition on a
+                 * tmpfs. Hence, let's try to find the backing block device through the /usr partition. */
 
-        r = devname_from_devnum(S_IFBLK, devno, &devname);
+                usr_fd = openat(fd, "usr", O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW);
+                if (usr_fd < 0)
+                        return log_error_errno(errno, "Failed to open '%s/usr': %m", canonical);
+
+                r = block_device_new_from_fd(usr_fd, BLOCK_DEVICE_LOOKUP_WHOLE_DISK | BLOCK_DEVICE_LOOKUP_BACKING, &dev);
+        }
         if (r < 0)
-                return log_error_errno(r, "Failed to get devname of block device " DEVNUM_FORMAT_STR ": %m",
-                                       DEVNUM_FORMAT_VAL(devno));
+                return log_error_errno(r, "Failed to find backing block device for '%s': %m", canonical);
 
-        r = loop_device_open_from_path(devname, 0, LOCK_EX, &d);
+        r = loop_device_open(dev, 0, LOCK_EX, &d);
         if (r < 0)
-                return log_error_errno(r, "Failed to open loop device '%s': %m", devname);
+                return log_device_error_errno(dev, r, "Failed to open loopback block device: %m");
 
         /* We've locked the loop device, now we're ready to unmount. To allow the unmount to succeed, we have
          * to close the O_PATH fd we opened earlier. */
index f939b2e8c24a0de4e18e6ca6eab454a57b39b8f1..f2f6cc1a53d901c9e2fc147acc7b75795dea165c 100644 (file)
@@ -358,23 +358,19 @@ static int add_automount(
 
         _cleanup_free_ char *unit = NULL, *p = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        const char *opt = "noauto";
         int r;
 
         assert(id);
         assert(where);
         assert(description);
 
-        if (options)
-                opt = strjoina(options, ",", opt);
-
         r = add_mount(id,
                       what,
                       where,
                       fstype,
                       rw,
                       growfs,
-                      opt,
+                      options,
                       description,
                       NULL);
         if (r < 0)
@@ -665,6 +661,11 @@ static int enumerate_partitions(dev_t devnum) {
                         NULL, NULL,
                         DISSECT_IMAGE_GPT_ONLY|
                         DISSECT_IMAGE_USR_NO_ROOT,
+                        /* NB! Unlike most other places where we dissect block devices we do not use
+                         * DISSECT_IMAGE_ADD_PARTITION_DEVICES here: we want that the kernel finds the
+                         * devices, and udev probes them before we mount them via .mount units much later
+                         * on. And thus we also don't set DISSECT_IMAGE_PIN_PARTITION_DEVICES here, because
+                         * we don't actually mount anything immediately. */
                         &m);
         if (r == -ENOPKG) {
                 log_debug_errno(r, "No suitable partition table found, ignoring.");
index 18e7542e1353ae501cf3309dab934019c6b1eb0d..20bbb4cfebedaab4bd15f451418a0b96dd9d534e 100644 (file)
@@ -59,7 +59,7 @@ struct Manager {
         char *userdb_service;
 
         EVP_PKEY *private_key; /* actually a pair of private and public key */
-        Hashmap *public_keys; /* key name [char*] → publick key [EVP_PKEY*] */
+        Hashmap *public_keys; /* key name [char*] → public key [EVP_PKEY*] */
 
         RebalanceState rebalance_state;
         usec_t rebalance_interval_usec;
index 5e1d5bbd6591cb35a10de3257161192952935cc8..39ad56808d12217d6a950a14dbafe2b4d398420b 100644 (file)
@@ -141,17 +141,19 @@ static int probe_file_system_by_fd(
         errno = 0;
         r = blkid_probe_set_device(b, fd, 0, 0);
         if (r != 0)
-                return errno > 0 ? -errno : -ENOMEM;
+                return errno_or_else(ENOMEM);
 
         (void) blkid_probe_enable_superblocks(b, 1);
         (void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID);
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (IN_SET(r, -2, 1)) /* nothing found or ambiguous result */
+        if (r == _BLKID_SAFEPROBE_ERROR)
+                return errno_or_else(EIO);
+        if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
                 return -ENOPKG;
-        if (r != 0)
-                return errno > 0 ? -errno : -EIO;
+
+        assert(r == _BLKID_SAFEPROBE_FOUND);
 
         (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
         if (!fstype)
@@ -656,7 +658,7 @@ static int luks_validate(
         errno = 0;
         r = blkid_probe_set_device(b, fd, 0, 0);
         if (r != 0)
-                return errno > 0 ? -errno : -ENOMEM;
+                return errno_or_else(ENOMEM);
 
         (void) blkid_probe_enable_superblocks(b, 1);
         (void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
@@ -665,10 +667,12 @@ static int luks_validate(
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (IN_SET(r, -2, 1)) /* nothing found or ambiguous result */
+        if (r == _BLKID_SAFEPROBE_ERROR)
+                return errno_or_else(EIO);
+        if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
                 return -ENOPKG;
-        if (r != 0)
-                return errno > 0 ? -errno : -EIO;
+
+        assert(r == _BLKID_SAFEPROBE_FOUND);
 
         (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
         if (streq_ptr(fstype, "crypto_LUKS")) {
@@ -687,22 +691,21 @@ static int luks_validate(
         errno = 0;
         pl = blkid_probe_get_partitions(b);
         if (!pl)
-                return errno > 0 ? -errno : -ENOMEM;
+                return errno_or_else(ENOMEM);
 
         errno = 0;
         n = blkid_partlist_numof_partitions(pl);
         if (n < 0)
-                return errno > 0 ? -errno : -EIO;
+                return errno_or_else(EIO);
 
         for (int i = 0; i < n; i++) {
-                blkid_partition pp;
                 sd_id128_t id = SD_ID128_NULL;
-                const char *sid;
+                blkid_partition pp;
 
                 errno = 0;
                 pp = blkid_partlist_get_partition(pl, i);
                 if (!pp)
-                        return errno > 0 ? -errno : -EIO;
+                        return errno_or_else(EIO);
 
                 if (sd_id128_string_equal(blkid_partition_get_type_string(pp), SD_GPT_USER_HOME) <= 0)
                         continue;
@@ -710,15 +713,12 @@ static int luks_validate(
                 if (!streq_ptr(blkid_partition_get_name(pp), label))
                         continue;
 
-                sid = blkid_partition_get_uuid(pp);
-                if (sid) {
-                        r = sd_id128_from_string(sid, &id);
-                        if (r < 0)
-                                log_debug_errno(r, "Couldn't parse partition UUID %s, weird: %m", sid);
 
-                        if (!sd_id128_is_null(partition_uuid) && !sd_id128_equal(id, partition_uuid))
-                                continue;
-                }
+                r = blkid_partition_get_uuid_id128(pp, &id);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to read partition UUID, ignoring: %m");
+                else if (!sd_id128_is_null(partition_uuid) && !sd_id128_equal(id, partition_uuid))
+                        continue;
 
                 if (found)
                         return -ENOPKG;
@@ -1837,7 +1837,7 @@ static int make_partition_table(
         _cleanup_(fdisk_unref_partitionp) struct fdisk_partition *p = NULL, *q = NULL;
         _cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *t = NULL;
         _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
-        _cleanup_free_ char *path = NULL, *disk_uuid_as_string = NULL;
+        _cleanup_free_ char *disk_uuid_as_string = NULL;
         uint64_t offset, size, first_lba, start, last_lba, end;
         sd_id128_t disk_uuid;
         int r;
@@ -1855,14 +1855,7 @@ static int make_partition_table(
         if (r < 0)
                 return log_error_errno(r, "Failed to initialize partition type: %m");
 
-        c = fdisk_new_context();
-        if (!c)
-                return log_oom();
-
-        if (asprintf(&path, "/proc/self/fd/%i", fd) < 0)
-                return log_oom();
-
-        r = fdisk_assign_device(c, path, 0);
+        r = fdisk_new_context_fd(fd, /* read_only= */ false, &c);
         if (r < 0)
                 return log_error_errno(r, "Failed to open device: %m");
 
@@ -2645,7 +2638,7 @@ static int prepare_resize_partition(
 
         _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
         _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
-        _cleanup_free_ char *path = NULL, *disk_uuid_as_string = NULL;
+        _cleanup_free_ char *disk_uuid_as_string = NULL;
         struct fdisk_partition *found = NULL;
         sd_id128_t disk_uuid;
         size_t n_partitions;
@@ -2668,14 +2661,7 @@ static int prepare_resize_partition(
                 return 0;
         }
 
-        c = fdisk_new_context();
-        if (!c)
-                return log_oom();
-
-        if (asprintf(&path, "/proc/self/fd/%i", fd) < 0)
-                return log_oom();
-
-        r = fdisk_assign_device(c, path, 0);
+        r = fdisk_new_context_fd(fd, /* read_only= */ false, &c);
         if (r < 0)
                 return log_error_errno(r, "Failed to open device: %m");
 
@@ -2759,7 +2745,6 @@ static int apply_resize_partition(
 
         _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
         _cleanup_free_ void *two_zero_lbas = NULL;
-        _cleanup_free_ char *path = NULL;
         ssize_t n;
         int r;
 
@@ -2791,14 +2776,7 @@ static int apply_resize_partition(
         if (n != 1024)
                 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while wiping partition table.");
 
-        c = fdisk_new_context();
-        if (!c)
-                return log_oom();
-
-        if (asprintf(&path, "/proc/self/fd/%i", fd) < 0)
-                return log_oom();
-
-        r = fdisk_assign_device(c, path, 0);
+        r = fdisk_new_context_fd(fd, /* read_only= */ false, &c);
         if (r < 0)
                 return log_error_errno(r, "Failed to open device: %m");
 
index d301d2896621d981231bcb1973cb630be302fc20..a2ebf97c9cb18b281392090e313dca75630c1957 100644 (file)
@@ -8,6 +8,7 @@
 #include "fd-util.h"
 #include "hexdecoct.h"
 #include "io-util.h"
+#include "journal-internal.h"
 #include "journald-audit.h"
 #include "missing_audit.h"
 #include "string-util.h"
@@ -441,7 +442,7 @@ void server_process_audit_message(
         }
 
         if (!NLMSG_OK(nl, buffer_size)) {
-                log_ratelimit_error(JOURNALD_LOG_RATELIMIT, "Audit netlink message truncated.");
+                log_ratelimit_error(JOURNAL_LOG_RATELIMIT, "Audit netlink message truncated.");
                 return;
         }
 
index 6d58422dddac0debc0f010dc6185a7248f36e287..b2f6fcc2a3c416068c423cf8c2b8195f7507ddee 100644 (file)
@@ -12,6 +12,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "io-util.h"
+#include "journal-internal.h"
 #include "journal-util.h"
 #include "journald-context.h"
 #include "parse-util.h"
@@ -771,7 +772,7 @@ void client_context_acquire_default(Server *s) {
 
                 r = client_context_acquire(s, ucred.pid, &ucred, NULL, 0, NULL, &s->my_context);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to acquire our own context, ignoring: %m");
         }
 
@@ -781,7 +782,7 @@ void client_context_acquire_default(Server *s) {
 
                 r = client_context_acquire(s, 1, NULL, NULL, 0, NULL, &s->pid1_context);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to acquire PID1's context, ignoring: %m");
 
         }
index 6c1e7892d1cb2b4f3810dd86bd80b9da1bcc85a5..99eace084876bb72b01a1faf078b5dca6800158a 100644 (file)
@@ -16,6 +16,7 @@
 #include "format-util.h"
 #include "fs-util.h"
 #include "io-util.h"
+#include "journal-internal.h"
 #include "journald-kmsg.h"
 #include "journald-server.h"
 #include "journald-syslog.h"
@@ -320,7 +321,7 @@ static int server_read_dev_kmsg(Server *s) {
         if (l < 0) {
                 /* Old kernels who don't allow reading from /dev/kmsg
                  * return EINVAL when we try. So handle this cleanly,
-                 * but don' try to ever read from it again. */
+                 * but don't try to ever read from it again. */
                 if (errno == EINVAL) {
                         s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source);
                         return 0;
@@ -329,7 +330,7 @@ static int server_read_dev_kmsg(Server *s) {
                 if (ERRNO_IS_TRANSIENT(errno) || errno == EPIPE)
                         return 0;
 
-                return log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT, "Failed to read from /dev/kmsg: %m");
+                return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT, "Failed to read from /dev/kmsg: %m");
         }
 
         dev_kmsg_record(s, buffer, l);
@@ -368,7 +369,7 @@ static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void
         assert(fd == s->dev_kmsg_fd);
 
         if (revents & EPOLLERR)
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                       "/dev/kmsg buffer overrun, some messages lost.");
 
         if (!(revents & EPOLLIN))
index 21e20db2d44f033690dcff7c170a40d12ba96150..847f69c1ffebe545b37ac864e9c7958dd53d0cd8 100644 (file)
@@ -11,6 +11,7 @@
 #include "fs-util.h"
 #include "io-util.h"
 #include "journal-importer.h"
+#include "journal-internal.h"
 #include "journal-util.h"
 #include "journald-console.h"
 #include "journald-kmsg.h"
@@ -309,7 +310,7 @@ void server_process_native_message(
         if (ucred && pid_is_valid(ucred->pid)) {
                 r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m",
                                                     ucred->pid);
         }
@@ -350,33 +351,33 @@ void server_process_native_file(
 
                 r = fd_get_path(fd, &k);
                 if (r < 0) {
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                   "readlink(/proc/self/fd/%i) failed: %m", fd);
                         return;
                 }
 
                 e = PATH_STARTSWITH_SET(k, "/dev/shm/", "/tmp/", "/var/tmp/");
                 if (!e) {
-                        log_ratelimit_error(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error(JOURNAL_LOG_RATELIMIT,
                                             "Received file outside of allowed directories. Refusing.");
                         return;
                 }
 
                 if (!filename_is_valid(e)) {
-                        log_ratelimit_error(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error(JOURNAL_LOG_RATELIMIT,
                                             "Received file in subdirectory of allowed directories. Refusing.");
                         return;
                 }
         }
 
         if (fstat(fd, &st) < 0) {
-                log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                           "Failed to stat passed file, ignoring: %m");
                 return;
         }
 
         if (!S_ISREG(st.st_mode)) {
-                log_ratelimit_error(JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_error(JOURNAL_LOG_RATELIMIT,
                                     "File passed is not regular. Ignoring.");
                 return;
         }
@@ -387,7 +388,7 @@ void server_process_native_file(
         /* When !sealed, set a lower memory limit. We have to read the file,
          * effectively doubling memory use. */
         if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2)) {
-                log_ratelimit_error(JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_error(JOURNAL_LOG_RATELIMIT,
                                     "File passed too large (%"PRIu64" bytes). Ignoring.",
                                     (uint64_t) st.st_size);
                 return;
@@ -402,7 +403,7 @@ void server_process_native_file(
                 ps = PAGE_ALIGN(st.st_size);
                 p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
                 if (p == MAP_FAILED) {
-                        log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                   "Failed to map memfd, ignoring: %m");
                         return;
                 }
@@ -415,7 +416,7 @@ void server_process_native_file(
                 ssize_t n;
 
                 if (fstatvfs(fd, &vfs) < 0) {
-                        log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                   "Failed to stat file system of passed file, not processing it: %m");
                         return;
                 }
@@ -426,7 +427,7 @@ void server_process_native_file(
                  * https://github.com/systemd/systemd/issues/1822
                  */
                 if (vfs.f_flag & ST_MANDLOCK) {
-                        log_ratelimit_error(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error(JOURNAL_LOG_RATELIMIT,
                                             "Received file descriptor from file system with mandatory locking enabled, not processing it.");
                         return;
                 }
@@ -440,7 +441,7 @@ void server_process_native_file(
                  * and so is SMB. */
                 r = fd_nonblock(fd, true);
                 if (r < 0) {
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                   "Failed to make fd non-blocking, not processing it: %m");
                         return;
                 }
@@ -457,7 +458,7 @@ void server_process_native_file(
 
                 n = pread(fd, p, st.st_size, 0);
                 if (n < 0)
-                        log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                   "Failed to read file, ignoring: %m");
                 else if (n > 0)
                         server_process_native_message(s, p, n, ucred, tv, label, label_len);
index cb94a037d572e744fb826c9278f26f37e8614b96..928e07104b40c48d6c1ca6f3fe38897fa29027b0 100644 (file)
@@ -102,10 +102,10 @@ static int determine_path_usage(
         d = opendir(path);
         if (!d)
                 return log_ratelimit_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
-                                                errno, JOURNALD_LOG_RATELIMIT, "Failed to open %s: %m", path);
+                                                errno, JOURNAL_LOG_RATELIMIT, "Failed to open %s: %m", path);
 
         if (fstatvfs(dirfd(d), &ss) < 0)
-                return log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                 "Failed to fstatvfs(%s): %m", path);
 
         *ret_free = ss.f_bsize * ss.f_bavail;
@@ -256,7 +256,7 @@ static void server_add_acls(ManagedJournalFile *f, uid_t uid) {
 
         r = fd_add_uid_acl_permission(f->file->fd, uid, ACL_READ);
         if (r < 0)
-                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                             "Failed to set ACL on %s, ignoring: %m", f->file->path);
 #endif
 }
@@ -357,7 +357,7 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
                         patch_min_use(&s->system_storage);
                 } else {
                         if (!IN_SET(r, -ENOENT, -EROFS))
-                                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                             "Failed to open system journal: %m");
 
                         r = 0;
@@ -387,7 +387,7 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
                         r = open_journal(s, false, fn, O_RDWR, false, &s->runtime_storage.metrics, &s->runtime_journal);
                         if (r < 0) {
                                 if (r != -ENOENT)
-                                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                                     "Failed to open runtime journal: %m");
 
                                 r = 0;
@@ -402,7 +402,7 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
 
                         r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_storage.metrics, &s->runtime_journal);
                         if (r < 0)
-                                return log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                                return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                                    "Failed to open runtime journal: %m");
                 }
 
@@ -500,10 +500,10 @@ static int do_rotate(
         r = managed_journal_file_rotate(f, s->mmap, file_flags, s->compress.threshold_bytes, s->deferred_closes);
         if (r < 0) {
                 if (*f)
-                        return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                          "Failed to rotate %s: %m", (*f)->file->path);
                 else
-                        return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                          "Failed to create new %s journal: %m", name);
         }
 
@@ -554,7 +554,7 @@ static int vacuum_offline_user_journals(Server *s) {
                 if (errno == ENOENT)
                         return 0;
 
-                return log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT,
+                return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                  "Failed to open %s: %m", s->system_storage.path);
         }
 
@@ -570,7 +570,7 @@ static int vacuum_offline_user_journals(Server *s) {
                 de = readdir_no_dot(d);
                 if (!de) {
                         if (errno != 0)
-                                log_ratelimit_warning_errno(errno, JOURNALD_LOG_RATELIMIT,
+                                log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                             "Failed to enumerate %s, ignoring: %m",
                                                             s->system_storage.path);
 
@@ -605,7 +605,7 @@ static int vacuum_offline_user_journals(Server *s) {
                 fd = openat(dirfd(d), de->d_name, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
                 if (fd < 0) {
                         log_ratelimit_full_errno(IN_SET(errno, ELOOP, ENOENT) ? LOG_DEBUG : LOG_WARNING,
-                                                 errno, JOURNALD_LOG_RATELIMIT,
+                                                 errno, JOURNAL_LOG_RATELIMIT,
                                                  "Failed to open journal file '%s' for rotation: %m", full);
                         continue;
                 }
@@ -628,13 +628,13 @@ static int vacuum_offline_user_journals(Server *s) {
                                 NULL,
                                 &f);
                 if (r < 0) {
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to read journal file %s for rotation, trying to move it out of the way: %m",
                                                     full);
 
                         r = journal_file_dispose(dirfd(d), de->d_name);
                         if (r < 0)
-                                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                             "Failed to move %s out of the way, ignoring: %m",
                                                             full);
                         else
@@ -692,21 +692,21 @@ void server_sync(Server *s) {
         if (s->system_journal) {
                 r = managed_journal_file_set_offline(s->system_journal, false);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to sync system journal, ignoring: %m");
         }
 
         ORDERED_HASHMAP_FOREACH(f, s->user_journals) {
                 r = managed_journal_file_set_offline(f, false);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to sync user journal, ignoring: %m");
         }
 
         if (s->sync_event_source) {
                 r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF);
                 if (r < 0)
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                   "Failed to disable sync timer source: %m");
         }
 
@@ -729,7 +729,7 @@ static void do_vacuum(Server *s, JournalStorage *storage, bool verbose) {
                                      storage->metrics.n_max_files, s->max_retention_usec,
                                      &s->oldest_file_usec, verbose);
         if (r < 0 && r != -ENOENT)
-                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                             "Failed to vacuum %s, ignoring: %m", storage->path);
 
         cache_space_invalidate(&storage->space);
@@ -801,38 +801,46 @@ static bool shall_try_append_again(JournalFile *f, int r) {
                 log_debug("%s: Allocation limit reached, rotating.", f->path);
                 return true;
 
+        case -EROFS: /* Read-only file system */
+                /* When appending an entry fails if shall_try_append_again returns true, the journal is
+                 * rotated. If the FS is read-only, rotation will fail and s->system_journal will be set to
+                 * NULL. After that, when find_journal will try to open the journal since s->system_journal
+                 * will be NULL, it will open the runtime journal. */
+                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT, "%s: Read-only file system, rotating.", f->path);
+                return true;
+
         case -EIO:             /* I/O error of some kind (mmap) */
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT, "%s: IO error, rotating.", f->path);
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: IO error, rotating.", f->path);
                 return true;
 
         case -EHOSTDOWN:       /* Other machine                 */
-                log_ratelimit_info(JOURNALD_LOG_RATELIMIT, "%s: Journal file from other machine, rotating.", f->path);
+                log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "%s: Journal file from other machine, rotating.", f->path);
                 return true;
 
         case -EBUSY:           /* Unclean shutdown              */
-                log_ratelimit_info(JOURNALD_LOG_RATELIMIT, "%s: Unclean shutdown, rotating.", f->path);
+                log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "%s: Unclean shutdown, rotating.", f->path);
                 return true;
 
         case -EPROTONOSUPPORT: /* Unsupported feature           */
-                log_ratelimit_info(JOURNALD_LOG_RATELIMIT, "%s: Unsupported feature, rotating.", f->path);
+                log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "%s: Unsupported feature, rotating.", f->path);
                 return true;
 
         case -EBADMSG:         /* Corrupted                     */
         case -ENODATA:         /* Truncated                     */
         case -ESHUTDOWN:       /* Already archived              */
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT, "%s: Journal file corrupted, rotating.", f->path);
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Journal file corrupted, rotating.", f->path);
                 return true;
 
         case -EIDRM:           /* Journal file has been deleted */
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT, "%s: Journal file has been deleted, rotating.", f->path);
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Journal file has been deleted, rotating.", f->path);
                 return true;
 
         case -ETXTBSY:         /* Journal file is from the future */
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT, "%s: Journal file is from the future, rotating.", f->path);
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "%s: Journal file is from the future, rotating.", f->path);
                 return true;
 
         case -EAFNOSUPPORT:
-                log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                       "%s: underlying file system does not support memory mapping or another required file system feature.",
                                       f->path);
                 return false;
@@ -864,7 +872,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
                  * to ensure that the entries in the journal files are strictly ordered by time, in order to ensure
                  * bisection works correctly. */
 
-                log_ratelimit_info(JOURNALD_LOG_RATELIMIT, "Time jumped backwards, rotating.");
+                log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Time jumped backwards, rotating.");
                 rotate = true;
         } else {
 
@@ -873,7 +881,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
                         return;
 
                 if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_INFO)) {
-                        log_ratelimit_info(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_info(JOURNAL_LOG_RATELIMIT,
                                            "%s: Journal header limits reached or header out-of-date, rotating.",
                                            f->file->path);
                         rotate = true;
@@ -1212,7 +1220,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
 
         r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY);
         if (r < 0)
-                return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+                return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                                  "Failed to read runtime journal: %m");
 
         sd_journal_set_data_threshold(j, 0);
@@ -1228,7 +1236,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
 
                 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
                 if (r < 0) {
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Can't read entry: %m");
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Can't read entry: %m");
                         goto finish;
                 }
 
@@ -1237,17 +1245,17 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
                         continue;
 
                 if (!shall_try_append_again(s->system_journal->file, r)) {
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Can't write entry: %m");
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Can't write entry: %m");
                         goto finish;
                 }
 
-                log_ratelimit_info(JOURNALD_LOG_RATELIMIT, "Rotating system journal.");
+                log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Rotating system journal.");
 
                 server_rotate(s);
                 server_vacuum(s, false);
 
                 if (!s->system_journal) {
-                        log_ratelimit_notice(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_notice(JOURNAL_LOG_RATELIMIT,
                                              "Didn't flush runtime journal since rotation of system journal wasn't successful.");
                         r = -EIO;
                         goto finish;
@@ -1256,7 +1264,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
                 log_debug("Retrying write.");
                 r = journal_file_copy_entry(f, s->system_journal->file, o, f->current_offset);
                 if (r < 0) {
-                        log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Can't write entry: %m");
+                        log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Can't write entry: %m");
                         goto finish;
                 }
         }
@@ -1284,7 +1292,7 @@ finish:
         fn = strjoina(s->runtime_directory, "/flushed");
         k = touch(fn);
         if (k < 0)
-                log_ratelimit_warning_errno(k, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(k, JOURNAL_LOG_RATELIMIT,
                                             "Failed to touch %s, ignoring: %m", fn);
 
         server_refresh_idle_timer(s);
@@ -1314,7 +1322,7 @@ static int server_relinquish_var(Server *s) {
 
         fn = strjoina(s->runtime_directory, "/flushed");
         if (unlink(fn) < 0 && errno != ENOENT)
-                log_ratelimit_warning_errno(errno, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT,
                                             "Failed to unlink %s, ignoring: %m", fn);
 
         server_refresh_idle_timer(s);
@@ -1387,11 +1395,11 @@ int server_process_datagram(
                 if (ERRNO_IS_TRANSIENT(n))
                         return 0;
                 if (n == -EXFULL) {
-                        log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                               "Got message with truncated control data (too many fds sent?), ignoring.");
                         return 0;
                 }
-                return log_ratelimit_error_errno(n, JOURNALD_LOG_RATELIMIT, "recvmsg() failed: %m");
+                return log_ratelimit_error_errno(n, JOURNAL_LOG_RATELIMIT, "recvmsg() failed: %m");
         }
 
         CMSG_FOREACH(cmsg, &msghdr)
@@ -1424,7 +1432,7 @@ int server_process_datagram(
                 if (n > 0 && n_fds == 0)
                         server_process_syslog_message(s, s->buffer, n, ucred, tv, label, label_len);
                 else if (n_fds > 0)
-                        log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                               "Got file descriptors via syslog socket. Ignoring.");
 
         } else if (fd == s->native_fd) {
@@ -1433,7 +1441,7 @@ int server_process_datagram(
                 else if (n == 0 && n_fds == 1)
                         server_process_native_file(s, fds[0], ucred, tv, label, label_len);
                 else if (n_fds > 0)
-                        log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                               "Got too many file descriptors via native socket. Ignoring.");
 
         } else {
@@ -1442,7 +1450,7 @@ int server_process_datagram(
                 if (n > 0 && n_fds == 0)
                         server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
                 else if (n_fds > 0)
-                        log_ratelimit_warning(JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
                                               "Got file descriptors via audit socket. Ignoring.");
         }
 
@@ -1496,7 +1504,7 @@ static void server_full_rotate(Server *s) {
         fn = strjoina(s->runtime_directory, "/rotated");
         r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
         if (r < 0)
-                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                             "Failed to write %s, ignoring: %m", fn);
 }
 
@@ -1600,7 +1608,7 @@ static void server_full_sync(Server *s) {
         fn = strjoina(s->runtime_directory, "/synced");
         r = write_timestamp_file_atomic(fn, now(CLOCK_MONOTONIC));
         if (r < 0)
-                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                             "Failed to write %s, ignoring: %m", fn);
 
         return;
index fb512dcfeb7664906f3c19464053145848a014b7..ee8f37419088c2e7e9c99e29ba078ec28b4923d5 100644 (file)
@@ -20,8 +20,6 @@ typedef struct Server Server;
 #include "time-util.h"
 #include "varlink.h"
 
-#define JOURNALD_LOG_RATELIMIT ((const RateLimit) { .interval = 60 * USEC_PER_SEC, .burst = 3 })
-
 typedef enum Storage {
         STORAGE_AUTO,
         STORAGE_VOLATILE,
index abfd04683713f42c91ca08665119e74e0acedadf..49f28972ea205edf140b4fde8f7da0744871ea1c 100644 (file)
@@ -19,6 +19,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "io-util.h"
+#include "journal-internal.h"
 #include "journald-console.h"
 #include "journald-context.h"
 #include "journald-kmsg.h"
@@ -160,7 +161,7 @@ static int stdout_stream_save(StdoutStream *s) {
 
                 r = fstat(s->fd, &st);
                 if (r < 0)
-                        return log_ratelimit_warning_errno(errno, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to stat connected stream: %m");
 
                 /* We use device and inode numbers as identifier for the stream */
@@ -232,7 +233,7 @@ static int stdout_stream_save(StdoutStream *s) {
                 if (s->server->notify_event_source) {
                         r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
                         if (r < 0)
-                                log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to enable notify event source: %m");
+                                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to enable notify event source: %m");
                 }
         }
 
@@ -240,7 +241,7 @@ static int stdout_stream_save(StdoutStream *s) {
 
 fail:
         (void) unlink(s->state_file);
-        return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT,
+        return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
                                          "Failed to save stream data %s: %m", s->state_file);
 }
 
@@ -268,7 +269,7 @@ static int stdout_stream_log(
         else if (pid_is_valid(s->ucred.pid)) {
                 r = client_context_acquire(s->server, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to acquire client context, ignoring: %m");
         }
 
@@ -366,7 +367,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
 
         /* line breaks by NUL, line max length or EOF are not permissible during the negotiation part of the protocol */
         if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING)
-                return log_ratelimit_warning_errno(SYNTHETIC_ERRNO(EINVAL), JOURNALD_LOG_RATELIMIT,
+                return log_ratelimit_warning_errno(SYNTHETIC_ERRNO(EINVAL), JOURNAL_LOG_RATELIMIT,
                                                    "Control protocol line not properly terminated.");
 
         switch (s->state) {
@@ -398,7 +399,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
 
                 priority = syslog_parse_priority_and_facility(p);
                 if (priority < 0)
-                        return log_ratelimit_warning_errno(priority, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(priority, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to parse log priority line: %m");
 
                 s->priority = priority;
@@ -409,7 +410,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         case STDOUT_STREAM_LEVEL_PREFIX:
                 r = parse_boolean(p);
                 if (r < 0)
-                        return log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to parse level prefix line: %m");
 
                 s->level_prefix = r;
@@ -419,7 +420,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         case STDOUT_STREAM_FORWARD_TO_SYSLOG:
                 r = parse_boolean(p);
                 if (r < 0)
-                        return log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to parse forward to syslog line: %m");
 
                 s->forward_to_syslog = r;
@@ -429,7 +430,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         case STDOUT_STREAM_FORWARD_TO_KMSG:
                 r = parse_boolean(p);
                 if (r < 0)
-                        return log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to parse copy to kmsg line: %m");
 
                 s->forward_to_kmsg = r;
@@ -439,7 +440,7 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         case STDOUT_STREAM_FORWARD_TO_CONSOLE:
                 r = parse_boolean(p);
                 if (r < 0)
-                        return log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                            "Failed to parse copy to console line.");
 
                 s->forward_to_console = r;
@@ -597,7 +598,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
                 if (ERRNO_IS_TRANSIENT(errno))
                         return 0;
 
-                log_ratelimit_warning_errno(errno, JOURNALD_LOG_RATELIMIT, "Failed to read from stream: %m");
+                log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT, "Failed to read from stream: %m");
                 goto terminate;
         }
         cmsg_close_all(&msghdr);
@@ -656,7 +657,7 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
 
         r = sd_id128_randomize(&id);
         if (r < 0)
-                return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to generate stream ID: %m");
+                return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to generate stream ID: %m");
 
         stream = new(StdoutStream, 1);
         if (!stream)
@@ -672,7 +673,7 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
 
         r = getpeercred(fd, &stream->ucred);
         if (r < 0)
-                return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to determine peer credentials: %m");
+                return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to determine peer credentials: %m");
 
         r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
         if (r < 0)
@@ -681,18 +682,18 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
         if (mac_selinux_use()) {
                 r = getpeersec(fd, &stream->label);
                 if (r < 0 && r != -EOPNOTSUPP)
-                        (void) log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to determine peer security context: %m");
+                        (void) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to determine peer security context: %m");
         }
 
         (void) shutdown(fd, SHUT_WR);
 
         r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
         if (r < 0)
-                return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to add stream to event loop: %m");
+                return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to add stream to event loop: %m");
 
         r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
         if (r < 0)
-                return log_ratelimit_error_errno(r, JOURNALD_LOG_RATELIMIT, "Failed to adjust stdout event source priority: %m");
+                return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to adjust stdout event source priority: %m");
 
         stream->fd = fd;
 
@@ -724,7 +725,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
                 if (ERRNO_IS_ACCEPT_AGAIN(errno))
                         return 0;
 
-                return log_ratelimit_error_errno(errno, JOURNALD_LOG_RATELIMIT, "Failed to accept stdout connection: %m");
+                return log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT, "Failed to accept stdout connection: %m");
         }
 
         if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
index 6394adfdfdf2291d30b214c92b99f4770b82ff5e..d8708b07755ce98676ecbbfc79d349b11c43ea79 100644 (file)
@@ -10,6 +10,7 @@
 #include "fd-util.h"
 #include "format-util.h"
 #include "io-util.h"
+#include "journal-internal.h"
 #include "journald-console.h"
 #include "journald-kmsg.h"
 #include "journald-server.h"
@@ -334,7 +335,7 @@ void server_process_syslog_message(
         if (ucred && pid_is_valid(ucred->pid)) {
                 r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
                 if (r < 0)
-                        log_ratelimit_warning_errno(r, JOURNALD_LOG_RATELIMIT,
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
                                                     "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m",
                                                     ucred->pid);
         }
diff --git a/src/kernel-install/90-uki-copy.install b/src/kernel-install/90-uki-copy.install
new file mode 100755 (executable)
index 0000000..d6e3deb
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+COMMAND="${1:?}"
+KERNEL_VERSION="${2:?}"
+# shellcheck disable=SC2034
+ENTRY_DIR_ABS="$3"
+KERNEL_IMAGE="$4"
+
+[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
+
+ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
+BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
+
+UKI_DIR="$BOOT_ROOT/EFI/Linux"
+
+case "$COMMAND" in
+    remove)
+        [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+            echo "Removing $UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION*.efi"
+        exec rm -f \
+            "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi" \
+            "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+"*".efi"
+        ;;
+    add)
+        ;;
+    *)
+        exit 0
+        ;;
+esac
+
+if ! [ -d "$UKI_DIR" ]; then
+    echo "Error: entry directory '$UKI_DIR' does not exist" >&2
+    exit 1
+fi
+
+TRIES_FILE="${KERNEL_INSTALL_CONF_ROOT:-/etc/kernel}/tries"
+
+if [ -f "$TRIES_FILE" ]; then
+    read -r TRIES <"$TRIES_FILE"
+    if ! echo "$TRIES" | grep -q '^[0-9][0-9]*$'; then
+        echo "$TRIES_FILE does not contain an integer." >&2
+        exit 1
+    fi
+    UKI_FILE="$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.efi"
+else
+    UKI_FILE="$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi"
+fi
+
+# If there is a UKI named uki.efi on the staging area use that, if not use what
+# was passed in as $KERNEL_IMAGE but insist it has a .efi extension
+if [ -f "$KERNEL_INSTALL_STAGING_AREA/uki.efi" ]; then
+    [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_INSTALL_STAGING_AREA/uki.efi"
+    install -m 0644 "$KERNEL_INSTALL_STAGING_AREA/uki.efi" "$UKI_FILE" || {
+        echo "Error: could not copy '$KERNEL_INSTALL_STAGING_AREA/uki.efi' to '$UKI_FILE'." >&2
+        exit 1
+    }
+elif [ -n "$KERNEL_IMAGE" ]; then
+    [ -f "$KERNEL_IMAGE" ] || {
+        echo "Error: UKI '$KERNEL_IMAGE' not a file." >&2
+        exit 1
+    }
+    [ "$KERNEL_IMAGE" != "${KERNEL_IMAGE%*.efi}.efi" ] && {
+        echo "Error: $KERNEL_IMAGE is missing .efi suffix." >&2
+        exit 1
+    }
+    [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_IMAGE"
+    install -m 0644 "$KERNEL_IMAGE" "$UKI_FILE" || {
+        echo "Error: could not copy '$KERNEL_IMAGE' to '$UKI_FILE'." >&2
+        exit 1
+    }
+else
+    [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "No UKI available. Nothing to do."
+    exit 0
+fi
+chown root:root "$UKI_FILE" || :
+
+exit 0
index e5cfdb824c478ab1ee2b0906cd77ff2da1b6abad..b0b6c27ede834c0f4ea461c5f82a004381d775f9 100644 (file)
@@ -12,6 +12,8 @@ loaderentry_install = custom_target(
         install_mode : 'rwxr-xr-x',
         install_dir : kernelinstalldir)
 
+uki_copy_install = files('90-uki-copy.install')
+
 if want_kernel_install
         install_data('50-depmod.install',
                      install_mode : 'rwxr-xr-x',
index fa98c8946ebe72e8e3676df097ffd1296148bd89..299a6a2c8ceb1f4c8bba79d55cea27e6f5423a00 100644 (file)
@@ -3177,7 +3177,7 @@ static int event_arm_timer(
         assert_se(d->fd >= 0);
 
         if (t == 0) {
-                /* We don' want to disarm here, just mean some time looooong ago. */
+                /* We don't want to disarm here, just mean some time looooong ago. */
                 its.it_value.tv_sec = 0;
                 its.it_value.tv_nsec = 1;
         } else
index 9084da41e3648171ad25049d847908b16f7bb380..507958dabdd5be142e5e8f01a890778e4911ec13 100644 (file)
@@ -23,6 +23,7 @@
 #include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
+#include "journal-internal.h"
 #include "lookup3.h"
 #include "memory-util.h"
 #include "path-util.h"
@@ -3582,22 +3583,24 @@ static int journal_file_warn_btrfs(JournalFile *f) {
 
         r = fd_is_fs_type(f->fd, BTRFS_SUPER_MAGIC);
         if (r < 0)
-                return log_warning_errno(r, "Failed to determine if journal is on btrfs: %m");
+                return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to determine if journal is on btrfs: %m");
         if (!r)
                 return 0;
 
         r = read_attr_fd(f->fd, &attrs);
         if (r < 0)
-                return log_warning_errno(r, "Failed to read file attributes: %m");
+                return log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to read file attributes: %m");
 
         if (attrs & FS_NOCOW_FL) {
                 log_debug("Detected btrfs file system with copy-on-write disabled, all is good.");
                 return 0;
         }
 
-        log_notice("Creating journal file %s on a btrfs file system, and copy-on-write is enabled. "
-                   "This is likely to slow down journal access substantially, please consider turning "
-                   "off the copy-on-write file attribute on the journal directory, using chattr +C.", f->path);
+        log_ratelimit_notice(JOURNAL_LOG_RATELIMIT,
+                             "Creating journal file %s on a btrfs file system, and copy-on-write is enabled. "
+                             "This is likely to slow down journal access substantially, please consider turning "
+                             "off the copy-on-write file attribute on the journal directory, using chattr +C.",
+                             f->path);
 
         return 1;
 }
@@ -4161,10 +4164,6 @@ int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, u
         return 1;
 }
 
-/* Ideally this would be a function parameter but initializers for static fields have to be compile
- * time constants so we hardcode the interval instead. */
-#define LOG_RATELIMIT ((const RateLimit) { .interval = 60 * USEC_PER_SEC, .burst = 3 })
-
 bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log_level) {
         assert(f);
         assert(f->header);
@@ -4172,7 +4171,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
         /* If we gained new header fields we gained new features,
          * hence suggest a rotation */
         if (le64toh(f->header->header_size) < sizeof(Header)) {
-                log_full(log_level, "%s uses an outdated header, suggesting rotation.", f->path);
+                log_ratelimit_full(log_level, JOURNAL_LOG_RATELIMIT,
+                                   "%s uses an outdated header, suggesting rotation.", f->path);
                 return true;
         }
 
@@ -4183,7 +4183,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
         if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
                 if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
                         log_ratelimit_full(
-                                log_level, LOG_RATELIMIT,
+                                log_level, JOURNAL_LOG_RATELIMIT,
                                 "Data hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.",
                                 f->path,
                                 100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
@@ -4197,7 +4197,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
         if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
                 if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
                         log_ratelimit_full(
-                                log_level, LOG_RATELIMIT,
+                                log_level, JOURNAL_LOG_RATELIMIT,
                                 "Field hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.",
                                 f->path,
                                 100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
@@ -4211,7 +4211,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
         if (JOURNAL_HEADER_CONTAINS(f->header, data_hash_chain_depth) &&
             le64toh(f->header->data_hash_chain_depth) > HASH_CHAIN_DEPTH_MAX) {
                 log_ratelimit_full(
-                        log_level, LOG_RATELIMIT,
+                        log_level, JOURNAL_LOG_RATELIMIT,
                         "Data hash table of %s has deepest hash chain of length %" PRIu64 ", suggesting rotation.",
                         f->path, le64toh(f->header->data_hash_chain_depth));
                 return true;
@@ -4220,7 +4220,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
         if (JOURNAL_HEADER_CONTAINS(f->header, field_hash_chain_depth) &&
             le64toh(f->header->field_hash_chain_depth) > HASH_CHAIN_DEPTH_MAX) {
                 log_ratelimit_full(
-                        log_level, LOG_RATELIMIT,
+                        log_level, JOURNAL_LOG_RATELIMIT,
                         "Field hash table of %s has deepest hash chain of length at %" PRIu64 ", suggesting rotation.",
                         f->path, le64toh(f->header->field_hash_chain_depth));
                 return true;
@@ -4232,7 +4232,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
             le64toh(f->header->n_data) > 0 &&
             le64toh(f->header->n_fields) == 0) {
                 log_ratelimit_full(
-                        log_level, LOG_RATELIMIT,
+                        log_level, JOURNAL_LOG_RATELIMIT,
                         "Data objects of %s are not indexed by field objects, suggesting rotation.",
                         f->path);
                 return true;
@@ -4246,7 +4246,7 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec, int log
 
                 if (h > 0 && t > h + max_file_usec) {
                         log_ratelimit_full(
-                                log_level, LOG_RATELIMIT,
+                                log_level, JOURNAL_LOG_RATELIMIT,
                                 "Oldest entry in %s is older than the configured file retention duration (%s), suggesting rotation.",
                                 f->path, FORMAT_TIMESPAN(max_file_usec, USEC_PER_SEC));
                         return true;
index 7fc6896522e27df3c73cd52251ba83032b3af1e3..ed052d1b890de82277e6802dcf509afba658be7c 100644 (file)
@@ -14,6 +14,8 @@
 #include "list.h"
 #include "set.h"
 
+#define JOURNAL_LOG_RATELIMIT ((const RateLimit) { .interval = 60 * USEC_PER_SEC, .burst = 3 })
+
 typedef struct Match Match;
 typedef struct Location Location;
 typedef struct Directory Directory;
index eac35002023a1f379798227b304d604110d5b7d9..7b5e0fa65fa0ade51eedbef4fd064f0490534433 100644 (file)
@@ -13,6 +13,7 @@
 #include "fs-util.h"
 #include "journal-def.h"
 #include "journal-file.h"
+#include "journal-internal.h"
 #include "journal-vacuum.h"
 #include "sort-util.h"
 #include "string-util.h"
@@ -251,7 +252,9 @@ int journal_directory_vacuum(
 
                                 freed += size;
                         } else if (r != -ENOENT)
-                                log_warning_errno(r, "Failed to delete empty archived journal %s/%s: %m", directory, p);
+                                log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
+                                                            "Failed to delete empty archived journal %s/%s: %m",
+                                                            directory, p);
 
                         continue;
                 }
@@ -299,7 +302,9 @@ int journal_directory_vacuum(
                                 sum = 0;
 
                 } else if (r != -ENOENT)
-                        log_warning_errno(r, "Failed to delete archived journal %s/%s: %m", directory, list[i].filename);
+                        log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
+                                                    "Failed to delete archived journal %s/%s: %m",
+                                                    directory, list[i].filename);
         }
 
         if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
index 514f22511c342dab8109cd7627736d5b0ca04a8b..bca13bce57527801e10b90c11fd5163b054fce7a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "list.h"
 #include "netlink-types.h"
+#include "ordered-set.h"
 #include "prioq.h"
 #include "time-util.h"
 
@@ -72,11 +73,9 @@ struct sd_netlink {
         Hashmap *broadcast_group_refs;
         bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
 
-        sd_netlink_message **rqueue;
-        unsigned rqueue_size;
-
-        sd_netlink_message **rqueue_partial;
-        unsigned rqueue_partial_size;
+        OrderedSet *rqueue;
+        Hashmap *rqueue_by_serial;
+        Hashmap *rqueue_partial_by_serial;
 
         struct nlmsghdr *rbuffer;
 
@@ -148,8 +147,6 @@ void message_seal(sd_netlink_message *m);
 
 int netlink_open_family(sd_netlink **ret, int family);
 bool netlink_pid_changed(sd_netlink *nl);
-int netlink_rqueue_make_room(sd_netlink *nl);
-int netlink_rqueue_partial_make_room(sd_netlink *nl);
 
 int socket_bind(sd_netlink *nl);
 int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
index 1da459c01489d933cb538e584ad137727e2c8b68..96162963a75b222e80dd272b115278bc20fc28c2 100644 (file)
@@ -180,11 +180,12 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         return k;
 }
 
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
+static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret_mcast_group, bool peek) {
+        struct iovec iov = IOVEC_MAKE(buf, buf_size);
         union sockaddr_union sender;
         CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control;
         struct msghdr msg = {
-                .msg_iov = iov,
+                .msg_iov = &iov,
                 .msg_iovlen = 1,
                 .msg_name = &sender,
                 .msg_namelen = sizeof(sender),
@@ -194,14 +195,17 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
         ssize_t n;
 
         assert(fd >= 0);
-        assert(iov);
+        assert(peek || (buf && buf_size > 0));
 
         n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
         if (n < 0) {
                 if (n == -ENOBUFS)
                         return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun");
-                if (ERRNO_IS_TRANSIENT(n))
+                if (ERRNO_IS_TRANSIENT(n)) {
+                        if (ret_mcast_group)
+                                *ret_mcast_group = 0;
                         return 0;
+                }
                 return (int) n;
         }
 
@@ -216,9 +220,14 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
                                 return (int) n;
                 }
 
+                if (ret_mcast_group)
+                        *ret_mcast_group = 0;
                 return 0;
         }
 
+        if (!peek && (size_t) n > buf_size) /* message did not fit in read buffer */
+                return -EIO;
+
         if (ret_mcast_group) {
                 struct nl_pktinfo *pi;
 
@@ -232,151 +241,221 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr
         return (int) n;
 }
 
-/* On success, the number of bytes received is returned and *ret points to the received message
- * which has a valid header and the correct size.
- * If nothing useful was received 0 is returned.
- * On failure, a negative error code is returned.
- */
-int socket_read_message(sd_netlink *nl) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
-        bool multi_part = false, done = false;
-        size_t len, allocated;
-        struct iovec iov = {};
-        uint32_t group = 0;
-        unsigned i = 0;
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+        netlink_message_hash_ops,
+        void, trivial_hash_func, trivial_compare_func,
+        sd_netlink_message, sd_netlink_message_unref);
+
+static int netlink_queue_received_message(sd_netlink *nl, sd_netlink_message *m) {
+        uint32_t serial;
         int r;
 
         assert(nl);
-        assert(nl->rbuffer);
+        assert(m);
 
-        /* read nothing, just get the pending message size */
-        r = socket_recv_message(nl->fd, &iov, NULL, true);
-        if (r <= 0)
+        if (ordered_set_size(nl->rqueue) >= NETLINK_RQUEUE_MAX)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
+                                       "sd-netlink: exhausted the read queue size (%d)", NETLINK_RQUEUE_MAX);
+
+        r = ordered_set_ensure_put(&nl->rqueue, &netlink_message_hash_ops, m);
+        if (r < 0)
                 return r;
-        else
-                len = (size_t) r;
 
-        /* make room for the pending message */
-        if (!greedy_realloc((void**) &nl->rbuffer, len, sizeof(uint8_t)))
-                return -ENOMEM;
+        sd_netlink_message_ref(m);
 
-        allocated = MALLOC_SIZEOF_SAFE(nl->rbuffer);
-        iov = IOVEC_MAKE(nl->rbuffer, allocated);
+        if (sd_netlink_message_is_broadcast(m))
+                return 0;
 
-        /* read the pending message */
-        r = socket_recv_message(nl->fd, &iov, &group, false);
-        if (r <= 0)
-                return r;
-        else
-                len = (size_t) r;
+        serial = message_get_serial(m);
+        if (serial == 0)
+                return 0;
 
-        if (len > allocated)
-                /* message did not fit in read buffer */
-                return -EIO;
+        if (sd_netlink_message_get_errno(m) < 0) {
+                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *old = NULL;
 
-        if (NLMSG_OK(nl->rbuffer, len) && nl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
-                multi_part = true;
+                old = hashmap_remove(nl->rqueue_by_serial, UINT32_TO_PTR(serial));
+                if (old)
+                        log_debug("sd-netlink: received error message with serial %"PRIu32", but another message with "
+                                  "the same serial is already stored in the read queue, replacing.", serial);
+        }
 
-                for (i = 0; i < nl->rqueue_partial_size; i++)
-                        if (message_get_serial(nl->rqueue_partial[i]) ==
-                            nl->rbuffer->nlmsg_seq) {
-                                first = nl->rqueue_partial[i];
-                                break;
-                        }
+        r = hashmap_ensure_put(&nl->rqueue_by_serial, &netlink_message_hash_ops, UINT32_TO_PTR(serial), m);
+        if (r == -EEXIST) {
+                if (!sd_netlink_message_is_error(m))
+                        log_debug("sd-netlink: received message with serial %"PRIu32", but another message with "
+                                  "the same serial is already stored in the read queue, ignoring.", serial);
+                return 0;
+        }
+        if (r < 0) {
+                sd_netlink_message_unref(ordered_set_remove(nl->rqueue, m));
+                return r;
         }
 
-        for (struct nlmsghdr *new_msg = nl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
-                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-                size_t size;
+        sd_netlink_message_ref(m);
+        return 0;
+}
 
-                if (group == 0 && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
-                        /* not broadcast and not for us */
-                        continue;
+static int netlink_queue_partially_received_message(sd_netlink *nl, sd_netlink_message *m) {
+        uint32_t serial;
+        int r;
 
-                if (new_msg->nlmsg_type == NLMSG_NOOP)
-                        /* silently drop noop messages */
-                        continue;
+        assert(nl);
+        assert(m);
+        assert(m->hdr->nlmsg_flags & NLM_F_MULTI);
 
-                if (new_msg->nlmsg_type == NLMSG_DONE) {
-                        /* finished reading multi-part message */
-                        done = true;
+        if (hashmap_size(nl->rqueue_partial_by_serial) >= NETLINK_RQUEUE_MAX)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
+                                       "sd-netlink: exhausted the partial read queue size (%d)", NETLINK_RQUEUE_MAX);
 
-                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
-                        if (first)
-                                continue;
-                }
+        serial = message_get_serial(m);
+        r = hashmap_ensure_put(&nl->rqueue_partial_by_serial, &netlink_message_hash_ops, UINT32_TO_PTR(serial), m);
+        if (r < 0)
+                return r;
 
-                /* check that we support this message type */
-                r = netlink_get_policy_set_and_header_size(nl, new_msg->nlmsg_type, NULL, &size);
-                if (r < 0) {
-                        if (r == -EOPNOTSUPP)
-                                log_debug("sd-netlink: ignored message with unknown type: %i",
-                                          new_msg->nlmsg_type);
+        sd_netlink_message_ref(m);
+        return 0;
+}
 
-                        continue;
-                }
+static int parse_message_one(sd_netlink *nl, uint32_t group, const struct nlmsghdr *hdr, sd_netlink_message **ret) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        size_t size;
+        int r;
 
-                /* check that the size matches the message type */
-                if (new_msg->nlmsg_len < NLMSG_LENGTH(size)) {
-                        log_debug("sd-netlink: message is shorter than expected, dropping");
-                        continue;
-                }
+        assert(nl);
+        assert(hdr);
+        assert(ret);
+
+        /* not broadcast and not for us */
+        if (group == 0 && hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
+                goto finalize;
+
+        /* silently drop noop messages */
+        if (hdr->nlmsg_type == NLMSG_NOOP)
+                goto finalize;
+
+        /* check that we support this message type */
+        r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, NULL, &size);
+        if (r == -EOPNOTSUPP) {
+                log_debug("sd-netlink: ignored message with unknown type: %i", hdr->nlmsg_type);
+                goto finalize;
+        }
+        if (r < 0)
+                return r;
 
-                r = message_new_empty(nl, &m);
-                if (r < 0)
-                        return r;
+        /* check that the size matches the message type */
+        if (hdr->nlmsg_len < NLMSG_LENGTH(size)) {
+                log_debug("sd-netlink: message is shorter than expected, dropping.");
+                goto finalize;
+        }
 
-                m->multicast_group = group;
-                m->hdr = memdup(new_msg, new_msg->nlmsg_len);
-                if (!m->hdr)
-                        return -ENOMEM;
+        r = message_new_empty(nl, &m);
+        if (r < 0)
+                return r;
 
-                /* seal and parse the top-level message */
-                r = sd_netlink_message_rewind(m, nl);
-                if (r < 0)
-                        return r;
+        m->multicast_group = group;
+        m->hdr = memdup(hdr, hdr->nlmsg_len);
+        if (!m->hdr)
+                return -ENOMEM;
 
-                /* push the message onto the multi-part message stack */
-                if (first)
-                        m->next = first;
-                first = TAKE_PTR(m);
-        }
+        /* seal and parse the top-level message */
+        r = sd_netlink_message_rewind(m, nl);
+        if (r < 0)
+                return r;
 
-        if (len > 0)
-                log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
+        *ret = TAKE_PTR(m);
+        return 1;
 
-        if (!first)
+finalize:
+        *ret = NULL;
+        return 0;
+}
+
+/* On success, the number of bytes received is returned and *ret points to the received message
+ * which has a valid header and the correct size.
+ * If nothing useful was received 0 is returned.
+ * On failure, a negative error code is returned.
+ */
+int socket_read_message(sd_netlink *nl) {
+        bool done = false;
+        uint32_t group;
+        size_t len;
+        int r;
+
+        assert(nl);
+
+        /* read nothing, just get the pending message size */
+        r = socket_recv_message(nl->fd, NULL, 0, NULL, true);
+        if (r <= 0)
+                return r;
+        len = (size_t) r;
+
+        /* make room for the pending message */
+        if (!greedy_realloc((void**) &nl->rbuffer, len, sizeof(uint8_t)))
+                return -ENOMEM;
+
+        /* read the pending message */
+        r = socket_recv_message(nl->fd, nl->rbuffer, MALLOC_SIZEOF_SAFE(nl->rbuffer), &group, false);
+        if (r <= 0)
+                return r;
+        len = (size_t) r;
+
+        if (!NLMSG_OK(nl->rbuffer, len)) {
+                log_debug("sd-netlink: received invalid message, discarding %zu bytes of incoming message", len);
                 return 0;
+        }
+
+        for (struct nlmsghdr *hdr = nl->rbuffer; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) {
+                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
 
-        if (!multi_part || done) {
-                /* we got a complete message, push it on the read queue */
-                r = netlink_rqueue_make_room(nl);
+                r = parse_message_one(nl, group, hdr, &m);
                 if (r < 0)
                         return r;
+                if (r == 0)
+                        continue;
 
-                nl->rqueue[nl->rqueue_size++] = TAKE_PTR(first);
+                if (hdr->nlmsg_flags & NLM_F_MULTI) {
+                        if (hdr->nlmsg_type == NLMSG_DONE) {
+                                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *existing = NULL;
 
-                if (multi_part && (i < nl->rqueue_partial_size)) {
-                        /* remove the message form the partial read queue */
-                        memmove(nl->rqueue_partial + i, nl->rqueue_partial + i + 1,
-                                sizeof(sd_netlink_message*) * (nl->rqueue_partial_size - i - 1));
-                        nl->rqueue_partial_size--;
-                }
+                                /* finished reading multi-part message */
+                                existing = hashmap_remove(nl->rqueue_partial_by_serial, UINT32_TO_PTR(hdr->nlmsg_seq));
+
+                                /* if we receive only NLMSG_DONE, put it into the receive queue. */
+                                r = netlink_queue_received_message(nl, existing ?: m);
+                                if (r < 0)
+                                        return r;
+
+                                done = true;
+                        } else {
+                                sd_netlink_message *existing;
+
+                                existing = hashmap_get(nl->rqueue_partial_by_serial, UINT32_TO_PTR(hdr->nlmsg_seq));
+                                if (existing) {
+                                        /* This is the continuation of the previously read messages.
+                                         * Let's append this message at the end. */
+                                        while (existing->next)
+                                                existing = existing->next;
+                                        existing->next = TAKE_PTR(m);
+                                } else {
+                                        /* This is the first message. Put it into the queue for partially
+                                         * received messages. */
+                                        r = netlink_queue_partially_received_message(nl, m);
+                                        if (r < 0)
+                                                return r;
+                                }
+                        }
 
-                return 1;
-        } else {
-                /* we only got a partial multi-part message, push it on the
-                   partial read queue */
-                if (i < nl->rqueue_partial_size)
-                        nl->rqueue_partial[i] = TAKE_PTR(first);
-                else {
-                        r = netlink_rqueue_partial_make_room(nl);
+                } else {
+                        r = netlink_queue_received_message(nl, m);
                         if (r < 0)
                                 return r;
 
-                        nl->rqueue_partial[nl->rqueue_partial_size++] = TAKE_PTR(first);
+                        done = true;
                 }
-
-                return 0;
         }
+
+        if (len > 0)
+                log_debug("sd-netlink: discarding trailing %zu bytes of incoming message", len);
+
+        return done;
 }
index 12cdc99ff28e06297fe9c4f5a697f3bc0705751b..c6091542d28988ac209024040b98c3f0d8c854d8 100644 (file)
@@ -673,6 +673,15 @@ int netlink_open_family(sd_netlink **ret, int family) {
         return 0;
 }
 
+static bool serial_used(sd_netlink *nl, uint32_t serial) {
+        assert(nl);
+
+        return
+                hashmap_contains(nl->reply_callbacks, UINT32_TO_PTR(serial)) ||
+                hashmap_contains(nl->rqueue_by_serial, UINT32_TO_PTR(serial)) ||
+                hashmap_contains(nl->rqueue_partial_by_serial, UINT32_TO_PTR(serial));
+}
+
 void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m) {
         uint32_t picked;
 
@@ -689,7 +698,7 @@ void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m) {
                    such messages */
                 nl->serial = nl->serial == UINT32_MAX ? 1 : nl->serial + 1;
 
-        } while (hashmap_contains(nl->reply_callbacks, UINT32_TO_PTR(picked)));
+        } while (serial_used(nl, picked));
 
         m->hdr->nlmsg_seq = picked;
         message_seal(m);
index b99abae64003fa536057c026423529498c9b0d26..fe888926a1d70b900ec39d09a750a8dd1f87146d 100644 (file)
@@ -61,10 +61,6 @@ static int netlink_new(sd_netlink **ret) {
                 .serial = (uint32_t) (now(CLOCK_MONOTONIC) % UINT32_MAX) + 1,
         };
 
-        /* We guarantee that the read buffer has at least space for a message header */
-        if (!greedy_realloc((void**) &nl->rbuffer, sizeof(struct nlmsghdr), sizeof(uint8_t)))
-                return -ENOMEM;
-
         *ret = TAKE_PTR(nl);
         return 0;
 }
@@ -120,18 +116,12 @@ int sd_netlink_increase_rxbuf(sd_netlink *nl, size_t size) {
 
 static sd_netlink *netlink_free(sd_netlink *nl) {
         sd_netlink_slot *s;
-        unsigned i;
 
         assert(nl);
 
-        for (i = 0; i < nl->rqueue_size; i++)
-                sd_netlink_message_unref(nl->rqueue[i]);
-        free(nl->rqueue);
-
-        for (i = 0; i < nl->rqueue_partial_size; i++)
-                sd_netlink_message_unref(nl->rqueue_partial[i]);
-        free(nl->rqueue_partial);
-
+        ordered_set_free(nl->rqueue);
+        hashmap_free(nl->rqueue_by_serial);
+        hashmap_free(nl->rqueue_partial_by_serial);
         free(nl->rbuffer);
 
         while ((s = nl->slots)) {
@@ -179,57 +169,28 @@ int sd_netlink_send(
         return 1;
 }
 
-int netlink_rqueue_make_room(sd_netlink *nl) {
-        assert(nl);
-
-        if (nl->rqueue_size >= NETLINK_RQUEUE_MAX)
-                return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
-                                       "sd-netlink: exhausted the read queue size (%d)",
-                                       NETLINK_RQUEUE_MAX);
-
-        if (!GREEDY_REALLOC(nl->rqueue, nl->rqueue_size + 1))
-                return -ENOMEM;
-
-        return 0;
-}
-
-int netlink_rqueue_partial_make_room(sd_netlink *nl) {
-        assert(nl);
-
-        if (nl->rqueue_partial_size >= NETLINK_RQUEUE_MAX)
-                return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
-                                       "sd-netlink: exhausted the partial read queue size (%d)",
-                                       NETLINK_RQUEUE_MAX);
-
-        if (!GREEDY_REALLOC(nl->rqueue_partial, nl->rqueue_partial_size + 1))
-                return -ENOMEM;
-
-        return 0;
-}
-
-static int dispatch_rqueue(sd_netlink *nl, sd_netlink_message **message) {
+static int dispatch_rqueue(sd_netlink *nl, sd_netlink_message **ret) {
+        sd_netlink_message *m;
         int r;
 
         assert(nl);
-        assert(message);
+        assert(ret);
 
-        if (nl->rqueue_size <= 0) {
+        if (ordered_set_size(nl->rqueue) <= 0) {
                 /* Try to read a new message */
                 r = socket_read_message(nl);
-                if (r == -ENOBUFS) /* FIXME: ignore buffer overruns for now */
+                if (r == -ENOBUFS) /* FIXME: ignore buffer overruns for now */
                         log_debug_errno(r, "sd-netlink: Got ENOBUFS from netlink socket, ignoring.");
-                        return 1;
-                }
-                if (r <= 0)
+                else if (r < 0)
                         return r;
         }
 
         /* Dispatch a queued message */
-        *message = nl->rqueue[0];
-        nl->rqueue_size--;
-        memmove(nl->rqueue, nl->rqueue + 1, sizeof(sd_netlink_message*) * nl->rqueue_size);
-
-        return 1;
+        m = ordered_set_steal_first(nl->rqueue);
+        if (m)
+                sd_netlink_message_unref(hashmap_remove_value(nl->rqueue_by_serial, UINT32_TO_PTR(message_get_serial(m)), m));
+        *ret = m;
+        return !!m;
 }
 
 static int process_timeout(sd_netlink *nl) {
@@ -469,7 +430,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
         assert_return(nl, -EINVAL);
         assert_return(!netlink_pid_changed(nl), -ECHILD);
 
-        if (nl->rqueue_size > 0)
+        if (ordered_set_size(nl->rqueue) > 0)
                 return 0;
 
         r = netlink_poll(nl, false, timeout_usec);
@@ -570,39 +531,32 @@ int sd_netlink_read(
         timeout = calc_elapse(usec);
 
         for (;;) {
+                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
                 usec_t left;
 
-                for (unsigned i = 0; i < nl->rqueue_size; i++) {
-                        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
-                        uint32_t received_serial;
+                m = hashmap_remove(nl->rqueue_by_serial, UINT32_TO_PTR(serial));
+                if (m) {
                         uint16_t type;
 
-                        received_serial = message_get_serial(nl->rqueue[i]);
-                        if (received_serial != serial)
-                                continue;
-
-                        incoming = nl->rqueue[i];
-
                         /* found a match, remove from rqueue and return it */
-                        memmove(nl->rqueue + i, nl->rqueue + i + 1,
-                                sizeof(sd_netlink_message*) * (nl->rqueue_size - i - 1));
-                        nl->rqueue_size--;
+                        sd_netlink_message_unref(ordered_set_remove(nl->rqueue, m));
 
-                        r = sd_netlink_message_get_errno(incoming);
+                        r = sd_netlink_message_get_errno(m);
                         if (r < 0)
                                 return r;
 
-                        r = sd_netlink_message_get_type(incoming, &type);
+                        r = sd_netlink_message_get_type(m, &type);
                         if (r < 0)
                                 return r;
 
                         if (type == NLMSG_DONE) {
-                                *ret = NULL;
+                                if (ret)
+                                        *ret = NULL;
                                 return 0;
                         }
 
                         if (ret)
-                                *ret = TAKE_PTR(incoming);
+                                *ret = TAKE_PTR(m);
                         return 1;
                 }
 
@@ -656,7 +610,7 @@ int sd_netlink_get_events(sd_netlink *nl) {
         assert_return(nl, -EINVAL);
         assert_return(!netlink_pid_changed(nl), -ECHILD);
 
-        return nl->rqueue_size == 0 ? POLLIN : 0;
+        return ordered_set_size(nl->rqueue) == 0 ? POLLIN : 0;
 }
 
 int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
@@ -666,7 +620,7 @@ int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
         assert_return(timeout_usec, -EINVAL);
         assert_return(!netlink_pid_changed(nl), -ECHILD);
 
-        if (nl->rqueue_size > 0) {
+        if (ordered_set_size(nl->rqueue) > 0) {
                 *timeout_usec = 0;
                 return 1;
         }
@@ -678,7 +632,6 @@ int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
         }
 
         *timeout_usec = c->timeout;
-
         return 1;
 }
 
index 86a5decf3f3106ec7e5a3358d7b60e8bc8b25c72..2ab26b9c6d4b9280dd7ea29034913fb5d20f526a 100644 (file)
@@ -3970,6 +3970,12 @@ int manager_start_scope(
         if (r < 0)
                 return r;
 
+        /* For login session scopes, if a process is OOM killed by the kernel, *don't* terminate the rest of
+           the scope */
+        r = sd_bus_message_append(m, "(sv)", "OOMPolicy", "s", "continue");
+        if (r < 0)
+                return r;
+
         /* disable TasksMax= for the session scope, rely on the slice setting for it */
         r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", UINT64_MAX);
         if (r < 0)
index cc153fd6bfd3c0014e4093b3bd7c7bd876957d51..a564f94bfe918c839b9ad98f13378a20dbf9d01b 100644 (file)
@@ -18,6 +18,7 @@
 #include "daemon-util.h"
 #include "device-util.h"
 #include "dirent-util.h"
+#include "escape.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "fs-util.h"
@@ -299,11 +300,16 @@ static int manager_enumerate_linger_users(Manager *m) {
 
         FOREACH_DIRENT(de, d, return -errno) {
                 int k;
+                _cleanup_free_ char *n = NULL;
 
                 if (!dirent_is_file(de))
                         continue;
-
-                k = manager_add_user_by_name(m, de->d_name, NULL);
+                k = cunescape(de->d_name, 0, &n);
+                if (k < 0) {
+                        r = log_warning_errno(k, "Failed to unescape username '%s', ignoring: %m", de->d_name);
+                        continue;
+                }
+                k = manager_add_user_by_name(m, n, NULL);
                 if (k < 0)
                         r = log_warning_errno(k, "Couldn't add lingering user %s, ignoring: %m", de->d_name);
         }
index 95dcf1bab0610f45ba00e7ec7422b74b7f06d867..f7dd705c5e6865b2844b7c7a2defbb9bbf27987e 100644 (file)
@@ -776,53 +776,51 @@ static int find_mount_points(const char *what, char ***list) {
         return n;
 }
 
-static int find_loop_device(const char *backing_file, char **loop_dev) {
-        _cleanup_closedir_ DIR *d = NULL;
-        _cleanup_free_ char *l = NULL;
+static int find_loop_device(const char *backing_file, sd_device **ret) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int r;
 
         assert(backing_file);
-        assert(loop_dev);
+        assert(ret);
 
-        d = opendir("/sys/devices/virtual/block");
-        if (!d)
-                return -errno;
+        r = sd_device_enumerator_new(&e);
+        if (r < 0)
+                return log_oom();
 
-        FOREACH_DIRENT(de, d, return -errno) {
-                _cleanup_free_ char *sys = NULL, *fname = NULL;
-                int r;
+        r = sd_device_enumerator_add_match_subsystem(e, "block", /* match = */ true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add subsystem match: %m");
 
-                if (de->d_type != DT_DIR)
-                        continue;
+        r = sd_device_enumerator_add_match_property(e, "ID_FS_USAGE", "filesystem");
+        if (r < 0)
+                return log_error_errno(r, "Failed to add property match: %m");
 
-                if (!startswith(de->d_name, "loop"))
-                        continue;
+        r = sd_device_enumerator_add_match_sysname(e, "loop*");
+        if (r < 0)
+                return log_error_errno(r, "Failed to add sysname match: %m");
 
-                sys = path_join("/sys/devices/virtual/block", de->d_name, "loop/backing_file");
-                if (!sys)
-                        return -ENOMEM;
+        r = sd_device_enumerator_add_match_sysattr(e, "loop/backing_file", /* value = */ NULL, /* match = */ true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add sysattr match: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                const char *s;
 
-                r = read_one_line_file(sys, &fname);
+                r = sd_device_get_sysattr_value(dev, "loop/backing_file", &s);
                 if (r < 0) {
-                        log_debug_errno(r, "Failed to read %s, ignoring: %m", sys);
+                        log_device_debug_errno(dev, r, "Failed to read \"loop/backing_file\" sysattr, ignoring: %m");
                         continue;
                 }
 
-                if (files_same(fname, backing_file, 0) <= 0)
+                if (files_same(s, backing_file, 0) <= 0)
                         continue;
 
-                l = path_join("/dev", de->d_name);
-                if (!l)
-                        return -ENOMEM;
-
-                break;
+                *ret = sd_device_ref(dev);
+                return 0;
         }
 
-        if (!l)
-                return -ENXIO;
-
-        *loop_dev = TAKE_PTR(l);
-
-        return 0;
+        return -ENXIO;
 }
 
 static int stop_mount(
@@ -914,62 +912,69 @@ static int stop_mounts(
         return 0;
 }
 
-static int umount_by_device(sd_bus *bus, const char *what) {
+static int umount_by_device(sd_bus *bus, sd_device *dev) {
         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
         _cleanup_strv_free_ char **list = NULL;
-        struct stat st;
         const char *v;
-        char **l;
-        int r, r2 = 0;
-
-        assert(what);
+        int r, ret = 0;
 
-        if (stat(what, &st) < 0)
-                return log_error_errno(errno, "Can't stat %s: %m", what);
+        assert(bus);
+        assert(dev);
 
-        if (!S_ISBLK(st.st_mode))
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK),
-                                       "Not a block device: %s", what);
-
-        r = sd_device_new_from_stat_rdev(&d, &st);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get device from device number: %m");
+        if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) >= 0)
+                ret = stop_mounts(bus, v);
 
-        r = sd_device_get_property_value(d, "ID_FS_USAGE", &v);
+        r = sd_device_get_devname(dev, &v);
         if (r < 0)
-                return log_device_error_errno(d, r, "Failed to get device property: %m");
-
-        if (!streq(v, "filesystem"))
-                return log_device_error_errno(d, SYNTHETIC_ERRNO(EINVAL),
-                                              "%s does not contain a known file system.", what);
-
-        if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) >= 0)
-                r2 = stop_mounts(bus, v);
+                return r;
 
-        r = find_mount_points(what, &list);
+        r = find_mount_points(v, &list);
         if (r < 0)
                 return r;
 
-        for (l = list; *l; l++) {
+        STRV_FOREACH(l, list) {
                 r = stop_mounts(bus, *l);
                 if (r < 0)
-                        r2 = r;
+                        ret = r;
         }
 
-        return r2;
+        return ret;
+}
+
+static int umount_by_device_node(sd_bus *bus, const char *node) {
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+        const char *v;
+        int r;
+
+        assert(bus);
+        assert(node);
+
+        r = sd_device_new_from_devname(&dev, node);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device from %s: %m", node);
+
+        r = sd_device_get_property_value(dev, "ID_FS_USAGE", &v);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to get \"ID_FS_USAGE\" device property: %m");
+
+        if (!streq(v, "filesystem"))
+                return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s does not contain a known file system.", node);
+
+        return umount_by_device(bus, dev);
 }
 
 static int umount_loop(sd_bus *bus, const char *backing_file) {
-        _cleanup_free_ char *loop_dev = NULL;
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
         int r;
 
         assert(backing_file);
 
-        r = find_loop_device(backing_file, &loop_dev);
+        r = find_loop_device(backing_file, &dev);
         if (r < 0)
                 return log_error_errno(r, r == -ENXIO ? "File %s is not mounted." : "Can't get loop device for %s: %m", backing_file);
 
-        return umount_by_device(bus, loop_dev);
+        return umount_by_device(bus, dev);
 }
 
 static int action_umount(
@@ -1014,7 +1019,7 @@ static int action_umount(
                         return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]);
 
                 if (S_ISBLK(st.st_mode))
-                        r = umount_by_device(bus, p);
+                        r = umount_by_device_node(bus, p);
                 else if (S_ISREG(st.st_mode))
                         r = umount_loop(bus, p);
                 else if (S_ISDIR(st.st_mode))
@@ -1136,24 +1141,31 @@ static int acquire_mount_where(sd_device *d) {
         return 1;
 }
 
-static int acquire_mount_where_for_loop_dev(const char *loop_dev) {
+static int acquire_mount_where_for_loop_dev(sd_device *dev) {
         _cleanup_strv_free_ char **list = NULL;
+        const char *node;
         int r;
 
+        assert(dev);
+
         if (arg_mount_where)
                 return 0;
 
-        r = find_mount_points(loop_dev, &list);
+        r = sd_device_get_devname(dev, &node);
         if (r < 0)
                 return r;
-        else if (r == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Can't find mount point of %s. It is expected that %s is already mounted on a place.",
-                                       loop_dev, loop_dev);
-        else if (r >= 2)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s is mounted on %d places. It is expected that %s is mounted on a place.",
-                                       loop_dev, r, loop_dev);
+
+        r = find_mount_points(node, &list);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "Can't find mount point of %s. It is expected that %s is already mounted on a place.",
+                                              node, node);
+        if (r >= 2)
+                return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s is mounted on %d places. It is expected that %s is mounted on a place.",
+                                              node, r, node);
 
         arg_mount_where = strdup(list[0]);
         if (!arg_mount_where)
@@ -1234,12 +1246,9 @@ static int acquire_removable(sd_device *d) {
 
 static int discover_loop_backing_file(void) {
         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
-        _cleanup_free_ char *loop_dev = NULL;
-        struct stat st;
-        const char *v;
         int r;
 
-        r = find_loop_device(arg_mount_what, &loop_dev);
+        r = find_loop_device(arg_mount_what, &d);
         if (r < 0 && r != -ENXIO)
                 return log_error_errno(errno, "Can't get loop device for %s: %m", arg_mount_what);
 
@@ -1265,21 +1274,6 @@ static int discover_loop_backing_file(void) {
                 return 0;
         }
 
-        if (stat(loop_dev, &st) < 0)
-                return log_error_errno(errno, "Can't stat %s: %m", loop_dev);
-
-        if (!S_ISBLK(st.st_mode))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Invalid file type: %s", loop_dev);
-
-        r = sd_device_new_from_stat_rdev(&d, &st);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get device from device number: %m");
-
-        if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem"))
-                return log_device_error_errno(d, SYNTHETIC_ERRNO(EINVAL),
-                                              "%s does not contain a known file system.", arg_mount_what);
-
         r = acquire_mount_type(d);
         if (r < 0)
                 return r;
@@ -1288,7 +1282,7 @@ static int discover_loop_backing_file(void) {
         if (r < 0)
                 return r;
 
-        r = acquire_mount_where_for_loop_dev(loop_dev);
+        r = acquire_mount_where_for_loop_dev(d);
         if (r < 0)
                 return r;
 
index 107f19fd154871f9733aa29f3e390f2976fc42b5..eae374323e9352e931ef556b7d832a70d571eb06 100644 (file)
@@ -462,14 +462,9 @@ static int address_add(Link *link, Address *address) {
 }
 
 static int address_update(Address *address) {
-        Link *link;
+        Link *link = ASSERT_PTR(ASSERT_PTR(address)->link);
         int r;
 
-        assert(address);
-        assert(address->link);
-
-        link = address->link;
-
         if (address_is_ready(address) &&
             address->family == AF_INET6 &&
             in6_addr_is_link_local(&address->in_addr.in6) &&
@@ -485,7 +480,7 @@ static int address_update(Address *address) {
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 0;
 
-        r = address_set_masquerade(address, true);
+        r = address_set_masquerade(address, /* add = */ true);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
 
@@ -497,23 +492,16 @@ static int address_update(Address *address) {
                         return r;
         }
 
-        link_update_operstate(link, true);
+        link_update_operstate(link, /* also_update_master = */ true);
         link_check_ready(link);
         return 0;
 }
 
 static int address_drop(Address *address) {
-        Link *link;
-        bool ready;
+        Link *link = ASSERT_PTR(ASSERT_PTR(address)->link);
         int r;
 
-        assert(address);
-        assert(address->link);
-
-        ready = address_is_ready(address);
-        link = address->link;
-
-        r = address_set_masquerade(address, false);
+        r = address_set_masquerade(address, /* add = */ false);
         if (r < 0)
                 log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
 
@@ -522,11 +510,8 @@ static int address_drop(Address *address) {
         if (address->state == 0)
                 address_free(address);
 
-        link_update_operstate(link, true);
-
-        if (link && !ready)
-                link_check_ready(link);
-
+        link_update_operstate(link, /* also_update_master = */ true);
+        link_check_ready(link);
         return 0;
 }
 
index ce7dff222bbd01b8616d8b74ecdf6110e24e10f9..c7ed5fcfe1a2b5da6898e7386565ed9e4e63c3d5 100644 (file)
@@ -168,6 +168,7 @@ static void ndisc_set_route_priority(Link *link, Route *route) {
 static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
         _cleanup_(route_freep) Route *route = in;
         struct in6_addr router;
+        bool is_new;
         int r;
 
         assert(route);
@@ -186,11 +187,16 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
         if (!route->protocol_set)
                 route->protocol = RTPROT_RA;
 
-        if (route_get(NULL, link, route, NULL) < 0)
+        is_new = route_get(NULL, link, route, NULL) < 0;
+
+        r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
+                               ndisc_route_handler, NULL);
+        if (r < 0)
+                return r;
+        if (r > 0 && is_new)
                 link->ndisc_configured = false;
 
-        return link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
-                                  ndisc_route_handler, NULL);
+        return 0;
 }
 
 static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
@@ -212,6 +218,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
 static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
         _cleanup_(address_freep) Address *address = in;
         struct in6_addr router;
+        bool is_new;
         int r;
 
         assert(address);
@@ -229,11 +236,16 @@ static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return r;
 
-        if (address_get(link, address, NULL) < 0)
-                link->ndisc_configured = false;
+        is_new = address_get(link, address, NULL) < 0;
 
-        return link_request_address(link, TAKE_PTR(address), true, &link->ndisc_messages,
+        r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_messages,
                                  ndisc_address_handler, NULL);
+        if (r < 0)
+                return r;
+        if (r > 0 && is_new)
+                link->ndisc_configured = false;
+
+        return 0;
 }
 
 static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
@@ -442,7 +454,6 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
                 return log_oom();
 
         route->family = AF_INET6;
-        route->flags = RTM_F_PREFIX;
         route->dst.in6 = prefix;
         route->dst_prefixlen = prefixlen;
         route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
index e8c390196e1a329412a86ad2075d45836b557152..31ff4bc4256adf5df878df078994d25e4716f436 100644 (file)
@@ -91,6 +91,7 @@ int network_config_state_to_string_alloc(NetworkConfigState s, char **ret);
                                     0);                                 \
         }                                                               \
         static inline bool name##_is_requesting(type *t) {              \
+                assert(t);                                              \
                 return FLAGS_SET(t->state, NETWORK_CONFIG_STATE_REQUESTING); \
         }                                                               \
         static inline void name##_enter_configuring(type *t) {          \
index 0d025804fad14c283132a3a218df1d370bdb8bfa..1282c8b98b7afcd50d75e612cee74fd1e1e1e764 100644 (file)
@@ -1250,7 +1250,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 arg_uid_range = UINT32_C(0x10000);
 
                         } else if (streq(optarg, "identity")) {
-                                /* identitiy: User namespaces on, UID range is map the 0…0xFFFF range to
+                                /* identity: User namespaces on, UID range is map the 0…0xFFFF range to
                                  * itself, i.e. we don't actually map anything, but do take benefit of
                                  * isolation of capability sets. */
                                 arg_userns_mode = USER_NAMESPACE_FIXED;
@@ -3746,7 +3746,7 @@ static int outer_child(
                  * place, so that we can make changes to its mount structure (for example, to implement
                  * --volatile=) without this interfering with our ability to access files such as
                  * /etc/localtime to copy into the container. Note that we use a fixed place for this
-                 * (instead of a temporary directory, since we are living in our own mount namspace here
+                 * (instead of a temporary directory, since we are living in our own mount namespace here
                  * already, and thus don't need to be afraid of colliding with anyone else's mounts). */
                 (void) mkdir_p("/run/systemd/nspawn-root", 0755);
 
@@ -5703,7 +5703,9 @@ static int run(int argc, char *argv[]) {
                         DISSECT_IMAGE_GENERIC_ROOT |
                         DISSECT_IMAGE_REQUIRE_ROOT |
                         DISSECT_IMAGE_RELAX_VAR_CHECK |
-                        DISSECT_IMAGE_USR_NO_ROOT;
+                        DISSECT_IMAGE_USR_NO_ROOT |
+                        DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                        DISSECT_IMAGE_PIN_PARTITION_DEVICES;
                 assert(arg_image);
                 assert(!arg_template);
 
@@ -5845,7 +5847,7 @@ static int run(int argc, char *argv[]) {
                 arg_quiet = true;
 
         if (!arg_quiet)
-                log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",
+                log_info("Spawning container %s on %s.\nPress Ctrl-] three times within 1s to kill container.",
                          arg_machine, arg_image ?: arg_directory);
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
index 120e76be45c013f7fe46d4cfc62cd7751e3888cc..3af1d2f0c13fbac994ab6d233b33392e18ae6db7 100644 (file)
@@ -12,6 +12,7 @@
 #include "local-addresses.h"
 #include "macro.h"
 #include "nss-util.h"
+#include "resolve-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
 #include "string-util.h"
@@ -21,7 +22,7 @@
  * IPv6 we use ::1 which unfortunately will not translate back to the
  * hostname but instead something like "localhost" or so. */
 
-#define LOCALADDRESS_IPV4 (htobe32(0x7F000002))
+#define LOCALADDRESS_IPV4 (htobe32(INADDR_LOCALADDRESS))
 #define LOCALADDRESS_IPV6 &in6addr_loopback
 
 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
index 1fc81d184341723d3729a1f4fb15b524e15571e8..7291e044eb1fd369f604791ed9119e55f7e4b716 100644 (file)
@@ -145,7 +145,7 @@ bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad)
 }
 
 int oomd_fetch_cgroup_oom_preference(OomdCGroupContext *ctx, const char *prefix) {
-        uid_t uid, prefix_uid;
+        uid_t uid;
         int r;
 
         assert(ctx);
@@ -160,28 +160,34 @@ int oomd_fetch_cgroup_oom_preference(OomdCGroupContext *ctx, const char *prefix)
         if (r < 0)
                 return log_debug_errno(r, "Failed to get owner/group from %s: %m", ctx->path);
 
-        r = cg_get_owner(SYSTEMD_CGROUP_CONTROLLER, prefix, &prefix_uid);
-        if (r < 0)
-                return log_debug_errno(r, "Failed to get owner/group from %s: %m", ctx->path);
+        if (uid != 0) {
+                uid_t prefix_uid;
 
-        if (uid == prefix_uid) {
-                /* Ignore most errors when reading the xattr since it is usually unset and cgroup xattrs are only used
-                 * as an optional feature of systemd-oomd (and the system might not even support them). */
-                r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_avoid");
-                if (r == -ENOMEM)
-                        return log_oom_debug();
-                if (r < 0 && !ERRNO_IS_XATTR_ABSENT(r))
-                        log_debug_errno(r, "Failed to get xattr user.oomd_avoid, ignoring: %m");
-                ctx->preference = r > 0 ? MANAGED_OOM_PREFERENCE_AVOID : ctx->preference;
+                r = cg_get_owner(SYSTEMD_CGROUP_CONTROLLER, prefix, &prefix_uid);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to get owner/group from %s: %m", prefix);
 
-                r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_omit");
-                if (r == -ENOMEM)
-                        return log_oom_debug();
-                if (r < 0 && !ERRNO_IS_XATTR_ABSENT(r))
-                        log_debug_errno(r, "Failed to get xattr user.oomd_omit, ignoring: %m");
-                ctx->preference = r > 0 ? MANAGED_OOM_PREFERENCE_OMIT : ctx->preference;
-        } else
-                ctx->preference = MANAGED_OOM_PREFERENCE_NONE;
+                if (uid != prefix_uid) {
+                        ctx->preference = MANAGED_OOM_PREFERENCE_NONE;
+                        return 0;
+                }
+        }
+
+        /* Ignore most errors when reading the xattr since it is usually unset and cgroup xattrs are only used
+         * as an optional feature of systemd-oomd (and the system might not even support them). */
+        r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_avoid");
+        if (r == -ENOMEM)
+                return log_oom_debug();
+        if (r < 0 && !ERRNO_IS_XATTR_ABSENT(r))
+                log_debug_errno(r, "Failed to get xattr user.oomd_avoid, ignoring: %m");
+        ctx->preference = r > 0 ? MANAGED_OOM_PREFERENCE_AVOID : ctx->preference;
+
+        r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_omit");
+        if (r == -ENOMEM)
+                return log_oom_debug();
+        if (r < 0 && !ERRNO_IS_XATTR_ABSENT(r))
+                log_debug_errno(r, "Failed to get xattr user.oomd_omit, ignoring: %m");
+        ctx->preference = r > 0 ? MANAGED_OOM_PREFERENCE_OMIT : ctx->preference;
 
         return 0;
 }
index 7fd9e92109a51abec6e1a59ad2dfddb0a811174c..a758d5589bf6f4ee8022f0f832fabcafe2186659 100644 (file)
@@ -109,9 +109,10 @@ static inline int compare_swap_usage(OomdCGroupContext * const *c1, OomdCGroupCo
  * Returns the number of sorted items; negative on error. */
 int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const char *prefix, OomdCGroupContext ***ret);
 
-/* If the cgroups represented by `ctx` and `prefix` are owned by the same user,
- * then set `ctx->preference` using the `user.oomd_avoid` and `user.oomd_omit`
- * xattrs. Otherwise, set `ctx->preference` to MANAGED_OOM_PREFERENCE_NONE.
+/* If the the cgroup is owned by root, or the cgroups represented by `ctx` and
+ * `prefix` are owned by the same user, then set `ctx->preference` using the
+ * `user.oomd_avoid` and `user.oomd_omit` xattrs. Otherwise, set
+ * `ctx->preference` to MANAGED_OOM_PREFERENCE_NONE.
  *
  * If `prefix` is NULL or the empty string, it is treated as root. If `prefix`
  * does not specify an ancestor cgroup of `ctx`, -EINVAL is returned. Returns
index 176e3a8d691226dc05f64d00616c7e2166ece24b..faa75c55788f874f4adc7576c0fae232cfe4da5e 100644 (file)
@@ -475,9 +475,9 @@ static void test_oomd_fetch_cgroup_oom_preference(void) {
 
         /* Assert that avoid/omit are not set if the cgroup and prefix are not
          * owned by the same user.*/
-        if (test_xattrs && !empty_or_root(ctx->path)) {
+        if (test_xattrs && !empty_or_root(cgroup)) {
                 ctx = oomd_cgroup_context_free(ctx);
-                assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 65534, 0) >= 0);
+                assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 61183, 0) >= 0);
                 assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
 
                 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
index e23a0c335092fe335506727ff6a2888f212ecda2..46b68c730cb1bddc7fbcc52bd7f1fd1bf61e6bed 100644 (file)
@@ -143,8 +143,10 @@ static char *arg_tpm2_public_key = NULL;
 static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
 static bool arg_split = false;
 static sd_id128_t *arg_filter_partitions = NULL;
-static size_t arg_filter_partitions_size = 0;
+static size_t arg_n_filter_partitions = 0;
 static FilterPartitionsType arg_filter_partitions_type = FILTER_PARTITIONS_NONE;
+static sd_id128_t *arg_skip_partitions = NULL;
+static size_t arg_n_skip_partitions = 0;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -385,19 +387,29 @@ static void partition_foreignize(Partition *p) {
         p->verity = VERITY_OFF;
 }
 
-static bool partition_skip(const Partition *p) {
+static bool partition_exclude(const Partition *p) {
         assert(p);
 
         if (arg_filter_partitions_type == FILTER_PARTITIONS_NONE)
                 return false;
 
-        for (size_t i = 0; i < arg_filter_partitions_size; i++)
+        for (size_t i = 0; i < arg_n_filter_partitions; i++)
                 if (sd_id128_equal(p->type.uuid, arg_filter_partitions[i]))
                         return arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE;
 
         return arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE;
 }
 
+static bool partition_skip(const Partition *p) {
+        assert(p);
+
+        for (size_t i = 0; i < arg_n_skip_partitions; i++)
+                if (sd_id128_equal(p->type.uuid, arg_skip_partitions[i]))
+                        return true;
+
+        return false;
+}
+
 static Partition* partition_unlink_and_free(Context *context, Partition *p) {
         if (!p)
                 return NULL;
@@ -1559,6 +1571,9 @@ static int partition_read_definition(Partition *p, const char *path, const char
         if (r < 0)
                 return r;
 
+        if (partition_exclude(p))
+                return 0;
+
         if (p->size_min != UINT64_MAX && p->size_max != UINT64_MAX && p->size_min > p->size_max)
                 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
                                   "SizeMinBytes= larger than SizeMaxBytes=, refusing.");
@@ -1657,7 +1672,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
         } else if (streq(p->split_name_format, "-"))
                 p->split_name_format = mfree(p->split_name_format);
 
-        return 0;
+        return 1;
 }
 
 static int find_verity_sibling(Context *context, Partition *p, VerityMode mode, Partition **ret) {
@@ -1732,6 +1747,8 @@ static int context_read_definitions(
                 r = partition_read_definition(p, *f, dirs);
                 if (r < 0)
                         return r;
+                if (r == 0)
+                        continue;
 
                 LIST_INSERT_AFTER(partitions, context->partitions, last, p);
                 last = TAKE_PTR(p);
@@ -1928,16 +1945,17 @@ static int context_load_partition_table(
         assert(context->end == UINT64_MAX);
         assert(context->total == UINT64_MAX);
 
-        c = fdisk_new_context();
-        if (!c)
-                return log_oom();
-
         /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
          * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
-        if (*backing_fd < 0)
+        if (*backing_fd < 0) {
+                c = fdisk_new_context();
+                if (!c)
+                        return log_oom();
+
                 r = fdisk_assign_device(c, node, arg_dry_run);
-        else
-                r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(*backing_fd), arg_dry_run);
+        } else
+                r = fdisk_new_context_fd(*backing_fd, arg_dry_run, &c);
+
         if (r == -EINVAL && arg_size_auto) {
                 struct stat st;
 
@@ -2074,8 +2092,7 @@ static int context_load_partition_table(
                 _cleanup_free_ char *label_copy = NULL;
                 Partition *last = NULL;
                 struct fdisk_partition *p;
-                struct fdisk_parttype *pt;
-                const char *pts, *ids, *label;
+                const char *label;
                 uint64_t sz, start;
                 bool found = false;
                 sd_id128_t ptid, id;
@@ -2093,25 +2110,13 @@ static int context_load_partition_table(
                     fdisk_partition_has_partno(p) <= 0)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a position, size or number.");
 
-                pt = fdisk_partition_get_type(p);
-                if (!pt)
-                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition: %m");
-
-                pts = fdisk_parttype_get_string(pt);
-                if (!pts)
-                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition as string: %m");
-
-                r = sd_id128_from_string(pts, &ptid);
+                r = fdisk_partition_get_type_as_id128(p, &ptid);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse partition type UUID %s: %m", pts);
+                        return log_error_errno(r, "Failed to query partition type UUID: %m");
 
-                ids = fdisk_partition_get_uuid(p);
-                if (!ids)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a UUID.");
-
-                r = sd_id128_from_string(ids, &id);
+                r = fdisk_partition_get_uuid_as_id128(p, &id);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse partition UUID %s: %m", ids);
+                        return log_error_errno(r, "Failed to query partition UUID: %m");
 
                 label = fdisk_partition_get_name(p);
                 if (!isempty(label)) {
@@ -3019,6 +3024,36 @@ static PartitionTarget *partition_target_free(PartitionTarget *t) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(PartitionTarget*, partition_target_free);
 
+static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
+        _cleanup_(unlink_and_freep) char *temp = NULL;
+        _cleanup_close_ int fd = -1;
+        const char *vt;
+        int r;
+
+        assert(t);
+
+        r = var_tmp_dir(&vt);
+        if (r < 0)
+                return log_error_errno(r, "Could not determine temporary directory: %m");
+
+        temp = path_join(vt, "repart-XXXXXX");
+        if (!temp)
+                return log_oom();
+
+        fd = mkostemp_safe(temp);
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to create temporary file: %m");
+
+        if (ftruncate(fd, size) < 0)
+                return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
+                                        FORMAT_BYTES(size));
+
+        t->fd = TAKE_FD(fd);
+        t->path = TAKE_PTR(temp);
+
+        return 0;
+}
+
 static int partition_target_prepare(
                 Context *context,
                 Partition *p,
@@ -3027,9 +3062,8 @@ static int partition_target_prepare(
                 PartitionTarget **ret) {
 
         _cleanup_(partition_target_freep) PartitionTarget *t = NULL;
-        struct stat st;
-        int whole_fd;
-        int r;
+        _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+        int whole_fd, r;
 
         assert(context);
         assert(p);
@@ -3037,16 +3071,6 @@ static int partition_target_prepare(
 
         assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
 
-        if (fstat(whole_fd, &st) < 0)
-                return -errno;
-
-        /* If we're operating on a block device, we definitely need privileges to access block devices so we
-         * can just use loop devices as our target. Otherwise, we're operating on a regular file, in that
-         * case, let's write to regular files and copy those into the final image so we can run without root
-         * privileges. On filesystems with reflinking support, we can take advantage of this and just reflink
-         * the result into the image.
-         */
-
         t = new(PartitionTarget, 1);
         if (!t)
                 return log_oom();
@@ -3055,46 +3079,37 @@ static int partition_target_prepare(
                 .whole_fd = -1,
         };
 
-        if (S_ISBLK(st.st_mode) || (p->format && !mkfs_supports_root_option(p->format))) {
-                _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+        if (!need_path) {
+                if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
+                        return log_error_errno(errno, "Failed to seek to partition offset: %m");
 
-                /* Loopback block devices are not only useful to turn regular files into block devices, but
-                 * also to cut out sections of block devices into new block devices. */
+                t->whole_fd = whole_fd;
+                *ret = TAKE_PTR(t);
+                return 0;
+        }
 
-                r = loop_device_make(whole_fd, O_RDWR, p->offset, size, 0, 0, LOCK_EX, &d);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
+        /* Loopback block devices are not only useful to turn regular files into block devices, but
+         * also to cut out sections of block devices into new block devices. */
 
+        r = loop_device_make(whole_fd, O_RDWR, p->offset, size, 0, 0, LOCK_EX, &d);
+        if (r < 0 && r != -ENOENT && !ERRNO_IS_PRIVILEGE(r))
+                return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
+        if (r >= 0) {
                 t->loop = TAKE_PTR(d);
-        } else if (need_path) {
-                _cleanup_(unlink_and_freep) char *temp = NULL;
-                _cleanup_close_ int fd = -1;
-                const char *vt;
-
-                r = var_tmp_dir(&vt);
-                if (r < 0)
-                        return log_error_errno(r, "Could not determine temporary directory: %m");
-
-                temp = path_join(vt, "repart-XXXXXX");
-                if (!temp)
-                        return log_oom();
-
-                fd = mkostemp_safe(temp);
-                if (fd < 0)
-                        return log_error_errno(fd, "Failed to create temporary file: %m");
+                *ret = TAKE_PTR(t);
+                return 0;
+        }
 
-                if (ftruncate(fd, size) < 0)
-                        return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
-                                               FORMAT_BYTES(size));
+        /* If we can't allocate a loop device, let's write to a regular file that we copy into the final
+         * image so we can run in containers and without needing root privileges. On filesystems with
+         * reflinking support, we can take advantage of this and just reflink the result into the image.
+         */
 
-                t->fd = TAKE_FD(fd);
-                t->path = TAKE_PTR(temp);
-        } else {
-                if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
-                        return log_error_errno(errno, "Failed to seek to partition offset: %m");
+        log_debug_errno(r, "No access to loop devices, falling back to a regular file");
 
-                t->whole_fd = whole_fd;
-        }
+        r = prepare_temporary_file(t, size);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PTR(t);
 
@@ -3660,7 +3675,12 @@ static int context_copy_blocks(Context *context) {
         return 0;
 }
 
-static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
+static int do_copy_files(
+                Partition *p,
+                const char *root,
+                uid_t override_uid,
+                gid_t override_gid,
+                const Set *denylist) {
 
         int r;
 
@@ -3703,18 +3723,22 @@ static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
                                 if (pfd < 0)
                                         return log_error_errno(pfd, "Failed to open parent directory of target: %m");
 
+                                /* Make sure everything is owned by the user running repart so that
+                                 * make_filesystem() can map the user running repart to "root" in a user
+                                 * namespace to have the files owned by root in the final image. */
+
                                 r = copy_tree_at(
                                                 sfd, ".",
                                                 pfd, fn,
-                                                getuid(), getgid(),
-                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
+                                                override_uid, override_gid,
+                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
                                                 denylist);
                         } else
                                 r = copy_tree_at(
                                                 sfd, ".",
                                                 tfd, ".",
-                                                getuid(), getgid(),
-                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
+                                                override_uid, override_gid,
+                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
                                                 denylist);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
@@ -3751,6 +3775,9 @@ static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
 
+                        if (fchown(tfd, override_uid, override_gid) < 0)
+                                return log_error_errno(r, "Failed to change ownership of %s", *target);
+
                         (void) copy_xattr(sfd, tfd, COPY_ALL_XATTRS);
                         (void) copy_access(sfd, tfd);
                         (void) copy_times(sfd, tfd, 0);
@@ -3760,7 +3787,7 @@ static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
         return 0;
 }
 
-static int do_make_directories(Partition *p, const char *root) {
+static int do_make_directories(Partition *p, uid_t override_uid, gid_t override_gid, const char *root) {
         int r;
 
         assert(p);
@@ -3768,7 +3795,7 @@ static int do_make_directories(Partition *p, const char *root) {
 
         STRV_FOREACH(d, p->make_directories) {
 
-                r = mkdir_p_root(root, *d, getuid(), getgid(), 0755);
+                r = mkdir_p_root(root, *d, override_uid, override_gid, 0755);
                 if (r < 0)
                         return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
         }
@@ -3776,6 +3803,11 @@ static int do_make_directories(Partition *p, const char *root) {
         return 0;
 }
 
+static bool partition_needs_populate(Partition *p) {
+        assert(p);
+        return !strv_isempty(p->copy_files) || !strv_isempty(p->make_directories);
+}
+
 static int partition_populate_directory(Partition *p, const Set *denylist, char **ret) {
         _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
         _cleanup_close_ int rfd = -1;
@@ -3783,11 +3815,6 @@ static int partition_populate_directory(Partition *p, const Set *denylist, char
 
         assert(ret);
 
-        if (strv_isempty(p->copy_files) && strv_isempty(p->make_directories)) {
-                *ret = NULL;
-                return 0;
-        }
-
         rfd = mkdtemp_open("/var/tmp/repart-XXXXXX", 0, &root);
         if (rfd < 0)
                 return log_error_errno(rfd, "Failed to create temporary directory: %m");
@@ -3795,15 +3822,11 @@ static int partition_populate_directory(Partition *p, const Set *denylist, char
         if (fchmod(rfd, 0755) < 0)
                 return log_error_errno(errno, "Failed to change mode of temporary directory: %m");
 
-        /* Make sure everything is owned by the user running repart so that make_filesystem() can map the
-         * user running repart to "root" in a user namespace to have the files owned by root in the final
-         * image. */
-
-        r = do_copy_files(p, root, denylist);
+        r = do_copy_files(p, root, getuid(), getgid(), denylist);
         if (r < 0)
                 return r;
 
-        r = do_make_directories(p, root);
+        r = do_make_directories(p, getuid(), getgid(), root);
         if (r < 0)
                 return r;
 
@@ -3812,27 +3835,11 @@ static int partition_populate_directory(Partition *p, const Set *denylist, char
 }
 
 static int partition_populate_filesystem(Partition *p, const char *node, const Set *denylist) {
-        _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
-        struct stat st;
         int r;
 
         assert(p);
         assert(node);
 
-        if (strv_isempty(p->copy_files) && strv_isempty(p->make_directories))
-                return 0;
-
-        if (stat(node, &st) < 0)
-                return log_error_errno(errno, "Failed to stat %s: %m", node);
-
-        if (!S_ISBLK(st.st_mode)) {
-                r = loop_device_make_by_path(node, O_RDWR, 0, LOCK_EX, &d);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to make loopback device of %s: %m", node);
-
-                node = d->node;
-        }
-
         log_info("Populating %s filesystem with files.", p->format);
 
         /* We copy in a child process, since we have to mount the fs for that, and we don't want that fs to
@@ -3855,10 +3862,10 @@ static int partition_populate_filesystem(Partition *p, const char *node, const S
                 if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0)
                         _exit(EXIT_FAILURE);
 
-                if (do_copy_files(p, fs, denylist) < 0)
+                if (do_copy_files(p, fs, 0, 0, denylist) < 0)
                         _exit(EXIT_FAILURE);
 
-                if (do_make_directories(p, fs) < 0)
+                if (do_make_directories(p, 0, 0, fs) < 0)
                         _exit(EXIT_FAILURE);
 
                 r = syncfs_path(AT_FDCWD, fs);
@@ -3961,11 +3968,16 @@ static int context_mkfs(Context *context) {
 
                 log_info("Formatting future partition %" PRIu64 ".", p->partno);
 
-                /* We prefer (or are required in the case of read-only filesystems) to populate filesystems
-                 * directly via the corresponding mkfs binary if it supports a --rootdir (or equivalent)
-                 * option. To do that, we need to setup the final directory tree beforehand. */
+                /* If we're not writing to a loop device or if we're populating a read-only filesystem, we
+                 * have to populate using the filesystem's mkfs's --root (or equivalent) option. To do that,
+                 * we need to set up the final directory tree beforehand. */
+
+                if (partition_needs_populate(p) && (!t->loop || fstype_is_ro(p->format))) {
+                        if (!mkfs_supports_root_option(p->format))
+                                return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
+                                                        "Loop device access is required to populate %s filesystems.",
+                                                        p->format);
 
-                if (mkfs_supports_root_option(p->format)) {
                         r = partition_populate_directory(p, denylist, &root);
                         if (r < 0)
                                 return r;
@@ -3978,9 +3990,11 @@ static int context_mkfs(Context *context) {
 
                 log_info("Successfully formatted future partition %" PRIu64 ".", p->partno);
 
-                /* Now, we can populate all the other filesystems that we couldn't populate earlier. */
-                if (!mkfs_supports_root_option(p->format)) {
-                        r = partition_populate_filesystem(p, partition_target_path(t), denylist);
+                /* If we're writing to a loop device, we can now mount the empty filesystem and populate it. */
+                if (partition_needs_populate(p) && !root) {
+                        assert(t->loop);
+
+                        r = partition_populate_filesystem(p, t->loop->node, denylist);
                         if (r < 0)
                                 return r;
                 }
@@ -4826,12 +4840,14 @@ static int resolve_copy_blocks_auto_candidate(
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (IN_SET(r, -2, 1)) { /* nothing found or ambiguous result */
+        if (r == _BLKID_SAFEPROBE_ERROR)
+                return log_error_errno(errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p);
+        if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) {
                 log_debug("Didn't find partition table on block device '%s'.", p);
                 return false;
         }
-        if (r != 0)
-                return log_error_errno(errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p);
+
+        assert(r == _BLKID_SAFEPROBE_FOUND);
 
         (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
         if (!streq_ptr(pttype, "gpt")) {
@@ -4843,7 +4859,6 @@ static int resolve_copy_blocks_auto_candidate(
         pl = blkid_probe_get_partitions(b);
         if (!pl)
                 return log_error_errno(errno_or_else(EIO), "Unable read partition table of '%s': %m", p);
-        errno = 0;
 
         pp = blkid_partlist_devno_to_partition(pl, partition_devno);
         if (!pp) {
@@ -4872,21 +4887,18 @@ static int resolve_copy_blocks_auto_candidate(
                 return false;
         }
 
-        t = blkid_partition_get_uuid(pp);
-        if (isempty(t)) {
-                log_debug("Partition %u:%u has no UUID.",
-                          major(partition_devno), minor(partition_devno));
+        r = blkid_partition_get_uuid_id128(pp, &u);
+        if (r == -ENXIO) {
+                log_debug_errno(r, "Partition " DEVNUM_FORMAT_STR " has no UUID.", DEVNUM_FORMAT_VAL(partition_devno));
                 return false;
         }
-
-        r = sd_id128_from_string(t, &u);
         if (r < 0) {
-                log_debug_errno(r, "Failed to parse partition UUID \"%s\": %m", t);
+                log_debug_errno(r, "Failed to read partition UUID of " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(partition_devno));
                 return false;
         }
 
-        log_debug("Automatically found partition %u:%u of right type " SD_ID128_FORMAT_STR ".",
-                  major(partition_devno), minor(partition_devno),
+        log_debug("Automatically found partition " DEVNUM_FORMAT_STR " of right type " SD_ID128_FORMAT_STR ".",
+                  DEVNUM_FORMAT_VAL(partition_devno),
                   SD_ID128_FORMAT_VAL(pt_parsed));
 
         if (ret_uuid)
@@ -5225,6 +5237,7 @@ static int context_minimize(Context *context) {
         LIST_FOREACH(partitions, p, context->partitions) {
                 _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
                 _cleanup_(unlink_and_freep) char *temp = NULL;
+                _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
                 _cleanup_close_ int fd = -1;
                 sd_id128_t fs_uuid;
                 uint64_t fsz;
@@ -5241,6 +5254,9 @@ static int context_minimize(Context *context) {
                 if (!p->minimize)
                         continue;
 
+                if (!partition_needs_populate(p))
+                        continue;
+
                 assert(!p->copy_blocks_path);
 
                 r = tempfn_random_child(vt, "repart", &temp);
@@ -5255,11 +5271,15 @@ static int context_minimize(Context *context) {
                                 return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
 
                         /* This may seem huge but it will be created sparse so it doesn't take up any space
-                        * on disk until written to. */
+                         * on disk until written to. */
                         if (ftruncate(fd, 1024ULL * 1024ULL * 1024ULL * 1024ULL) < 0)
                                 return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
                                                        FORMAT_BYTES(1024ULL * 1024ULL * 1024ULL * 1024ULL));
 
+                        r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, 0, LOCK_EX, &d);
+                        if (r < 0 && r != -ENOENT && !ERRNO_IS_PRIVILEGE(r))
+                                return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
+
                         /* We're going to populate this filesystem twice so use a random UUID the first time
                          * to avoid UUID conflicts. */
                         r = sd_id128_randomize(&fs_uuid);
@@ -5267,13 +5287,18 @@ static int context_minimize(Context *context) {
                                 return r;
                 }
 
-                if (mkfs_supports_root_option(p->format)) {
+                if (!d || fstype_is_ro(p->format)) {
+                        if (!mkfs_supports_root_option(p->format))
+                                return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
+                                                       "Loop device access is required to populate %s filesystems",
+                                                       p->format);
+
                         r = partition_populate_directory(p, denylist, &root);
                         if (r < 0)
                                 return r;
                 }
 
-                r = make_filesystem(temp, p->format, strempty(p->new_label), root, fs_uuid, arg_discard);
+                r = make_filesystem(d ? d->node : temp, p->format, strempty(p->new_label), root, fs_uuid, arg_discard);
                 if (r < 0)
                         return r;
 
@@ -5284,8 +5309,10 @@ static int context_minimize(Context *context) {
                         continue;
                 }
 
-                if (!mkfs_supports_root_option(p->format)) {
-                        r = partition_populate_filesystem(p, temp, denylist);
+                if (!root) {
+                        assert(d);
+
+                        r = partition_populate_filesystem(p, d->node, denylist);
                         if (r < 0)
                                 return r;
                 }
@@ -5310,6 +5337,8 @@ static int context_minimize(Context *context) {
                 if (minimal_size_by_fs_name(p->format) != UINT64_MAX)
                         fsz = MAX(minimal_size_by_fs_name(p->format), fsz);
 
+                d = loop_device_unref(d);
+
                 /* Erase the previous filesystem first. */
                 if (ftruncate(fd, 0))
                         return log_error_errno(errno, "Failed to erase temporary file: %m");
@@ -5317,12 +5346,18 @@ static int context_minimize(Context *context) {
                 if (ftruncate(fd, fsz))
                         return log_error_errno(errno, "Failed to truncate temporary file to %s: %m", FORMAT_BYTES(fsz));
 
-                r = make_filesystem(temp, p->format, strempty(p->new_label), root, p->fs_uuid, arg_discard);
+                r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, 0, LOCK_EX, &d);
+                if (r < 0 && r != -ENOENT && !ERRNO_IS_PRIVILEGE(r))
+                        return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
+
+                r = make_filesystem(d ? d->node : temp, p->format, strempty(p->new_label), root, p->fs_uuid, arg_discard);
                 if (r < 0)
                         return r;
 
-                if (!mkfs_supports_root_option(p->format)) {
-                        r = partition_populate_filesystem(p, temp, denylist);
+                if (!root) {
+                        assert(d);
+
+                        r = partition_populate_filesystem(p, d->node, denylist);
                         if (r < 0)
                                 return r;
                 }
@@ -5333,9 +5368,12 @@ static int context_minimize(Context *context) {
         return 0;
 }
 
-static int parse_filter_partitions(const char *p) {
+static int parse_partition_types(const char *p, sd_id128_t **partitions, size_t *n_partitions) {
         int r;
 
+        assert(partitions);
+        assert(n_partitions);
+
         for (;;) {
                 _cleanup_free_ char *name = NULL;
                 GptPartitionType type;
@@ -5350,10 +5388,10 @@ static int parse_filter_partitions(const char *p) {
                 if (r < 0)
                         return log_error_errno(r, "'%s' is not a valid partition type identifier or GUID", name);
 
-                if (!GREEDY_REALLOC(arg_filter_partitions, arg_filter_partitions_size + 1))
+                if (!GREEDY_REALLOC(*partitions, *n_partitions + 1))
                         return log_oom();
 
-                arg_filter_partitions[arg_filter_partitions_size++] = type.uuid;
+                (*partitions)[(*n_partitions)++] = type.uuid;
         }
 
         return 0;
@@ -5402,9 +5440,12 @@ static int help(void) {
                "                          Generate JSON output\n"
                "     --split=BOOL         Whether to generate split artifacts\n"
                "     --include-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
-               "                          Only operate on partitions of the specified types\n"
+               "                          Ignore partitions not of the specified types\n"
                "     --exclude-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
-               "                          Don't operate on partitions of the specified types\n"
+               "                          Ignore partitions of the specified types\n"
+               "     --skip-partitions=PARTITION1,PARTITION2,PARTITION3,…\n"
+               "                          Take partitions of the specified types into account\n"
+               "                          but don't populate them yet\n"
                "\nSee the %s for details.\n",
                program_invocation_short_name,
                ansi_highlight(),
@@ -5442,6 +5483,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_SPLIT,
                 ARG_INCLUDE_PARTITIONS,
                 ARG_EXCLUDE_PARTITIONS,
+                ARG_SKIP_PARTITIONS,
         };
 
         static const struct option options[] = {
@@ -5471,6 +5513,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "split",                required_argument, NULL, ARG_SPLIT                },
                 { "include-partitions",   required_argument, NULL, ARG_INCLUDE_PARTITIONS   },
                 { "exclude-partitions",   required_argument, NULL, ARG_EXCLUDE_PARTITIONS   },
+                { "skip-partitions",      required_argument, NULL, ARG_SKIP_PARTITIONS      },
                 {}
         };
 
@@ -5730,7 +5773,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Combination of --include-partitions= and --exclude-partitions= is invalid.");
 
-                        r = parse_filter_partitions(optarg);
+                        r = parse_partition_types(optarg, &arg_filter_partitions, &arg_n_filter_partitions);
                         if (r < 0)
                                 return r;
 
@@ -5743,7 +5786,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Combination of --include-partitions= and --exclude-partitions= is invalid.");
 
-                        r = parse_filter_partitions(optarg);
+                        r = parse_partition_types(optarg, &arg_filter_partitions, &arg_n_filter_partitions);
                         if (r < 0)
                                 return r;
 
@@ -5751,6 +5794,13 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_SKIP_PARTITIONS:
+                        r = parse_partition_types(optarg, &arg_skip_partitions, &arg_n_skip_partitions);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -6033,11 +6083,7 @@ static int resize_pt(int fd) {
          * possession of the enlarged backing file. For this it suffices to open the device with libfdisk and
          * immediately write it again, with no changes. */
 
-        c = fdisk_new_context();
-        if (!c)
-                return log_oom();
-
-        r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), 0);
+        r = fdisk_new_context_fd(fd, /* read_only= */ false, &c);
         if (r < 0)
                 return log_error_errno(r, "Failed to open device '%s': %m", FORMAT_PROC_FD_PATH(fd));
 
@@ -6291,11 +6337,6 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
-        if (context->n_partitions <= 0 && arg_empty == EMPTY_REFUSE) {
-                log_info("Didn't find any partition definition files, nothing to do.");
-                return 0;
-        }
-
         r = find_root(&node, &backing_fd);
         if (r < 0)
                 return r;
index 76af743771ee5c05aca7378afc3792bb7fed6f35..0909e14aab664885853b6ba93c4540ac6e5b6651 100644 (file)
@@ -375,7 +375,9 @@ static int portable_extract_by_path(
                                 DISSECT_IMAGE_REQUIRE_ROOT |
                                 DISSECT_IMAGE_DISCARD_ON_LOOP |
                                 DISSECT_IMAGE_RELAX_VAR_CHECK |
-                                DISSECT_IMAGE_USR_NO_ROOT,
+                                DISSECT_IMAGE_USR_NO_ROOT |
+                                DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                                DISSECT_IMAGE_PIN_PARTITION_DEVICES,
                                 &m);
                 if (r == -ENOPKG)
                         sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
index f8e6582d5bf2dcc47dbf11f17596f5be37a6d1ce..6c3d5775077a07e8a1134397a5b23b8c1b4e960b 100644 (file)
@@ -114,7 +114,7 @@ static int compare_pstore_entries(const PStoreEntry *a, const PStoreEntry *b) {
         return strcmp(a->dirent.d_name, b->dirent.d_name);
 }
 
-static int move_file(PStoreEntry *pe, const char *subdir) {
+static int move_file(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
         _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
         _cleanup_free_ void *field = NULL;
         const char *suffix, *message;
@@ -128,7 +128,7 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
         if (!ifd_path)
                 return log_oom();
 
-        ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name);
+        ofd_path = path_join(arg_archivedir, subdir1, subdir2, pe->dirent.d_name);
         if (!ofd_path)
                 return log_oom();
 
@@ -171,153 +171,115 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
         return 0;
 }
 
-static int write_dmesg(const char *dmesg, size_t size, const char *id) {
-        _cleanup_(unlink_and_freep) char *tmp_path = NULL;
+static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
+        /* Append dmesg chunk to end, create if needed */
         _cleanup_free_ char *ofd_path = NULL;
         _cleanup_close_ int ofd = -1;
         ssize_t wr;
-        int r;
 
-        if (size == 0)
-                return 0;
+        assert(pe);
 
-        assert(dmesg);
+        if (pe->content_size == 0)
+                return 0;
 
-        ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
+        ofd_path = path_join(arg_archivedir, subdir1, subdir2, "dmesg.txt");
         if (!ofd_path)
                 return log_oom();
 
-        ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path);
+        ofd = open(ofd_path, O_CREAT|O_NOFOLLOW|O_NOCTTY|O_CLOEXEC|O_APPEND|O_WRONLY, 0640);
         if (ofd < 0)
-                return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path);
-        wr = write(ofd, dmesg, size);
+                return log_error_errno(ofd, "Failed to open file %s: %m", ofd_path);
+        wr = write(ofd, pe->content, pe->content_size);
         if (wr < 0)
                 return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path);
-        if (wr != (ssize_t)size)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr);
-        r = link_tmpfile(ofd, tmp_path, ofd_path);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
-        tmp_path = mfree(tmp_path);
+        if ((size_t)wr != pe->content_size)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, pe->content_size - wr);
 
         return 0;
 }
 
-static void process_dmesg_files(PStoreList *list) {
+static int process_dmesg_files(PStoreList *list) {
         /* Move files, reconstruct dmesg.txt */
-        _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
-        size_t dmesg_size = 0;
-        bool dmesg_bad = false;
-        PStoreEntry *pe;
+        _cleanup_free_ char *erst_subdir = NULL;
+        uint64_t last_record_id = 0;
+
+        /* When dmesg is written into pstore, it is done so in small chunks, whatever the exchange buffer
+         * size is with the underlying pstore backend (ie. EFI may be ~2KiB), which means an example
+         * pstore with approximately 64KB of storage may have up to roughly 32 dmesg files, some likely
+         * related.
+         *
+         * Here we look at the dmesg filename and try to discern if files are part of a related group,
+         * meaning the same original dmesg.
+         *
+         * The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER,
+         * record id, a 64-bit number.
+         *
+         * Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.*/
 
-        /* Handle each dmesg file: files processed in reverse
-         * order so as to properly reconstruct original dmesg */
         for (size_t n = list->n_entries; n > 0; n--) {
-                bool move_file_and_continue = false;
-                _cleanup_free_ char *pe_id = NULL;
+                PStoreEntry *pe;
                 char *p;
-                size_t plen;
 
                 pe = &list->entries[n-1];
 
                 if (pe->handled)
                         continue;
-                if (!startswith(pe->dirent.d_name, "dmesg-"))
-                        continue;
-
                 if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */
-                        move_file_and_continue = true;
-                p = strrchr(pe->dirent.d_name, '-');
-                if (!p)
-                        move_file_and_continue = true;
-
-                if (move_file_and_continue) {
-                        /* A dmesg file on which we do NO additional processing */
-                        (void) move_file(pe, NULL);
-                        continue;
-                }
-
-                /* See if this file is one of a related group of files
-                 * in order to reconstruct dmesg */
-
-                /* When dmesg is written into pstore, it is done so in
-                 * small chunks, whatever the exchange buffer size is
-                 * with the underlying pstore backend (ie. EFI may be
-                 * ~2KiB), which means an example pstore with approximately
-                 * 64KB of storage may have up to roughly 32 dmesg files
-                 * that could be related, depending upon the size of the
-                 * original dmesg.
-                 *
-                 * Here we look at the dmesg filename and try to discern
-                 * if files are part of a related group, meaning the same
-                 * original dmesg.
-                 *
-                 * The two known pstore backends are EFI and ERST. These
-                 * backends store data in the Common Platform Error
-                 * Record, CPER, format. The dmesg- filename contains the
-                 * CPER record id, a 64bit number (in decimal notation).
-                 * In Linux, the record id is encoded with two digits for
-                 * the dmesg part (chunk) number and 3 digits for the
-                 * count number. So allowing an additional digit to
-                 * compensate for advancing time, this code ignores the
-                 * last six digits of the filename in determining the
-                 * record id.
-                 *
-                 * For the EFI backend, the record id encodes an id in the
-                 * upper 32 bits, and a timestamp in the lower 32-bits.
-                 * So ignoring the least significant 6 digits has proven
-                 * to generally identify related dmesg entries.  */
-#define PSTORE_FILENAME_IGNORE 6
-
-                /* determine common portion of record id */
-                ++p; /* move beyond dmesg- */
-                plen = strlen(p);
-                if (plen > PSTORE_FILENAME_IGNORE) {
-                        pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE);
-                        if (!pe_id) {
-                                log_oom();
-                                return;
-                        }
-                } else
-                        pe_id = mfree(pe_id);
-
-                /* Now move file from pstore to archive storage */
-                move_file(pe, pe_id);
-
-                if (dmesg_bad)
                         continue;
-
-                /* If the current record id is NOT the same as the
-                 * previous record id, then start a new dmesg.txt file */
-                if (!streq_ptr(pe_id, dmesg_id)) {
-                        /* Encountered a new dmesg group, close out old one, open new one */
-                        (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
-                        dmesg_size = 0;
-
-                        /* now point dmesg_id to storage of pe_id */
-                        free_and_replace(dmesg_id, pe_id);
-                }
-
-                /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled
-                 * output either. */
-                size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1;
-                if (!GREEDY_REALLOC(dmesg, dmesg_size + needed)) {
-                        log_oom();
-                        dmesg_bad = true;
+                if (!startswith(pe->dirent.d_name, "dmesg-"))
                         continue;
-                }
-
-                dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name);
-                if (pe->content) {
-                        memcpy(dmesg + dmesg_size, pe->content, pe->content_size);
-                        dmesg_size += pe->content_size;
-                }
 
-                pe_id = mfree(pe_id);
+                if ((p = startswith(pe->dirent.d_name, "dmesg-efi-"))) {
+                        /* For the EFI backend, the 3 least significant digits of record id encodes a
+                         * "count" number, the next 2 least significant digits for the dmesg part
+                         * (chunk) number, and the remaining digits as the timestamp.  See
+                         * linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write(). */
+                        _cleanup_free_ char *subdir1 = NULL, *subdir2 = NULL;
+                        size_t plen = strlen(p);
+
+                        if (plen < 6)
+                                continue;
+
+                        /* Extract base record id */
+                        subdir1 = strndup(p, plen - 5);
+                        if (!subdir1)
+                                return log_oom();
+                        /* Extract "count" field */
+                        subdir2 = strndup(p + plen - 3, 3);
+                        if (!subdir2)
+                                return log_oom();
+
+                        /* Now move file from pstore to archive storage */
+                        (void) move_file(pe, subdir1, subdir2);
+
+                        /* Append to the dmesg */
+                        (void) append_dmesg(pe, subdir1, subdir2);
+                } else if ((p = startswith(pe->dirent.d_name, "dmesg-erst-"))) {
+                        /* For the ERST backend, the record is a monotonically increasing number, seeded as
+                         * a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer(). */
+                        uint64_t record_id;
+
+                        if (safe_atou64(p, &record_id) < 0)
+                                continue;
+                        if (last_record_id - 1 != record_id)
+                                /* A discontinuity in the number has been detected, this current record id
+                                 * will become the directory name for all pieces of the dmesg in this
+                                 * series. */
+                                if (free_and_strdup(&erst_subdir, p) < 0)
+                                        return log_oom();
+
+                        /* Now move file from pstore to archive storage */
+                        (void) move_file(pe, erst_subdir, NULL);
+
+                        /* Append to the dmesg */
+                        (void) append_dmesg(pe, erst_subdir, NULL);
+
+                        /* Update, but keep erst_subdir for next file */
+                        last_record_id = record_id;
+                } else
+                        log_debug("Unknown backend, ignoring \"%s\".", pe->dirent.d_name);
         }
-
-        if (!dmesg_bad)
-                (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+        return 0;
 }
 
 static int list_files(PStoreList *list, const char *sourcepath) {
@@ -393,11 +355,11 @@ static int run(int argc, char *argv[]) {
         typesafe_qsort(list.entries, list.n_entries, compare_pstore_entries);
 
         /* Process known file types */
-        process_dmesg_files(&list);
+        (void) process_dmesg_files(&list);
 
         /* Move left over files out of pstore */
         for (size_t n = 0; n < list.n_entries; n++)
-                move_file(&list.entries[n], NULL);
+                (void) move_file(&list.entries[n], NULL, NULL);
 
         return 0;
 }
diff --git a/src/resolve/fuzz-resource-record.c b/src/resolve/fuzz-resource-record.c
new file mode 100644 (file)
index 0000000..15c4659
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "fd-util.h"
+#include "fuzz.h"
+#include "memory-util.h"
+#include "resolved-dns-packet.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_free_ char *out = NULL; /* out should be freed after f */
+        size_t out_size;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *copy = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+        if (outside_size_range(size, 0, DNS_PACKET_SIZE_MAX))
+                return 0;
+
+        if (dns_resource_record_new_from_raw(&rr, data, size) < 0)
+                return 0;
+
+        assert_se(copy = dns_resource_record_copy(rr));
+        assert_se(dns_resource_record_equal(copy, rr) > 0);
+
+        assert_se(f = open_memstream_unlocked(&out, &out_size));
+        (void) fprintf(f, "%s", strna(dns_resource_record_to_string(rr)));
+
+        if (dns_resource_record_to_json(rr, &v) < 0)
+                return 0;
+
+        (void) json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, f, NULL);
+        (void) dns_resource_record_to_wire_format(rr, false);
+        (void) dns_resource_record_to_wire_format(rr, true);
+
+        return 0;
+}
index e11aefce7acb7418b2fed984ab926e5924a12d92..cd02c880396eea4cc612f9f43c264293f6bdfecd 100644 (file)
@@ -237,6 +237,11 @@ fuzzers += [
           libshared],
          [lib_openssl_or_gcrypt,
           libm]],
+        [files('fuzz-resource-record.c'),
+         [libsystemd_resolve_core,
+          libshared],
+         [lib_openssl_or_gcrypt,
+          libm]],
 ]
 
 systemd_resolved_sources += files('resolved.c')
index ff645fc0d704315e422067b110a6bfa46505702a..5889bd772f3c3e9b99de8a978493a0d83d6e2f81 100644 (file)
@@ -480,7 +480,11 @@ static bool single_label_nonsynthetic(const char *name) {
         if (!dns_name_is_single_label(name))
                 return false;
 
-        if (is_localhost(name) || is_gateway_hostname(name))
+        if (is_localhost(name) ||
+            is_gateway_hostname(name) ||
+            is_outbound_hostname(name) ||
+            is_dns_stub_hostname(name) ||
+            is_dns_proxy_stub_hostname(name))
                 return false;
 
         r = resolve_system_hostname(NULL, &first_label);
index 8123ca1f98ed28fafd7b2965bc106fa539545398..f4fa219ab7c241fa0a80bf59633b53826806d845 100644 (file)
@@ -1137,12 +1137,15 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
                 break;
 
         default:
-                t = hexmem(rr->generic.data, rr->generic.data_size);
-                if (!t)
-                        return NULL;
-
                 /* Format as documented in RFC 3597, Section 5 */
-                r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t);
+                if (rr->generic.data_size == 0)
+                        r = asprintf(&s, "%s \\# 0", k);
+                else {
+                        t = hexmem(rr->generic.data, rr->generic.data_size);
+                        if (!t)
+                                return NULL;
+                        r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t);
+                }
                 if (r < 0)
                         return NULL;
                 break;
@@ -1865,7 +1868,6 @@ static int type_bitmap_to_json(Bitmap *b, JsonVariant **ret) {
         unsigned t;
         int r;
 
-        assert(b);
         assert(ret);
 
         BITMAP_FOREACH(t, b) {
index b586d2c56f42210071d8f2ed99384f190633f31b..635763954be360677f451a156a388aa73d7225fd 100644 (file)
@@ -635,8 +635,11 @@ DnsScopeMatch dns_scope_good_domain(
         if (dns_name_dont_resolve(domain))
                 return DNS_SCOPE_NO;
 
-        /* Never go to network for the _gateway or _outbound domain — they're something special, synthesized locally. */
-        if (is_gateway_hostname(domain) || is_outbound_hostname(domain))
+        /* Never go to network for the _gateway, _outbound, _localdnsstub, _localdnsproxy domain — they're something special, synthesized locally. */
+        if (is_gateway_hostname(domain) ||
+            is_outbound_hostname(domain) ||
+            is_dns_stub_hostname(domain) ||
+            is_dns_proxy_stub_hostname(domain))
                 return DNS_SCOPE_NO;
 
         switch (s->protocol) {
@@ -687,7 +690,7 @@ DnsScopeMatch dns_scope_good_domain(
                 }
 
                 /* If there's a true search domain defined for this scope, and the query is single-label,
-                 * then let's resolve things here, prefereably. Note that LLMNR considers itself
+                 * then let's resolve things here, preferably. Note that LLMNR considers itself
                  * authoritative for single-label names too, at the same preference, see below. */
                 if (has_search_domains && dns_name_is_single_label(domain))
                         return DNS_SCOPE_YES_BASE + 1;
@@ -764,8 +767,6 @@ DnsScopeMatch dns_scope_good_domain(
                         return DNS_SCOPE_MAYBE;
 
                 if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
-                     !is_gateway_hostname(domain) && /* don't resolve "_gateway" with LLMNR, let local synthesizing logic handle that */
-                     !is_outbound_hostname(domain) && /* similar for "_outbound" */
                      dns_name_equal(domain, "local") == 0 && /* don't resolve "local" with LLMNR, it's the top-level domain of mDNS after all, see above */
                      manager_is_own_hostname(s->manager, domain) <= 0))  /* never resolve the local hostname via LLMNR */
                         return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
@@ -1116,7 +1117,7 @@ DnsTransaction *dns_scope_find_transaction(
                     !(t->query_flags & SD_RESOLVED_NO_CACHE))
                         continue;
 
-                /* If we are asked to clamp ttls an the existing transaction doesn't do it, we can't
+                /* If we are asked to clamp ttls and the existing transaction doesn't do it, we can't
                  * reuse */
                 if ((query_flags & SD_RESOLVED_CLAMP_TTL) &&
                     !(t->query_flags & SD_RESOLVED_CLAMP_TTL))
index b3442ad90674818f0f6f4410bb1870e525b7055e..51e06bb91ea0debd50730915687b1ec1de47f613 100644 (file)
@@ -7,20 +7,6 @@
 #include "missing_network.h"
 #include "resolved-dns-synthesize.h"
 
-int dns_synthesize_ifindex(int ifindex) {
-
-        /* When the caller asked for resolving on a specific
-         * interface, we synthesize the answer for that
-         * interface. However, if nothing specific was claimed and we
-         * only return localhost RRs, we synthesize the answer for
-         * localhost. */
-
-        if (ifindex > 0)
-                return ifindex;
-
-        return LOOPBACK_IFINDEX;
-}
-
 int dns_synthesize_family(uint64_t flags) {
 
         /* Picks an address family depending on set flags. This is
@@ -57,7 +43,7 @@ DnsProtocol dns_synthesize_protocol(uint64_t flags) {
         return DNS_PROTOCOL_DNS;
 }
 
-static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
+static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, DnsAnswer **answer) {
         int r;
 
         assert(m);
@@ -77,7 +63,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
 
                 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
 
-                r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
+                r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
                 if (r < 0)
                         return r;
         }
@@ -91,7 +77,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
 
                 rr->aaaa.in6_addr = in6addr_loopback;
 
-                r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
+                r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
                 if (r < 0)
                         return r;
         }
@@ -113,7 +99,7 @@ static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to,
         return dns_answer_add(*answer, rr, ifindex, flags, NULL);
 }
 
-static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
+static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, DnsAnswer **answer) {
         int r;
 
         assert(m);
@@ -125,7 +111,7 @@ static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int i
                 if (r < 0)
                         return r;
 
-                r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+                r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
                 if (r < 0)
                         return r;
         }
@@ -225,20 +211,19 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
                 if (n == 0) {
                         struct local_address buffer[2];
 
-                        /* If we have no local addresses then use ::1
-                         * and 127.0.0.2 as local ones. */
+                        /* If we have no local addresses then use ::1 and 127.0.0.2 as local ones. */
 
                         if (IN_SET(af, AF_INET, AF_UNSPEC))
                                 buffer[n++] = (struct local_address) {
                                         .family = AF_INET,
-                                        .ifindex = dns_synthesize_ifindex(ifindex),
-                                        .address.in.s_addr = htobe32(0x7F000002),
+                                        .ifindex = LOOPBACK_IFINDEX,
+                                        .address.in.s_addr = htobe32(INADDR_LOCALADDRESS),
                                 };
 
                         if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled())
                                 buffer[n++] = (struct local_address) {
                                         .family = AF_INET6,
-                                        .ifindex = dns_synthesize_ifindex(ifindex),
+                                        .ifindex = LOOPBACK_IFINDEX,
                                         .address.in6 = in6addr_loopback,
                                 };
 
@@ -260,7 +245,7 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
         assert(address);
         assert(answer);
 
-        if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
+        if (af == AF_INET && address->in.s_addr == htobe32(INADDR_LOCALADDRESS)) {
 
                 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
 
@@ -268,19 +253,19 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
                 if (r < 0)
                         return r;
 
-                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
                 if (r < 0)
                         return r;
 
-                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
                 if (r < 0)
                         return r;
 
-                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
                 if (r < 0)
                         return r;
 
-                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+                r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
                 if (r < 0)
                         return r;
 
@@ -356,7 +341,90 @@ static int synthesize_gateway_rr(
         return 1; /* > 0 means: we have some gateway */
 }
 
-static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
+static int synthesize_dns_stub_rr(
+                Manager *m,
+                const DnsResourceKey *key,
+                in_addr_t addr,
+                DnsAnswer **answer) {
+
+        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+        int r;
+
+        assert(m);
+        assert(key);
+        assert(answer);
+
+        if (!IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY))
+                return 1; /* we still consider ourselves the owner of this name */
+
+        r = dns_answer_reserve(answer, 1);
+        if (r < 0)
+                return r;
+
+        rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
+        if (!rr)
+                return -ENOMEM;
+
+        rr->a.in_addr.s_addr = htobe32(addr);
+
+        r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int synthesize_dns_stub_ptr(
+                Manager *m,
+                int af,
+                const union in_addr_union *address,
+                DnsAnswer **answer) {
+
+        int r;
+
+        assert(m);
+        assert(address);
+        assert(answer);
+
+        if (af != AF_INET)
+                return 0;
+
+        if (address->in.s_addr == htobe32(INADDR_DNS_STUB)) {
+
+                r = dns_answer_reserve(answer, 1);
+                if (r < 0)
+                        return r;
+
+                r = answer_add_ptr(answer, "53.0.0.127.in-addr.arpa", "_localdnsstub", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        if (address->in.s_addr == htobe32(INADDR_DNS_PROXY_STUB)) {
+
+                r = dns_answer_reserve(answer, 1);
+                if (r < 0)
+                        return r;
+
+                r = answer_add_ptr(answer, "54.0.0.127.in-addr.arpa", "_localdnsproxy", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        return 0;
+}
+
+static int synthesize_gateway_ptr(
+                Manager *m,
+                int af,
+                const union in_addr_union *address,
+                int ifindex,
+                DnsAnswer **answer) {
+
         _cleanup_free_ struct local_address *addresses = NULL;
         int n;
 
@@ -405,7 +473,7 @@ int dns_synthesize_answer(
 
                 } else if (is_localhost(name)) {
 
-                        r = synthesize_localhost_rr(m, key, ifindex, &answer);
+                        r = synthesize_localhost_rr(m, key, &answer);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
 
@@ -437,15 +505,30 @@ int dns_synthesize_answer(
                                 continue;
                         }
 
-                } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
+                } else if (is_dns_stub_hostname(name)) {
+
+                        r = synthesize_dns_stub_rr(m, key, INADDR_DNS_STUB, &answer);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to synthesize local DNS stub RRs: %m");
+
+                } else if (is_dns_proxy_stub_hostname(name)) {
+
+                        r = synthesize_dns_stub_rr(m, key, INADDR_DNS_PROXY_STUB, &answer);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to synthesize local DNS stub RRs: %m");
+
+                } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 &&
+                            dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0 &&
+                            dns_name_equal(name, "53.0.0.127.in-addr.arpa") == 0 &&
+                            dns_name_equal(name, "54.0.0.127.in-addr.arpa") == 0) ||
                            dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
 
-                        r = synthesize_localhost_ptr(m, key, ifindex, &answer);
+                        r = synthesize_localhost_ptr(m, key, &answer);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
 
                 } else if (dns_name_address(name, &af, &address) > 0) {
-                        int v, w;
+                        int v, w, u;
 
                         if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
                                 continue;
@@ -458,7 +541,11 @@ int dns_synthesize_answer(
                         if (w < 0)
                                 return log_error_errno(w, "Failed to synthesize gateway hostname PTR RR: %m");
 
-                        if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
+                        u = synthesize_dns_stub_ptr(m, af, &address, &answer);
+                        if (u < 0)
+                                return log_error_errno(u, "Failed to synthesize local stub hostname PTR PR: %m");
+
+                        if (v == 0 && w == 0 && u == 0) /* This IP address is neither a local one, nor a gateway, nor a stub address */
                                 continue;
 
                         /* Note that we never synthesize reverse PTR for _outbound, since those are local
index fb624589d75f5afe689edadf681603fc0f558427..bf271e862d54decfcdf7de57f0c3062a19d332fe 100644 (file)
@@ -5,7 +5,6 @@
 #include "resolved-dns-question.h"
 #include "resolved-manager.h"
 
-int dns_synthesize_ifindex(int ifindex);
 int dns_synthesize_family(uint64_t flags);
 DnsProtocol dns_synthesize_protocol(uint64_t flags);
 
index ab8cdc0ff96db92e08ddc6bc3d9617e69d305405..b35d952fab0d3d0c5a7107c07f28e47cbcd8c492 100755 (executable)
@@ -19,21 +19,21 @@ case "$command" in
 
     remove-system-units)
         if [ -d /run/systemd/system ]; then
-            systemctl --no-reload disable --now "$@"
+            systemctl --no-reload disable --now --no-warn "$@"
         else
-            systemctl --no-reload disable "$@"
+            systemctl --no-reload disable --no-warn "$@"
         fi
         ;;
 
     remove-user-units)
-        systemctl --global disable "$@"
+        systemctl --global disable --no-warn "$@"
 
         [ -d /run/systemd/system ] || exit 0
 
         users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
         for user in $users; do
             SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
-                    systemctl --user -M "$user@" disable --now "$@" &
+                    systemctl --user -M "$user@" disable --now --no-warn "$@" &
         done
         wait
         ;;
index c6c673984d20672f094539d84063089794757f97..b734ee1e0c97f1d7095fe0ce3e2db6dc51884812 100644 (file)
@@ -90,6 +90,7 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
         _cleanup_(acl_freep) acl_t basic = NULL;
 
         assert(acl_p);
+        assert(path);
 
         for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
              r > 0;
@@ -208,12 +209,16 @@ int acl_search_groups(const char *path, char ***ret_groups) {
         return ret;
 }
 
-int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
+int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, bool want_mask) {
         _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not freed */
         _cleanup_strv_free_ char **split = NULL;
         int r = -EINVAL;
         _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL;
 
+        assert(text);
+        assert(ret_acl_access);
+        assert(ret_acl_default);
+
         split = strv_split(text, ",");
         if (!split)
                 return -ENOMEM;
@@ -266,8 +271,8 @@ int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want
                 }
         }
 
-        *acl_access = TAKE_PTR(a_acl);
-        *acl_default = TAKE_PTR(d_acl);
+        *ret_acl_access = TAKE_PTR(a_acl);
+        *ret_acl_default = TAKE_PTR(d_acl);
 
         return 0;
 }
@@ -322,7 +327,7 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) {
         }
 }
 
-static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) {
+static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *ret) {
         acl_entry_t i;
         int r;
 
@@ -334,36 +339,40 @@ static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) {
                 if (r < 0)
                         return r;
                 if (r > 0) {
-                        *out = i;
-                        return 1;
+                        if (ret)
+                                *ret = i;
+                        return 0;
                 }
         }
         if (r < 0)
                 return -errno;
-        return 0;
+
+        return -ENOENT;
 }
 
-int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
-        _cleanup_(acl_freep) acl_t old;
+int acls_for_file(const char *path, acl_type_t type, acl_t acl, acl_t *ret) {
+        _cleanup_(acl_freep) acl_t applied = NULL;
         acl_entry_t i;
         int r;
 
-        old = acl_get_file(path, type);
-        if (!old)
+        assert(path);
+
+        applied = acl_get_file(path, type);
+        if (!applied)
                 return -errno;
 
-        for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
+        for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
              r > 0;
-             r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
+             r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
 
                 acl_entry_t j;
 
-                r = find_acl_entry(old, i, &j);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        if (acl_create_entry(&old, &j) < 0)
+                r = find_acl_entry(applied, i, &j);
+                if (r == -ENOENT) {
+                        if (acl_create_entry(&applied, &j) < 0)
                                 return -errno;
+                } else if (r < 0)
+                        return r;
 
                 if (acl_copy_entry(j, i) < 0)
                         return -errno;
@@ -371,7 +380,8 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
         if (r < 0)
                 return -errno;
 
-        *acl = TAKE_PTR(old);
+        if (ret)
+                *ret = TAKE_PTR(applied);
 
         return 0;
 }
index 03595c665152ba5e6936a13be08ef752af7c8cde..d3a341fbe612f4062f5d8750e92fb2f40c106905 100644 (file)
@@ -15,8 +15,8 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry);
 int calc_acl_mask_if_needed(acl_t *acl_p);
 int add_base_acls_if_needed(acl_t *acl_p, const char *path);
 int acl_search_groups(const char* path, char ***ret_groups);
-int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask);
-int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);
+int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, bool want_mask);
+int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *ret);
 int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask);
 
 /* acl_free takes multiple argument types.
index aa444990fd8b4b83ef6ccc8cff94824cd46fd870..abc4b6166d3886080129a849fe0b58dced0f4844 100644 (file)
@@ -4,7 +4,44 @@
 #if HAVE_BLKID
 #  include <blkid.h>
 
+#  include "sd-id128.h"
+
 #  include "macro.h"
+#  include "string-util.h"
 
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(blkid_probe, blkid_free_probe, NULL);
+
+static inline int blkid_partition_get_uuid_id128(blkid_partition p, sd_id128_t *ret) {
+        const char *s;
+
+        assert(p);
+
+        s = blkid_partition_get_uuid(p);
+        if (isempty(s))
+                return -ENXIO;
+
+        return sd_id128_from_string(s, ret);
+}
+
+static inline int blkid_partition_get_type_id128(blkid_partition p, sd_id128_t *ret) {
+        const char *s;
+
+        assert(p);
+
+        s = blkid_partition_get_type_string(p);
+        if (isempty(s))
+                return -ENXIO;
+
+        return sd_id128_from_string(s, ret);
+}
+
+/* Define symbolic names for blkid_do_safeprobe() return values, since blkid only uses literal numbers. We
+ * prefix these symbolic definitions with underscores, to not invade libblkid's namespace needlessly. */
+enum {
+        _BLKID_SAFEPROBE_FOUND     =  0,
+        _BLKID_SAFEPROBE_NOT_FOUND =  1,
+        _BLKID_SAFEPROBE_AMBIGUOUS = -2,
+        _BLKID_SAFEPROBE_ERROR     = -1,
+};
+
 #endif
index 72fad160edf39d6c9655135451d3eae49c785a63..eb9f54306f60fd63370a617d337239112999b9f5 100644 (file)
@@ -43,23 +43,7 @@ static int fd_get_devnum(int fd, BlockDeviceLookupFlag flags, dev_t *ret) {
                 /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
                  * handing, to get the backing device node. */
 
-                r = fcntl(fd, F_GETFL);
-                if (r < 0)
-                        return -errno;
-
-                if (FLAGS_SET(r, O_PATH)) {
-                        _cleanup_close_ int regfd = -1;
-
-                        /* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot.
-                         * Hence acquire a "real" fd first, without the O_PATH flag. */
-
-                        regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-                        if (regfd < 0)
-                                return regfd;
-
-                        r = btrfs_get_block_device_fd(regfd, &devnum);
-                } else
-                        r = btrfs_get_block_device_fd(fd, &devnum);
+                r = btrfs_get_block_device_fd(fd, &devnum);
                 if (r == -ENOTTY) /* not btrfs */
                         return -ENOTBLK;
                 if (r < 0)
@@ -288,21 +272,7 @@ int get_block_device_fd(int fd, dev_t *ret) {
                 return 1;
         }
 
-        r = fcntl(fd, F_GETFL);
-        if (r < 0)
-                return -errno;
-        if (FLAGS_SET(r, O_PATH) && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
-                _cleanup_close_ int real_fd = -1;
-
-                /* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. Hence
-                 * acquire a "real" fd first, without the O_PATH flag. */
-
-                real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC);
-                if (real_fd < 0)
-                        return real_fd;
-                r = btrfs_get_block_device_fd(real_fd, ret);
-        } else
-                r = btrfs_get_block_device_fd(fd, ret);
+        r = btrfs_get_block_device_fd(fd, ret);
         if (r > 0)
                 return 1;
         if (r != -ENOTTY) /* not btrfs */
index 789b89ea9302a73300ca9b83ba7b5c0e0ba1eaf9..83960b99d3fdd3c1f676bd8cb62d0ab9755b2887 100644 (file)
@@ -980,6 +980,8 @@ static int boot_config_find(const BootConfig *config, const char *id) {
         if (id[0] == '@') {
                 if (!strcaseeq(id, "@saved"))
                         return -1;
+                if (!config->entry_selected)
+                        return -1;
                 id = config->entry_selected;
         }
 
@@ -1268,7 +1270,7 @@ static void boot_entry_file_list(
         int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
 
         /* Note that this shows two '/' between the root and the file. This is intentional to highlight (in
-         * the abscence of color support) to the user that the boot loader is only interested in the second
+         * the absence of color support) to the user that the boot loader is only interested in the second
          * part of the file. */
         printf("%13s%s %s%s/%s", strempty(field), field ? ":" : " ", ansi_grey(), root, ansi_normal());
 
index 4574a7899e1cfd3eaa67240ac9f62201c5af8707..ba02de17f8523876c54e790ba59393f4f025e276 100644 (file)
@@ -107,19 +107,11 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume) {
         if (r < 0)
                 return r;
 
-        r = fcntl(fd, F_GETFL);
-        if (r < 0)
-                return -errno;
-        if (FLAGS_SET(r, O_PATH)) {
-                /* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
-                 * O_PATH. */
-
-                real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
-                if (real_fd < 0)
-                        return real_fd;
-
-                fd = real_fd;
-        }
+        /* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
+         * with O_PATH. */
+        fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
+        if (fd < 0)
+                return fd;
 
         strncpy(args.name, subvolume, sizeof(args.name)-1);
 
@@ -255,12 +247,17 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs
 
 int btrfs_get_block_device_fd(int fd, dev_t *dev) {
         struct btrfs_ioctl_fs_info_args fsi = {};
+        _cleanup_close_ int regfd = -1;
         uint64_t id;
         int r;
 
         assert(fd >= 0);
         assert(dev);
 
+        fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, O_PATH, &regfd);
+        if (fd < 0)
+                return fd;
+
         r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
         if (r < 0)
                 return r;
@@ -1768,6 +1765,7 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
 
 int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
         _cleanup_free_ uint64_t *qgroups = NULL;
+        _cleanup_close_ int real_fd = -1;
         uint64_t parent_subvol;
         bool changed = false;
         int n = 0, r;
@@ -1811,6 +1809,11 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed
          * qgroup that then includes all its own child subvolumes.
          */
 
+        /* Turn this into a proper fd, if it is currently O_PATH */
+        fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC, O_PATH, &real_fd);
+        if (fd < 0)
+                return fd;
+
         if (subvol_id == 0) {
                 r = btrfs_is_subvol_fd(fd);
                 if (r < 0)
index 784ae7794dce7bd7450fb4dd3b5a4f6df7952c88..6b6383b60b780b61da00203981db0f917a8953da 100644 (file)
@@ -2143,6 +2143,9 @@ static int bus_append_scope_property(sd_bus_message *m, const char *field, const
         if (STR_IN_SET(field, "User", "Group"))
                 return bus_append_string(m, field, eq);
 
+        if (streq(field, "OOMPolicy"))
+                return bus_append_string(m, field, eq);
+
         return 0;
 }
 
index 2b492c38a5af63a2fba1453a2b86b84dd260f7fa..e6265e2c9663f6ce7502483dc1d321629e89c21c 100644 (file)
@@ -486,11 +486,17 @@ static int fd_copy_symlink(
                 if (r < 0)
                         return r;
         }
-        r = symlinkat(target, dt, to);
+        r = RET_NERRNO(symlinkat(target, dt, to));
         if (copy_flags & COPY_MAC_CREATE)
                 mac_selinux_create_file_clear();
-        if (r < 0)
-                return -errno;
+        if (r < 0) {
+                if (FLAGS_SET(copy_flags, COPY_GRACEFUL_WARN) && (ERRNO_IS_PRIVILEGE(r) || ERRNO_IS_NOT_SUPPORTED(r))) {
+                        log_notice_errno(r, "Failed to copy symlink '%s', ignoring: %m", from);
+                        return 0;
+                }
+
+                return r;
+        }
 
         if (fchownat(dt, to,
                      uid_is_valid(override_uid) ? override_uid : st->st_uid,
@@ -798,11 +804,17 @@ static int fd_copy_fifo(
                 if (r < 0)
                         return r;
         }
-        r = mkfifoat(dt, to, st->st_mode & 07777);
+        r = RET_NERRNO(mkfifoat(dt, to, st->st_mode & 07777));
         if (copy_flags & COPY_MAC_CREATE)
                 mac_selinux_create_file_clear();
-        if (r < 0)
-                return -errno;
+        if (r < 0) {
+                if (FLAGS_SET(copy_flags, COPY_GRACEFUL_WARN) && (ERRNO_IS_PRIVILEGE(r) || ERRNO_IS_NOT_SUPPORTED(r))) {
+                        log_notice_errno(r, "Failed to copy fifo '%s', ignoring: %m", from);
+                        return 0;
+                }
+
+                return r;
+        }
 
         if (fchownat(dt, to,
                      uid_is_valid(override_uid) ? override_uid : st->st_uid,
@@ -846,11 +858,17 @@ static int fd_copy_node(
                 if (r < 0)
                         return r;
         }
-        r = mknodat(dt, to, st->st_mode, st->st_rdev);
+        r = RET_NERRNO(mknodat(dt, to, st->st_mode, st->st_rdev));
         if (copy_flags & COPY_MAC_CREATE)
                 mac_selinux_create_file_clear();
-        if (r < 0)
-                return -errno;
+        if (r < 0) {
+                if (FLAGS_SET(copy_flags, COPY_GRACEFUL_WARN) && (ERRNO_IS_PRIVILEGE(r) || ERRNO_IS_NOT_SUPPORTED(r))) {
+                        log_notice_errno(r, "Failed to copy node '%s', ignoring: %m", from);
+                        return 0;
+                }
+
+                return r;
+        }
 
         if (fchownat(dt, to,
                      uid_is_valid(override_uid) ? override_uid : st->st_uid,
index d19361c9a29352ae5cc4517cc7ed9d38ce06324b..1eb6d1ce0532e041cc66f617d5d6468f82e180f2 100644 (file)
 #include "set.h"
 
 typedef enum CopyFlags {
-        COPY_REFLINK     = 1 << 0,  /* Try to reflink */
-        COPY_MERGE       = 1 << 1,  /* Merge existing trees with our new one to copy */
-        COPY_REPLACE     = 1 << 2,  /* Replace an existing file if there's one */
-        COPY_SAME_MOUNT  = 1 << 3,  /* Don't descend recursively into other file systems, across mount point boundaries */
-        COPY_MERGE_EMPTY = 1 << 4,  /* Merge an existing, empty directory with our new tree to copy */
-        COPY_CRTIME      = 1 << 5,  /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
-        COPY_SIGINT      = 1 << 6,  /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
-        COPY_SIGTERM     = 1 << 7,  /* ditto, but for SIGTERM */
-        COPY_MAC_CREATE  = 1 << 8,  /* Create files with the correct MAC label (currently SELinux only) */
-        COPY_HARDLINKS   = 1 << 9,  /* Try to reproduce hard links */
-        COPY_FSYNC       = 1 << 10, /* fsync() after we are done */
-        COPY_FSYNC_FULL  = 1 << 11, /* fsync_full() after we are done */
-        COPY_SYNCFS      = 1 << 12, /* syncfs() the *top-level* dir after we are done */
-        COPY_ALL_XATTRS  = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
-        COPY_HOLES       = 1 << 14, /* Copy holes */
+        COPY_REFLINK       = 1 << 0,  /* Try to reflink */
+        COPY_MERGE         = 1 << 1,  /* Merge existing trees with our new one to copy */
+        COPY_REPLACE       = 1 << 2,  /* Replace an existing file if there's one */
+        COPY_SAME_MOUNT    = 1 << 3,  /* Don't descend recursively into other file systems, across mount point boundaries */
+        COPY_MERGE_EMPTY   = 1 << 4,  /* Merge an existing, empty directory with our new tree to copy */
+        COPY_CRTIME        = 1 << 5,  /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
+        COPY_SIGINT        = 1 << 6,  /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
+        COPY_SIGTERM       = 1 << 7,  /* ditto, but for SIGTERM */
+        COPY_MAC_CREATE    = 1 << 8,  /* Create files with the correct MAC label (currently SELinux only) */
+        COPY_HARDLINKS     = 1 << 9,  /* Try to reproduce hard links */
+        COPY_FSYNC         = 1 << 10, /* fsync() after we are done */
+        COPY_FSYNC_FULL    = 1 << 11, /* fsync_full() after we are done */
+        COPY_SYNCFS        = 1 << 12, /* syncfs() the *top-level* dir after we are done */
+        COPY_ALL_XATTRS    = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
+        COPY_HOLES         = 1 << 14, /* Copy holes */
+        COPY_GRACEFUL_WARN = 1 << 15, /* Skip copying file types that aren't supported by the target filesystem */
 } CopyFlags;
 
 typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
index f697429852a8703d8b6f34c4baf3098c5b55560b..c6614d35796e91c67c745c6e4cf0abaa6fd62a2c 100644 (file)
@@ -208,7 +208,7 @@ int dlopen_cryptsetup(void) {
         /* libcryptsetup added crypt_reencrypt() in 2.2.0, and marked it obsolete in 2.4.0, replacing it with
          * crypt_reencrypt_run(), which takes one extra argument but is otherwise identical. The old call is
          * still available though, and given we want to support 2.2.0 for a while longer, we'll stick to the
-         * old symbol. Howerver, the old symbols now has a GCC deprecation decorator, hence let's turn off
+         * old symbol. However, the old symbols now has a GCC deprecation decorator, hence let's turn off
          * warnings about this for now. */
 
         DISABLE_WARNING_DEPRECATED_DECLARATIONS;
index 073e5e84338d50f0881bc4ad992e0774720c234d..9a7a1c990a74b6b1b4d9c5b072f639c00db61b05 100644 (file)
@@ -1201,7 +1201,9 @@ int image_read_metadata(Image *i) {
                                 DISSECT_IMAGE_REQUIRE_ROOT |
                                 DISSECT_IMAGE_RELAX_VAR_CHECK |
                                 DISSECT_IMAGE_READ_ONLY |
-                                DISSECT_IMAGE_USR_NO_ROOT,
+                                DISSECT_IMAGE_USR_NO_ROOT |
+                                DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                                DISSECT_IMAGE_PIN_PARTITION_DEVICES,
                                 &m);
                 if (r < 0)
                         return r;
index 53682b254206ad67a1229e4bbd158a60e9fbd21b..b3d35e9fbf34c6545160a80b4fbf80b2640c3f4d 100644 (file)
 /* how many times to wait for the device nodes to appear */
 #define N_DEVICE_NODE_LIST_ATTEMPTS 10
 
-int probe_filesystem_full(int fd, const char *path, char **ret_fstype) {
+int probe_filesystem_full(
+                int fd,
+                const char *path,
+                uint64_t offset,
+                uint64_t size,
+                char **ret_fstype) {
+
         /* Try to find device content type and return it in *ret_fstype. If nothing is found,
-         * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an
+         * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and a
          * different error otherwise. */
 
 #if HAVE_BLKID
@@ -105,12 +111,19 @@ int probe_filesystem_full(int fd, const char *path, char **ret_fstype) {
                 path = path_by_fd;
         }
 
+        if (size == 0) /* empty size? nothing found! */
+                goto not_found;
+
         b = blkid_new_probe();
         if (!b)
                 return -ENOMEM;
 
         errno = 0;
-        r = blkid_probe_set_device(b, fd, 0, 0);
+        r = blkid_probe_set_device(
+                        b,
+                        fd,
+                        offset,
+                        size == UINT64_MAX ? 0 : size); /* when blkid sees size=0 it understands "everything". We prefer using UINT64_MAX for that */
         if (r != 0)
                 return errno_or_else(ENOMEM);
 
@@ -119,14 +132,16 @@ int probe_filesystem_full(int fd, const char *path, char **ret_fstype) {
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (r == 1)
+        if (r == _BLKID_SAFEPROBE_NOT_FOUND)
                 goto not_found;
-        if (r == -2)
+        if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
                 return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
                                        "Results ambiguous for partition %s", path);
-        if (r != 0)
+        if (r == _BLKID_SAFEPROBE_ERROR)
                 return log_debug_errno(errno_or_else(EIO), "Failed to probe partition %s: %m", path);
 
+        assert(r == _BLKID_SAFEPROBE_FOUND);
+
         (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
 
         if (fstype) {
@@ -152,7 +167,7 @@ not_found:
 }
 
 #if HAVE_BLKID
-static int dissected_image_probe_filesystem(DissectedImage *m) {
+static int dissected_image_probe_filesystems(DissectedImage *m, int fd) {
         int r;
 
         assert(m);
@@ -165,9 +180,14 @@ static int dissected_image_probe_filesystem(DissectedImage *m) {
                 if (!p->found)
                         continue;
 
-                if (!p->fstype && p->mount_node_fd >= 0 && !p->decrypted_node) {
-                        r = probe_filesystem_full(p->mount_node_fd, p->node, &p->fstype);
-                        if (r < 0 && r != -EUCLEAN)
+                if (!p->fstype) {
+                        /* If we have an fd referring to the partition block device, use that. Otherwise go
+                         * via the whole block device or backing regular file, and read via offset. */
+                        if (p->mount_node_fd >= 0)
+                                r = probe_filesystem_full(p->mount_node_fd, p->node, 0, UINT64_MAX, &p->fstype);
+                        else
+                                r = probe_filesystem_full(fd, p->node, p->offset, p->size, &p->fstype);
+                        if (r < 0)
                                 return r;
                 }
 
@@ -439,10 +459,12 @@ static int dissect_image(
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (IN_SET(r, -2, 1))
-                return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to identify any partition table.");
-        if (r != 0)
+        if (r == _BLKID_SAFEPROBE_ERROR)
                 return errno_or_else(EIO);
+        if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to identify any partition table.");
+
+        assert(r == _BLKID_SAFEPROBE_FOUND);
 
         if ((!(flags & DISSECT_IMAGE_GPT_ONLY) &&
             (flags & DISSECT_IMAGE_GENERIC_ROOT)) ||
@@ -458,7 +480,7 @@ static int dissect_image(
                         _cleanup_close_ int mount_node_fd = -1;
                         sd_id128_t uuid = SD_ID128_NULL;
 
-                        if (FLAGS_SET(flags, DISSECT_IMAGE_OPEN_PARTITION_DEVICES)) {
+                        if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) {
                                 mount_node_fd = open_partition(devname, /* is_partition = */ false, m->loop);
                                 if (mount_node_fd < 0)
                                         return mount_node_fd;
@@ -491,13 +513,10 @@ static int dissect_image(
                         m->encrypted = streq_ptr(fstype, "crypto_LUKS");
 
                         m->has_verity = verity && verity->data_path;
-                        m->verity_ready = m->has_verity &&
-                                verity->root_hash &&
-                                (verity->designator < 0 || verity->designator == PARTITION_ROOT);
+                        m->verity_ready = verity_settings_data_covers(verity, PARTITION_ROOT);
 
                         m->has_verity_sig = false; /* signature not embedded, must be specified */
-                        m->verity_sig_ready = m->verity_ready &&
-                                verity->root_hash_sig;
+                        m->verity_sig_ready = m->verity_ready && verity->root_hash_sig;
 
                         m->image_uuid = uuid;
 
@@ -539,7 +558,7 @@ static int dissect_image(
         if (verity && verity->data_path)
                 return -EBADR;
 
-        if (FLAGS_SET(flags, DISSECT_IMAGE_MANAGE_PARTITION_DEVICES)) {
+        if (FLAGS_SET(flags, DISSECT_IMAGE_ADD_PARTITION_DEVICES)) {
                 /* Safety check: refuse block devices that carry a partition table but for which the kernel doesn't
                  * do partition scanning. */
                 r = blockdev_partscan_enabled(fd);
@@ -615,7 +634,7 @@ static int dissect_image(
                  * Kernel returns EBUSY if there's already a partition by that number or an overlapping
                  * partition already existent. */
 
-                if (FLAGS_SET(flags, DISSECT_IMAGE_MANAGE_PARTITION_DEVICES)) {
+                if (FLAGS_SET(flags, DISSECT_IMAGE_ADD_PARTITION_DEVICES)) {
                         r = block_device_add_partition(fd, node, nr, (uint64_t) start * 512, (uint64_t) size * 512);
                         if (r < 0) {
                                 if (r != -EBUSY)
@@ -627,39 +646,32 @@ static int dissect_image(
                 }
 
                 if (is_gpt) {
-                        const char *stype, *sid, *fstype = NULL, *label;
+                        const char *fstype = NULL, *label;
                         sd_id128_t type_id, id;
                         GptPartitionType type;
                         bool rw = true, growfs = false;
 
-                        sid = blkid_partition_get_uuid(pp);
-                        if (!sid)
-                                continue;
-                        if (sd_id128_from_string(sid, &id) < 0)
+                        r = blkid_partition_get_uuid_id128(pp, &id);
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to read partition UUID, ignoring: %m");
                                 continue;
+                        }
 
-                        stype = blkid_partition_get_type_string(pp);
-                        if (!stype)
-                                continue;
-                        if (sd_id128_from_string(stype, &type_id) < 0)
+                        r = blkid_partition_get_type_id128(pp, &type_id);
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to read partition type UUID, ignoring: %m");
                                 continue;
+                        }
 
                         type = gpt_partition_type_from_uuid(type_id);
 
                         label = blkid_partition_get_name(pp); /* libblkid returns NULL here if empty */
 
-                        if (type.designator == PARTITION_HOME) {
-
-                                check_partition_flags(node, pflags,
-                                                      SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
-
-                                if (pflags & SD_GPT_FLAG_NO_AUTO)
-                                        continue;
-
-                                rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
-                                growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
-
-                        } else if (type.designator == PARTITION_SRV) {
+                        if (IN_SET(type.designator,
+                                   PARTITION_HOME,
+                                   PARTITION_SRV,
+                                   PARTITION_XBOOTLDR,
+                                   PARTITION_TMP)) {
 
                                 check_partition_flags(node, pflags,
                                                       SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
@@ -682,17 +694,6 @@ static int dissect_image(
 
                                 fstype = "vfat";
 
-                        } else if (type.designator == PARTITION_XBOOTLDR) {
-
-                                check_partition_flags(node, pflags,
-                                                      SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
-
-                                if (pflags & SD_GPT_FLAG_NO_AUTO)
-                                        continue;
-
-                                rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
-                                growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
-
                         } else if (type.designator == PARTITION_ROOT) {
 
                                 check_partition_flags(node, pflags,
@@ -811,6 +812,8 @@ static int dissect_image(
                                 if (pflags & SD_GPT_FLAG_NO_AUTO)
                                         continue;
 
+                                fstype = "swap";
+
                         /* We don't have a designator for SD_GPT_LINUX_GENERIC so check the UUID instead. */
                         } else if (sd_id128_equal(type.uuid, SD_GPT_LINUX_GENERIC)) {
 
@@ -832,17 +835,6 @@ static int dissect_image(
                                                 return -ENOMEM;
                                 }
 
-                        } else if (type.designator == PARTITION_TMP) {
-
-                                check_partition_flags(node, pflags,
-                                                      SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
-
-                                if (pflags & SD_GPT_FLAG_NO_AUTO)
-                                        continue;
-
-                                rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
-                                growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
-
                         } else if (type.designator == PARTITION_VAR) {
 
                                 check_partition_flags(node, pflags,
@@ -867,7 +859,9 @@ static int dissect_image(
                                                 return r;
 
                                         if (!sd_id128_equal(var_uuid, id)) {
-                                                log_debug("Found a /var/ partition, but its UUID didn't match our expectations, ignoring.");
+                                                log_debug("Found a /var/ partition, but its UUID didn't match our expectations "
+                                                          "(found: " SD_ID128_UUID_FORMAT_STR ", expected: " SD_ID128_UUID_FORMAT_STR "), ignoring.",
+                                                          SD_ID128_FORMAT_VAL(id), SD_ID128_FORMAT_VAL(var_uuid));
                                                 continue;
                                         }
                                 }
@@ -897,7 +891,8 @@ static int dissect_image(
                                         dissected_partition_done(m->partitions + type.designator);
                                 }
 
-                                if (FLAGS_SET(flags, DISSECT_IMAGE_OPEN_PARTITION_DEVICES)) {
+                                if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES) &&
+                                    type.designator != PARTITION_SWAP) {
                                         mount_node_fd = open_partition(node, /* is_partition = */ true, m->loop);
                                         if (mount_node_fd < 0)
                                                 return mount_node_fd;
@@ -936,6 +931,7 @@ static int dissect_image(
                                         .mount_node_fd = TAKE_FD(mount_node_fd),
                                         .offset = (uint64_t) start * 512,
                                         .size = (uint64_t) size * 512,
+                                        .gpt_flags = pflags,
                                 };
                         }
 
@@ -965,21 +961,19 @@ static int dissect_image(
                                 _cleanup_close_ int mount_node_fd = -1;
                                 _cleanup_free_ char *o = NULL;
                                 sd_id128_t id = SD_ID128_NULL;
-                                const char *sid, *options = NULL;
+                                const char *options = NULL;
 
                                 /* First one wins */
                                 if (m->partitions[PARTITION_XBOOTLDR].found)
                                         continue;
 
-                                if (FLAGS_SET(flags, DISSECT_IMAGE_OPEN_PARTITION_DEVICES)) {
+                                if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) {
                                         mount_node_fd = open_partition(node, /* is_partition = */ true, m->loop);
                                         if (mount_node_fd < 0)
                                                 return mount_node_fd;
                                 }
 
-                                sid = blkid_partition_get_uuid(pp);
-                                if (sid)
-                                        (void) sd_id128_from_string(sid, &id);
+                                (void) blkid_partition_get_uuid_id128(pp, &id);
 
                                 options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR);
                                 if (options) {
@@ -1053,7 +1047,7 @@ static int dissect_image(
                         _cleanup_free_ char *o = NULL;
                         const char *options;
 
-                        if (FLAGS_SET(flags, DISSECT_IMAGE_OPEN_PARTITION_DEVICES)) {
+                        if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) {
                                 mount_node_fd = open_partition(generic_node, /* is_partition = */ true, m->loop);
                                 if (mount_node_fd < 0)
                                         return mount_node_fd;
@@ -1141,6 +1135,10 @@ static int dissect_image(
                 }
         }
 
+        r = dissected_image_probe_filesystems(m, fd);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 #endif
@@ -1158,7 +1156,6 @@ int dissect_image_file(
         int r;
 
         assert(path);
-        assert((flags & DISSECT_IMAGE_BLOCK_DEVICE) == 0);
         assert(ret);
 
         fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
@@ -2265,7 +2262,7 @@ int dissected_image_decrypt(
                 }
 
                 if (!p->decrypted_fstype && p->mount_node_fd >= 0 && p->decrypted_node) {
-                        r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, &p->decrypted_fstype);
+                        r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, &p->decrypted_fstype);
                         if (r < 0 && r != -EUCLEAN)
                                 return r;
                 }
@@ -2973,11 +2970,7 @@ int dissect_loop_device(
 
         m->loop = loop_device_ref(loop);
 
-        r = dissect_image(m, loop->fd, loop->node, verity, mount_options, flags | DISSECT_IMAGE_BLOCK_DEVICE);
-        if (r < 0)
-                return r;
-
-        r = dissected_image_probe_filesystem(m);
+        r = dissect_image(m, loop->fd, loop->node, verity, mount_options, flags);
         if (r < 0)
                 return r;
 
@@ -3136,6 +3129,10 @@ int mount_image_privately_interactively(
         assert(ret_directory);
         assert(ret_loop_device);
 
+        /* We intend to mount this right-away, hence add the partitions if needed and pin them*/
+        flags |= DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                DISSECT_IMAGE_PIN_PARTITION_DEVICES;
+
         r = verity_settings_load(&verity, image, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to load root hash data: %m");
@@ -3230,7 +3227,9 @@ int verity_dissect_and_mount(
                 return log_debug_errno(r, "Failed to load root hash: %m");
 
         dissect_image_flags = (verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0) |
-                (relax_extension_release_check ? DISSECT_IMAGE_RELAX_SYSEXT_CHECK : 0);
+                (relax_extension_release_check ? DISSECT_IMAGE_RELAX_SYSEXT_CHECK : 0) |
+                DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                DISSECT_IMAGE_PIN_PARTITION_DEVICES;
 
         /* Note that we don't use loop_device_make here, as the FD is most likely O_PATH which would not be
          * accepted by LOOP_CONFIGURE, so just let loop_device_make_by_path reopen it as a regular FD. */
index 1a398010b53b9d9210c9fb8e4ea8336d12daa22f..059b9aecbb9e36dcfc4faf32157995698c8385f3 100644 (file)
@@ -33,6 +33,7 @@ struct DissectedPartition {
         int mount_node_fd;
         uint64_t size;
         uint64_t offset;
+        uint64_t gpt_flags;
 };
 
 #define DISSECTED_PARTITION_NULL                                        \
@@ -74,10 +75,8 @@ typedef enum DissectImageFlags {
                                                  DISSECT_IMAGE_MOUNT_READ_ONLY,
         DISSECT_IMAGE_GROWFS                   = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
         DISSECT_IMAGE_MOUNT_IDMAPPED           = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
-        DISSECT_IMAGE_MANAGE_PARTITION_DEVICES = 1 << 20, /* Manage partition devices, e.g. probe each partition in more detail */
-        DISSECT_IMAGE_OPEN_PARTITION_DEVICES   = 1 << 21, /* Open dissected partitions and decrypted partitions */
-        DISSECT_IMAGE_BLOCK_DEVICE             = DISSECT_IMAGE_MANAGE_PARTITION_DEVICES |
-                                                 DISSECT_IMAGE_OPEN_PARTITION_DEVICES,
+        DISSECT_IMAGE_ADD_PARTITION_DEVICES    = 1 << 20, /* Create partition devices via BLKPG_ADD_PARTITION */
+        DISSECT_IMAGE_PIN_PARTITION_DEVICES    = 1 << 21, /* Open dissected partitions and decrypted partitions and pin them by fd */
         DISSECT_IMAGE_RELAX_SYSEXT_CHECK       = 1 << 22, /* Don't insist that the extension-release file name matches the image name */
 } DissectImageFlags;
 
@@ -135,9 +134,9 @@ MountOptions* mount_options_free_all(MountOptions *options);
 DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
 const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
 
-int probe_filesystem_full(int fd, const char *path, char **ret_fstype);
+int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, char **ret_fstype);
 static inline int probe_filesystem(const char *path, char **ret_fstype) {
-        return probe_filesystem_full(-1, path, ret_fstype);
+        return probe_filesystem_full(-1, path, 0, UINT64_MAX, ret_fstype);
 }
 int dissect_image_file(
                 const char *path,
@@ -167,6 +166,14 @@ int dissected_image_relinquish(DissectedImage *m);
 int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
 void verity_settings_done(VeritySettings *verity);
 
+static inline bool verity_settings_data_covers(const VeritySettings *verity, PartitionDesignator d) {
+        /* Returns true if the verity settings contain sufficient information to cover the specified partition */
+        return verity &&
+                ((d >= 0 && verity->designator == d) || (d == PARTITION_ROOT && verity->designator < 0)) &&
+                verity->root_hash &&
+                verity->data_path;
+}
+
 int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity);
 
 bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
diff --git a/src/shared/fdisk-util.c b/src/shared/fdisk-util.c
new file mode 100644 (file)
index 0000000..eeed184
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "fd-util.h"
+#include "fdisk-util.h"
+
+#if HAVE_LIBFDISK
+
+int fdisk_new_context_fd(int fd, bool read_only, struct fdisk_context **ret) {
+        _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
+        int r;
+
+        assert(ret);
+
+        if (fd < 0)
+                return -EBADF;
+
+        c = fdisk_new_context();
+        if (!c)
+                return -ENOMEM;
+
+        r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), read_only);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(c);
+        return 0;
+}
+
+int fdisk_partition_get_uuid_as_id128(struct fdisk_partition *p, sd_id128_t *ret) {
+        const char *ids;
+
+        assert(p);
+        assert(ret);
+
+        ids = fdisk_partition_get_uuid(p);
+        if (!ids)
+                return -ENXIO;
+
+        return sd_id128_from_string(ids, ret);
+}
+
+int fdisk_partition_get_type_as_id128(struct fdisk_partition *p, sd_id128_t *ret) {
+        struct fdisk_parttype *pt;
+        const char *pts;
+
+        assert(p);
+        assert(ret);
+
+        pt = fdisk_partition_get_type(p);
+        if (!pt)
+                return -ENXIO;
+
+        pts = fdisk_parttype_get_string(pt);
+        if (!pts)
+                return -ENXIO;
+
+        return sd_id128_from_string(pts, ret);
+}
+
+#endif
index 64c0c2f324f1b13d57349a6adaf16a3f97a1b00d..7f34a042ec52fe12062569e3367e5a1a44ea6ff4 100644 (file)
@@ -5,6 +5,8 @@
 
 #include <libfdisk.h>
 
+#include "sd-id128.h"
+
 #include "macro.h"
 
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_context*, fdisk_unref_context, NULL);
@@ -12,4 +14,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_partition*, fdisk_unref_partition,
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_parttype*, fdisk_unref_parttype, NULL);
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_table*, fdisk_unref_table, NULL);
 
+int fdisk_new_context_fd(int fd, bool read_only, struct fdisk_context **ret);
+
+int fdisk_partition_get_uuid_as_id128(struct fdisk_partition *p, sd_id128_t *ret);
+int fdisk_partition_get_type_as_id128(struct fdisk_partition *p, sd_id128_t *ret);
+
 #endif
index fa234c8b5fe96ddb92f52d2710f6020779c2066c..e019b816205f330bfef8d87d033fc9172a8f6677 100644 (file)
@@ -564,19 +564,21 @@ static int verify_xbootldr_blkid(
         errno = 0;
         b = blkid_new_probe_from_filename(node);
         if (!b)
-                return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "%s: Failed to create blkid probe: %m", node);
+                return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
 
         blkid_probe_enable_partitions(b, 1);
         blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (r == -2)
+        if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
                 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
-        else if (r == 1)
+        if (r == _BLKID_SAFEPROBE_NOT_FOUND)
                 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system does not contain a label.", node);
-        else if (r != 0)
-                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe file system: %m", node);
+        if (r == _BLKID_SAFEPROBE_ERROR)
+                return log_error_errno(errno_or_else(EIO), "%s: Failed to probe file system: %m", node);
+
+        assert(r == _BLKID_SAFEPROBE_FOUND);
 
         r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
         if (r != 0)
@@ -588,7 +590,7 @@ static int verify_xbootldr_blkid(
                 errno = 0;
                 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
                 if (r != 0)
-                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
+                        return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
                 if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0)
                         return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
                                               searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
@@ -597,7 +599,7 @@ static int verify_xbootldr_blkid(
                 errno = 0;
                 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
                 if (r != 0)
-                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
+                        return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
                 r = sd_id128_from_string(v, &uuid);
                 if (r < 0)
                         return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
@@ -607,7 +609,7 @@ static int verify_xbootldr_blkid(
                 errno = 0;
                 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
                 if (r != 0)
-                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
+                        return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
                 if (!streq(v, "0xea"))
                         return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
                                               searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
index 51aa60bb5253cf8e4bca64b52a7068af7e2af8bb..c38ba1bd7aa4aa35b99f634b22f50a4f0d597508 100644 (file)
@@ -2790,25 +2790,38 @@ static int do_unit_file_disable(
 
         _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+        InstallInfo *info;
+        bool has_install_info = false;
         int r;
 
         STRV_FOREACH(name, names) {
                 if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
                         return install_changes_add(changes, n_changes, -EUCLEAN, *name, NULL);
 
-                r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
+                r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, &info);
+                if (r >= 0)
+                        r = install_info_traverse(&ctx, lp, info, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
+
                 if (r < 0)
-                        return r;
+                        return install_changes_add(changes, n_changes, r, *name, NULL);
+
+                /* If we enable multiple units, some with install info and others without,
+                 * the "empty [Install] section" warning is not shown. Let's make the behavior
+                 * of disable align with that. */
+                has_install_info = has_install_info || install_info_has_rules(info) || install_info_has_also(info);
         }
 
         r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes);
+        if (r >= 0)
+                r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
+
         if (r < 0)
                 return r;
 
-        return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
+        /* The warning is shown only if it's a no-op */
+        return install_changes_have_modification(*changes, *n_changes) || has_install_info;
 }
 
-
 int unit_file_disable(
                 LookupScope scope,
                 UnitFileFlags flags,
index 5f66b865de3ef6072be3666f90b10c8fa64a4256..3be7ba17bf15b2754d8f52992cc3fe264b8cdbed 100644 (file)
@@ -125,7 +125,6 @@ shared_sources = files(
         'exit-status.h',
         'extension-release.c',
         'extension-release.h',
-        'fdisk-util.h',
         'fdset.c',
         'fdset.h',
         'fileio-label.c',
@@ -493,3 +492,18 @@ libshared = shared_library(
         dependencies : libshared_deps,
         install : true,
         install_dir : rootpkglibdir)
+
+shared_fdisk_sources = files(
+        'fdisk-util.h',
+        'fdisk-util.c',
+)
+
+if get_option('fdisk') != 'false'
+        libshared_fdisk = static_library(
+                'shared-fdisk',
+                shared_fdisk_sources,
+                include_directories : includes,
+                dependencies : [libfdisk],
+                c_args : ['-fvisibility=default'],
+                build_by_default : false)
+endif
index 5a56c5e473a870829fc2e04dc6e4bad3c80d2762..68e8f12eabb42176ebd8db5800c50ad1c8ba025f 100644 (file)
@@ -128,8 +128,10 @@ static int setup_userns(uid_t uid, gid_t gid) {
 }
 
 static int do_mcopy(const char *node, const char *root) {
+        _cleanup_free_ char *mcopy = NULL;
         _cleanup_strv_free_ char **argv = NULL;
-        _cleanup_closedir_ DIR *rootdir = NULL;
+        _cleanup_close_ int rfd = -1;
+        _cleanup_free_ DirectoryEntries *de = NULL;
         struct stat st;
         int r;
 
@@ -140,22 +142,39 @@ static int do_mcopy(const char *node, const char *root) {
         if (dir_is_empty(root, /*ignore_hidden_or_backup=*/ false))
                 return 0;
 
-        argv = strv_new("mcopy", "-b", "-s", "-p", "-Q", "-n", "-m", "-i", node);
+        r = find_executable("mcopy", &mcopy);
+        if (r == -ENOENT)
+                return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "Could not find mcopy binary.");
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine whether mcopy binary exists: %m");
+
+        argv = strv_new(mcopy, "-s", "-p", "-Q", "-m", "-i", node);
         if (!argv)
                 return log_oom();
 
         /* mcopy copies the top level directory instead of everything in it so we have to pass all
          * the subdirectories to mcopy instead to end up with the correct directory structure. */
 
-        rootdir = opendir(root);
-        if (!rootdir)
-                return log_error_errno(errno, "Failed to open directory '%s'", root);
+        rfd = open(root, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        if (rfd < 0)
+                return log_error_errno(errno, "Failed to open directory '%s': %m", root);
+
+        r = readdir_all(rfd, RECURSE_DIR_SORT|RECURSE_DIR_ENSURE_TYPE, &de);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read '%s' contents: %m", root);
 
-        FOREACH_DIRENT(de, rootdir, return -errno) {
-                char *p = path_join(root, de->d_name);
+        for (size_t i = 0; i < de->n_entries; i++) {
+                _cleanup_free_ char *p = NULL;
+
+                p = path_join(root, de->entries[i]->d_name);
                 if (!p)
                         return log_oom();
 
+                if (!IN_SET(de->entries[i]->d_type, DT_REG, DT_DIR)) {
+                        log_debug("%s is not a file/directory which are the only file types supported by vfat, ignoring", p);
+                        continue;
+                }
+
                 r = strv_consume(&argv, TAKE_PTR(p));
                 if (r < 0)
                         return log_oom();
@@ -165,7 +184,7 @@ static int do_mcopy(const char *node, const char *root) {
         if (r < 0)
                 return log_oom();
 
-        if (fstat(dirfd(rootdir), &st) < 0)
+        if (fstat(rfd, &st) < 0)
                 return log_error_errno(errno, "Failed to stat '%s': %m", root);
 
         r = safe_fork("(mcopy)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_NEW_USERNS|FORK_CLOSE_ALL_FDS, NULL);
@@ -178,7 +197,7 @@ static int do_mcopy(const char *node, const char *root) {
 
                 /* Avoid failures caused by mismatch in expectations between mkfs.vfat and mcopy by disabling
                  * the stricter mcopy checks using MTOOLS_SKIP_CHECK. */
-                execvpe("mcopy", argv, STRV_MAKE("MTOOLS_SKIP_CHECK=1"));
+                execve(mcopy, argv, STRV_MAKE("MTOOLS_SKIP_CHECK=1"));
 
                 log_error_errno(errno, "Failed to execute mcopy: %m");
 
@@ -262,7 +281,7 @@ static int make_protofile(const char *root, char **ret) {
               "0 0\n"
               "d--755 0 0\n", f);
 
-        r = recurse_dir_at(AT_FDCWD, root, STATX_TYPE|STATX_MODE, UINT_MAX, 0, protofile_print_item, f);
+        r = recurse_dir_at(AT_FDCWD, root, STATX_TYPE|STATX_MODE, UINT_MAX, RECURSE_DIR_SORT, protofile_print_item, f);
         if (r < 0)
                 return log_error_errno(r, "Failed to recurse through %s: %m", root);
 
index e58173d864dad8976d2b4d4e66b6f6fded29b381..7c9008c7053f80b1f8b5d839cce59b9d8de3bcdb 100644 (file)
@@ -11,6 +11,9 @@
 /* 127.0.0.54 in native endian (The IP address we listen on we only implement "proxy" mode) */
 #define INADDR_DNS_PROXY_STUB ((in_addr_t) 0x7f000036U)
 
+/* 127.0.0.2 is an address we always map to the local hostname. This is different from 127.0.0.1 which maps to "localhost" */
+#define INADDR_LOCALADDRESS ((in_addr_t) 0x7f000002U)
+
 typedef enum DnsCacheMode DnsCacheMode;
 
 enum DnsCacheMode {
index 9a7ef8eb2906a29ed36cf87d77bf4ef96b61d06b..b9147fbd78d67b961cde87045656436702d75160 100644 (file)
@@ -522,7 +522,9 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
                                 DISSECT_IMAGE_GENERIC_ROOT |
                                 DISSECT_IMAGE_REQUIRE_ROOT |
                                 DISSECT_IMAGE_MOUNT_ROOT_ONLY |
-                                DISSECT_IMAGE_USR_NO_ROOT;
+                                DISSECT_IMAGE_USR_NO_ROOT |
+                                DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+                                DISSECT_IMAGE_PIN_PARTITION_DEVICES;
 
                         r = verity_settings_load(&verity_settings, img->path, NULL, NULL);
                         if (r < 0)
index 92f6ecaa8d044145b87ae87f91ec71c66e48f7d8..52574ba9968f99409d85a904af47c1ed8a257a66 100644 (file)
@@ -19,6 +19,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_close_ int orig_stdout_fd = -1;
         int r;
 
+        if (size > 4*1024*1024)
+                return 0; /* See the comment below about the limit for strv_length(). */
+
         /* We don't want to fill the logs with messages about parse errors.
          * Disable most logging if not running standalone */
         if (!getenv("SYSTEMD_LOG_LEVEL"))
index 5be4c0c7250faee6d028a471f942674519a60cbe..86d9f602fa0c5493d9f9a3c402fec727020dff94 100644 (file)
@@ -67,7 +67,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
         InstallChange *changes = NULL;
         size_t n_changes = 0;
         int carries_install_info = -1;
-        bool ignore_carries_install_info = arg_quiet;
+        bool ignore_carries_install_info = arg_quiet || arg_no_warn;
         int r;
 
         if (!argv[1])
@@ -109,9 +109,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
                 if (streq(verb, "enable")) {
                         r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
                         carries_install_info = r;
-                } else if (streq(verb, "disable"))
+                } else if (streq(verb, "disable")) {
                         r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
-                else if (streq(verb, "reenable")) {
+                        carries_install_info = r;
+                } else if (streq(verb, "reenable")) {
                         r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
                         carries_install_info = r;
                 } else if (streq(verb, "link"))
@@ -165,7 +166,8 @@ int verb_enable(int argc, char *argv[], void *userdata) {
                         method = "EnableUnitFiles";
                         expect_carries_install_info = true;
                 } else if (streq(verb, "disable")) {
-                        method = "DisableUnitFiles";
+                        method = "DisableUnitFilesWithFlagsAndInstallInfo";
+                        expect_carries_install_info = true;
                         send_force = false;
                 } else if (streq(verb, "reenable")) {
                         method = "ReenableUnitFiles";
@@ -208,7 +210,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
                 }
 
                 if (send_runtime) {
-                        r = sd_bus_message_append(m, "b", arg_runtime);
+                        if (streq(method, "DisableUnitFilesWithFlagsAndInstallInfo"))
+                                r = sd_bus_message_append(m, "t", arg_runtime ? UNIT_FILE_RUNTIME : 0);
+                        else
+                                r = sd_bus_message_append(m, "b", arg_runtime);
                         if (r < 0)
                                 return bus_log_create_error(r);
                 }
@@ -245,7 +250,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
         if (carries_install_info == 0 && !ignore_carries_install_info)
                 log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
                            "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
-                           "units). This means they are not meant to be enabled using systemctl.\n"
+                           "units). This means they are not meant to be enabled or disabled using systemctl.\n"
                            " \n" /* trick: the space is needed so that the line does not get stripped from output */
                            "Possible reasons for having this kind of units are:\n"
                            "%1$s A unit may be statically enabled by being symlinked from another unit's\n"
index 9363764cd70e6e7d256beddbfe9e5b01667a5f5e..edc907c832d4634ad305dfbfa1d5898070d474d5 100644 (file)
@@ -153,19 +153,8 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
                 return r;
 
         if (a == ACTION_REBOOT) {
-                const char *arg = NULL;
-
-                if (argc > 1) {
-                        if (arg_reboot_argument)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Both --reboot-argument= and positional argument passed to reboot command, refusing.");
-
-                        log_notice("Positional argument to reboot command is deprecated, please use --reboot-argument= instead. Accepting anyway.");
-                        arg = argv[1];
-                } else
-                        arg = arg_reboot_argument;
-
-                if (arg) {
-                        r = update_reboot_parameter_and_warn(arg, false);
+                if (arg_reboot_argument) {
+                        r = update_reboot_parameter_and_warn(arg_reboot_argument, false);
                         if (r < 0)
                                 return r;
                 }
index 3f28bcc3dc916cc326aac165290393d288850602..0a12bcebc30fee7fd63f1430e751b14e154a9712 100644 (file)
@@ -84,6 +84,7 @@ bool arg_show_types = false;
 int arg_check_inhibitors = -1;
 bool arg_dry_run = false;
 bool arg_quiet = false;
+bool arg_no_warn = false;
 bool arg_full = false;
 bool arg_recursive = false;
 bool arg_with_dependencies = false;
@@ -277,6 +278,8 @@ static int systemctl_help(void) {
                "                             kexec, suspend, hibernate, suspend-then-hibernate,\n"
                "                             hybrid-sleep, default, rescue, emergency, and exit.\n"
                "  -q --quiet             Suppress output\n"
+               "     --no-warn           Don't generate warning when trying to enable/disable\n"
+               "                         units without install information\n"
                "     --wait              For (re)start, wait until service stopped again\n"
                "                         For is-system-running, wait until startup is completed\n"
                "     --no-block          Do not wait until operation finished\n"
@@ -433,6 +436,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_READ_ONLY,
                 ARG_MKDIR,
                 ARG_MARKED,
+                ARG_NO_WARN,
         };
 
         static const struct option options[] = {
@@ -465,6 +469,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
                 { "dry-run",             no_argument,       NULL, ARG_DRY_RUN             },
                 { "quiet",               no_argument,       NULL, 'q'                     },
+                { "no-warn",             no_argument,       NULL, ARG_NO_WARN             },
                 { "root",                required_argument, NULL, ARG_ROOT                },
                 { "image",               required_argument, NULL, ARG_IMAGE               },
                 { "force",               no_argument,       NULL, 'f'                     },
@@ -926,6 +931,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_marked = true;
                         break;
 
+                case ARG_NO_WARN:
+                        arg_no_warn = true;
+                        break;
+
                 case '.':
                         /* Output an error mimicking getopt, and print a hint afterwards */
                         log_error("%s: invalid option -- '.'", program_invocation_name);
@@ -1087,7 +1096,7 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "import-environment",    VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_import_environment      },
                 { "halt",                  VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
                 { "poweroff",              VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
-                { "reboot",                VERB_ANY, 2,        VERB_ONLINE_ONLY, verb_start_system_special    },
+                { "reboot",                VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
                 { "kexec",                 VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
                 { "suspend",               VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
                 { "hibernate",             VERB_ANY, 1,        VERB_ONLINE_ONLY, verb_start_system_special    },
index 2454c4c714f7f26f79d76c396743daacc6e28ff9..1a7a6e28d39c961c7320bc8c8c3fe18566e4f399 100644 (file)
@@ -65,6 +65,7 @@ extern bool arg_show_types;
 extern int arg_check_inhibitors;
 extern bool arg_dry_run;
 extern bool arg_quiet;
+extern bool arg_no_warn;
 extern bool arg_full;
 extern bool arg_recursive;
 extern bool arg_with_dependencies;
index 33d0e584ba0706c1f8bf3d1e3daa20a427adf726..bd0486d99ed50e93714298941e408b0234584dc8 100644 (file)
@@ -106,9 +106,8 @@ int read_partition_info(
                 PartitionInfo *ret) {
 
         _cleanup_free_ char *label_copy = NULL, *device = NULL;
-        const char *pts, *ids, *label;
+        const char *label;
         struct fdisk_partition *p;
-        struct fdisk_parttype *pt;
         uint64_t start, size, flags;
         sd_id128_t ptid, id;
         GptPartitionType type;
@@ -147,25 +146,13 @@ int read_partition_info(
         if (!label)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a label.");
 
-        pt = fdisk_partition_get_type(p);
-        if (!pt)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition: %m");
-
-        pts = fdisk_parttype_get_string(pt);
-        if (!pts)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire type of partition as string: %m");
-
-        r = sd_id128_from_string(pts, &ptid);
+        r = fdisk_partition_get_type_as_id128(p, &ptid);
         if (r < 0)
-                return log_error_errno(r, "Failed to parse partition type UUID %s: %m", pts);
-
-        ids = fdisk_partition_get_uuid(p);
-        if (!ids)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a UUID.");
+                return log_error_errno(r, "Failed to read partition type UUID: %m");
 
-        r = sd_id128_from_string(ids, &id);
+        r = fdisk_partition_get_uuid_as_id128(p, &id);
         if (r < 0)
-                return log_error_errno(r, "Failed to parse partition UUID %s: %m", ids);
+                return log_error_errno(r, "Failed to read partition UUID: %m");
 
         r = fdisk_partition_get_attrs_as_uint64(p, &flags);
         if (r < 0)
index 2b85ceab822d521805f41fef92e722aa7007c579..df6ca13785faa5a1c5138ba8b5f49962488511a9 100644 (file)
@@ -483,6 +483,53 @@ TEST(fd_reopen) {
         fd1 = -1;
 }
 
+TEST(fd_reopen_condition) {
+        _cleanup_close_ int fd1 = -1, fd3 = -1;
+        int fd2, fl;
+
+        /* Open without O_PATH */
+        fd1 = open("/usr/", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        assert_se(fd1 >= 0);
+
+        fl = fcntl(fd1, F_GETFL);
+        assert_se(FLAGS_SET(fl, O_DIRECTORY));
+        assert_se(!FLAGS_SET(fl, O_PATH));
+
+        fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
+        assert_se(fd2 == fd1);
+        assert_se(fd3 < 0);
+
+        /* Switch on O_PATH */
+        fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
+        assert_se(fd2 != fd1);
+        assert_se(fd3 == fd2);
+
+        fl = fcntl(fd2, F_GETFL);
+        assert_se(FLAGS_SET(fl, O_DIRECTORY));
+        assert_se(FLAGS_SET(fl, O_PATH));
+
+        close_and_replace(fd1, fd3);
+
+        fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
+        assert_se(fd2 == fd1);
+        assert_se(fd3 < 0);
+
+        /* Switch off O_PATH again */
+        fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
+        assert_se(fd2 != fd1);
+        assert_se(fd3 == fd2);
+
+        fl = fcntl(fd2, F_GETFL);
+        assert_se(FLAGS_SET(fl, O_DIRECTORY));
+        assert_se(!FLAGS_SET(fl, O_PATH));
+
+        close_and_replace(fd1, fd3);
+
+        fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
+        assert_se(fd2 == fd1);
+        assert_se(fd3 < 0);
+}
+
 TEST(take_fd) {
         _cleanup_close_ int fd1 = -1, fd2 = -1;
         int array[2] = { -1, -1 }, i = 0;
index e2b97dd56ff5c7ff3d27b112876305da2e39c7a7..b06ab0d172614b7616d60d6078a10d48468eb462 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/loop.h>
 #include <pthread.h>
 #include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
 
 #include "alloc-util.h"
 #include "capability-util.h"
@@ -44,6 +46,15 @@ static void verify_dissected_image(DissectedImage *dissected) {
         assert_se(dissected->partitions[PARTITION_HOME].node);
 }
 
+static void verify_dissected_image_harder(DissectedImage *dissected) {
+        verify_dissected_image(dissected);
+
+        assert_se(streq(dissected->partitions[PARTITION_ESP].fstype, "vfat"));
+        assert_se(streq(dissected->partitions[PARTITION_XBOOTLDR].fstype, "vfat"));
+        assert_se(streq(dissected->partitions[PARTITION_ROOT].fstype, "ext4"));
+        assert_se(streq(dissected->partitions[PARTITION_HOME].fstype, "ext4"));
+}
+
 static void* thread_func(void *ptr) {
         int fd = PTR_TO_FD(ptr);
         int r;
@@ -71,7 +82,7 @@ static void* thread_func(void *ptr) {
 
                 log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted);
 
-                r = dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_READ_ONLY, &dissected);
+                r = dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected);
                 if (r < 0)
                         log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node);
                 assert_se(r >= 0);
@@ -220,7 +231,7 @@ static int run(int argc, char *argv[]) {
         assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_EX, &loop) >= 0);
 
 #if HAVE_BLKID
-        assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0);
+        assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0);
         verify_dissected_image(dissected);
 
         FOREACH_STRING(fs, "vfat", "ext4") {
@@ -246,8 +257,23 @@ static int run(int argc, char *argv[]) {
         assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", NULL, id, true) >= 0);
 
         dissected = dissected_image_unref(dissected);
+
+        /* We created the file systems now via the per-partition block devices. But the dissection code might
+         * probe them via the whole block device. These block devices have separate buffer caches though,
+         * hence what was written via the partition device might not appear on the whole block device
+         * yet. Let's hence explicitly flush the whole block device, so that the read-back definitely
+         * works. */
+        assert_se(ioctl(loop->fd, BLKFLSBUF, 0) >= 0);
+
+        /* Try to read once, without pinning or adding partitions, i.e. by only accessing the whole block
+         * device. */
         assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0);
-        verify_dissected_image(dissected);
+        verify_dissected_image_harder(dissected);
+        dissected = dissected_image_unref(dissected);
+
+        /* Now go via the loopback device after all, but this time add/pin, because now we want to mount it. */
+        assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0);
+        verify_dissected_image_harder(dissected);
 
         assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
 
index bf5192c56fecc716a21585c06f4158dc6455402f..f156d90073dc27557648ce4e5b6868303614207c 100644 (file)
@@ -1979,7 +1979,7 @@ static int create_fifo(Item *i) {
 
         creation = r >= 0 ? CREATION_NORMAL : CREATION_EXISTING;
 
-        /* Open the inode via O_PATH, regardless if we managed to create it or not. Maybe it is is already the FIFO we want */
+        /* Open the inode via O_PATH, regardless if we managed to create it or not. Maybe it is already the FIFO we want */
         fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
         if (fd < 0) {
                 if (r < 0)
index 9f5646ffdd997a2a0eece0c3873d5b81c5b09143..9b5dfbe33be4c6dd4eefde258e354457a403e7d9 100644 (file)
@@ -119,8 +119,9 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
 
 #if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI
 
-        _cleanup_free_ char *root_id = NULL, *root_label = NULL;
+        _cleanup_free_ char *root_label = NULL;
         bool found_esp_or_xbootldr = false;
+        sd_id128_t root_id = SD_ID128_NULL;
         int r;
 
         assert(pr);
@@ -137,34 +138,32 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
         int nvals = blkid_partlist_numof_partitions(pl);
         for (int i = 0; i < nvals; i++) {
                 blkid_partition pp;
-                const char *stype, *sid, *label;
-                sd_id128_t type;
+                const char *label;
+                sd_id128_t type, id;
 
                 pp = blkid_partlist_get_partition(pl, i);
                 if (!pp)
                         continue;
 
-                sid = blkid_partition_get_uuid(pp);
-                if (!sid)
+                r = blkid_partition_get_uuid_id128(pp, &id);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to get partition UUID, ignoring: %m");
                         continue;
+                }
 
-                label = blkid_partition_get_name(pp); /* returns NULL if empty */
-
-                stype = blkid_partition_get_type_string(pp);
-                if (!stype)
+                r = blkid_partition_get_type_id128(pp, &type);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to get partition type UUID, ignoring: %m");
                         continue;
+                }
 
-                if (sd_id128_from_string(stype, &type) < 0)
-                        continue;
+                label = blkid_partition_get_name(pp); /* returns NULL if empty */
 
                 if (sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) {
-                        sd_id128_t id, esp_or_xbootldr;
+                        sd_id128_t esp_or_xbootldr;
 
                         /* We found an ESP or XBOOTLDR, let's see if it matches the ESP/XBOOTLDR we booted from. */
 
-                        if (sd_id128_from_string(sid, &id) < 0)
-                                continue;
-
                         r = efi_loader_get_device_part_uuid(&esp_or_xbootldr);
                         if (r < 0)
                                 return r;
@@ -182,10 +181,8 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
                         /* We found a suitable root partition, let's remember the first one, or the one with
                          * the newest version, as determined by comparing the partition labels. */
 
-                        if (!root_id || strverscmp_improved(label, root_label) > 0) {
-                                r = free_and_strdup(&root_id, sid);
-                                if (r < 0)
-                                        return r;
+                        if (sd_id128_is_null(root_id) || strverscmp_improved(label, root_label) > 0) {
+                                root_id = id;
 
                                 r = free_and_strdup(&root_label, label);
                                 if (r < 0)
@@ -196,8 +193,8 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
 
         /* We found the ESP/XBOOTLDR on this disk, and also found a root partition, nice! Let's export its
          * UUID */
-        if (found_esp_or_xbootldr && root_id)
-                udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id);
+        if (found_esp_or_xbootldr && !sd_id128_is_null(root_id))
+                udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", SD_ID128_TO_UUID_STRING(root_id));
 #endif
 
         return 0;
diff --git a/test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120 b/test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120
new file mode 100644 (file)
index 0000000..8804abd
--- /dev/null
@@ -0,0 +1 @@
+{"config":"default @saved","loader":[""]}
\ No newline at end of file
diff --git a/test/fuzz/fuzz-resource-record/crash-type-bitmap-to-json b/test/fuzz/fuzz-resource-record/crash-type-bitmap-to-json
new file mode 100644 (file)
index 0000000..a7d5b43
Binary files /dev/null and b/test/fuzz/fuzz-resource-record/crash-type-bitmap-to-json differ
diff --git a/test/fuzz/fuzz-resource-record/ub-zero-length-rdata b/test/fuzz/fuzz-resource-record/ub-zero-length-rdata
new file mode 100644 (file)
index 0000000..b5301ee
Binary files /dev/null and b/test/fuzz/fuzz-resource-record/ub-zero-length-rdata differ
index e181f976bea580e8fb5ed0f84b568c8a1e6dd257..ae2c0ad6282a76d20341294e689da41b70c9522f 100755 (executable)
@@ -1,10 +1,11 @@
 #!/usr/bin/python3
 # SPDX-License-Identifier: LGPL-2.1-or-later
-#
+# pylint: disable=line-too-long,invalid-name,missing-module-docstring,missing-function-docstring,too-many-statements,broad-except
 
 import argparse
 import logging
 import sys
+import time
 
 import pexpect
 
@@ -53,12 +54,12 @@ def run(args):
         console.sendcontrol('a')
         console.send('0')
         logger.info("verify broadcast message")
-        console.expect('Broadcast message from root@H on %s' % pty, 2)
-        console.expect('The system will reboot at %s' % date, 2)
+        console.expect(f'Broadcast message from root@H on {pty}', 2)
+        console.expect(f'The system will reboot at {date}', 2)
 
         logger.info("check show output")
         console.sendline('shutdown --show')
-        console.expect("Reboot scheduled for %s, use 'shutdown -c' to cancel" % date, 2)
+        console.expect(f"Reboot scheduled for {date}, use 'shutdown -c' to cancel", 2)
 
         logger.info("cancel shutdown")
         console.sendline('shutdown -c')
@@ -90,7 +91,23 @@ def run(args):
     except Exception as e:
         logger.error(e)
         logger.info("killing child pid %d", console.pid)
-        console.terminate(force=True)
+        # We can't use console.terminate(force=True) right away, since
+        # the internal delay between sending a signal and checking the process
+        # is just 0.1s [0], which means we'd get SIGKILLed pretty quickly.
+        # Let's send SIGHUP/SIGINT first, wait a bit, and then follow-up with
+        # SIGHUP/SIGINT/SIGKILL if the process is still alive.
+        # [0] https://github.com/pexpect/pexpect/blob/acb017a97332c19a9295660fe87316926a8adc55/pexpect/spawnbase.py#L71
+        console.terminate()
+        for _ in range(10):
+            if not console.isalive():
+                break
+
+            time.sleep(1)
+        else:
+            # We haven't exited the loop early, so check if the process is
+            # still alive - if so, force-kill it.
+            if console.isalive():
+                console.terminate(force=True)
 
     return ret
 
index a225ac8beec83f22ef436812c52f12ade387ae18..01eec207459489838c422ce2dba49cc47dc48d21 100755 (executable)
@@ -154,13 +154,14 @@ device: $imgs/zzz
 unit: sectors
 first-lba: 2048
 last-lba: 2097118
-$imgs/zzz1 : start=        2048, size=      591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
-$imgs/zzz4 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
+$imgs/zzz1 : start=        2048, size=     1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
+$imgs/zzz2 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
 
     runas testuser systemd-repart --definitions="$defs" \
                                   --dry-run=no \
                                   --seed="$seed" \
-                                  --exclude-partitions=root \
+                                  --empty=force \
+                                  --skip-partitions=home,root \
                                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
@@ -171,7 +172,6 @@ device: $imgs/zzz
 unit: sectors
 first-lba: 2048
 last-lba: 2097118
-$imgs/zzz1 : start=        2048, size=      591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
 $imgs/zzz4 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
 
     runas testuser systemd-repart --definitions="$defs" \
index 7673036335044280a665fa20ad49a08b15ef7c06..8e4653312baf0fee5c8977f06c4527201e3c58db 100755 (executable)
@@ -243,6 +243,7 @@ EOF
     echo "${FUNCNAME[0]}: test failover"
     local device expected link mpoint part
     local -a devices
+    mkdir -p /mnt
     mpoint="$(mktemp -d /mnt/mpathXXX)"
     wwid="deaddeadbeef0000"
     path="/dev/disk/by-id/wwn-0x$wwid"
index b1cf7e83c4b5b5d37fcd3428ff3a1bac49e4a2dc..89cd2a3f827ad9b3193a9580a6e9f8cfbbc54c99 100755 (executable)
@@ -102,8 +102,17 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
     openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out "/tmp/pcrsign-private.pem"
     openssl rsa -pubout -in "/tmp/pcrsign-private.pem" -out "/tmp/pcrsign-public.pem"
 
+    MEASURE_BANKS=("--bank=sha256")
+    # Check if SHA1 signatures are supported
+    #
+    # Some distros have started phasing out SHA1, so make sure the SHA1
+    # signatures are supported before trying to use them.
+    if echo hello | openssl dgst -sign /tmp/pcrsign-private.pem -sha1 >/dev/null; then
+        MEASURE_BANKS+=("--bank=sha1")
+    fi
+
     # Sign current PCR state with it
-    /usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: | tee "/tmp/pcrsign.sig"
+    /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: | tee "/tmp/pcrsign.sig"
     dd if=/dev/urandom of=/tmp/pcrtestdata bs=1024 count=64
     systemd-creds encrypt /tmp/pcrtestdata /tmp/pcrtestdata.encrypted --with-key=host+tpm2-with-public-key --tpm2-public-key="/tmp/pcrsign-public.pem"
     systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" | cmp - /tmp/pcrtestdata
@@ -113,7 +122,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
     systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" > /dev/null && { echo 'unexpected success'; exit 1; }
 
     # Sign new PCR state, decrypting should work now.
-    /usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig2"
+    /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig2"
     systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig2" | cmp - /tmp/pcrtestdata
 
     # Now, do the same, but with a cryptsetup binding
@@ -135,7 +144,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
     SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; }
 
     # But once we sign the current PCRs, we should be able to unlock again
-    /usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig3"
+    /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig3"
     SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1
     /usr/lib/systemd/systemd-cryptsetup detach test-volume2
     SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1
index 8141ec1b1f81260ac9b012b58bbca8695fb51be6..6f08362e7c2dbc2ac5d9746f9a885f4163820bb7 100755 (executable)
@@ -15,8 +15,8 @@ systemd-cgtop --cpu=percentage
 systemd-cgtop --cpu=time
 systemd-cgtop -P
 systemd-cgtop -k
-# FIXME: https://github.com/systemd/systemd/issues/25248
-#systemd-cgtop --recursive=no
+systemd-cgtop --recursive=no -P
+systemd-cgtop --recursive=no -k
 systemd-cgtop --depth=0
 systemd-cgtop --depth=100
 
@@ -29,4 +29,5 @@ systemd-cgtop -p -t -c -m -i
 (! systemd-cgtop --order=foo)
 (! systemd-cgtop --depth=-1)
 (! systemd-cgtop --recursive=foo)
+(! systemd-cgtop --recursive=no)
 (! systemd-cgtop --delay=1foo)
index fdea34b5c8918899e8ee780d957ebfa24a9d1b5c..36e265edfee7384ff1b4d2f329f247fade7f6097 100755 (executable)
@@ -24,6 +24,12 @@ ROOT_HASHED_PASSWORD1='$6$foobarsalt$YbwdaATX6IsFxvWbY3QcZj2gB31R/LFRFrjlFrJtTTq
 # shellcheck disable=SC2016
 ROOT_HASHED_PASSWORD2='$6$foobarsalt$q.P2932zYMLbKnjFwIxPI8y3iuxeuJ2BgE372LcZMMnj3Gcg/9mJg2LPKUl.ha0TG/.fRNNnRQcLfzM0SNot3.'
 
+# Debian and Ubuntu use /etc/default/locale instead of /etc/locale.conf. Make
+# sure we use the appropriate path for locale configuration.
+LOCALE_PATH="/etc/locale.conf"
+[ -e "$LOCALE_PATH" ] || LOCALE_PATH="/etc/default/locale"
+[ -e "$LOCALE_PATH" ] || systemd-firstboot --locale=C.UTF-8
+
 # Create a minimal root so we don't modify the testbed
 ROOT=test-root
 mkdir -p "$ROOT/bin"
@@ -31,14 +37,14 @@ mkdir -p "$ROOT/bin"
 touch "$ROOT/bin/fooshell" "$ROOT/bin/barshell"
 
 systemd-firstboot --root="$ROOT" --locale=foo
-grep -q "LANG=foo" "$ROOT/etc/locale.conf"
-rm -fv "$ROOT/etc/locale.conf"
+grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
+rm -fv "$ROOT$LOCALE_PATH"
 systemd-firstboot --root="$ROOT" --locale-messages=foo
-grep -q "LC_MESSAGES=foo" "$ROOT/etc/locale.conf"
-rm -fv "$ROOT/etc/locale.conf"
+grep -q "LC_MESSAGES=foo" "$ROOT$LOCALE_PATH"
+rm -fv "$ROOT$LOCALE_PATH"
 systemd-firstboot --root="$ROOT" --locale=foo --locale-messages=bar
-grep -q "LANG=foo" "$ROOT/etc/locale.conf"
-grep -q "LC_MESSAGES=bar" "$ROOT/etc/locale.conf"
+grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
+grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
 
 systemd-firstboot --root="$ROOT" --keymap=foo
 grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf"
@@ -82,8 +88,8 @@ systemd-firstboot --root="$ROOT" \
                   --root-password-hashed="$ROOT_HASHED_PASSWORD2" \
                   --root-shell=/bin/barshell \
                   --kernel-command-line="hello.world=0"
-grep -q "LANG=foo" "$ROOT/etc/locale.conf"
-grep -q "LC_MESSAGES=bar" "$ROOT/etc/locale.conf"
+grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
+grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
 grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf"
 readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$"
 grep -q "foobar" "$ROOT/etc/hostname"
@@ -103,8 +109,8 @@ systemd-firstboot --root="$ROOT" --force \
                   --root-password-hashed="$ROOT_HASHED_PASSWORD2" \
                   --root-shell=/bin/barshell \
                   --kernel-command-line="hello.world=0"
-grep -q "LANG=locale-overwrite" "$ROOT/etc/locale.conf"
-grep -q "LC_MESSAGES=messages-overwrite" "$ROOT/etc/locale.conf"
+grep -q "LANG=locale-overwrite" "$ROOT$LOCALE_PATH"
+grep -q "LC_MESSAGES=messages-overwrite" "$ROOT$LOCALE_PATH"
 grep -q "KEYMAP=keymap-overwrite" "$ROOT/etc/vconsole.conf"
 readlink "$ROOT/etc/localtime" | grep -q "/CET$"
 grep -q "hostname-overwrite" "$ROOT/etc/hostname"
@@ -118,7 +124,7 @@ rm -fr "$ROOT"
 mkdir "$ROOT"
 # Copy everything at once (--copy)
 systemd-firstboot --root="$ROOT" --copy
-diff /etc/locale.conf "$ROOT/etc/locale.conf"
+diff $LOCALE_PATH "$ROOT$LOCALE_PATH"
 diff <(awk -F: '/^root/ { print $7; }' /etc/passwd) <(awk -F: '/^root/ { print $7; }' "$ROOT/etc/passwd")
 diff <(awk -F: '/^root/ { print $2; }' /etc/shadow) <(awk -F: '/^root/ { print $2; }' "$ROOT/etc/shadow")
 [[ -e /etc/vconsole.conf ]] && diff /etc/vconsole.conf "$ROOT/etc/vconsole.conf"
@@ -127,7 +133,7 @@ rm -fr "$ROOT"
 mkdir "$ROOT"
 # Copy everything at once, but now by using separate switches
 systemd-firstboot --root="$ROOT" --copy-locale --copy-keymap --copy-timezone --copy-root-password --copy-root-shell
-diff /etc/locale.conf "$ROOT/etc/locale.conf"
+diff $LOCALE_PATH "$ROOT$LOCALE_PATH"
 diff <(awk -F: '/^root/ { print $7; }' /etc/passwd) <(awk -F: '/^root/ { print $7; }' "$ROOT/etc/passwd")
 diff <(awk -F: '/^root/ { print $2; }' /etc/shadow) <(awk -F: '/^root/ { print $2; }' "$ROOT/etc/shadow")
 [[ -e /etc/vconsole.conf ]] && diff /etc/vconsole.conf "$ROOT/etc/vconsole.conf"
@@ -140,8 +146,8 @@ touch "$ROOT/bin/fooshell" "$ROOT/bin/barshell"
 # We can do only limited testing here, since it's all an interactive stuff,
 # so --prompt and --prompt-root-password are skipped on purpose
 echo -ne "\nfoo\nbar\n" | systemd-firstboot --root="$ROOT" --prompt-locale
-grep -q "LANG=foo" "$ROOT/etc/locale.conf"
-grep -q "LC_MESSAGES=bar" "$ROOT/etc/locale.conf"
+grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
+grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
 echo -ne "\nfoo\n" | systemd-firstboot --root="$ROOT" --prompt-keymap
 grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf"
 echo -ne "\nEurope/Berlin\n" | systemd-firstboot --root="$ROOT" --prompt-timezone
index 1a656fcdc1a09eb9455db4b0b1e7e52321939a04..0c68e0636f92b692ab54eaf3effeff299f3355ab 100755 (executable)
@@ -56,6 +56,17 @@ echo nameserver 10.0.3.3 10.0.3.4 | "$RESOLVCONF" -a hoge.foo.dhcp
 assert_in '10.0.3.1 10.0.3.2' "$(resolvectl dns hoge)"
 assert_in '10.0.3.3 10.0.3.4' "$(resolvectl dns hoge.foo)"
 
+# Tests for _localdnsstub and _localdnsproxy
+assert_in '127.0.0.53' "$(resolvectl query _localdnsstub)"
+assert_in '_localdnsstub' "$(resolvectl query 127.0.0.53)"
+assert_in '127.0.0.54' "$(resolvectl query _localdnsproxy)"
+assert_in '_localdnsproxy' "$(resolvectl query 127.0.0.54)"
+
+assert_in '127.0.0.53' "$(dig @127.0.0.53 _localdnsstub)"
+assert_in '_localdnsstub' "$(dig @127.0.0.53 -x 127.0.0.53)"
+assert_in '127.0.0.54' "$(dig @127.0.0.53 _localdnsproxy)"
+assert_in '_localdnsproxy' "$(dig @127.0.0.53 -x 127.0.0.54)"
+
 # Tests for mDNS and LLMNR settings
 mkdir -p /run/systemd/resolved.conf.d
 {
index 63e523bb3e8068ad60d9c2819622dc98cda5aa1c..ef5577549e4ad62fe1b18a166a71f38157a16c6d 100644 (file)
@@ -17,8 +17,8 @@ Conflicts=shutdown.target initrd-switch-root.target
 Before=shutdown.target initrd-switch-root.target
 
 # Only run this if the boot loader can support random seed initialization.
-ConditionPathExists|=/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
-ConditionPathExists|=/sys/firmware/efi/efivars/StubFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
+ConditionPathExists=|/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
+ConditionPathExists=|/sys/firmware/efi/efivars/StubFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
 
 # Only run this if there is no system token defined yet
 ConditionPathExists=!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
index 10d8b08c8e03e6c27e4bd233efa5f8557f091098..09698fc535d2090fd4259372bd4b1e7759019df6 100644 (file)
@@ -12,7 +12,7 @@ Description=Wait for Network to be Configured
 Documentation=man:systemd-networkd-wait-online.service(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-Requires=systemd-networkd.service
+BindsTo=systemd-networkd.service
 After=systemd-networkd.service
 Before=network-online.target shutdown.target
 
index 949695f53e2139b95b7ef64102f04584fb263811..2fae26d1c0cef483fd7d995ac7a01c163cd16a3f 100644 (file)
@@ -12,7 +12,7 @@ Description=Wait for Network Interface %i to be Configured
 Documentation=man:systemd-networkd-wait-online.service(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-Requires=systemd-networkd.service
+BindsTo=systemd-networkd.service
 After=systemd-networkd.service
 Before=network-online.target shutdown.target