Commit Graph
6944 Commits
Author SHA1 Message Date
dongshengyuan aa776aefba machine-id-setup: follow symlink target on --commit
Resolve /etc/machine-id before checking the mount state and before
writing back, so symlinked targets are committed correctly.

Fixes: #43104
Follow-up for: efabf4e044
2026-07-24 14:10:30 +09:00
gkehren 9d217e051b core: tolerate kernels without POSIX mqueue support
PrivateIPC= sets up a private mqueue mount for the service. When
CONFIG_POSIX_MQUEUE is disabled, mounting mqueue fails with ENODEV and
prevents the service from starting.

Treat ENODEV as an unavailable optional kernel feature while preserving
the private IPC namespace. Keep all other mount errors fatal.

Add coverage verifying that PrivateIPC= still creates a separate IPC
namespace when POSIX message queues are unavailable.

Fixes #42582
2026-07-24 13:44:59 +09:00
Ananth 34c60f113e timer: clamp future calendar base after clock jumps back
A calendar timer that is already waiting keeps the base timestamp it was
last armed from. When the wall clock is set backwards, that base can end
up in the future relative to the new realtime, and passing it to
calendar_spec_next_usec() schedules the next elapse relative to the old
future time instead of recalculating from now. systemctl list-timers
then keeps showing the stale pre-adjustment elapse (e.g. "3 years left"
after the clock moved back two years) and the timer never catches up.

Clamp the selected calendar base to the current realtime before asking
calendar_spec_next_usec() for the next occurrence. The clamp only kicks
in when the base is genuinely in the future, so Persistent=yes timers
whose last trigger is still in the past keep their catch-up behaviour and
we don't reintroduce the missed-run regression seen after suspend.

Fixes #6036.
2026-07-24 01:54:40 +09:00
Zbigniew Jędrzejewski-Szmek af4c5730e5 meson: disable dlopen tests by default, enable in gcc github workflow
1f76654f94 added support to build .standalone
variants of most binaries. test-dlopen-note.py is hooked in the test suite for
everything that can do .standalone, but this means that the .standalone
variants become a prerequisite for tests. This means that meson will build the
.standalone variants for all binaries before running tests, which takes quite a
bit of time in some situations. (Arguably, the dlopen test suite was excluded
by default, so maybe meson could be smart and figure out that those tests are
not enabled by default. But it doesn't seem to make this distinction.)
2026-07-24 01:51:22 +09:00
dongshengyuan 8a5c8b751b machined: refresh resolve hook addresses per machine
Track which machine the cached address list belongs to and refresh it
when ResolveRecord() advances to another machine. This keeps A/AAAA
reuse for the same machine while avoiding mixed name/address records.

Reproducer: register two machines with private addresses 10.88.1.1
and 10.88.2.1, then call io.systemd.Resolve.Hook.ResolveRecord
with both A questions in one request.

Before: the answer for the second machine used its own name but
reused the first machine's address, e.g. resolve-bug-m2 returned
10.88.1.1 instead of 10.88.2.1.

Follow-up: 3cd929f837
2026-07-23 13:19:11 +09:00
Luca Boccassi 765dc96746 homed: verify privileged worker changes
Workers may return a newer embedded identity while processing
an owner update. Accept self-modifiable changes, but require
privileged changes to carry a trusted signature.

Follow-up for 70a5db5822
2026-07-22 17:11:08 +02:00
Yu Watanabe bda98358d2 tools: reject invalid inputs and align machine-readable output (#43040) 2026-07-21 12:23:00 +09:00
Ross Burton ab9be70e94 hwdb: strip the root from filenames when generating hwdb.bin
The modern hwdb.bin format contains the filenames of the input data that
makes up the database.  This is useful but in offline builds where
--root is used, the filenames are the full build paths including the
specified root.  This introduces build paths and thus information
leakage and non-reproducible data.

Solve this by stripping the root prefix off the original path when
passing to import_file.

Add TEST-17-UDEV.hwdb.sh to verify that hwdb.bin files contain the
path inside the root, but not the path of the root.
2026-07-20 14:31:15 +01:00
Nandakumar Raghavan 13aec9fddf networkctl,networkd: add --no-reconfigure flag to networkctl reload
Add a new --no-reconfigure flag to 'networkctl reload' that reloads
.network and .netdev files from disk without reconfiguring any network
interfaces. This may be useful to avoid reconfiguring multiple interfaces
simultaneously when multiple .network files are updated, or when an updated
.network file is applied to multiple interfaces.

On the networkd side, manager_reload() gains a reconfigure_links parameter
that gates the per-link reconfiguration loop. A new io.systemd.Network.Reload
varlink method is added that exposes this as an optional reconfigureLinks
boolean (defaults to true). Both plain 'networkctl reload' and
'--no-reconfigure' now unconditionally call this method first. If an older
networkd returns MethodNotFound, plain reload falls back to
io.systemd.service.Reload for backward compatibility; '--no-reconfigure'
fails with a clear error in that case.
2026-07-20 14:35:04 +09:00
Zbigniew Jędrzejewski-Szmek 0f81431e35 portable: tighten image handling and command error reporting (#43033)
Let's further improve portable image handling and command error
reporting.
2026-07-19 21:09:24 +02:00
dongshengyuan 7a81ad4b6b creds: reject empty validity intervals
Reject credentials whose not-after timestamp is equal to the timestamp
at each encryption entry point.

Reproducer: systemd-creds --timestamp=TS --not-after=TS encrypt in out

Before: encryption succeeded, but decrypt refused the credential as not
in order.

Follow-up: 21bc0b6fa1
2026-07-18 15:53:00 +08:00
dongshengyuan dab2a82a30 dissect: include image size in JSON output
Use the image metadata size when building JSON output, matching the
value already shown by the text output.

Reproducer: systemd-dissect --json=short image.raw

Before: text output showed Size, but JSON omitted the top-level size
field.

Follow-up: be5bee2a13
2026-07-18 15:53:00 +08:00
dongshengyuan 928cc86772 sysupdate: keep JSON check-new exit status consistent
Return failure for --json check-new when no candidate is available.
Let sysupdated accept that exact JSON no-update result from workers.

Reproducer: systemd-sysupdate --verify=no --json=short check-new

Before: the command printed {"available":null} and exited successfully.

Follow-up: 42c0b689a8
2026-07-18 15:53:00 +08:00
dongshengyuan e7e68ec449 repart: skip generated files during dry runs
Skip generated fstab and crypttab output when --dry-run=yes is used,
after confirming there is eligible content to generate.

Reproducer: systemd-repart --dry-run=yes --generate-fstab=/tmp/root/etc/fstab -

Before: the command exited successfully and still wrote the requested
fstab file.

Follow-up: 1a0541d44c
2026-07-18 15:48:34 +08:00
dongshengyuan 50eaa51ce1 firstboot: validate root shell credentials
Validate passwd.shell.root after reading the credential so it uses
the same target-root shell checks as --root-shell= and prompted input.

Reproducer: CREDENTIALS_DIRECTORY=... systemd-firstboot --root=...
with passwd.shell.root=/bin/nonexistentshell

Before: /etc/passwd was written with the nonexistent root shell and
the command exited successfully.

Follow-up: 416f7b3a11
2026-07-18 15:48:34 +08:00
dongshengyuan 05b49871a2 sysusers: validate shell credentials
Validate passwd.shell.<user> credentials with the same login-shell
rules used for sysusers.d shell fields before writing passwd entries.

Reproducer: CREDENTIALS_DIRECTORY=... systemd-sysusers --root=...
with --inline 'u creduser 999 "Cred User" / -'

Before: relative-shell was written as the login shell and the command
exited successfully.

Follow-up: 99e9f896fb
2026-07-18 15:48:34 +08:00
dongshengyuan 8729fa0e4b id128: reject app-specific IDs for new
Reject --app-specific= for the new verb. The option only makes sense
for verbs that derive IDs from an existing base ID.

Reproducer: systemd-id128 new --app-specific=4f68bce3e8cd4db196e7fbcaf984b709

Before: the command printed a random ID and exited successfully.

Follow-up: 0d1d512f7f
2026-07-17 11:09:34 +08:00
Yu Watanabe 4d4e9be0ea Assorted remote/shared/resolved hardening fixes flagged by kres (#42978) 2026-07-17 01:12:32 +09:00
Frantisek Sumsal f9348b3bc8 discover-image: don't ignore symlinks to raw images
Since 5c6bb28999 image_discover() uses
chaseat() to chase the path to the image. This however breaks the raw
image check in image_make() as "path" is now not the symlink itself, but
the symlink target.

So with:

$ ls -l /var/lib/machines
total 872104
lrwxrwxrwx. 1 root root         12 Jul 14 06:10 foo.raw -> foo.squashfs
-rw-r--r--. 1 root root 5368709120 Jul 13 02:07 foo.squashfs

The endswith(path, ".raw") check is now performed on "/.../foo.squashfs"
instead of "/.../foo.raw", making it false and thus ignoring the image
symlink completely.

Address this by also checking if the pretty name is set - if so, and the
path is a regular file, the caller must've been image_find() or
image_discover() which already checked if the original path ends in .raw
and is a regular file.

Follow-up for 5c6bb28999.

Resolves: #41656
2026-07-16 14:31:32 +02:00
Luca Boccassi 0755bb125c homed: fix verification of local identity file
Follow-up for 70a5db5822
2026-07-16 14:24:18 +02:00
Luca Boccassi cec14f99d2 sysupdate: add config file with metadata for sysupdate components (#42651)
This carries some metadata for components. It's supposed to grow a bit,
and include a way to enable/disable transfers, and to condition them.
2026-07-16 12:48:10 +01:00
Lennart Poettering d14c40919a ci: add test suite for verity+luks disk images 2026-07-16 07:10:07 +02:00
dongshengyuan 75d2686794 portable: honor --force for directory extensions
Pass relax_extension_release_check through the directory extraction
path instead of hardcoding false. Directory extensions now honor the
same --force relaxation as dissected images.

Reproducer:
  cp -a /tmp/app0 /tmp/app10
  sudo portablectl attach --force --runtime \
      --extension /tmp/app10 /tmp/rootdir app0

Before:
  directory image extraction always used strict extension-release name
  checks. --force relaxed other extension paths but still rejected a
  renamed directory extension with matching metadata.

Follow-up: 06768b90a3
2026-07-16 10:03:19 +08:00
Luca Boccassi 9d4cb85cf5 sysext: validate work directory metadata before removal
unmerge_hierarchy() joined the persisted work_dir value directly with
--root=. An empty value therefore resolved to the root itself and was passed
to rm_rf().

Require the decoded metadata to name a non-empty, safe, normalized relative
path before constructing the removal target. Add coverage using a disposable
root with deliberately emptied metadata.

Follow-up for 9cfad502f4
2026-07-15 21:13:24 +01:00
dongshengyuan cb7b533b92 journalctl: reject field listing with filters
Reproducer:
  journalctl -F _SYSTEMD_UNIT -u test.service --no-pager
  journalctl -u test.service --no-pager -n 1

Before, the field listing ignored the unit filter and listed unrelated
units, while the normal journal query applied the filter.

sd_journal_query_unique() cannot represent journalctl filters such as
unit, boot, time, cursor, or grep filters. Walking the journal line by
line would make field listing linear in the number of entries and
duplicate unique-value handling.

Keep the scope-option predicate next to add_filters(), and reject field
listings combined with options that actually limit the journal.
Display-only options such as --pager-end are left alone.
2026-07-16 01:52:39 +09:00
dongshengyuan 3121e14658 journalctl: use root machine ID for namespaces
journalctl --root=... --list-namespaces scans the target root's
journal tree, but used the host machine ID when matching namespace
directories.

Reproducer:
  root="$(mktemp -d)"
  mid=11111111111111111111111111111111
  mkdir -p "$root/etc" "$root/var/log/journal/$mid.testns"
  printf '%s\n' "$mid" >"$root/etc/machine-id"
  journalctl --root="$root" --list-namespaces --quiet

Before:
  no output

Follow-up for: 68f66a1713.
2026-07-16 01:26:46 +09:00
Aritra Basu 08bebda611 network: add IPv4ProxyARPAddress= and consolidate proxy ARP/NDP handling
This adds an IPv4 counterpart to `IPv6ProxyNDPAddress=` for adding
manual entries to the kernel's IPv4 neighbour proxy table (check via
`ip -4 neighbour show proxy dev <dev>`). systemd-networkd only exposed
`IPv4ProxyARP=` for per-interface `proxy_arp` sysctl (automatic proxy
ARP) with no way to manage manual entries from a .network file.

To avoid duplicating the IPv6 proxy NDP code path, both families are
now combined into a single new `networkd-neighbor-proxy` module. The
IPv6 behaviour is preserved: `IPv6ProxyNDPAddress=` still implies
`IPv6ProxyNDP=yes` unless `IPv6ProxyNDP=` is explicitly disabled and
entries are still dropped if the kernel has no IPv6 support.
The same rule is applied to `IPv4ProxyARPAddress=`. It implies
`IPv4ProxyARP=yes` when the sysctl is not explicitly set and has no
effect if `IPv4ProxyARP=` has been set to false.

This keeps the user model symmetric and predictable across both
families: a single per-address setting that turns on the matching
per-interface sysctl automatically, while still letting system
administrators opt out by setting the boolean explicitly to false.

Note that the IPv4 manual NTF_PROXY entries installed here would
actually function without `proxy_arp` (unlike IPv6, where `proxy_ndp`
gates the manual entries); the implication is kept for symmetry with
`IPv6ProxyNDPAddress=` and is now called out explicitly in the man
page, together with the fact that enabling `proxy_arp` also activates
interface-wide automatic proxy ARP for routed-toward addresses on
connected subnets.

Parser-time validation rejects addresses the kernel would refuse:
the ANY/null address for both families, IPv4 and IPv6 multicast
and the IPv4 limited broadcast 255.255.255.255.

Signed-off-by: Aritra Basu <aritrbas+gh@cisco.com>
2026-07-16 01:23:40 +09:00
Lennart Poettering b0cf7d60ac ci: add test for the various new sysupdate features 2026-07-15 13:27:48 +02:00
dongshengyuan 018c2b229f portablectl: normalize remove image paths
Normalize each remove argument with determine_image() before building
the RemoveImage request. Relative paths are converted before reaching
portabled.

Reproducer:
  cd /tmp
  portablectl remove ./portable-repro

Before:
  ./portable-repro was sent unchanged to portabled and rejected as an
  invalid image name/path. Removing an image by a relative path failed
  even though the path referred to a valid local image.

Follow-up: 61d0578b07
2026-07-15 18:16:29 +08:00
dongshengyuan 797dd11524 portable: keep unit symlinks inside the image
Open unit files with chase_and_openat() rooted at the image instead of
plain openat(). Symlinks are now resolved under the image root and must
end at a regular file.

Reproducer:
  ln -s /tmp/portable-host-unit \
      IMAGE/usr/lib/systemd/system/PREFIX.service
  portablectl inspect --cat IMAGE PREFIX.service

Before:
  inspect followed the absolute symlink on the host and printed host
  file contents as image unit metadata. Image inspection could leak or
  trust files outside the portable image.

Follow-up: 61d0578b07
2026-07-15 18:16:29 +08:00
dongshengyuan 9773189e56 portablectl: keep inspect --force unit metadata
Parse the WithExtensions metadata block whenever --force selects that
bus method. This keeps the following unit-file array aligned with the
reply layout.

Reproducer:
  portablectl inspect --force /usr/share/minimal_0.raw \
      minimal-app0.service

Before:
  inspect printed the image metadata but dropped the matching unit
  list. Scripts could not see which unit files were selected when
  --force was used with the WithExtensions bus reply.

Follow-up: bdfa3f3a5c
2026-07-15 16:30:15 +08:00
Daan De Meyer 28b1e4ea16 repart: make COW behavior configurable
systemd-repart currently forces newly created image files into NOCOW mode.
That prevents files from being reflinked into the image, making image builds
slower and increasing their disk usage on filesystems that support cloning.

Add a tristate --cow= option. By default, leave the filesystem or parent
directory COW policy unchanged. With --cow=yes, explicitly enable COW; with
--cow=no, retain the previous behavior of forcing NOCOW. Add XO_COW as the
counterpart to XO_NOCOW so xopenat_full() applies either policy while retaining
its normal creation-error cleanup.

Document the new option and extend TEST-58-REPART to verify inherited COW and
NOCOW policies as well as explicit COW and NOCOW overrides. Compare the unset
behavior with the filesystem default so the test also works on nodatacow
mounts, and skip it when the inode attribute is unsupported.

Signed-off-by: Daan De Meyer <daan@amutable.com>
2026-07-15 09:22:58 +02:00
Luca Boccassi bd612520e4 bcd, id128, sysupdate: tighten edge-case handling (#43018) 2026-07-15 00:03:03 +01:00
Lennart Poettering e6acf0bab7 resolved: fix spurious BrowseServices add/remove flapping with ifindex=0 (#42982)
## Problem
A `BrowseServices` subscription with `"ifindex":0` (browse all
interfaces) receives a continuous flap of `added`/`removed` events for a
service that is still present — within a second, and with no goodbye
packet involved.

## Root cause
For `ifindex==0`, `mdns_browser_revisit_cache()` looked up each mDNS
scope's cache separately and called `mdns_manage_services_answer()`
**once per scope**. That function derives `removed` events by diffing
the browser's *global* discovered-service list (all interfaces, filtered
only by owner family) against the single answer it's handed. So with ≥2
mDNS-relevant interfaces of the same family, a service present on
interface A isn't in interface B's answer and is spuriously removed
while B is reconciled, then re-added on the next revisit tick.

## Fix
Accumulate the pruned cache answers from every matching mDNS scope into
one combined `DnsAnswer` and reconcile **once**, so removals diff the
global list against the union across interfaces. Items are merged with
`dns_answer_add_full()` (not `dns_answer_extend()`, which defaults each
item's `until` to `USEC_INFINITY` and would skew the RFC 6762 §5.2
TTL-maintenance schedule). The single-interface (`ifindex>0`) path is
unchanged.

## Test
`TEST-89-RESOLVED-MDNS.sh` gains `testcase_browse_ifindex_zero_no_flap`:
it adds a service-less dummy mDNS link to guarantee ≥2 same-family
scopes (the flap precondition), browses `ifindex=0`, waits for
discovery, then asserts **zero** `removed` events while every publisher
stays up. The subscription uses `varlinkctl --timeout=infinity`, since
it sits idle after discovery and the default 45s idle timeout would
sever it (and the assertion) mid-observation.

## Testing status
Builds clean; `shellcheck -x` clean. First CI round: `TEST-89`
(including this testcase) passed on all mkosi platforms; the failing
jobs all traced to unrelated flakes/infra.
2026-07-14 23:58:34 +02:00
Lennart Poettering 64a3846ced sysupdate: Add ListFeatures() and ListTargets() varlink methods (#42900)
Following on from adding the basic varlink scaffolding to sysupdate,
let’s varlinkify a couple of the D-Bus methods. Because varlink doesn’t
have a concept of object paths, the D-Bus path structure which allows a
target to be selected has been squashed down to a target argument for
each relevant method.

Varlinkify the way to list targets, and also the way to list features
because that was simple to do at the same time.

More methods need varlinkifying in the future, but let’s do it in small
and manageable chunks.
2026-07-14 23:14:22 +02:00
Philip Withnall f6cd126137 test: Remove a redundant exit call
`[[ blah ]] || exit 1` is equivalent to `[[ blah ]]`.

Fixes: b0ca987cd9
2026-07-14 14:57:39 +01:00
Philip Withnall 8cb7531390 sysupdate: Add varlink ListTargets() method
And add integration tests for it using `jq`.
2026-07-14 14:57:31 +01:00
Philip Withnall 3e34ccf6df sysupdate: Add varlink ListFeatures() method
And add integration tests for it using `jq`.
2026-07-14 14:57:13 +01:00
Jonas Dreßler 04e3d8933b repart: Properly pre-calculate auto size of images
When passing --size=auto to repart, it will pre-calculate the image size and
resize the image to that size before partitioning. Currently, that fails when
passing a large grain size, complaining that the auto-sized image is too small
to fit the data.

The reason for this is that the current code simply assumes the GPT metadata
size taken away from the usable size by fdisk is static (1044KiB), when it
actually is more complicated than that:

There's two ranges of GPT metadata: One at the beginning of the image, and one
at the end of the image. And there's the first usable block that is defined by
fdisk when creating the partition table.

The static value of 1044KiB usually works, because fdisk sets the first usable
block to 1MiB (so 1024KiB), leaving 20KiB of leeway for the secondary GPT at
the end of the image.

Now as soon as the first partition starts at an offset higher than 1024KiB, we
lose the 20KiB leeway for the secondary GPT, and the partitions will no longer
fit.

What we should do, is first of all round up to the grain size instead of 4096
(as that's the minimum offset our first partition will start at), and second of
all properly subtract the secondary GPT at the end.

Also confirm we don't regress on this anymore by adding a test that uses a 2MiB
grain size, breaking the old code.
2026-07-14 12:46:50 +01:00
dongshengyuan 9ed8392a3c sysupdate: print version details once
list VERSION printed the version status header twice in plain output.

Keep the complete later header and add a regression check.

Follow-up for: 42c0b689a8.
2026-07-14 18:52:52 +08:00
dongshengyuan e72d9b0d70 id128: honor json output for single ids
JSON mode was accepted by single-ID verbs but still printed bare IDs.

Print JSON objects for those verbs and reject ambiguous JSON combinations.

Follow-up for: a50666e376.
2026-07-14 18:52:26 +08:00
Luca Boccassi a5ac81ae4c systemd-run: reject unsupported option combinations (#43003)
Boundary tests were conducted on the "run" command tool, and the
identified issues were resolved.
2026-07-14 11:29:11 +01:00
Lennart Poettering 89025e8f86 repart: Fix growing the partition preceding a FreeArea from leftover space (#42969)
The "Donate to preceding partition" logic is dead code since commit

https://github.com/jonas2515/systemd/commit/19903a433507897449c086b72abb5e133e431336
("repart: split out context_grow_partition_one()").
context_grow_partition_one() gets passed a free area and a partition,
and it has
an early-return check to ensure the partition it got passed belongs to
the free
area it got passed. That means we compare the FreeArea a to the FreeArea
a->after->allocated_to_area, which always yields FALSE.

Fix the behavior of donating any left over space to the preceding
partition
by adding that partition to the loop below (and relying on the
partitions list
being ordered according to physical partition offsets).

Since this behavior is not that easy to trigger, mention how to trigger
it in a
comment, and add a test for it as well.
2026-07-14 11:27:57 +02:00
dongshengyuan 63b30468a5 portablectl: retry inspect with PORTABLE_PREFIXES
When no prefix is specified, portablectl inspect first tries the
prefix derived from the image name. This keeps inspect aligned with
attach behavior.

If that lookup finds no matching units, retry with validated
PORTABLE_PREFIXES read from the image os-release. This makes inspect
work for images whose filename does not match their portable service
prefix.

Keep metadata error handling explicit so request-construction failures
are not logged twice, while sd_bus_call() failures still include the
inspect context.

Add a TEST-29-PORTABLE regression case for a directory image whose
name does not match the portable service prefix.

Fixes #37296.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-14 11:26:40 +02:00
dongshengyuan 34649e3d66 sysext: honor confext config during notify refresh
systemd-sysext handles the sysupdate notification hook,
but the hook refreshes both sysexts and confexts.

Build the refresh context for each image class so confext settings,
such as Mutable=yes, are applied when confexts are refreshed.

Add regression coverage for the mutable confext overlay.

Fixes #42873
Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-14 11:26:10 +02:00
dongshengyuan 06247b0804 run: reject waiting for remain-after-exit services
Reproducer:
  unit=run-wait-rae-$(date +%s)
  sudo timeout 3s systemd-run --wait --remain-after-exit \
      --unit="$unit" /bin/true
  echo $?
  systemctl is-active "$unit.service"

Before, the command timed out with exit status 124 while the service
stayed active. --wait waits for deactivation, but RemainAfterExit=yes
keeps the service active after the command exits.

Follow-up for 2a453c2ee3
2026-07-14 12:03:22 +08:00
dongshengyuan 7e76e93142 run: reject JSON output with verbose logs
Reproducer:
  sudo systemd-run --wait --verbose --json=short /bin/echo hi

Before, systemd-run printed JSON metadata to stdout while --verbose
also spawned journalctl output on stdout. The resulting stream mixed JSON
with journal lines, so reject the conflicting options.

Follow-up for 744ca8f616
2026-07-14 12:03:22 +08:00
dongshengyuan 2a4750c3e1 run: reject JSON output in scope mode
Reproducer:
  sudo systemd-run --scope --json=short /bin/echo hi

Before, systemd-run printed JSON metadata to stdout and then executed
the scope command on the same stdout. The combined stream was not valid
JSON, so reject --json= in scope mode.

Follow-up for fe5a6c47af
2026-07-14 12:03:22 +08:00
dongshengyuan 3fa641d01f run: reject JSON output for trigger units
Reproducer:
  unit=run-json-trigger-$(date +%s)
  sudo systemd-run --json=short --unit="$unit" \
      --on-active=30s \
      /bin/true

Before, trigger mode accepted --json=short but printed only human-readable
"Running timer as unit" and "Will run service" lines. Reject the option
until trigger mode has structured output.

Follow-up for fe5a6c47af
2026-07-14 12:03:22 +08:00
dongshengyuan ecf38b0e22 run: reject JSON output with stdio forwarding
Reproducer:
  sudo systemd-run --wait --pipe --json=short /bin/echo hi

Before, systemd-run wrote its JSON metadata to stdout and then passed
the command stdout through the same stream. The combined output was not
valid machine-readable JSON, so reject the conflicting modes.

Follow-up for fe5a6c47af
2026-07-14 12:03:22 +08:00