1
0
mirror of https://github.com/systemd/systemd synced 2026-03-10 07:04:46 +01:00

Compare commits

..

61 Commits

Author SHA1 Message Date
Yu Watanabe
ed6a2eaa31
ask-password-api: several modernizations for ask_password_agent(); use CLEANUP_TMPFILE_AT more (#40631) 2026-02-16 20:07:32 +09:00
Daan De Meyer
4e40c2a515
namespace-util: Merge namespace_enter_delegated() into namespace_enter() (#40669)
There's no need to pass in a boolean to decide whether we use
namespace_enter_delegated() or not. Instead, we can just check if we
have CAP_SYS_ADMIN in our own user namespace. If we don't, then we have
to insist on a child user namespace being passed in and we have to enter
it first to get CAP_SYS_ADMIN as without CAP_SYS_ADMIN we wouldn't be
able
to call setns() in the first place. If we do have CAP_SYS_ADMIN, we can
always enter the other namespaces first before entering the user
namespace.

Additionally, we don't fail anymore if we can't reset the UID/GID since
a
root user might not always be available in every user namespace we might
enter.
2026-02-16 11:26:41 +01:00
r-vdp
e271497d97 dns-delegates: add support for setting a firewall mark
This makes it possible to have DNS requests for certain domains routed
differently than normal requests, which is for instance useful when
using policy routing to route traffic over a VPN but DNS requests for
the VPN endpoint itself, should be routed differently.

It doesn't make much sense to configure a firewall mark at the level of
a network interface, but at the level of a DNS delegate it can be very
useful.
2026-02-16 11:09:48 +01:00
Daan De Meyer
a5ceab95ab
Varlink fixlets and several other follow-ups (#40687) 2026-02-16 11:02:08 +01:00
Daan De Meyer
d1e0b59843
oomd: Fix bug where we drop queued kill state on duplicate cgroup (#40690) 2026-02-16 10:52:49 +01:00
Daan De Meyer
211c3c9d41 namespace-util: Merge namespace_enter_delegated() into namespace_enter()
There's no need to pass in a boolean to decide whether we use
namespace_enter_delegated() or not. Instead, we can just check if we
have CAP_SYS_ADMIN in our own user namespace. If we don't, then we have
to insist on a child user namespace being passed in and we have to enter
it first to get CAP_SYS_ADMIN as without CAP_SYS_ADMIN we wouldn't be able
to call setns() in the first place. If we do have CAP_SYS_ADMIN, we can
always enter the other namespaces first before entering the user namespace.

Additionally, we don't fail anymore if we can't reset the UID/GID since a
root user might not always be available in every user namespace we might
enter.
2026-02-16 10:27:02 +01:00
Zbigniew Jędrzejewski-Szmek
dae5af119b
timesync: fix parsing FallbackNTP= (#40692)
Follow-up for 3745770ae4dcf262707882a38f6c5ba2684329a3.
Fixes #40621.
2026-02-16 10:16:21 +01:00
Mike Yuan
389cd296ec
core: serialize metrics varlink server as well 2026-02-16 09:44:58 +01:00
Mike Yuan
5561623ef4
core/manager-serialize: discern daemon-reload/reexec via objective 2026-02-16 09:44:58 +01:00
Mike Yuan
b166461f82
varlink-serialize: deserialize to correct event priority 2026-02-16 09:44:58 +01:00
Mike Yuan
9676845efa
core/varlink: several cleanups for metrics varlink server
Follow-up for bb1ef2edf7d62de35291702635067ee85f09bad5

The commit introduced a new "metrics" varlink server, but for
user scope stuff it is not bound anywhere. The copy-pasted
"fresh" handling for deserialization is also essentially
meaningless as metrics_setup_varlink_server() doesn't even report
whether the varlink server is fresh (let alone that no serialization
is being done at all right now). Moreover, currently the event
priority is hardcoded, while event loop and associated priority
assignment ought to be subject to each daemon.

While fixing the mentioned issues I took the chance to restructure
the existing code a bit for readability. Note that serialization
for the metrics server is still missing - it will be tackled
in subsequent commits.
2026-02-16 09:44:58 +01:00
Yu Watanabe
ba08fa3230
shared/metrics: add two more assertions 2026-02-16 09:44:58 +01:00
Mike Yuan
702db03034
shared/metrics: name the sd_varlink_server in our usual fashion
This is used for internal reference, in debug logging and such,
hence let's do nothing fancy but instead make it identifiable.
2026-02-16 09:44:57 +01:00
Mike Yuan
ba5bd88db3
core/varlink-metrics: suffix metrics methods with _metrics
This is not even the prominent "Describe" method in pid1,
as typically one would be looking for _describe_manager().
2026-02-16 09:44:57 +01:00
Mike Yuan
3cfd35eef9
core/varlink-metrics: include core-forward.h 2026-02-16 09:44:57 +01:00
Mike Yuan
fe48347ce6
core/varlink-cgroup: add BindNetworkInterface to varlink CGContext
Follow-up for c1c787651b34c0a0f1082b9d32cf47ea3abe0af2
2026-02-16 09:44:57 +01:00
Mike Yuan
eeead6e177
sd-varlink: fail if a method call wasn't replied to and the callback didn't store it 2026-02-16 09:44:56 +01:00
Mike Yuan
1f9ba6ba73
sd-varlink: take output queue into account in sd_varlink_flush() 2026-02-16 09:44:56 +01:00
Mike Yuan
86ac1083c9
sd-varlink: _reset_fds() should reset fds for the reply being constructed
... (aka pushed_fds), not what's already enqueued to be sent out.
2026-02-16 09:44:56 +01:00
Mike Yuan
959f6923e5
sd-varlink: use free_and_replace at one more place 2026-02-16 09:44:56 +01:00
Mike Yuan
9257690859
sd-varlink: replace manual move_fd() with FORK_PACK_FDS + FORK_CLOEXEC_OFF
Note that this actually matters: we might otherwise clobber
the logging fds reopened when rearranging fd '3'.

While at it, avoid logging from library functions.
2026-02-16 09:44:56 +01:00
Mike Yuan
122bde2c45
sd-varlink: also validate peer ucred for SD_VARLINK_SERVER_MYSELF_ONLY 2026-02-16 09:44:55 +01:00
Mike Yuan
3482e4dd70
sd-varlink: log about client uid that hit connection limit 2026-02-16 09:44:55 +01:00
Mike Yuan
e2fb041564
sd-varlink: shorten the code a bit 2026-02-16 09:44:55 +01:00
Mike Yuan
097243cc30
repart: io.systemd.Repart.ListCandidateDevices requires 'more' 2026-02-16 09:44:55 +01:00
Mike Yuan
03023fd12c
resolve: io.systemd.Resolve.BrowseServices requires 'more' 2026-02-16 09:44:55 +01:00
Mike Yuan
41e675996d
mute-console: io.systemd.MuteConsole requires 'more' 2026-02-16 09:44:54 +01:00
Mike Yuan
09388a6b9e
tree-wide: drop redundant check for SD_VARLINK_METHOD_MORE flag
If the IDL declares the method requires 'more' yet the call doesn't
have it set, varlink_idl_validate_method_call() should have rejected
it and the callback shouldn't be reached.
2026-02-16 09:44:54 +01:00
Mike Yuan
42ed373294
varlink-io.systemd.Network: minor coding style cleanups
Follow-up for cf27c70d70f5912078f68b66869d16198aaa36a5
2026-02-16 09:44:54 +01:00
Mike Yuan
05d1cfee90
sd-json: unify JSON_BUILD_PAIR_IN?_ADDR_*
This also swaps family and address params for
plain JSON_BUILD(_PAIR)_IN_ADDR, aligning with
_WITH_STRING flavors.
2026-02-16 09:44:54 +01:00
Mike Yuan
926ae62a27
json-util: sort includes 2026-02-16 09:44:53 +01:00
Mike Yuan
daeb7dd390
sd-json: use FOREACH_ARRAY more 2026-02-16 09:44:53 +01:00
Mike Yuan
89769fb4ad
shared: conditionalize build of apparmor-util.c in meson 2026-02-16 09:44:53 +01:00
Mike Yuan
3ac675dff3
process-util: drop unused TAKE_PID
Follow-up for fbd276cb86a2f0292cc19fd57ee3d72bf73592dc

We now track helper processes via PidRef throughout the codebase.
2026-02-16 09:44:53 +01:00
Mike Yuan
36f82366d0
process-util: group oom_score_adjust_is_valid() with getter/setter 2026-02-16 09:44:53 +01:00
Mike Yuan
763f615c3a
log-context: drop redundant forward decl
We consolidated all these into forward.h.
2026-02-16 09:44:52 +01:00
Mike Yuan
e0fb180483
backlight: update comment to match the new clamp value
Follow-up for 4ed1e2ea17e0f29a23d7a3dd65af192def9b3214
2026-02-16 09:44:52 +01:00
Daan De Meyer
e2c1f3ca2a user-util: Don't setgroups() if /proc/self/gid_map is empty
If /proc/self/gid_map is empty, the kernel will refuse setgroups(),
so don't attempt it if that's the case on top of the /proc/self/setgroups
check we already have.
2026-02-16 09:37:32 +01:00
Daan De Meyer
051d228b1c tree-wide: Add some extra debug logging 2026-02-16 09:37:32 +01:00
Daan De Meyer
77b3ddf2aa mkosi: Install musl in tools trees on Fedora/Arch
For debugging purposes.
2026-02-16 09:37:14 +01:00
Lennart Poettering
e1ecec0274 update TODO 2026-02-16 09:06:03 +01:00
Yu Watanabe
618952f07e CODING_STYLE: fix typo
Follow-up for 83b4a5bb3d6a0f565aebcba975efad8dac73abea.
2026-02-16 14:35:21 +09:00
Yu Watanabe
06dca3f629 man: fix typo
Follow-up for 91b3620b07f29342261a3cbdaaaa3f83f21895e1.
2026-02-16 14:34:04 +09:00
Yu Watanabe
c33b112cac sd-varlink: fix typo
Follow-up for c0696f1f5d3a2be1c8e4c8b45ca7e8a6df7998fa.
2026-02-16 14:32:15 +09:00
Yu Watanabe
5ac9a481cd network: fix typo
Follow-up for f8a4c3d375b83f3ee249ca3f4b7f407b618a9491.
2026-02-16 14:30:38 +09:00
Yu Watanabe
3be36e6d64 NEWS: fix typo
Follow-up for 4ed1e2ea17e0f29a23d7a3dd65af192def9b3214.
2026-02-16 14:28:55 +09:00
gvenugo3
2291cf0626 network: implement varlink LinkUp and LinkDown methods
The new varlink methods are basically equivalent to 'ip link set INTERFACE up/down',
but they support polkit authentication. Also, on LinkDown, it gracefully
stops dynamic engines like DHCP client/server before the interface is
bring down. Hence, e.g. an empty RA on stop should be sent.

Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
2026-02-16 14:28:52 +09:00
Yu Watanabe
a48145203c network: use voffsetof() at more places 2026-02-16 14:28:52 +09:00
Yu Watanabe
345208a49b
udev: guess if usb devices are internal external (#40649)
Actually we are defining databases to determine when a usb device is
inherent part of the system or if it's a external device.

Let's use the removable attribute of the port where it is connected to
say that. That gives us the ability to not rely on a particular vendor
only does external devices or to not having the need to be quirking
input subsystem for that purpose that will become unreliable as more and
more internal devices are connected over usb instead over ps2 or i2c
buses. Eg.
02b495e790

Actually this has been seen as reliable in a small set of device from
normal laptops, to detachable ones. The need to check maxchild is 0 is
for detachable devices, pogo pin usbs are fixed, while we attach the
keyboard|touchpad dock the input devices tend to be directly connected
to that port and if the dock has more usbs tend to be a hub that then
exposes removable as unknow. If we don't set maxchild 0 we will not only
guess that the keyboard and touchpad are internal but also incorrectly
other input devices like mice connected to the dock's usb ports.

I have use a very generic name like INTEGRATION because is not actually
used for any other thing and is used to determine not only over usb bus
but for acpi, pci, platform actually.

Also a remap to actual libinput variables is done for compatibility
purposes. if it's possible to have only the INTEGRATION variable instead
multiple ones will be done in the future but is actually unclear.

This can also be used for example to achieve an actual feature that we
lack in linux, when a device with accelerometers and cameras is rotated
the video output is not, this tag the own device cameras as internal
while external ones as external to be able to only do that for the
internal ones.

Note that this has nothing to do with the removable attribute found in
usb storage devices where it's values can be 0 or 1. There is no
conflict at all because the removable attribute we check is specifically
the one found in usb port ones.
2026-02-16 13:25:35 +09:00
Oleksandr Andrushchenko
f8a4c3d375 network: add ModemManager support
[Match]
Name=wwan*

[Network]
LLDP=no
LinkLocalAddressing=no
IPv6AcceptRA=no

[ModemManager]
SimpleConnectPropertie]s=apn=internet ip-type=ipv4 allow-roaming=no pin=1111 operator-id=25503
RouteMetric=200
UseGateway=yes

Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
2026-02-16 13:22:21 +09:00
David Santamaría Rogado
4ed1e2ea17 backlight: reduce clamp to 1%
Actually GNOME sets a clamp of 1% and divides in 20 steps the brightness
control. Using 5% clamp makes things like in a device with max value 640
to always be in the first brightness step in GNOME and we can't leave in
the minimum.

GNOME set steps of 640/20 = 32 with the zero step 640 * 1% = 6. When we
restart the device with the lowest bright systemd sees 6 but sets
640 * 5% = 32, so we get the brightness in the first step.

Tests in IPS and OLED panels have been done and 1% still seems a
comprensive minimun usable value so use that to allow all environments
to be able to set lower brightness values that won't be raised by
systemd at boot.

If your user enviroment allow to set excesive lower unusable values you
should blame it or yourself if you directle changes it through sysfs but
not systemd.
2026-02-16 13:20:55 +09:00
David Santamaría Rogado
a4381cae8b udev: rules: guess devices if internal or external
Set ID_INTEGRATION variable to hint if a device is internal (inherent
part of the system) or external otherwise.
2026-02-16 03:46:25 +01:00
David Santamaría Rogado
babfd9cbaa hwdb: don't error on empty hwdb file 2026-02-16 03:39:08 +01:00
Yu Watanabe
1b1799e9ba timesync: actually disables built-in fallback NTP servers when an empty string is specified
Follow-up for 3745770ae4dcf262707882a38f6c5ba2684329a3.
Fixes #40621.
2026-02-16 09:53:03 +09:00
Yu Watanabe
b0ca2ef264 timesync: return earlier when an empty string is specified 2026-02-16 09:51:36 +09:00
Yu Watanabe
1bb9306f1e timesync: rename have_fallbacks -> fallback_set 2026-02-16 09:50:46 +09:00
Chris Down
e93511b10e oomd: Return tristate status from oomd_cgroup_kill_mark()
oomd_cgroup_kill_mark() currently returns 0 on all non-error paths. But
the manager only logs that it marked for killing on `if (r > 0)`, which
is thus unreachable.

Changing it to `r >= 0` would also be wrong, because then we would log
on no-op paths.

So let's fix this by making the return value express what actually
happened:

- < 0: failure to queue the kill state
-   0: no new mark was created (already queued or dry-run)
- > 0: a new kill state was queued
2026-02-16 01:39:21 +08:00
Chris Down
f4f1956d42 oomd: Fix bug where we drop queued kill state on duplicate cgroup
oomd_cgroup_kill_mark() allocates a temporary OomdKillState and inserts
it into kill_states via set_ensure_put(). This is keyed by cgroup path.
When the same cgroup is already queued, set_ensure_put() dutifully
returns 0.

The function then returns with
_cleanup_(oomd_kill_state_removep) still armed, which eventually calls
oomd_kill_state_free().

oomd_kill_state_free() removes from kill_states by cgroup-path key, so
because this path already exists, it will remove the existing queued
kill state instead of just dropping the temporary object.

This is wrong and results in mistakenly drops the queued kill state on
duplicates.

This can happen when a cgroup is marked multiple times before the first
queued kill state is consumed. The result is lost kill-state tracking
and incorrect prekill/kill sequencing.

Handle r == 0 explicitly by freeing only the temporary object and
leaving the already queued state intact.
2026-02-16 01:39:04 +08:00
Mike Yuan
4153a2a6f4
ask-password-api: several modernizations for ask_password_agent()
* Replace goto cleanup with block_signals_reset + CLEANUP_TMPFILE_AT
* Use RENAME_NOREPLACE to make sure we don't overwrite any ongoing request
* Reword log messages a bit
2026-02-11 02:39:26 +01:00
Mike Yuan
41615d59fa
various: port manual goto cleanup to CLEANUP_TMPFILE_AT 2026-02-11 02:39:26 +01:00
Mike Yuan
0132a02bd6
tmpfile-util: do not skip CLEANUP_TMPFILE_AT for AT_FDCWD
Preparation for later commits.
2026-02-11 02:39:25 +01:00
93 changed files with 3265 additions and 913 deletions

View File

@ -50,10 +50,6 @@ jobs:
[Build]
ToolsTreeDistribution=fedora
ToolsTreeRelease=rawhide
ToolsTreePackages=
libgcrypt-devel
libgpg-error-devel
musl-gcc
EOF
mkosi -f box -- true

8
NEWS
View File

@ -44,6 +44,14 @@ CHANGES WITH 260 in spe:
SYSTEMD_COLORS=256, and SYSTEMD_COLORS=24bit respectively when output
is to a non-dumb TTY, and like SYSTEMD_COLORS=no otherwise.
* Minimum backlight brightness clamp for restoring it at boot has been
lowered from 5% to 1%. This is a safe change allowing more chance to
user environments to set lower values that won't be set higher at boot
while still giving the chance to recover from blackouts because
excessive lower bright values by just rebooting. Notice that if your
environment allow you to set excessive low brightness values this has
nothing to do with systemd's brightness clamp.
CHANGES WITH 259:
Announcements of Future Feature Removals and Incompatible Changes:

3
TODO
View File

@ -121,6 +121,9 @@ Deprecations and removals:
Features:
* networkd: maintain a file in /run/ that can be symlinked into /run/issue.d/
that always shows the current primary IP address
* report:
- should the list of metrics use JSON-SEQ? or maybe be wrapped in a json
array (the latter might be necessary, once we sign the combination)

View File

@ -705,7 +705,7 @@ SPDX-License-Identifier: LGPL-2.1-or-later
- Think about the log level you choose: for functions that are of the "logging"
kind (see above), please ensure that failures we propagate should be logged
about at `LOG_ERR` level. Failures that are noteworthy, but we proceed anyway,
should be loged at `LOG_WARN` level. Important informational messages should
should be logged at `LOG_WARN` level. Important informational messages should
use `LOG_NOTICE` and regular informational messages should use
`LOG_INFO`. Note that the latter is the default maximum log level, i.e. only
`LOG_DEBUG` messages are hidden by default.

View File

@ -30,15 +30,12 @@
#
# If the property is missing, user-space can assume:
# ID_INPUT_JOYSTICK_INTEGRATION=external
#
# By default i8042, i2c, and rmi devices are assumed to be internal,
# bluetooth devices are assumed to be external, usb devices are assumed
# to be internal when connected to a PCB port and external otherwise.
joystick:bluetooth:*
ID_INPUT_JOYSTICK_INTEGRATION=external
###########################################################
# GPD
###########################################################
# GPD Win, Classic and XBox 360 compat modes
joystick:usb:v11c5p5507*
joystick:usb:v045ep028e*
ID_INPUT_JOYSTICK_INTEGRATION=internal
# Example entry; vid: ffff, pid: 0000; both must be lowecase.
# this will make this usb joystick to behave as internal.
#joystick:usb:vffffp0000*
# ID_INPUT_JOYSTICK_INTEGRATION=internal

View File

@ -28,44 +28,18 @@
# Permitted keys:
# Specify whether a touchpad is a built-in one or external:
# ID_INPUT_TOUCHPAD_INTEGRATION=internal|external
#
# By default i8042, i2c, and rmi devices are assumed to be internal,
# bluetooth devices are assumed to be external, usb devices are assumed
# to be internal when connected to a PCB port and external otherwise.
touchpad:i8042:*
touchpad:rmi:*
touchpad:usb:*
ID_INPUT_TOUCHPAD_INTEGRATION=internal
touchpad:bluetooth:*
ID_INPUT_TOUCHPAD_INTEGRATION=external
###########################################################
# Apple
###########################################################
# Magic Trackpad (1 and 2)
touchpad:usb:v05acp030e:*
touchpad:usb:v05acp0265:*
touchpad:usb:v05acp0324:*
ID_INPUT_TOUCHPAD_INTEGRATION=external
###########################################################
# HP Elite x2 1013 G3
###########################################################
touchpad:usb:v044ep1221:*
ID_INPUT_TOUCHPAD_INTEGRATION=external
# Example entry; vid: ffff, pid: 0000; both must be lowecase.
# this will make this bluetooth touchpad to behave as internal.
#touchpad:bluetooth:vffffp0000:*
# ID_INPUT_TOUCHPAD_INTEGRATION=internal
###########################################################
# Lenovo IdeaPad Duet3 10IGL5 (82AT)
###########################################################
touchpad:bluetooth:v17efp60fa:*
ID_INPUT_TOUCHPAD_INTEGRATION=internal
###########################################################
# Logitech
###########################################################
touchpad:usb:v046d*
ID_INPUT_TOUCHPAD_INTEGRATION=external
###########################################################
# Wacom
###########################################################
touchpad:usb:v056a*
ID_INPUT_TOUCHPAD_INTEGRATION=external

View File

@ -350,7 +350,7 @@ def print_summary(fname, groups):
print(f'{fname}: {len(groups)} match groups, {n_matches} matches, {n_props} properties')
if n_matches == 0 or n_props == 0:
error(f'{fname}: no matches or props')
print(f'{fname}: no matches or props')
if __name__ == '__main__':
args = sys.argv[1:] or sorted([

View File

@ -529,7 +529,7 @@
<listitem><para>Takes a boolean, defaults to false. Controls whether to append disk model information
to the firmware boot option item description (as configured with
<option>--efi-boot-option-description=</option> above). This is useful when installing multiple
operating systems on separate disks on the same system, as it ensures the firmware boot options are discernable
operating systems on separate disks on the same system, as it ensures the firmware boot options are discernible
and give a hint which disk is booted into. Note that this uses hardware model information, and hence
might not be too useful in case multiple disks of an identical model are used.</para>

View File

@ -69,6 +69,18 @@
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FirewallMark=</varname></term>
<listitem>
<para>Takes a 32 bit unsigned integer value. Controls the firewall mark of packets generated by the
socket used to make DNS requests for this DNS delegate. This can be used in the firewall logic to
filter packets from this socket.
This sets the <constant>SO_MARK</constant> socket option. See <citerefentry
project='die-net'><refentrytitle>iptables</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
details.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -79,10 +91,11 @@
<programlisting># /etc/systemd/dns-delegate.d/foobar.dns-delegate
[Delegate]
DNS=203.0.113.47
Domains=foobar.com</programlisting>
Domains=foobar.com
FirewallMark=42</programlisting>
<para>This ensures lookups of <literal>foobar.com</literal> and any domains below it are directed to
DNS server 203.0.113.47.</para>
DNS server 203.0.113.47 and any packets related to this lookup have a firewall mark set to 42.</para>
</example>
</refsect1>

View File

@ -6444,6 +6444,117 @@ ServerAddress=192.168.0.1/24</programlisting>
</variablelist>
</refsect1>
<refsect1>
<title>[ModemManager] Section Options</title>
<para>This section configures the default setting of the ModemManager integration. See
<ulink url="https://modemmanager.org/docs/modemmanager/" /> for more information about ModemManager.</para>
<para>Regardless of the [ModemManager] section settings consider using the following for LTE modems (take into account
that LTE modems do not typically support LLDP because LLDP is a Layer 2 protocol for Ethernet networks and an LTE
modem connects to a cellular network, not a local Ethernet LAN):
<programlisting>[Network]
LLDP=no
LinkLocalAddressing=no
IPv6AcceptRA=no
</programlisting>
</para>
<para>The following options are available in the [ModemManager] section:</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>SimpleConnectProperties=</varname></term>
<listitem>
<para>Specifies the white-space separated list of simple connect properties used to connect a modem. See
<ulink url="https://www.freedesktop.org/software/ModemManager/man/latest/mmcli.1.html" /> for more
information about simple connect. If no properties provided then the connection is not initiated.</para>
<varlistentry>
<term><option>apn</option>=<replaceable>NAME</replaceable></term>
<listitem><para>An Access Point Name (APN) is the name of a gateway between a mobile network
(GSM, GPRS, 3G, 4G and 5G) and another computer network. Required in 3GPP.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>allowed-auth</option>=<replaceable>METHOD</replaceable></term>
<listitem><para>Authentication method to use. Takes one of "none", "pap", "chap", "mschap", "mschapv2" or "eap".
Optional in 3GPP.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>user</option>=<replaceable>NAME</replaceable></term>
<listitem><para>User name (if any) required by the network. Optional in 3GPP.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>password</option>=<replaceable>PASSWORD</replaceable></term>
<listitem><para>Password (if any) required by the network. Optional in 3GPP.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>ip-type</option>=<replaceable>TYPE</replaceable></term>
<listitem><para>Addressing type. Takes one of "none", "ipv4", "ipv6", "ipv4v6" or "any".
Optional in 3GPP and CDMA.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>allow-roaming</option>=<replaceable>BOOL</replaceable></term>
<listitem><para>A boolean. When true, connection is allowed during roaming. When false,
connection is not allowed during roaming. Optional in 3GPP.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>pin</option>=<replaceable>PIN</replaceable></term>
<listitem><para>SIM-PIN unlock code.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>operator-id</option>=<replaceable>ID</replaceable></term>
<listitem><para>ETSI MCC-MNC of a network to force registration.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteMetric=</varname></term>
<listitem>
<para>Set the routing metric for routes specified by the mobile network (including the prefix route
added for the specified prefix). Takes an unsigned integer in the range 0…4294967295.
When unset or set to 0, the kernel's default value will be used.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseGateway=</varname></term>
<listitem>
<para>When true (the default), the router address will be configured as the default gateway.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<example>
@ -6771,6 +6882,29 @@ Xfrm=xfrm0</programlisting>
This allows hardware based ipsec offloading to the <literal>eth0</literal> nic.
If offloading is not needed, xfrm interfaces can be assigned to the <literal>lo</literal> device.
</para>
</example>
<example>
<title>Connecting to a cellular network with ModemManager</title>
<programlisting># /etc/systemd/network/27-wwan0.network
[Match]
Name=wwan0
[Network]
LLDP=no
LinkLocalAddressing=no
IPv6AcceptRA=no
[ModemManager]
SimpleConnectProperties=apn=internet pin=1111
RouteMetric=30
UseGateway=yes</programlisting>
<para>This connects a cellular modem to a broadband network matched with the network interface <literal>wwan0</literal>,
with APN name <literal>internet</literal>, SIM card pin unlock code <literal>1111</literal> and sets up a default
gateway with route metric of 30.
</para>
</example>
</refsect1>

View File

@ -11,6 +11,7 @@ Packages=
github-cli
lcov
libucontext
musl
mypy
pkgconf
ruff

View File

@ -5,7 +5,12 @@ Distribution=fedora
[Content]
Packages=
lcov
gh
lcov
libgcrypt-devel
libgpg-error-devel
musl-libc
musl-clang
musl-gcc
ruff
shellcheck

View File

@ -5,11 +5,19 @@ SUBSYSTEM!="input", GOTO="persistent_input_end"
SUBSYSTEMS=="bluetooth", ENV{ID_BUS}="bluetooth", GOTO="persistent_input_end"
# Bluetooth devices don't always have the bluetooth subsystem
ATTRS{id/bustype}=="0005", ENV{ID_BUS}="bluetooth", GOTO="persistent_input_end"
SUBSYSTEMS=="acpi", ENV{ID_BUS}="acpi"
# platform must be before serio as serio can be child
SUBSYSTEMS=="platform", ENV{ID_BUS}="platform"
SUBSYSTEMS=="i2c", ENV{ID_BUS}="i2c"
SUBSYSTEMS=="rmi4", ENV{ID_BUS}="rmi"
SUBSYSTEMS=="serio", ENV{ID_BUS}="i8042"
SUBSYSTEMS=="usb", ENV{ID_BUS}=="", IMPORT{builtin}="usb_id"
# subsystems before (usb, platform, i2c) can be under pci so only set them if we still have no ID_BUS.
# we could set this the first but will break the ENV{ID_BUS}=="" condition for usb.
SUBSYSTEMS=="pci", ENV{ID_BUS}=="", ENV{ID_BUS}="pci"
# determine class name for persistent symlinks
ENV{ID_INPUT_KEYBOARD}=="?*", ENV{.INPUT_CLASS}="kbd"
ENV{ID_INPUT_MOUSE}=="?*", ENV{.INPUT_CLASS}="mouse"

View File

@ -0,0 +1,25 @@
# do not edit this file, it will be overwritten on update
# ID_INTEGRATION variable tells us if a device is internal (inherent part of the system) or external otherwise.
# This must be loaded after 60-persistent-*.rules to have ID_BUS.
ACTION=="remove", GOTO="integration_end"
ENV{ID_BUS}=="", GOTO="integration_end"
# ACPI, platform, PS/2, I2C, RMI and PCI devices: Internal by default.
ENV{ID_BUS}=="acpi|platform|i8042|i2c|rmi|pci", ENV{ID_INTEGRATION}="internal"
# Bluetooth devices: External by default.
ENV{ID_BUS}=="bluetooth", ENV{ID_INTEGRATION}="external"
# USB devices: Internal if it's connected to a fixed port, external to a removable or unknown.
ENV{ID_BUS}=="usb", DRIVERS=="usb", ATTRS{maxchild}=="0", ATTRS{removable}=="fixed", ENV{ID_INTEGRATION}="internal"
ENV{ID_BUS}=="usb", DRIVERS=="usb", ATTRS{maxchild}=="0", ATTRS{removable}=="removable|unknown", ENV{ID_INTEGRATION}="external"
# libinput compatibility variables, must be loaded before 70-(joystick|touchpad).rules to allow hwdb quirks to override.
ENV{ID_INPUT}=="", GOTO="integration_libinput_end"
ENV{ID_INPUT_JOYSTICK}=="1", ENV{ID_INPUT_JOYSTICK_INTEGRATION}="$env{ID_INTEGRATION}"
ENV{ID_INPUT_TOUCHPAD}=="1", ENV{ID_INPUT_TOUCHPAD_INTEGRATION}="$env{ID_INTEGRATION}"
LABEL="integration_libinput_end"
LABEL="integration_end"

View File

@ -23,6 +23,7 @@ rules = [
'60-persistent-v4l.rules',
'60-sensor.rules',
'60-serial.rules',
'65-integration.rules',
'70-camera.rules',
'70-joystick.rules',
'70-mouse.rules',

View File

@ -348,8 +348,8 @@ static int clamp_brightness(
assert(brightness);
/* Some systems turn the backlight all the way off at the lowest levels. This clamps the saved
* brightness to at least 1 or 5% of max_brightness in case of 'backlight' subsystem. This
* avoids preserving an unreadably dim screen, which would otherwise force the user to disable
* brightness to at least 1 or 1% of max_brightness (whichever is bigger) in case of 'backlight' subsystem.
* This avoids preserving an unreadably dim screen, which would otherwise force the user to disable
* state restoration. */
min_brightness = (unsigned) ((double) max_brightness * percent / 100);
@ -385,7 +385,7 @@ static int shall_clamp(sd_device *device, unsigned *ret) {
return r;
if (r > 0) {
property = "ID_BACKLIGHT_CLAMP";
default_percent = 5;
default_percent = 1;
} else {
property = "ID_LEDS_CLAMP";
default_percent = 0;

View File

@ -32,8 +32,6 @@
* message.
*/
struct iovec;
typedef struct LogContext {
unsigned n_ref;
/* Depending on which destructor is used (log_context_free() or log_context_detach()) the memory

View File

@ -8,6 +8,7 @@
#include <sys/mount.h>
#include <unistd.h>
#include "capability-util.h"
#include "dlfcn-util.h"
#include "errno-util.h"
#include "fd-util.h"
@ -215,53 +216,6 @@ int namespace_open(
return pidref_namespace_open(&pidref, ret_pidns_fd, ret_mntns_fd, ret_netns_fd, ret_userns_fd, ret_root_fd);
}
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
int r;
/* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
block_dlopen();
if (userns_fd >= 0) {
/* Can't setns to your own userns, since then you could escalate from non-root to root in
* your own namespace, so check if namespaces are equal before attempting to enter. */
r = is_our_namespace(userns_fd, NAMESPACE_USER);
if (r < 0)
return r;
if (r > 0)
userns_fd = -EBADF;
}
if (pidns_fd >= 0)
if (setns(pidns_fd, CLONE_NEWPID) < 0)
return -errno;
if (mntns_fd >= 0)
if (setns(mntns_fd, CLONE_NEWNS) < 0)
return -errno;
if (netns_fd >= 0)
if (setns(netns_fd, CLONE_NEWNET) < 0)
return -errno;
if (userns_fd >= 0)
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
if (chroot(".") < 0)
return -errno;
}
if (userns_fd >= 0)
return reset_uid_gid();
return 0;
}
static int namespace_enter_one_idempotent(int nsfd, NamespaceType type) {
int r;
@ -283,20 +237,43 @@ static int namespace_enter_one_idempotent(int nsfd, NamespaceType type) {
return 1;
}
int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
int r;
/* Similar to namespace_enter(), but operates on a set of namespaces that are potentially owned
* by the userns ("delegated"), in which case we'll need to gain CAP_SYS_ADMIN by joining
* the userns first, and the rest later. */
assert(userns_fd >= 0);
/* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
block_dlopen();
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
if (userns_fd >= 0) {
/* Can't setns to your own userns, since then you could escalate from non-root to root in
* your own namespace, so check if namespaces are equal before attempting to enter. */
r = is_our_namespace(userns_fd, NAMESPACE_USER);
if (r < 0)
return r;
if (r > 0)
userns_fd = -EBADF;
}
r = have_effective_cap(CAP_SYS_ADMIN);
if (r < 0)
return r;
bool have_cap_sys_admin = r > 0;
if (!have_cap_sys_admin) {
/* If we don't have CAP_SYS_ADMIN in our own user namespace, our best bet is to enter the
* user namespace first (if we got one) to get CAP_SYS_ADMIN within the child user namespace,
* and then hope the other namespaces are owned by the child user namespace. If they aren't,
* we'll just get an EPERM later on when trying to setns() to them. */
if (userns_fd < 0)
return log_debug_errno(
SYNTHETIC_ERRNO(EPERM),
"Need CAP_SYS_ADMIN or a child user namespace to enter namespaces.");
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
}
if (pidns_fd >= 0) {
r = namespace_enter_one_idempotent(pidns_fd, NAMESPACE_PID);
@ -316,6 +293,10 @@ int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int net
return r;
}
if (userns_fd >= 0 && have_cap_sys_admin)
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
@ -324,7 +305,15 @@ int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int net
return -errno;
}
return maybe_setgroups(/* size = */ 0, NULL);
if (userns_fd >= 0) {
/* Try to become root in the user namespace but don't error out if we can't, since it's not
* uncommon to have user namespaces without a root user in them. */
r = reset_uid_gid();
if (r < 0)
log_debug_errno(r, "Unable to drop auxiliary groups or reset UID/GID, ignoring: %m");
}
return 0;
}
int fd_is_namespace(int fd, NamespaceType type) {

View File

@ -47,7 +47,6 @@ int namespace_open(
int *ret_root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int netns_fd, int root_fd);
int fd_is_namespace(int fd, NamespaceType type);
int is_our_namespace(int fd, NamespaceType type);

View File

@ -1128,10 +1128,6 @@ bool is_main_thread(void) {
return cached;
}
bool oom_score_adjust_is_valid(int oa) {
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
}
unsigned long personality_from_string(const char *s) {
Architecture architecture;
@ -1778,7 +1774,6 @@ int namespace_fork_full(
int netns_fd,
int userns_fd,
int root_fd,
bool delegated,
PidRef *ret) {
_cleanup_(pidref_done_sigkill_wait) PidRef pidref_outer = PIDREF_NULL;
@ -1824,10 +1819,7 @@ int namespace_fork_full(
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
if (delegated)
r = namespace_enter_delegated(userns_fd, pidns_fd, mntns_fd, netns_fd, root_fd);
else
r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
if (r < 0) {
log_full_errno(prio, r, "Failed to join namespace: %m");
report_errno_and_exit(errno_pipe_fd[1], r);
@ -1887,6 +1879,10 @@ int namespace_fork_full(
return 1;
}
bool oom_score_adjust_is_valid(int oa) {
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
}
int set_oom_score_adjust(int value) {
char t[DECIMAL_STR_MAX(int)];

View File

@ -87,8 +87,6 @@ int pidref_from_same_root_fs(PidRef *a, PidRef *b);
bool is_main_thread(void);
bool oom_score_adjust_is_valid(int oa);
#ifndef PERSONALITY_INVALID
/* personality(2) documents that 0xFFFFFFFFUL is used for querying the
* current personality, hence let's use that here as error
@ -201,7 +199,6 @@ int namespace_fork_full(
int netns_fd,
int userns_fd,
int root_fd,
bool delegated,
PidRef *ret);
static inline int namespace_fork(
@ -216,10 +213,11 @@ static inline int namespace_fork(
PidRef *ret) {
return namespace_fork_full(outer_name, inner_name, NULL, 0, flags,
pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd, false,
pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd,
ret);
}
bool oom_score_adjust_is_valid(int oa);
int set_oom_score_adjust(int value);
int get_oom_score_adjust(int *ret);
@ -235,9 +233,6 @@ int get_oom_score_adjust(int *ret);
assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
/* Like TAKE_PTR() but for pid_t, resetting them to 0 */
#define TAKE_PID(pid) TAKE_GENERIC(pid, pid_t, 0)
int setpriority_closest(int priority);
_noreturn_ void freeze(void);

View File

@ -31,6 +31,7 @@
#include "namespace-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "signal-util.h"
@ -1666,7 +1667,7 @@ int openpt_allocate_in_namespace(
r = pidref_namespace_open(pidref, &pidnsfd, &mntnsfd, /* ret_netns_fd= */ NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
return log_debug_errno(r, "Failed to open namespaces of PID "PID_FMT": %m", pidref->pid);
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pair) < 0)
return -errno;

View File

@ -437,7 +437,7 @@ void cleanup_tmpfile_data_done(struct cleanup_tmpfile_data *d) {
assert(d);
if (!d->dir_fd ||
*d->dir_fd < 0 ||
(*d->dir_fd < 0 && *d->dir_fd != AT_FDCWD) ||
!d->filename ||
!*d->filename)
return;

View File

@ -920,19 +920,28 @@ int maybe_setgroups(size_t size, const gid_t *list) {
/* Check if setgroups is allowed before we try to drop all the auxiliary groups */
if (size == 0) { /* Dropping all aux groups? */
/* The kernel refuses setgroups() if there are no GID mappings in the current
* user namespace, so check that beforehand and don't try to setgroups() if
* there are no GID mappings. */
_cleanup_fclose_ FILE *f = fopen("/proc/self/gid_map", "re");
if (!f && errno != ENOENT)
return -errno;
if (f) {
r = safe_fgetc(f, /* ret= */ NULL);
if (r < 0)
return r;
if (r == 0) {
log_debug("Skipping setgroups(), /proc/self/gid_map is empty");
return 0;
}
}
_cleanup_free_ char *setgroups_content = NULL;
bool can_setgroups;
r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
if (r == -ENOENT)
/* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
can_setgroups = true;
else if (r < 0)
if (r < 0 && r != -ENOENT)
return r;
else
can_setgroups = streq(setgroups_content, "allow");
if (!can_setgroups) {
if (r > 0 && streq(setgroups_content, "deny")) {
log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
return 0;
}

View File

@ -175,26 +175,22 @@ int install_random_seed(const char *esp) {
if (fd < 0)
return log_error_errno(fd, "Failed to open random seed file for writing: %m");
CLEANUP_TMPFILE_AT(loader_dir_fd, tmp);
if (!warned) /* only warn once per seed file */
(void) random_seed_verify_permissions(fd, S_IFREG);
r = loop_write(fd, buffer, sizeof(buffer));
if (r < 0) {
log_error_errno(r, "Failed to write random seed file: %m");
goto fail;
}
if (r < 0)
return log_error_errno(r, "Failed to write random seed file: %m");
if (fsync(fd) < 0 || fsync(loader_dir_fd) < 0) {
r = log_error_errno(errno, "Failed to sync random seed file: %m");
goto fail;
}
if (fsync(fd) < 0 || fsync(loader_dir_fd) < 0)
return log_error_errno(errno, "Failed to sync random seed file: %m");
if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0) {
r = log_error_errno(errno, "Failed to move random seed file into place: %m");
goto fail;
}
if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0)
return log_error_errno(errno, "Failed to move random seed file into place: %m");
tmp = mfree(tmp);
tmp = mfree(tmp); /* disarm CLEANUP_TMPFILE_AT() */
if (syncfs(fd) < 0)
return log_error_errno(errno, "Failed to sync ESP file system: %m");
@ -202,12 +198,6 @@ int install_random_seed(const char *esp) {
log_info("Random seed file %s/loader/random-seed successfully %s (%zu bytes).", esp, refreshed ? "refreshed" : "written", sizeof(buffer));
return set_system_token();
fail:
assert(tmp);
(void) unlinkat(loader_dir_fd, tmp, 0);
return r;
}
int verb_random_seed(int argc, char *argv[], void *userdata) {

View File

@ -642,14 +642,12 @@ int vl_method_list_boot_entries(sd_varlink *link, sd_json_variant *parameters, s
int r;
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = acquire_esp(/* unprivileged_mode= */ false,
/* graceful= */ false,
/* ret_part= */ NULL,

View File

@ -1255,7 +1255,6 @@ int unit_refresh_credentials(Unit *u) {
(int[]) { tunnel_fds[1] }, 1,
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
pidns_fd, mntns_fd, /* netns_fd = */ -EBADF, userns_fd, root_fd,
/* delegated = */ MANAGER_IS_USER(u->manager),
&child);
if (r < 0)
return log_full_errno(ERRNO_IS_NEG_PRIVILEGE(r) ? LOG_WARNING : LOG_ERR, r,

View File

@ -171,7 +171,11 @@ int manager_serialize(
if (r < 0)
return r;
r = varlink_server_serialize(m->varlink_server, f, fds);
r = varlink_server_serialize(m->varlink_server, /* name = */ NULL, f, fds);
if (r < 0)
return r;
r = varlink_server_serialize(m->metrics_varlink_server, "metrics", f, fds);
if (r < 0)
return r;
@ -282,7 +286,6 @@ static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
}
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
bool deserialize_varlink_sockets = false;
int r;
assert(m);
@ -490,23 +493,28 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
r = strv_extend(&m->subscribed_as_strv, val);
if (r < 0)
return r;
} else if ((val = startswith(l, "varlink-server-socket-address="))) {
if (!m->varlink_server) {
r = manager_setup_varlink_server(m);
if (r < 0) {
log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
continue;
}
} else if ((val = startswith(l, "varlink-server-metrics-"))) {
if (m->objective == MANAGER_RELOAD)
/* We don't destroy varlink server on daemon-reload (in contrast to reexec) -> skip! */
continue;
deserialize_varlink_sockets = true;
}
r = manager_setup_varlink_metrics_server(m);
if (r < 0)
log_warning_errno(r, "Failed to setup metrics varlink server, ignoring: %m");
else
(void) varlink_server_deserialize_one(m->metrics_varlink_server, val, fds);
/* To avoid unnecessary deserialization (i.e. during reload vs. reexec) we only deserialize
* the FDs if we had to create a new m->varlink_server. The deserialize_varlink_sockets flag
* is initialized outside of the loop, is flipped after the VarlinkServer is setup, and
* remains set until all serialized contents are handled. */
if (deserialize_varlink_sockets)
} else if ((val = startswith(l, "varlink-server-"))) {
if (m->objective == MANAGER_RELOAD)
/* We don't destroy varlink server on daemon-reload (in contrast to reexec) -> skip! */
continue;
r = manager_setup_varlink_server(m);
if (r < 0)
log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
else
(void) varlink_server_deserialize_one(m->varlink_server, val, fds);
} else if ((val = startswith(l, "dump-ratelimit=")))
deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val);
else if ((val = startswith(l, "reload-reexec-ratelimit=")))

View File

@ -112,7 +112,7 @@ static int ip_address_access_build_json(sd_json_variant **ret, const char *name,
r = sd_json_variant_append_arraybo(
&v,
SD_JSON_BUILD_PAIR_INTEGER("family", i->family),
JSON_BUILD_PAIR_IN_ADDR("address", &i->address, i->family),
JSON_BUILD_PAIR_IN_ADDR("address", i->family, &i->address),
SD_JSON_BUILD_PAIR_UNSIGNED("prefixLength", i->prefixlen));
if (r < 0)
return r;
@ -299,6 +299,7 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void
SD_JSON_BUILD_OBJECT(
SD_JSON_BUILD_PAIR_BOOLEAN("isAllowList", c->restrict_network_interfaces_is_allow_list),
JSON_BUILD_PAIR_STRING_SET("interfaces", c->restrict_network_interfaces))),
JSON_BUILD_PAIR_STRING_NON_EMPTY("BindNetworkInterface", c->bind_network_interface),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("NFTSet", nft_set_build_json, &c->nft_set_context),
/* BPF programs */

View File

@ -1,5 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "sd-varlink.h"
#include "hashmap.h"
#include "manager.h"
#include "metrics.h"
@ -175,10 +178,10 @@ const MetricFamily metric_family_table[] = {
{}
};
int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_describe(metric_family_table, link, parameters, flags, userdata);
}
int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_list(metric_family_table, link, parameters, flags, userdata);
}

View File

@ -1,10 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink.h"
#include "sd-json.h"
#include "core-forward.h"
#define METRIC_IO_SYSTEMD_MANAGER_PREFIX "io.systemd.Manager."
int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);

View File

@ -9,7 +9,6 @@
#include "path-util.h"
#include "pidref.h"
#include "string-util.h"
#include "strv.h"
#include "unit.h"
#include "varlink.h"
#include "varlink-dynamic-user.h"
@ -375,6 +374,8 @@ int manager_setup_varlink_server(Manager *m) {
if (r < 0)
return log_debug_errno(r, "Failed to allocate Varlink server: %m");
(void) sd_varlink_server_set_description(s, "varlink-api");
r = sd_varlink_server_add_interface_many(
s,
&vl_interface_io_systemd_Manager,
@ -425,26 +426,64 @@ int manager_setup_varlink_server(Manager *m) {
return 1;
}
static int manager_setup_varlink_metrics_server(Manager *m) {
sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA;
int r;
int manager_setup_varlink_metrics_server(Manager *m) {
assert(m);
sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA;
if (MANAGER_IS_SYSTEM(m))
flags |= SD_VARLINK_SERVER_ACCOUNT_UID;
r = metrics_setup_varlink_server(
&m->metrics_varlink_server, flags, m->event, vl_method_list, vl_method_describe, m);
if (r < 0)
return r;
return 0;
return metrics_setup_varlink_server(&m->metrics_varlink_server, flags,
m->event, EVENT_PRIORITY_IPC,
vl_method_list_metrics, vl_method_describe_metrics,
m);
}
static int manager_varlink_init_system(Manager *m) {
static int varlink_server_listen_many_idempotent_sentinel(
sd_varlink_server *s,
bool known_fresh,
const char *prefix,
...) {
va_list ap;
int r = 0;
assert(s);
va_start(ap, prefix);
for (const char *address; (address = va_arg(ap, const char*)); ) {
_cleanup_free_ char *p = NULL;
if (prefix) {
p = path_join(prefix, address);
if (!p) {
r = log_oom();
break;
}
address = p;
}
/* We might have got sockets through deserialization. Do not bind to them twice. */
if (!known_fresh && varlink_server_contains_socket(s, address))
continue;
r = sd_varlink_server_listen_address(s, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0) {
log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
break;
}
}
va_end(ap);
return r;
}
#define varlink_server_listen_many_idempotent(s, known_fresh, prefix, ...) \
varlink_server_listen_many_idempotent_sentinel((s), (known_fresh), (prefix), __VA_ARGS__, NULL)
static int manager_varlink_init_system_api(Manager *m) {
int r;
_cleanup_free_ char *metrics_address = NULL;
assert(m);
@ -453,38 +492,21 @@ static int manager_varlink_init_system(Manager *m) {
return log_error_errno(r, "Failed to set up varlink server: %m");
bool fresh = r > 0;
r = manager_setup_varlink_metrics_server(m);
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");
bool metrics_fresh = r > 0;
r = runtime_directory_generic(m->runtime_scope, "systemd/report/io.systemd.Manager", &metrics_address);
if (r < 0)
return r;
if (!MANAGER_IS_TEST_RUN(m)) {
FOREACH_STRING(address,
"/run/systemd/userdb/io.systemd.DynamicUser",
VARLINK_PATH_MANAGED_OOM_SYSTEM,
"/run/systemd/io.systemd.Manager",
metrics_address) {
sd_varlink_server *server = streq(address, metrics_address) ? m->metrics_varlink_server : m->varlink_server;
fresh = streq(address, metrics_address) ? metrics_fresh : fresh;
/* We might have got sockets through deserialization. Do not bind to them twice. */
if (!fresh && varlink_server_contains_socket(server, address))
continue;
r = sd_varlink_server_listen_address(server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
}
r = varlink_server_listen_many_idempotent(
m->varlink_server, fresh,
/* prefix = */ NULL,
"/run/systemd/io.systemd.Manager",
"/run/systemd/userdb/io.systemd.DynamicUser",
VARLINK_PATH_MANAGED_OOM_SYSTEM);
if (r < 0)
return r;
}
return 1;
return 0;
}
static int manager_varlink_init_user(Manager *m) {
static int manager_varlink_init_user_api(Manager *m) {
int r;
assert(m);
@ -497,30 +519,46 @@ static int manager_varlink_init_user(Manager *m) {
return log_error_errno(r, "Failed to set up varlink server: %m");
bool fresh = r > 0;
FOREACH_STRING(a,
"systemd/io.systemd.Manager") {
_cleanup_free_ char *address = NULL;
address = path_join(m->prefix[EXEC_DIRECTORY_RUNTIME], a);
if (!address)
return -ENOMEM;
/* We might have got sockets through deserialization. Do not bind to them twice. */
if (!fresh && varlink_server_contains_socket(m->varlink_server, address))
continue;
r = sd_varlink_server_listen_address(m->varlink_server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
}
r = manager_setup_varlink_metrics_server(m);
r = varlink_server_listen_many_idempotent(
m->varlink_server, fresh,
m->prefix[EXEC_DIRECTORY_RUNTIME],
"systemd/io.systemd.Manager");
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");
return r;
return manager_varlink_managed_oom_connect(m);
}
static int manager_varlink_init_metrics(Manager *m) {
int r;
assert(m);
if (MANAGER_IS_TEST_RUN(m))
return 0;
r = manager_setup_varlink_metrics_server(m);
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");
bool fresh = r > 0;
return varlink_server_listen_many_idempotent(
m->metrics_varlink_server, fresh,
m->prefix[EXEC_DIRECTORY_RUNTIME],
"systemd/report/io.systemd.Manager");
}
int manager_varlink_init(Manager *m) {
return MANAGER_IS_SYSTEM(m) ? manager_varlink_init_system(m) : manager_varlink_init_user(m);
int r;
if (MANAGER_IS_SYSTEM(m))
r = manager_varlink_init_system_api(m);
else
r = manager_varlink_init_user_api(m);
if (r < 0)
return r;
return manager_varlink_init_metrics(m);
}
void manager_varlink_done(Manager *m) {
@ -534,6 +572,7 @@ void manager_varlink_done(Manager *m) {
m->varlink_server = sd_varlink_server_unref(m->varlink_server);
m->managed_oom_varlink = sd_varlink_close_unref(m->managed_oom_varlink);
m->metrics_varlink_server = sd_varlink_server_unref(m->metrics_varlink_server);
}

View File

@ -4,6 +4,7 @@
#include "core-forward.h"
int manager_setup_varlink_server(Manager *m);
int manager_setup_varlink_metrics_server(Manager *m);
int manager_varlink_init(Manager *m);
void manager_varlink_done(Manager *m);

View File

@ -1793,14 +1793,12 @@ static int vl_method_list_transfers(sd_varlink *link, sd_json_variant *parameter
assert(link);
assert(parameters);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = varlink_set_sentinel(link, "io.systemd.Import.NoTransfers");
if (r < 0)
return r;

View File

@ -317,8 +317,6 @@ int dhcp_server_static_leases_append_json(sd_dhcp_server *server, sd_json_varian
int dhcp_server_save_leases(sd_dhcp_server *server) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
sd_id128_t boot_id;
int r;
@ -355,25 +353,27 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
if (r < 0)
return r;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
r = fopen_temporary_at(server->lease_dir_fd, server->lease_file, &f, &temp_path);
if (r < 0)
return r;
CLEANUP_TMPFILE_AT(server->lease_dir_fd, temp_path);
(void) fchmod(fileno(f), 0644);
r = sd_json_variant_dump(v, SD_JSON_FORMAT_NEWLINE | SD_JSON_FORMAT_FLUSH, f, /* prefix= */ NULL);
if (r < 0)
goto failure;
return r;
r = conservative_renameat(server->lease_dir_fd, temp_path, server->lease_dir_fd, server->lease_file);
if (r < 0)
goto failure;
return r;
temp_path = mfree(temp_path); /* disarm CLEANUP_TMPFILE_AT() */
return 0;
failure:
(void) unlinkat(server->lease_dir_fd, temp_path, /* flags= */ 0);
return r;
}
static int json_dispatch_chaddr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {

View File

@ -5,8 +5,8 @@
#include "sd-json.h"
#include "sd-forward.h"
#include "log.h"
#include "sd-forward.h"
#include "string-util.h" /* IWYU pragma: keep */
#define JSON_VARIANT_REPLACE(v, q) \
@ -175,9 +175,9 @@ enum {
_JSON_BUILD_PAIR_VARIANT_NON_EMPTY,
/* _SD_JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, */
_JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY,
_JSON_BUILD_PAIR_IN4_ADDR_NON_NULL,
_JSON_BUILD_PAIR_IN6_ADDR_NON_NULL,
_JSON_BUILD_PAIR_IN_ADDR_NON_NULL,
_JSON_BUILD_PAIR_IN_ADDR_WITH_STRING,
_JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL,
_JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL,
_JSON_BUILD_PAIR_HW_ADDR_NON_NULL,
_JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL,
@ -190,12 +190,6 @@ enum {
_JSON_BUILD_PAIR_TRISTATE_NON_NULL,
_JSON_BUILD_PAIR_PIDREF_NON_NULL,
_JSON_BUILD_PAIR_DEVNUM,
_JSON_BUILD_PAIR_IN_ADDR_WITH_STRING,
_JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING,
_JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING,
_JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL,
_JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL,
_JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL,
_SD_JSON_BUILD_REALLYMAX,
};
@ -206,7 +200,7 @@ enum {
#define JSON_BUILD_CONST_STRING(s) _SD_JSON_BUILD_VARIANT, JSON_VARIANT_STRING_CONST(s)
#define JSON_BUILD_IN4_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY((const struct in_addr*) { v }, sizeof(struct in_addr))
#define JSON_BUILD_IN6_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY((const struct in6_addr*) { v }, sizeof(struct in6_addr))
#define JSON_BUILD_IN_ADDR(v, f) SD_JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f))
#define JSON_BUILD_IN_ADDR(f, v) SD_JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f))
#define JSON_BUILD_ETHER_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr))
#define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v }
#define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s }
@ -229,9 +223,15 @@ enum {
#define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (sd_json_variant*) { v }
#define JSON_BUILD_PAIR_VARIANT_NON_EMPTY(name, v) _JSON_BUILD_PAIR_VARIANT_NON_EMPTY, (const char*) { name }, (sd_json_variant*) { v }
#define JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v }
#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v }
#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, v, f) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (const union in_addr_union*) { v }, (int) { f }
#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v }
#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) }
#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) }
#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v }
#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) }
#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) }
#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v }
#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) }
#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) }
#define JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, (const char*) { name }, (const struct ether_addr*) { v }
#define JSON_BUILD_PAIR_HW_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, (const char*) { name }, (const struct hw_addr_data*) { v }
#define JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL(name, t) _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL, (const char*) { name }, (dual_timestamp*) { t }
@ -243,18 +243,12 @@ enum {
#define JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n }
#define JSON_BUILD_PAIR_TRISTATE_NON_NULL(name, i) _JSON_BUILD_PAIR_TRISTATE_NON_NULL, (const char*) { name }, (int) { i }
#define JSON_BUILD_PAIR_PIDREF_NON_NULL(name, p) _JSON_BUILD_PAIR_PIDREF_NON_NULL, (const char*) { name }, (const PidRef*) { p }
#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v }
#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING, (const char*) { name }, (const struct in6_addr*) { v }
#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING, (const char*) { name }, (const struct in_addr*) { v }
#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v }
#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v }
#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (const struct in_addr*) { v }
#define JSON_BUILD_PAIR_IOVEC_BASE64(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_BASE64(iov))
#define JSON_BUILD_PAIR_IOVEC_HEX(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_HEX(iov))
#define JSON_BUILD_PAIR_IN4_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN4_ADDR(v))
#define JSON_BUILD_PAIR_IN6_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN6_ADDR(v))
#define JSON_BUILD_PAIR_IN_ADDR(name, v, f) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(v, f))
#define JSON_BUILD_PAIR_IN_ADDR(name, f, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(f, v))
#define JSON_BUILD_PAIR_ETHER_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v))
#define JSON_BUILD_PAIR_HW_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v))
#define JSON_BUILD_PAIR_STRING_SET(name, s) SD_JSON_BUILD_PAIR(name, JSON_BUILD_STRING_SET(s))

View File

@ -3370,8 +3370,8 @@ done:
r = 0;
finish:
for (size_t i = 0; i < n_stack; i++)
json_stack_release(stack + i);
FOREACH_ARRAY(i, stack, n_stack)
json_stack_release(i);
free(stack);
@ -4666,63 +4666,9 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
break;
}
case _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL: {
const struct in_addr *a;
const char *n;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char *);
a = va_arg(ap, const struct in_addr *);
if (a && in4_addr_is_set(a) && current->n_suppress == 0) {
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr));
if (r < 0)
goto finish;
}
n_subtract = 2; /* we generated two items */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL: {
const struct in6_addr *a;
const char *n;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char *);
a = va_arg(ap, const struct in6_addr *);
if (a && in6_addr_is_set(a) && current->n_suppress == 0) {
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr));
if (r < 0)
goto finish;
}
n_subtract = 2; /* we generated two items */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL: {
case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL:
case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL:
case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING: {
const union in_addr_union *a;
const char *n;
int f;
@ -4733,10 +4679,16 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
}
n = va_arg(ap, const char *);
a = va_arg(ap, const union in_addr_union *);
f = va_arg(ap, int);
a = va_arg(ap, const union in_addr_union *);
if (current->n_suppress == 0 &&
((a && in_addr_is_set(f, a)) ||
command == _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING)) {
if (!a)
a = &IN_ADDR_NULL;
if (a && in_addr_is_set(f, a) && current->n_suppress == 0) {
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
@ -4744,9 +4696,36 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
r = sd_json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE_SAFE(f));
if (r < 0)
goto finish;
if (IN_SET(command, _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL)) {
_cleanup_free_ char *string_key_name = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL;
string_key_name = strjoin(n, "String");
if (!string_key_name) {
r = -ENOMEM;
goto finish;
}
r = sd_json_variant_new_string(&string_key, string_key_name);
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_value, IN_ADDR_TO_STRING(f, a));
if (r < 0)
goto finish;
if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) {
r = -ENOMEM;
goto finish;
}
current->elements[current->n_elements++] = TAKE_PTR(string_key);
current->elements[current->n_elements++] = TAKE_PTR(string_value);
}
}
n_subtract = 2; /* we generated two items */
n_subtract = command == _JSON_BUILD_PAIR_IN_ADDR_NON_NULL ? 2 : 4;
current->expect = EXPECT_OBJECT_KEY;
break;
@ -4896,207 +4875,6 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
break;
}
case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL:
case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING: {
const union in_addr_union *a;
const char *n;
int f;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char *);
f = va_arg(ap, int);
a = va_arg(ap, const union in_addr_union *);
if (current->n_suppress == 0) {
bool have_address = a && in_addr_is_set(f, a);
if (have_address || command != _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL) {
_cleanup_free_ char *addr_str = NULL, *string_key_name = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL;
/* For non-NON_NULL variant, always convert address to string (even if all zeros).
* For NON_NULL variant, we only get here when have_address is true. */
if (a) {
r = in_addr_to_string(f, a, &addr_str);
if (r < 0)
goto finish;
}
string_key_name = strjoin(n, "String");
if (!string_key_name) {
r = -ENOMEM;
goto finish;
}
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE_SAFE(f));
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_key, string_key_name);
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_value, addr_str);
if (r < 0)
goto finish;
if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) {
r = -ENOMEM;
goto finish;
}
current->elements[current->n_elements++] = TAKE_PTR(string_key);
current->elements[current->n_elements++] = TAKE_PTR(string_value);
}
}
n_subtract = 4; /* we generated two pairs (binary and string) */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL:
case _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING: {
const struct in6_addr *a;
const char *n;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char *);
a = va_arg(ap, const struct in6_addr *);
if (current->n_suppress == 0) {
bool have_address = a && in6_addr_is_set(a);
if (have_address || command != _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL) {
_cleanup_free_ char *addr_str = NULL, *string_key_name = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL;
/* For non-NON_NULL variant, always convert address to string (even if all zeros).
* For NON_NULL variant, we only get here when have_address is true. */
if (a) {
r = in6_addr_to_string(a, &addr_str);
if (r < 0)
goto finish;
}
string_key_name = strjoin(n, "String");
if (!string_key_name) {
r = -ENOMEM;
goto finish;
}
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr));
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_key, string_key_name);
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_value, addr_str);
if (r < 0)
goto finish;
if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) {
r = -ENOMEM;
goto finish;
}
current->elements[current->n_elements++] = TAKE_PTR(string_key);
current->elements[current->n_elements++] = TAKE_PTR(string_value);
}
}
n_subtract = 4; /* we generated two pairs (binary and string) */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL:
case _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING: {
const struct in_addr *a;
const char *n;
if (current->expect != EXPECT_OBJECT_KEY) {
r = -EINVAL;
goto finish;
}
n = va_arg(ap, const char *);
a = va_arg(ap, const struct in_addr *);
if (current->n_suppress == 0) {
bool have_address = a && !in4_addr_is_null(a);
if (have_address || command != _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL) {
_cleanup_free_ char *addr_str = NULL, *string_key_name = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL;
/* For non-NON_NULL variant, always convert address to string (even if all zeros).
* For NON_NULL variant, we only get here when have_address is true. */
if (a) {
union in_addr_union addr_union = { .in = *a };
r = in_addr_to_string(AF_INET, &addr_union, &addr_str);
if (r < 0)
goto finish;
}
string_key_name = strjoin(n, "String");
if (!string_key_name) {
r = -ENOMEM;
goto finish;
}
r = sd_json_variant_new_string(&add, n);
if (r < 0)
goto finish;
r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr));
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_key, string_key_name);
if (r < 0)
goto finish;
r = sd_json_variant_new_string(&string_value, addr_str);
if (r < 0)
goto finish;
if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) {
r = -ENOMEM;
goto finish;
}
current->elements[current->n_elements++] = TAKE_PTR(string_key);
current->elements[current->n_elements++] = TAKE_PTR(string_value);
}
}
n_subtract = 4; /* we generated two pairs (binary and string) */
current->expect = EXPECT_OBJECT_KEY;
break;
}
case _JSON_BUILD_PAIR_CALLBACK_NON_NULL: {
sd_json_build_callback_t cb;
void *userdata;
@ -5227,8 +5005,8 @@ done:
r = 0;
finish:
for (size_t i = 0; i < n_stack; i++)
json_stack_release(stack + i);
FOREACH_ARRAY(i, stack, n_stack)
json_stack_release(i);
free(stack);

View File

@ -247,28 +247,20 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha
/* stdio_fds= */ NULL,
/* except_fds= */ (int[]) { pair[1] },
/* n_except_fds= */ 1,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_PACK_FDS|FORK_CLOEXEC_OFF|FORK_REOPEN_LOG|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE,
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
if (r == 0) {
char spid[DECIMAL_STR_MAX(pid_t)+1];
const char *setenv_list[] = {
"LISTEN_FDS", "1",
"LISTEN_PID", spid,
"LISTEN_FDS", "1",
"LISTEN_FDNAMES", "varlink",
NULL, NULL,
};
/* Child */
pair[0] = -EBADF;
r = move_fd(pair[1], 3, /* cloexec= */ false);
if (r < 0) {
log_debug_errno(r, "Failed to move file descriptor to 3: %m");
_exit(EXIT_FAILURE);
}
xsprintf(spid, PID_FMT, pidref.pid);
uint64_t pidfdid;
@ -364,7 +356,7 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) {
/* stdio_fds= */ (int[]) { pair[1], pair[1], STDERR_FILENO },
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
@ -448,7 +440,7 @@ static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) {
/* stdio_fds= */ (int[]) { input_pipe[0], output_pipe[1], STDERR_FILENO },
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
@ -1389,15 +1381,14 @@ static int varlink_format_queue(sd_varlink *v) {
* would not corrupt our fd message boundaries */
while (v->output_queue) {
_cleanup_free_ int *array = NULL;
assert(v->n_output_queue > 0);
VarlinkJsonQueueItem *q = v->output_queue;
if (v->n_output_fds > 0) /* unwritten fds? if we'd add more we'd corrupt the fd message boundaries, hence wait */
return 0;
VarlinkJsonQueueItem *q = v->output_queue;
_cleanup_free_ int *array = NULL;
if (q->n_fds > 0) {
array = newdup(int, q->fds, q->n_fds);
if (!array)
@ -1409,8 +1400,7 @@ static int varlink_format_queue(sd_varlink *v) {
return r;
/* Take possession of the queue element's fds */
free(v->output_fds);
v->output_fds = TAKE_PTR(array);
free_and_replace(v->output_fds, array);
v->n_output_fds = q->n_fds;
q->n_fds = 0;
@ -1593,7 +1583,7 @@ static int varlink_dispatch_method(sd_varlink *v) {
r = callback(v, parameters, flags, v->userdata);
if (VARLINK_STATE_WANTS_REPLY(v->state)) {
if (r < 0) {
varlink_log_errno(v, r, "Callback for %s returned error: %m", method);
varlink_log_errno(v, r, "Callback for '%s' returned error: %m", method);
/* We got an error back from the callback. Propagate it to the client
* if the method call remains unanswered. */
@ -1622,6 +1612,16 @@ static int varlink_dispatch_method(sd_varlink *v) {
varlink_log_errno(v, r, "Failed to process sentinel for method '%s': %m", method);
} else {
assert(!v->previous);
/* We're at the bare minimum referenced by sd_varlink_server and
* sd_varlink_process() */
if (v->n_ref <= 2) {
r = varlink_log_errno(v, SYNTHETIC_ERRNO(EPROTO),
"Callback for method '%s' returned without enqueuing a reply or stashing connection, failing.",
method);
goto fail;
}
r = 0;
}
@ -1857,19 +1857,10 @@ _public_ int sd_varlink_wait(sd_varlink *v, uint64_t timeout) {
r = sd_varlink_get_timeout(v, &t);
if (r < 0)
return r;
if (t != USEC_INFINITY) {
usec_t n;
if (t != USEC_INFINITY)
t = usec_sub_unsigned(t, now(CLOCK_MONOTONIC));
n = now(CLOCK_MONOTONIC);
if (t < n)
t = 0;
else
t = usec_sub_unsigned(t, n);
}
if (timeout != USEC_INFINITY &&
(t == USEC_INFINITY || timeout < t))
t = timeout;
t = MIN(t, timeout);
events = sd_varlink_get_events(v);
if (events < 0)
@ -2019,7 +2010,7 @@ _public_ int sd_varlink_flush(sd_varlink *v) {
return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected.");
for (;;) {
if (v->output_buffer_size == 0)
if (v->output_buffer_size == 0 && !v->output_queue)
break;
if (v->write_disconnected)
return -ECONNRESET;
@ -2681,8 +2672,8 @@ _public_ int sd_varlink_reset_fds(sd_varlink *v) {
* rollback the fds. Note that this is implicitly called whenever an error reply is sent, see
* below. */
close_many(v->output_fds, v->n_output_fds);
v->n_output_fds = 0;
close_many(v->pushed_fds, v->n_pushed_fds);
v->n_pushed_fds = 0;
return 0;
}
@ -2706,7 +2697,7 @@ _public_ int sd_varlink_error(sd_varlink *v, const char *error_id, sd_json_varia
return r;
/* If we have a previous reply still ready make sure we queue it before the error. We only
* ever set "previous" if we're in a streaming method so we pass more=true uncondtionally
* ever set "previous" if we're in a streaming method so we pass more=true unconditionally
* here as we know we're still going to queue an error afterwards. */
r = varlink_enqueue_item(v, v->previous);
if (r < 0)
@ -3556,8 +3547,8 @@ static int validate_connection(sd_varlink_server *server, const struct ucred *uc
c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid)));
if (c >= server->connections_per_uid_max) {
varlink_server_log(server, "Per-UID connection limit of %u reached, refusing.",
server->connections_per_uid_max);
varlink_server_log(server, "Per-UID connection limit of %u for '" UID_FMT "' reached, refusing.",
server->connections_per_uid_max, ucred->uid);
return 0;
}
}
@ -3610,7 +3601,7 @@ _public_ int sd_varlink_server_add_connection_pair(
assert_return(input_fd >= 0, -EBADF);
assert_return(output_fd >= 0, -EBADF);
if ((server->flags & (SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_ACCOUNT_UID)) != 0) {
if ((server->flags & (SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_MYSELF_ONLY|SD_VARLINK_SERVER_ACCOUNT_UID)) != 0) {
if (override_ucred)
ucred = *override_ucred;
@ -3752,11 +3743,7 @@ static int varlink_server_create_listen_fd_socket(sd_varlink_server *s, int fd,
};
if (s->event) {
r = sd_event_add_io(s->event, &ss->event_source, fd, EPOLLIN, connect_callback, ss);
if (r < 0)
return r;
r = sd_event_source_set_priority(ss->event_source, s->event_priority);
r = varlink_server_add_socket_event_source(s, ss);
if (r < 0)
return r;
}
@ -4080,13 +4067,14 @@ _public_ int sd_varlink_server_set_exit_on_idle(sd_varlink_server *s, int b) {
return 0;
}
int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss, int64_t priority) {
int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss) {
_cleanup_(sd_event_source_unrefp) sd_event_source *es = NULL;
int r;
assert(s);
assert(s->event);
assert(ss);
assert(ss->server == s);
assert(ss->fd >= 0);
assert(!ss->event_source);
@ -4094,7 +4082,7 @@ int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSo
if (r < 0)
return r;
r = sd_event_source_set_priority(es, priority);
r = sd_event_source_set_priority(es, s->event_priority);
if (r < 0)
return r;
@ -4116,13 +4104,14 @@ _public_ int sd_varlink_server_attach_event(sd_varlink_server *s, sd_event *e, i
return r;
}
s->event_priority = priority;
LIST_FOREACH(sockets, ss, s->sockets) {
r = varlink_server_add_socket_event_source(s, ss, priority);
r = varlink_server_add_socket_event_source(s, ss);
if (r < 0)
goto fail;
}
s->event_priority = priority;
return 0;
fail:
@ -4293,20 +4282,16 @@ _public_ int sd_varlink_server_add_interface_many_internal(sd_varlink_server *s,
}
_public_ unsigned sd_varlink_server_connections_max(sd_varlink_server *s) {
int dts;
/* If a server is specified, return the setting for that server, otherwise the default value */
if (s)
return s->connections_max;
dts = getdtablesize();
int dts = getdtablesize();
assert_se(dts > 0);
/* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */
if (VARLINK_DEFAULT_CONNECTIONS_MAX > (unsigned) dts / 4 * 3)
return dts / 4 * 3;
return VARLINK_DEFAULT_CONNECTIONS_MAX;
return MIN(VARLINK_DEFAULT_CONNECTIONS_MAX, (unsigned) dts / 4 * 3);
}
_public_ unsigned sd_varlink_server_connections_per_uid_max(sd_varlink_server *s) {

View File

@ -262,4 +262,4 @@ static inline const char* varlink_server_description(sd_varlink_server *s) {
VarlinkServerSocket* varlink_server_socket_free(VarlinkServerSocket *ss);
DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServerSocket *, varlink_server_socket_free);
int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss, int64_t priority);
int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss);

View File

@ -376,7 +376,10 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (m->uid != 0 && m->class != MACHINE_HOST) {
r = pidref_in_same_namespace(&PIDREF_MAKE_FROM_PID(1), &m->leader, NAMESPACE_USER);
if (r < 0)
return r;
return log_debug_errno(
r,
"Failed to check if machine '%s' is running in the root user namespace: %m",
m->name);
if (r != 0)
return sd_bus_error_set(
error,

View File

@ -273,6 +273,7 @@ static int vl_method_mute(
int r;
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
_cleanup_free_ Context *nc = new(Context, 1);
if (!nc)
@ -294,9 +295,6 @@ static int vl_method_mute(
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = sd_varlink_server_bind_disconnect(sd_varlink_get_server(link), vl_on_disconnect);
if (r < 0)
return r;

View File

@ -89,6 +89,8 @@ systemd_networkd_extract_sources = files(
'networkd-util.c',
'networkd-wifi.c',
'networkd-wiphy.c',
'networkd-wwan.c',
'networkd-wwan-bus.c',
'tc/cake.c',
'tc/codel.c',
'tc/drr.c',

View File

@ -29,6 +29,7 @@
#include "networkd-route.h"
#include "networkd-setlink.h"
#include "networkd-state-file.h"
#include "networkd-wwan.h"
#include "parse-util.h"
#include "set.h"
#include "socket-util.h"
@ -1770,6 +1771,9 @@ int dhcp4_start_full(Link *link, bool set_ipv6_connectivity) {
if (!link->dhcp_client)
return 0;
if (link_dhcp_enabled_by_bearer(link, AF_INET) == 0)
return 0;
if (!link_has_carrier(link))
return 0;

View File

@ -24,6 +24,7 @@
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-state-file.h"
#include "networkd-wwan.h"
#include "set.h"
#include "string-table.h"
#include "string-util.h"
@ -494,6 +495,9 @@ int dhcp6_start(Link *link) {
if (!link_dhcp6_enabled(link))
return 0;
if (link_dhcp_enabled_by_bearer(link, AF_INET6) == 0)
return 0;
if (!link_has_carrier(link))
return 0;

View File

@ -26,6 +26,7 @@
#include "networkd-route.h"
#include "networkd-route-util.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-wwan.h"
#include "ordered-set.h"
#include "set.h"
#include "string-util.h"
@ -541,6 +542,15 @@ static int dns_append_json(Link *link, sd_json_variant **v) {
return r;
}
Bearer *b;
if (link_get_bearer(link, &b) >= 0)
FOREACH_ARRAY(dns, b->dns, b->n_dns) {
r = dns_append_json_one(link, *dns, NETWORK_CONFIG_SOURCE_MODEM_MANAGER, NULL, &array);
if (r < 0)
return r;
}
if (link->dhcp_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
const struct in_addr *dns;
union in_addr_union s;
@ -613,7 +623,7 @@ static int dnr_append_json_one(Link *link, const struct sd_dns_resolver *res, Ne
FOREACH_ARRAY(addr, res->addrs, res->n_addrs) {
r = sd_json_variant_append_arrayb(
&addrs_array,
JSON_BUILD_IN_ADDR(addr, res->family));
JSON_BUILD_IN_ADDR(res->family, addr));
if (r < 0)
return r;
}
@ -634,7 +644,7 @@ static int dnr_append_json_one(Link *link, const struct sd_dns_resolver *res, Ne
JSON_BUILD_PAIR_STRING_NON_EMPTY("DoHPath", res->dohpath),
JSON_BUILD_PAIR_STRV_NON_EMPTY("Transports", transports),
SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, res->family)));
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", res->family, p)));
}
static int dnr_append_json(Link *link, sd_json_variant **v) {
@ -723,7 +733,7 @@ static int server_append_json_one_addr(int family, const union in_addr_union *a,
return sd_json_variant_append_arraybo(
array,
SD_JSON_BUILD_PAIR_INTEGER("Family", family),
JSON_BUILD_PAIR_IN_ADDR("Address", a, family),
JSON_BUILD_PAIR_IN_ADDR("Address", family, a),
SD_JSON_BUILD_PAIR_STRING("AddressString", address_str),
SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL("ConfigProvider", family, p));

View File

@ -63,6 +63,7 @@
#include "networkd-state-file.h"
#include "networkd-sysctl.h"
#include "networkd-wifi.h"
#include "networkd-wwan-bus.h"
#include "ordered-set.h"
#include "parse-util.h"
#include "set.h"
@ -529,6 +530,9 @@ void link_check_ready(Link *link) {
if (!link->sr_iov_configured)
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
if (!link->bearer_configured)
return (void) log_link_debug(link, "%s(): Bearer has not been applied.", __func__);
/* IPv6LL is assigned after the link gains its carrier. */
if (!link->network->configure_without_carrier &&
link_ipv6ll_enabled(link) &&
@ -538,7 +542,7 @@ void link_check_ready(Link *link) {
/* All static addresses must be ready. */
bool has_static_address = false;
SET_FOREACH(a, link->addresses) {
if (a->source != NETWORK_CONFIG_SOURCE_STATIC)
if (!IN_SET(a->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_MODEM_MANAGER))
continue;
if (!address_is_ready(a))
return (void) log_link_debug(link, "%s(): static address %s is not ready.", __func__,
@ -1293,6 +1297,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_modem_reconfigure(link);
if (r < 0)
return r;
if (!link_has_carrier(link))
return 0;

View File

@ -108,6 +108,7 @@ typedef struct Link {
unsigned set_link_messages;
unsigned set_flags_messages;
unsigned create_stacked_netdev_messages;
unsigned bearer_messages;
Set *addresses;
Set *neighbors;
@ -141,6 +142,7 @@ typedef struct Link {
bool master_set:1;
bool stacked_netdevs_created:1;
bool bridge_vlan_set:1;
bool bearer_configured:1;
sd_dhcp_server *dhcp_server;

View File

@ -16,6 +16,7 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-manager-varlink.h"
#include "networkd-setlink.h"
#include "stat-util.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.service.h"
@ -92,26 +93,30 @@ static int vl_method_get_namespace_id(sd_varlink *link, sd_json_variant *paramet
SD_JSON_BUILD_PAIR_CONDITION(nsid != UINT32_MAX, "NamespaceNSID", SD_JSON_BUILD_UNSIGNED(nsid)));
}
typedef struct InterfaceInfo {
int ifindex;
const char *ifname;
} InterfaceInfo;
static int dispatch_interface(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, Link **ret) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(InterfaceInfo, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(InterfaceInfo, ifname), 0 },
{}
};
InterfaceInfo info = {};
static int dispatch_interface(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool polkit, Link **ret) {
struct {
int ifindex;
const char *ifname;
} info = {};
Link *link = NULL;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
{}
}, dispatch_polkit_table[] = {
{ "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, voffsetof(info, ifindex), SD_JSON_RELAX },
{ "InterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(info, ifname), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
assert(vlink);
assert(manager);
assert(ret);
r = sd_varlink_dispatch(vlink, parameters, dispatch_table, &info);
r = sd_varlink_dispatch(vlink, parameters, polkit ? dispatch_polkit_table : dispatch_table, &info);
if (r != 0)
return r;
@ -158,7 +163,7 @@ static int vl_method_get_lldp_neighbors(sd_varlink *vlink, sd_json_variant *para
assert(vlink);
assert(manager);
r = dispatch_interface(vlink, parameters, manager, &link);
r = dispatch_interface(vlink, parameters, manager, /* polkit= */ false, &link);
if (r != 0)
return r;
@ -279,6 +284,46 @@ static int vl_method_set_persistent_storage(sd_varlink *vlink, sd_json_variant *
return sd_varlink_reply(vlink, NULL);
}
static int vl_method_link_up_or_down(sd_varlink *vlink, sd_json_variant *parameters, Manager *manager, bool up) {
Link *link;
int r;
assert(vlink);
assert(manager);
r = dispatch_interface(vlink, parameters, manager, /* polkit= */ true, &link);
if (r != 0)
return r;
/* Require a specific link to be specified. */
if (!link)
return sd_varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
r = varlink_verify_polkit_async(
vlink,
manager->bus,
"org.freedesktop.network1.manage-links",
/* details= */ NULL,
&manager->polkit_registry);
if (r <= 0)
return r;
if (!up)
/* Stop all network engines while interface is still up to allow proper cleanup,
* e.g. sending IPv6 shutdown RA messages before the interface is brought down. */
(void) link_stop_engines(link, /* may_keep_dynamic = */ false);
return link_up_or_down_now_by_varlink(link, up, vlink);
}
static int vl_method_link_up(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return vl_method_link_up_or_down(vlink, parameters, userdata, /* up= */ true);
}
static int vl_method_link_down(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return vl_method_link_up_or_down(vlink, parameters, userdata, /* up= */ false);
}
int manager_varlink_init(Manager *m, int fd) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
_unused_ _cleanup_close_ int fd_close = fd; /* take possession */
@ -313,6 +358,8 @@ int manager_varlink_init(Manager *m, int fd) {
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id,
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors,
"io.systemd.Network.SetPersistentStorage", vl_method_set_persistent_storage,
"io.systemd.Network.LinkUp", vl_method_link_up,
"io.systemd.Network.LinkDown", vl_method_link_down,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
"io.systemd.service.GetEnvironment", varlink_method_get_environment);

View File

@ -46,6 +46,7 @@
#include "networkd-state-file.h"
#include "networkd-wifi.h"
#include "networkd-wiphy.h"
#include "networkd-wwan-bus.h"
#include "ordered-set.h"
#include "qdisc.h"
#include "set.h"
@ -96,6 +97,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
if (m->product_uuid_requested)
(void) manager_request_product_uuid(m);
(void) manager_notify_mm_bus_connected(m);
return 0;
}
@ -145,6 +148,8 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
(void) manager_match_mm_signals(m);
return 0;
}
@ -733,6 +738,9 @@ Manager* manager_free(Manager *m) {
set_free(m->rules);
sd_bus_slot_unref(m->slot_mm);
hashmap_free(m->modems_by_path);
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
sd_netlink_unref(m->nfnl);

View File

@ -99,6 +99,10 @@ typedef struct Manager {
Hashmap *wiphy_by_index;
Hashmap *wiphy_by_name;
/* ModemManager support */
sd_bus_slot *slot_mm;
Hashmap *modems_by_path;
/* For link speed meter */
bool use_speed_meter;
sd_event_source *speed_meter_event_source;

View File

@ -40,6 +40,7 @@ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-wwan.h"
#include "qdisc.h"
#include "socket-util.h"
#include "tclass.h"
@ -492,6 +493,9 @@ CAN.ClassicDataLengthCode, config_parse_can_control_mode,
CAN.Termination, config_parse_can_termination, 0, 0
IPoIB.Mode, config_parse_ipoib_mode, 0, offsetof(Network, ipoib_mode)
IPoIB.IgnoreUserspaceMulticastGroups, config_parse_tristate, 0, offsetof(Network, ipoib_umcast)
ModemManager.SimpleConnectProperties, config_parse_strv, 0, offsetof(Network, mm_simple_connect_props)
ModemManager.RouteMetric, config_parse_mm_route_metric, 0, 0
ModemManager.UseGateway, config_parse_tristate, 0, offsetof(Network, mm_use_gateway)
QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0
BFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_BFIFO, 0

View File

@ -512,6 +512,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
.ipoib_umcast = -1,
.mm_use_gateway = -1,
};
r = config_parse_many_full(
@ -551,6 +553,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"LLDP\0"
"TrafficControlQueueingDiscipline\0"
"CAN\0"
"ModemManager\0"
"QDisc\0"
"BFIFO\0"
"CAKE\0"
@ -847,6 +850,9 @@ static Network *network_free(Network *network) {
hashmap_free(network->qdiscs_by_section);
hashmap_free(network->tclasses_by_section);
/* ModemManager */
strv_free(network->mm_simple_connect_props);
return mfree(network);
}

View File

@ -414,6 +414,12 @@ typedef struct Network {
/* NTP */
char **ntp;
/* ModemManager support */
char **mm_simple_connect_props;
int mm_use_gateway;
uint32_t mm_route_metric;
bool mm_route_metric_set;
} Network;
DECLARE_TRIVIAL_REF_UNREF_FUNC(Network, network);

View File

@ -5,7 +5,9 @@
#include <netinet/in.h>
#include "sd-netlink.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "device-private.h"
#include "missing-network.h"
#include "netif-util.h"
@ -1341,6 +1343,103 @@ int link_up_or_down_now(Link *link, bool up) {
return 0;
}
typedef struct SetLinkVarlinkContext {
Link *link;
sd_varlink *vlink;
bool up;
} SetLinkVarlinkContext;
static SetLinkVarlinkContext* set_link_varlink_context_free(SetLinkVarlinkContext *ctx) {
if (!ctx)
return NULL;
if (ctx->vlink)
sd_varlink_unref(ctx->vlink);
if (ctx->link)
link_unref(ctx->link);
return mfree(ctx);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(SetLinkVarlinkContext*, set_link_varlink_context_free);
static void set_link_varlink_context_destroy(SetLinkVarlinkContext *ctx) {
set_link_varlink_context_free(ctx);
}
static int link_up_or_down_now_varlink_handler(sd_netlink *rtnl, sd_netlink_message *m, SetLinkVarlinkContext *ctx) {
int r;
assert(m);
assert(ctx);
Link *link = ASSERT_PTR(ctx->link);
sd_varlink *vlink = ASSERT_PTR(ctx->vlink);
bool up = ctx->up;
assert(link->set_flags_messages > 0);
link->set_flags_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
(void) sd_varlink_error_errno(vlink, r);
log_link_message_warning_errno(link, m, r, "Could not bring %s interface", up_or_down(up));
} else
(void) sd_varlink_reply(vlink, NULL);
if (link->state == LINK_STATE_LINGER)
return 0;
r = link_call_getlink(link, get_link_update_flag_handler);
if (r < 0) {
link_enter_failed(link);
return 0;
}
link->set_flags_messages++;
return 0;
}
int link_up_or_down_now_by_varlink(Link *link, bool up, sd_varlink *vlink) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(link->manager->rtnl);
log_link_debug(link, "Bringing link %s (varlink)", up_or_down(up));
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_warning_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_flags(req, up ? IFF_UP : 0, IFF_UP);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set link flags: %m");
_cleanup_(set_link_varlink_context_freep) SetLinkVarlinkContext *ctx = new(SetLinkVarlinkContext, 1);
if (!ctx)
return log_oom();
*ctx = (SetLinkVarlinkContext) {
.link = link_ref(link),
.vlink = sd_varlink_ref(vlink),
.up = up,
};
r = netlink_call_async(link->manager->rtnl, NULL, req,
link_up_or_down_now_varlink_handler,
set_link_varlink_context_destroy,
ctx);
if (r < 0)
return log_link_warning_errno(link, r, "Could not send rtnetlink message: %m");
TAKE_PTR(ctx);
link->set_flags_messages++;
return 0;
}
int link_down_slave_links(Link *link) {
Link *slave;
int r;

View File

@ -22,6 +22,7 @@ int link_request_to_activate(Link *link);
int link_request_to_bring_up_or_down(Link *link, bool up);
int link_up_or_down_now(Link *link, bool up);
int link_up_or_down_now_by_varlink(Link *link, bool up, sd_varlink *vlink);
static inline int link_up_now(Link *link) {
return link_up_or_down_now(link, true);
}

View File

@ -23,6 +23,7 @@
#include "networkd-network.h"
#include "networkd-ntp.h"
#include "networkd-state-file.h"
#include "networkd-wwan.h"
#include "ordered-set.h"
#include "set.h"
#include "string-util.h"
@ -109,6 +110,14 @@ static int link_put_dns(Link *link, OrderedSet **s) {
if (r < 0)
return r;
Bearer *b;
if (link_get_bearer(link, &b) >= 0) {
r = ordered_set_put_dns_servers(s, link->ifindex, b->dns, b->n_dns);
if (r < 0)
return r;
}
if (link->dhcp_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
const struct in_addr *addresses;
@ -801,6 +810,11 @@ static int link_save(Link *link) {
space = false;
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
Bearer *b;
if (link_get_bearer(link, &b) >= 0)
link_save_dns(link, f, b->dns, b->n_dns, &space);
/* DNR resolvers are not required to provide Do53 service, however resolved doesn't
* know how to handle such a server so for now Do53 service is required, and
* assumed. */

View File

@ -17,14 +17,15 @@
/* This is used in log messages, and never used in parsing settings. So, upper cases are OK. */
static const char * const network_config_source_table[_NETWORK_CONFIG_SOURCE_MAX] = {
[NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
[NETWORK_CONFIG_SOURCE_STATIC] = "static",
[NETWORK_CONFIG_SOURCE_IPV4LL] = "IPv4LL",
[NETWORK_CONFIG_SOURCE_DHCP4] = "DHCPv4",
[NETWORK_CONFIG_SOURCE_DHCP6] = "DHCPv6",
[NETWORK_CONFIG_SOURCE_DHCP_PD] = "DHCP-PD",
[NETWORK_CONFIG_SOURCE_NDISC] = "NDisc",
[NETWORK_CONFIG_SOURCE_RUNTIME] = "runtime",
[NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
[NETWORK_CONFIG_SOURCE_STATIC] = "static",
[NETWORK_CONFIG_SOURCE_IPV4LL] = "IPv4LL",
[NETWORK_CONFIG_SOURCE_DHCP4] = "DHCPv4",
[NETWORK_CONFIG_SOURCE_DHCP6] = "DHCPv6",
[NETWORK_CONFIG_SOURCE_DHCP_PD] = "DHCP-PD",
[NETWORK_CONFIG_SOURCE_NDISC] = "NDisc",
[NETWORK_CONFIG_SOURCE_RUNTIME] = "runtime",
[NETWORK_CONFIG_SOURCE_MODEM_MANAGER] = "ModemManager",
};
DEFINE_STRING_TABLE_LOOKUP(network_config_source, NetworkConfigSource);

View File

@ -14,6 +14,7 @@ typedef enum NetworkConfigSource {
NETWORK_CONFIG_SOURCE_DHCP_PD,
NETWORK_CONFIG_SOURCE_NDISC,
NETWORK_CONFIG_SOURCE_RUNTIME, /* through D-Bus method */
NETWORK_CONFIG_SOURCE_MODEM_MANAGER,
_NETWORK_CONFIG_SOURCE_MAX,
_NETWORK_CONFIG_SOURCE_INVALID = -EINVAL,
} NetworkConfigSource;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
typedef struct Manager Manager;
typedef struct Link Link;
/* From ModemManager-enums.h */
typedef enum {
MM_BEARER_IP_FAMILY_NONE = 0,
MM_BEARER_IP_FAMILY_IPV4 = 1 << 0,
MM_BEARER_IP_FAMILY_IPV6 = 1 << 1,
MM_BEARER_IP_FAMILY_IPV4V6 = 1 << 2,
MM_BEARER_IP_FAMILY_ANY = 0xFFFFFFFF,
} MMBearerIpFamily;
typedef enum {
MM_BEARER_TYPE_UNKNOWN = 0,
MM_BEARER_TYPE_DEFAULT = 1,
MM_BEARER_TYPE_DEFAULT_ATTACH = 2,
MM_BEARER_TYPE_DEDICATED = 3,
} MMBearerType;
typedef enum {
MM_MODEM_STATE_FAILED = -1,
MM_MODEM_STATE_UNKNOWN = 0,
MM_MODEM_STATE_INITIALIZING = 1,
MM_MODEM_STATE_LOCKED = 2,
MM_MODEM_STATE_DISABLED = 3,
MM_MODEM_STATE_DISABLING = 4,
MM_MODEM_STATE_ENABLING = 5,
MM_MODEM_STATE_ENABLED = 6,
MM_MODEM_STATE_SEARCHING = 7,
MM_MODEM_STATE_REGISTERED = 8,
MM_MODEM_STATE_DISCONNECTING = 9,
MM_MODEM_STATE_CONNECTING = 10,
MM_MODEM_STATE_CONNECTED = 11,
} MMModemState;
typedef enum { /*< underscore_name=mm_modem_state_failed_reason >*/
MM_MODEM_STATE_FAILED_REASON_NONE = 0,
MM_MODEM_STATE_FAILED_REASON_UNKNOWN = 1,
MM_MODEM_STATE_FAILED_REASON_SIM_MISSING = 2,
MM_MODEM_STATE_FAILED_REASON_SIM_ERROR = 3,
MM_MODEM_STATE_FAILED_REASON_UNKNOWN_CAPABILITIES = 4,
MM_MODEM_STATE_FAILED_REASON_ESIM_WITHOUT_PROFILES = 5,
__MM_MODEM_STATE_FAILED_REASON_MAX = 6,
} MMModemStateFailedReason;
typedef enum {
MM_BEARER_IP_METHOD_UNKNOWN = 0,
MM_BEARER_IP_METHOD_PPP = 1,
MM_BEARER_IP_METHOD_STATIC = 2,
MM_BEARER_IP_METHOD_DHCP = 3,
} MMBearerIpMethod;
typedef enum { /*< underscore_name=mm_modem_port_type >*/
MM_MODEM_PORT_TYPE_UNKNOWN = 1,
MM_MODEM_PORT_TYPE_NET = 2,
MM_MODEM_PORT_TYPE_AT = 3,
MM_MODEM_PORT_TYPE_QCDM = 4,
MM_MODEM_PORT_TYPE_GPS = 5,
MM_MODEM_PORT_TYPE_QMI = 6,
MM_MODEM_PORT_TYPE_MBIM = 7,
MM_MODEM_PORT_TYPE_AUDIO = 8,
MM_MODEM_PORT_TYPE_IGNORED = 9,
MM_MODEM_PORT_TYPE_XMMRPC = 10,
} MMModemPortType;
typedef enum { /*< underscore_name=mm_bearer_allowed_auth >*/
MM_BEARER_ALLOWED_AUTH_UNKNOWN = 0,
/* bits 0..4 order match Ericsson device bitmap */
MM_BEARER_ALLOWED_AUTH_NONE = 1 << 0,
MM_BEARER_ALLOWED_AUTH_PAP = 1 << 1,
MM_BEARER_ALLOWED_AUTH_CHAP = 1 << 2,
MM_BEARER_ALLOWED_AUTH_MSCHAP = 1 << 3,
MM_BEARER_ALLOWED_AUTH_MSCHAPV2 = 1 << 4,
MM_BEARER_ALLOWED_AUTH_EAP = 1 << 5,
} MMBearerAllowedAuth;
typedef enum {
MODEM_RECONNECT_DONE, /* No reconnect is required, e.g. connected. */
MODEM_RECONNECT_SCHEDULED, /* Reconnect is in progress. */
MODEM_RECONNECT_WAITING, /* Waiting for modem to recover. */
} ModemReconnectState;
int manager_notify_mm_bus_connected(Manager *manager);
int manager_match_mm_signals(Manager *manager);
int link_modem_reconfigure(Link *link);

641
src/network/networkd-wwan.c Normal file
View File

@ -0,0 +1,641 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "bus-util.h"
#include "hashmap.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
#include "networkd-link.h"
#include "networkd-setlink.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-route.h"
#include "networkd-wwan.h"
#include "parse-util.h"
#include "sd-dhcp-client.h"
#include "sd-dhcp6-client.h"
#include "sd-ndisc.h"
#include "set.h"
#include "string-util.h"
Bearer* bearer_free(Bearer *b) {
if (!b)
return NULL;
if (b->modem) {
if (b->path)
hashmap_remove_value(b->modem->bearers_by_path, b->path, b);
if (b->name)
hashmap_remove_value(b->modem->bearers_by_name, b->name, b);
}
sd_bus_slot_unref(b->slot_getall);
free(b->path);
free(b->name);
free(b->apn);
in_addr_full_array_free(b->dns, b->n_dns);
return mfree(b);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
bearer_hash_ops,
char,
string_hash_func,
string_compare_func,
Bearer,
bearer_free);
int bearer_new(Modem *modem, const char *path, Bearer **ret) {
_cleanup_(bearer_freep) Bearer *b = NULL;
_cleanup_free_ char *p = NULL;
int r;
assert(modem);
assert(path);
if (hashmap_contains(modem->bearers_by_path, path))
return -EEXIST;
p = strdup(path);
if (!p)
return -ENOMEM;
b = new(Bearer, 1);
if (!b)
return -ENOMEM;
*b = (Bearer) {
.modem = modem,
.path = TAKE_PTR(p),
};
r = hashmap_ensure_put(&modem->bearers_by_path, &bearer_hash_ops, b->path, b);
if (r < 0)
return r;
if (ret)
*ret = b;
TAKE_PTR(b);
return 0;
}
int bearer_set_name(Bearer *b, const char *name) {
Bearer *old;
int r;
assert(b);
assert(b->modem);
assert(name);
if (streq_ptr(b->name, name))
return 0;
if (b->name)
hashmap_remove_value(b->modem->bearers_by_name, b->name, b);
if (isempty(name)) {
b->name = mfree(b->name);
return 0;
}
r = free_and_strdup(&b->name, name);
if (r < 0)
return r;
/*
* FIXME: it is possible during reconnect that an interface is already
* registered in the hash map: if simple connect options
* are changed, e.g. externally modified .network file and then
* reloaded with 'networkctl reload'. This may create a new bearer
* attached to the same interface name, e.g. "wwan0". The order in which
* we parse the bearer properties is undetermined and it can be that we
* need to raplce the old one with the new one now, so only one bearer
* with the given interface name exists.
*/
old = hashmap_get(b->modem->bearers_by_name, name);
if (old) {
hashmap_remove_value(old->modem->bearers_by_name, name, old);
old->name = mfree(old->name);
}
return hashmap_ensure_put(&b->modem->bearers_by_name, &bearer_hash_ops, b->name, b);
}
int bearer_get_by_path(Manager *manager, const char *path, Modem **ret_modem, Bearer **ret_bearer) {
Modem *modem;
Bearer *b;
assert(manager);
assert(path);
HASHMAP_FOREACH(modem, manager->modems_by_path) {
b = hashmap_get(modem->bearers_by_path, path);
if (!b)
continue;
if (ret_bearer)
*ret_bearer = b;
if (ret_modem)
*ret_modem = modem;
return 0;
}
return -ENOENT;
}
Modem* modem_free(Modem *modem) {
if (!modem)
return NULL;
if (modem->bearers_by_name)
hashmap_free(modem->bearers_by_name);
if (modem->bearers_by_path)
hashmap_free(modem->bearers_by_path);
if (modem->manager)
hashmap_remove_value(modem->manager->modems_by_path, modem->path, modem);
sd_bus_slot_unref(modem->slot_propertieschanged);
sd_bus_slot_unref(modem->slot_statechanged);
sd_bus_slot_unref(modem->slot_connect);
free(modem->path);
free(modem->manufacturer);
free(modem->model);
free(modem->port_name);
return mfree(modem);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
modems_hash_ops,
char,
string_hash_func,
string_compare_func,
Modem,
modem_free);
int modem_new(Manager *m, const char *path, Modem **ret) {
_cleanup_(modem_freep) Modem *modem = NULL;
_cleanup_free_ char *p = NULL;
int r;
assert(m);
assert(path);
if (hashmap_contains(m->modems_by_path, path))
return -EEXIST;
p = strdup(path);
if (!p)
return -ENOMEM;
modem = new(Modem, 1);
if (!modem)
return -ENOMEM;
*modem = (Modem) {
.manager = m,
.path = TAKE_PTR(p),
};
r = hashmap_ensure_put(&m->modems_by_path, &modems_hash_ops, modem->path, modem);
if (r < 0)
return r;
if (ret)
*ret = modem;
TAKE_PTR(modem);
return 0;
}
int modem_get_by_path(Manager *m, const char *path, Modem **ret) {
Modem *modem;
assert(m);
assert(path);
modem = hashmap_get(m->modems_by_path, path);
if (!modem)
return -ENOENT;
if (ret)
*ret = modem;
return 0;
}
int link_get_modem(Link *link, Modem **ret) {
Modem *modem;
assert(link);
assert(link->manager);
assert(link->ifname);
HASHMAP_FOREACH(modem, link->manager->modems_by_path)
if (modem->port_name && streq(modem->port_name, link->ifname)) {
*ret = modem;
return 0;
}
return -ENOENT;
}
int link_get_bearer(Link *link, Bearer **ret) {
Modem *modem;
assert(link);
assert(link->manager);
assert(link->ifname);
HASHMAP_FOREACH(modem, link->manager->modems_by_path) {
Bearer *b;
b = hashmap_get(modem->bearers_by_name, link->ifname);
if (!b)
continue;
if (ret)
*ret = b;
return 0;
}
return -ENOENT;
}
int link_dhcp_enabled_by_bearer(Link *link, int family) {
Bearer *b;
int r;
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
r = link_get_bearer(link, &b);
if (r < 0)
return r;
if (!b->connected)
return false;
if (!FLAGS_SET(b->ip_type, family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6))
return false;
return (family == AF_INET ? b->ip4_method : b->ip6_method) == MM_BEARER_IP_METHOD_DHCP;
}
static int bearer_address_handler(
sd_netlink *rtnl,
sd_netlink_message *m,
Request *req,
Link *link,
Address *address) {
int r;
assert(link);
r = address_configure_handler_internal(m, link, address);
if (r <= 0)
return r;
if (link->bearer_messages == 0) {
link->bearer_configured = true;
link_check_ready(link);
}
return 0;
}
static int link_request_bearer_address(
Link *link,
int family,
const union in_addr_union *addr,
unsigned prefixlen) {
_cleanup_(address_unrefp) Address *address = NULL;
Address *existing;
int r;
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(addr);
if (!in_addr_is_set(family, addr))
return 0;
r = address_new(&address);
if (r < 0)
return log_oom();
address->source = NETWORK_CONFIG_SOURCE_MODEM_MANAGER;
address->family = family;
address->in_addr = *addr;
address->prefixlen = prefixlen;
if (address_get(link, address, &existing) < 0) /* The address is new. */
link->bearer_configured = false;
else
address_unmark(existing);
r = link_request_address(link, address, &link->bearer_messages,
bearer_address_handler, /* ret = */ NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request address provided by bearer: %m");
return 0;
}
static int bearer_route_handler(
sd_netlink *rtnl,
sd_netlink_message *m,
Request *req,
Link *link,
Route *route) {
int r;
assert(link);
r = route_configure_handler_internal(m, req, route);
if (r <= 0)
return r;
if (link->bearer_messages == 0) {
link->bearer_configured = true;
link_check_ready(link);
}
return 0;
}
static int link_request_bearer_route(
Link *link,
int family,
const union in_addr_union *gw,
const union in_addr_union *prefsrc) {
_cleanup_(route_unrefp) Route *route = NULL;
Route *existing;
int r;
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(gw);
assert(prefsrc);
if (!in_addr_is_set(family, gw))
return 0;
if (link->network->mm_use_gateway == 0)
return 0;
r = route_new(&route);
if (r < 0)
return log_oom();
route->source = NETWORK_CONFIG_SOURCE_MODEM_MANAGER;
route->family = family;
route->nexthop.family = family;
route->nexthop.gw = *gw;
if (link->network->mm_route_metric_set) {
route->priority = link->network->mm_route_metric;
route->priority_set = true;
}
if (prefsrc)
route->prefsrc = *prefsrc;
if (route_get(link->manager, route, &existing) < 0) /* This is a new route. */
link->bearer_configured = false;
else
route_unmark(existing);
r = link_request_route(link, route, &link->bearer_messages, bearer_route_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request gateway provided by bearer: %m");
return 0;
}
static int link_apply_bearer_impl(Link *link, Bearer *b) {
Address *address;
Route *route;
int r, ret = 0;
assert(link);
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
/* First, mark bearer configs. */
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
continue;
address_mark(address);
}
SET_FOREACH(route, link->manager->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
continue;
route_mark(route);
}
if (b && FLAGS_SET(b->ip_type, ADDRESS_FAMILY_IPV4)) {
if (b->connected && b->ip4_method == MM_BEARER_IP_METHOD_STATIC) {
r = link_request_bearer_address(link, AF_INET, &b->ip4_address, b->ip4_prefixlen);
if (r < 0)
return r;
r = link_request_bearer_route(link, AF_INET, &b->ip4_gateway, &b->ip4_address);
if (r < 0)
return r;
}
if (b->connected && b->ip4_method == MM_BEARER_IP_METHOD_DHCP) {
if (!link_dhcp4_enabled(link))
log_link_notice(link, "The WWAN connection requested DHCPv4 client, but it is disabled.");
r = dhcp4_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
} else {
r = sd_dhcp_client_stop(link->dhcp_client);
if (r < 0)
ret = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
}
}
if (b && FLAGS_SET(b->ip_type, ADDRESS_FAMILY_IPV6)) {
if (b->connected && b->ip6_method == MM_BEARER_IP_METHOD_STATIC) {
r = link_request_bearer_address(link, AF_INET6, &b->ip6_address, b->ip6_prefixlen);
if (r < 0)
return r;
r = link_request_bearer_route(link, AF_INET6, &b->ip6_gateway, NULL);
if (r < 0)
return r;
}
if (b->connected && b->ip6_method == MM_BEARER_IP_METHOD_DHCP) {
if (!link_ndisc_enabled(link) && !link_dhcp6_enabled(link))
log_link_notice(link,
"The WWAN connection requested IPv6 dynamic address configuration,"
"but both IPv6 Router Discovery and DHCPv6 client are disabled.");
r = ndisc_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
r = dhcp6_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
} else {
r = sd_dhcp6_client_stop(link->dhcp6_client);
if (r < 0)
ret = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
r = sd_ndisc_stop(link->ndisc);
if (r < 0)
ret = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
}
}
/* Finally, remove all marked configs. */
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
continue;
if (!address_is_marked(address))
continue;
r = address_remove(address, link);
if (r < 0)
ret = r;
}
SET_FOREACH(route, link->manager->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
continue;
if (!route_is_marked(route))
continue;
r = route_remove(route, link->manager);
if (ret)
ret = r;
}
if (ret < 0)
return ret;
if (link->bearer_messages == 0)
link->bearer_configured = true;
if (!link->bearer_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}
int link_apply_bearer(Link *link) {
Bearer *b = NULL;
int r;
assert(link);
(void) link_get_bearer(link, &b);
r = link_apply_bearer_impl(link, b);
if (r < 0)
link_enter_failed(link);
return r;
}
int bearer_update_link(Bearer *b) {
Link *link;
int r;
assert(b);
assert(b->modem);
assert(b->modem->manager);
if (!b->name)
return 0;
if (link_get_by_name(b->modem->manager, b->name, &link) < 0)
return 0;
r = link_apply_bearer_impl(link, b);
if (r < 0)
link_enter_failed(link);
/*
* Need to bring up the interface after the modem has connected.
* This is because ModemManger does the following while connecting:
* <msg> [1755871777.322239] [modem2] state changed (registered -> connecting)
* <dbg> [1755871777.325012] [modem2/bearer5] launching connection with QMI port (cdc-wdm0) and data port (wwan0) (multiplex none)
* <dbg> [1755871777.327665] [cdc-wdm0/qmi] bringing down data interface 'wwan0'
* <dbg> [1755871777.330108] [modem2/wwan0/net] interface index: 9
* <dbg> [1755871777.335265] [cdc-wdm0/qmi] deleting all links in data interface 'wwan0'
*/
r = link_request_to_bring_up_or_down(link, b->connected);
if (r < 0)
link_enter_failed(link);
return 0;
}
void bearer_drop(Bearer *b) {
assert(b);
b->connected = false;
b->apn = mfree(b->apn);
(void) bearer_update_link(b);
bearer_free(b);
}
int config_parse_mm_route_metric(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
network->mm_route_metric_set = false;
return 0;
}
r = safe_atou32(rvalue, &network->mm_route_metric);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
network->mm_route_metric_set = true;
return 0;
}

View File

@ -0,0 +1,80 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "conf-parser-forward.h"
#include "in-addr-util.h"
#include "network-util.h"
#include "networkd-wwan-bus.h"
typedef struct Modem Modem;
typedef struct Bearer {
Modem *modem;
sd_bus_slot *slot_getall; /* for GetAll method */
char *path; /* DBus path e.g /org/freedesktop/ModemManager/Bearer/0 */
char *name; /* Interface property, e.g. wwan0 */
char *apn; /* "apn" field in Properties */
AddressFamily ip_type; /* "ip-type" field in Properties */
/* Ip4Config or IP6Config property */
MMBearerIpMethod ip4_method;
MMBearerIpMethod ip6_method;
unsigned ip4_prefixlen;
unsigned ip6_prefixlen;
union in_addr_union ip4_address;
union in_addr_union ip6_address;
union in_addr_union ip4_gateway;
union in_addr_union ip6_gateway;
struct in_addr_full **dns;
size_t n_dns;
uint32_t ip4_mtu;
uint32_t ip6_mtu;
bool connected; /* Connected property */
} Bearer;
typedef struct Modem {
Manager *manager;
sd_bus_slot *slot_propertieschanged;
sd_bus_slot *slot_statechanged;
sd_bus_slot *slot_connect;
char *path; /* DBus path e.g /org/freedesktop/ModemManager/Modem/0 */
char *manufacturer; /* The "Manufacturer" property */
char *model; /* The "Model" property */
char *port_name; /* MM_MODEM_PORT_TYPE_NET of Ports property */
Hashmap *bearers_by_path;
Hashmap *bearers_by_name;
MMModemState state;
MMModemStateFailedReason state_fail_reason;
ModemReconnectState reconnect_state;
} Modem;
int bearer_new(Modem *modem, const char *path, Bearer **ret);
Bearer* bearer_free(Bearer *b);
DEFINE_TRIVIAL_CLEANUP_FUNC(Bearer*, bearer_free);
int bearer_set_name(Bearer *b, const char *name);
int bearer_get_by_path(Manager *manager, const char *path, Modem **ret_modem, Bearer **ret_bearer);
int link_get_bearer(Link *link, Bearer **ret);
int link_dhcp_enabled_by_bearer(Link *link, int family);
int link_apply_bearer(Link *link);
int bearer_update_link(Bearer *b);
void bearer_drop(Bearer *b);
int modem_new(Manager *m, const char *path, Modem **ret);
Modem* modem_free(Modem *modem);
DEFINE_TRIVIAL_CLEANUP_FUNC(Modem*, modem_free);
int modem_get_by_path(Manager *m, const char *path, Modem **ret);
int link_get_modem(Link *link, Modem **ret);
CONFIG_PARSER_PROTOTYPE(config_parse_mm_route_metric);

View File

@ -194,4 +194,15 @@
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
</action>
<action id="org.freedesktop.network1.manage-links">
<description gettext-domain="systemd">Manage network links</description>
<message gettext-domain="systemd">Authentication is required to manage network links.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
</action>
</policyconfig>

View File

@ -541,9 +541,8 @@ static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t
log_error_errno(r, "Failed to select any cgroups under %s based on pressure, ignoring: %m", t->path);
else {
/* Don't act on all the high pressure cgroups at once; return as soon as we kill one.
* If r == 0 then it means there were not eligible candidates, the candidate cgroup
* disappeared, or the candidate cgroup has no processes by the time we tried to kill
* it. In either case, go through the event loop again and select a new candidate if
* If r == 0 then the cgroup is already queued for kill by an earlier iteration.
* In either case, go through the event loop again and select a new candidate if
* pressure is still high. */
m->mem_pressure_post_action_delay_start = usec_now;
if (selected && r > 0) {

View File

@ -494,12 +494,20 @@ int oomd_cgroup_kill_mark(Manager *m, OomdCGroupContext *ctx) {
r = set_ensure_put(&m->kill_states, &oomd_kill_state_hash_ops, ks);
if (r < 0)
return log_oom_debug();
if (r == 0) {
/* The cgroup is already queued. Drop only this temporary object, because running the normal
* cleanup path would remove by cgroup path key and could interfere with the existing queued
* kill state. */
oomd_cgroup_context_unref(ks->ctx);
ks = mfree(ks);
return 0;
}
r = oomd_prekill_hook(m, ks);
if (r < 0)
log_warning_errno(r, "oomd prekill hook failed for %s, ignoring: %m", ctx->path);
return 0;
return 1;
}
typedef void (*dump_candidate_func)(const OomdCGroupContext *ctx, FILE *f, const char *prefix);

View File

@ -5404,6 +5404,7 @@ static int vl_method_read_event_log(sd_varlink *link, sd_json_variant *parameter
int r;
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)

View File

@ -10324,14 +10324,12 @@ static int vl_method_list_candidate_devices(
int r;
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
BlockDevice *l = NULL;
size_t n = 0;
CLEANUP_ARRAY(l, n, block_device_array_free);

View File

@ -21,3 +21,4 @@ struct ConfigPerfItem;
Delegate.DNS, config_parse_delegate_dns_servers, 0, 0
Delegate.Domains, config_parse_delegate_domains, 0, 0
Delegate.DefaultRoute, config_parse_tristate, 0, offsetof(DnsDelegate, default_route)
Delegate.FirewallMark, config_parse_unsigned, 0, offsetof(DnsDelegate, fwmark)

View File

@ -23,6 +23,8 @@ typedef struct DnsDelegate {
int default_route;
uint32_t fwmark;
DnsScope *scope;
LIST_FIELDS(DnsDelegate, delegates);

View File

@ -475,6 +475,12 @@ static int dns_scope_socket(
return r;
}
if (s->delegate && s->delegate->fwmark > 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_MARK, s->delegate->fwmark);
if (r < 0)
return log_debug_errno(r, "Failed to set firewall mark on DNS socket: %m)");
}
bool addr_is_nonlocal = s->link &&
!manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0;

View File

@ -1374,7 +1374,7 @@ int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **r
return sd_json_buildo(
ret,
JSON_BUILD_PAIR_STRING_NON_EMPTY("addressString", dns_server_string(server)),
JSON_BUILD_PAIR_IN_ADDR("address", &server->address, server->family),
JSON_BUILD_PAIR_IN_ADDR("address", server->family, &server->address),
SD_JSON_BUILD_PAIR_INTEGER("family", server->family),
SD_JSON_BUILD_PAIR_UNSIGNED("port", dns_server_port(server)),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),

View File

@ -1214,10 +1214,7 @@ static int vl_method_browse_services(sd_varlink* link, sd_json_variant* paramete
int r = 0;
assert(link);
/* if the client didn't set the more flag, it is using us incorrectly */
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
m = ASSERT_PTR(sd_varlink_server_get_userdata(sd_varlink_get_server(link)));
@ -1239,9 +1236,7 @@ static int vl_method_subscribe_query_results(sd_varlink *link, sd_json_variant *
Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link)));
int r;
/* if the client didn't set the more flag, it is using us incorrectly */
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-query-results");
if (r <= 0)
@ -1382,9 +1377,7 @@ static int vl_method_subscribe_dns_configuration(sd_varlink *link, sd_json_varia
Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link)));
int r;
/* if the client didn't set the more flag, it is using us incorrectly */
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-dns-configuration");
if (r <= 0)

View File

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_APPARMOR
#include <syslog.h>
#include "alloc-util.h"
@ -67,4 +65,3 @@ bool mac_apparmor_use(void) {
return (cached_use = true);
}
#endif

View File

@ -831,10 +831,6 @@ int ask_password_agent(
_cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, inotify_fd = -EBADF, dfd = -EBADF;
_cleanup_(unlink_and_freep) char *socket_name = NULL;
_cleanup_free_ char *temp = NULL, *final = NULL;
_cleanup_strv_free_erase_ char **l = NULL;
_cleanup_fclose_ FILE *f = NULL;
sigset_t mask, oldmask;
int r;
assert(req);
@ -850,64 +846,59 @@ int ask_password_agent(
if (req->flag_file)
return -EOPNOTSUPP;
_cleanup_free_ char *askpwdir = NULL;
r = get_ask_password_directory_for_flags(flags, &askpwdir);
if (r < 0)
return r;
if (r == 0)
return -ENXIO;
dfd = open_mkdir(askpwdir, O_CLOEXEC, 0755);
if (dfd < 0)
return log_debug_errno(dfd, "Failed to open directory '%s': %m", askpwdir);
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req->keyring) {
r = ask_password_keyring(req, flags, ret);
if (r != -ENOKEY)
return r;
inotify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
if (inotify_fd < 0)
return -errno;
r = inotify_add_watch_fd(inotify_fd, dfd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
if (r < 0)
return r;
}
sigset_t mask, oldmask;
_unused_ _cleanup_(block_signals_reset) sigset_t *saved_ssp = NULL;
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
_cleanup_free_ char *askpwdir = NULL;
r = get_ask_password_directory_for_flags(flags, &askpwdir);
saved_ssp = &oldmask;
_cleanup_free_ char *fname = NULL, *final = NULL;
_cleanup_fclose_ FILE *f = NULL;
if (asprintf(&final, "ask.%" PRIu64, random_u64()) < 0)
return -ENOMEM;
r = fopen_temporary_at(dfd, final, &f, &fname);
if (r < 0)
goto finish;
if (r == 0) {
r = -ENXIO;
goto finish;
}
return r;
dfd = open_mkdir(askpwdir, O_RDONLY|O_CLOEXEC, 0755);
if (dfd < 0) {
r = log_debug_errno(dfd, "Failed to open directory '%s': %m", askpwdir);
goto finish;
}
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req->keyring) {
r = ask_password_keyring(req, flags, ret);
if (r >= 0) {
r = 0;
goto finish;
} else if (r != -ENOKEY)
goto finish;
inotify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
if (inotify_fd < 0) {
r = -errno;
goto finish;
}
r = inotify_add_watch_fd(inotify_fd, dfd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
if (r < 0)
goto finish;
}
if (asprintf(&final, "ask.%" PRIu64, random_u64()) < 0) {
r = -ENOMEM;
goto finish;
}
r = fopen_temporary_at(dfd, final, &f, &temp);
if (r < 0)
goto finish;
CLEANUP_TMPFILE_AT(dfd, fname);
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0) {
r = -errno;
goto finish;
}
if (signal_fd < 0)
return -errno;
socket_fd = create_socket(askpwdir, &socket_name);
if (socket_fd < 0) {
r = socket_fd;
goto finish;
}
if (socket_fd < 0)
return socket_fd;
fprintf(f,
"[Ask]\n"
@ -933,21 +924,19 @@ int ask_password_agent(
if (req->id)
fprintf(f, "Id=%s\n", req->id);
if (fchmod(fileno(f), 0644) < 0) {
r = -errno;
goto finish;
}
if (fchmod(fileno(f), 0644) < 0)
return -errno;
r = fflush_and_check(f);
if (r < 0)
goto finish;
return r;
if (renameat(dfd, temp, dfd, final) < 0) {
r = -errno;
goto finish;
}
/* Paranoia: never clobber an ongoing request */
r = rename_noreplace(dfd, fname, dfd, final);
if (r < 0)
return r;
temp = mfree(temp);
free_and_replace(fname, final);
enum {
POLL_SOCKET,
@ -969,20 +958,17 @@ int ask_password_agent(
.events = POLLIN,
};
if (req->hup_fd >= 0)
pollfd[hup_fd_idx = n_pollfd ++] = (struct pollfd) {
pollfd[hup_fd_idx = n_pollfd++] = (struct pollfd) {
.fd = req->hup_fd,
.events = POLLHUP,
};
assert(n_pollfd <= _POLL_MAX);
_cleanup_strv_free_erase_ char **l = NULL;
for (;;) {
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
char passphrase[LINE_MAX+1];
struct iovec iovec;
struct ucred *ucred;
usec_t timeout;
ssize_t n;
if (req->until > 0)
timeout = usec_sub_unsigned(req->until, now(CLOCK_MONOTONIC));
@ -993,45 +979,34 @@ int ask_password_agent(
if (r == -EINTR)
continue;
if (r < 0)
goto finish;
if (r == 0) {
r = -ETIME;
goto finish;
}
return r;
if (r == 0)
return -ETIME;
if (pollfd[POLL_SIGNAL].revents & POLLIN) {
r = -EINTR;
goto finish;
}
if (pollfd[POLL_SIGNAL].revents & POLLIN)
return -EINTR;
if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP) {
r = -ECONNRESET;
goto finish;
}
if (req->hup_fd >= 0 && pollfd[hup_fd_idx].revents & POLLHUP)
return -ECONNRESET;
if (inotify_fd >= 0 && pollfd[inotify_idx].revents != 0) {
(void) flush_fd(inotify_fd);
if (req->keyring) {
r = ask_password_keyring(req, flags, ret);
if (r >= 0) {
r = 0;
goto finish;
} else if (r != -ENOKEY)
goto finish;
if (r != -ENOKEY)
return r;
}
}
if (pollfd[POLL_SOCKET].revents == 0)
continue;
if (pollfd[POLL_SOCKET].revents != POLLIN)
return -EIO;
if (pollfd[POLL_SOCKET].revents != POLLIN) {
r = -EIO;
goto finish;
}
iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
char passphrase[LINE_MAX+1];
struct iovec iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
@ -1039,7 +1014,7 @@ int ask_password_agent(
.msg_controllen = sizeof(control),
};
n = recvmsg_safe(socket_fd, &msghdr, 0);
ssize_t n = recvmsg_safe(socket_fd, &msghdr, 0);
if (ERRNO_IS_NEG_TRANSIENT(n))
continue;
if (n == -ECHRNG) {
@ -1050,30 +1025,30 @@ int ask_password_agent(
log_debug_errno(n, "Got message with truncated payload data, ignoring.");
continue;
}
if (n < 0) {
r = (int) n;
goto finish;
}
if (n < 0)
return n;
CLEANUP_ERASE(passphrase);
cmsg_close_all(&msghdr);
if (n == 0) {
log_debug("Message too short");
log_debug("Got empty reply from ask-password agent, ignoring.");
continue;
}
ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
struct ucred *ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred) {
log_debug("Received message without credentials. Ignoring.");
log_debug("Received message without credentials, ignoring.");
continue;
}
if (ucred->uid != getuid() && ucred->uid != 0) {
log_debug("Got password response from bad user, ignoring.");
continue;
}
if (ucred->uid != getuid() && ucred->uid != 0) {
log_debug("Got response from bad user. Ignoring.");
continue;
}
if (passphrase[0] == '-')
return -ECANCELED;
if (passphrase[0] == '+') {
/* An empty message refers to the empty password */
@ -1081,45 +1056,23 @@ int ask_password_agent(
l = strv_new("");
else
l = strv_parse_nulstr(passphrase+1, n-1);
if (!l) {
r = -ENOMEM;
goto finish;
}
if (!l)
return -ENOMEM;
if (strv_isempty(l)) {
l = strv_free(l);
log_debug("Invalid packet");
continue;
}
if (!strv_isempty(l))
break;
break;
l = strv_free(l);
}
if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
}
log_debug("Invalid packet");
log_debug("Got invalid response from ask-password agent, ignoring.");
}
if (req->keyring)
(void) add_to_keyring_and_log(req->keyring, flags, l);
*ret = TAKE_PTR(l);
r = 0;
finish:
if (temp) {
assert(dfd >= 0);
(void) unlinkat(dfd, temp, 0);
} else if (final) {
assert(dfd >= 0);
(void) unlinkat(dfd, final, 0);
}
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
return r;
return 0;
}
static int ask_password_credential(const AskPasswordRequest *req, AskPasswordFlags flags, char ***ret) {

View File

@ -3,7 +3,6 @@
shared_sources = files(
'acl-util.c',
'acpi-fpdt.c',
'apparmor-util.c',
'ask-password-agent.c',
'ask-password-api.c',
'async.c',
@ -279,6 +278,10 @@ if conf.get('HAVE_LIBIDN2') == 1
shared_sources += files('idn-util.c')
endif
if conf.get('HAVE_APPARMOR') == 1
shared_sources += files('apparmor-util.c')
endif
generate_ip_protocol_list = files('generate-ip-protocol-list.sh')
ip_protocol_list_txt = custom_target(
input : [generate_ip_protocol_list, ipproto_sources],

View File

@ -11,6 +11,7 @@ int metrics_setup_varlink_server(
sd_varlink_server **server, /* in and out param */
sd_varlink_server_flags_t flags,
sd_event *event,
int64_t priority,
sd_varlink_method_t vl_method_list_cb,
sd_varlink_method_t vl_method_describe_cb,
void *userdata) {
@ -20,6 +21,8 @@ int metrics_setup_varlink_server(
assert(server);
assert(event);
assert(vl_method_list_cb);
assert(vl_method_describe_cb);
if (*server)
return 0;
@ -34,24 +37,21 @@ int metrics_setup_varlink_server(
r = sd_varlink_server_bind_method_many(
s,
"io.systemd.Metrics.List",
vl_method_list_cb,
"io.systemd.Metrics.Describe",
vl_method_describe_cb);
"io.systemd.Metrics.List", vl_method_list_cb,
"io.systemd.Metrics.Describe", vl_method_describe_cb);
if (r < 0)
return log_debug_errno(r, "Failed to register varlink metrics methods: %m");
r = sd_varlink_server_set_description(s, "systemd varlink metrics server");
r = sd_varlink_server_set_description(s, "varlink-metrics");
if (r < 0)
return log_debug_errno(r, "Failed to set varlink metrics server description: %m");
r = sd_varlink_server_attach_event(s, event, SD_EVENT_PRIORITY_NORMAL);
r = sd_varlink_server_attach_event(s, event, priority);
if (r < 0)
return log_debug_errno(r, "Failed to attach varlink metrics server to event loop: %m");
*server = TAKE_PTR(s);
return 0;
return 1;
}
static const char * const metric_family_type_table[_METRIC_FAMILY_TYPE_MAX] = {
@ -84,14 +84,12 @@ int metrics_method_describe(
assert(metric_family_table);
assert(link);
assert(parameters);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric");
if (r < 0)
return r;
@ -123,14 +121,12 @@ int metrics_method_list(
assert(metric_family_table);
assert(link);
assert(parameters);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric");
if (r < 0)
return r;

View File

@ -31,6 +31,7 @@ int metrics_setup_varlink_server(
sd_varlink_server **server, /* in and out param */
sd_varlink_server_flags_t flags,
sd_event *event,
int64_t priority,
sd_varlink_method_t vl_method_list_cb,
sd_varlink_method_t vl_method_describe_cb,
void *userdata);

View File

@ -240,6 +240,8 @@ static int archive_unpack_regular(
if (fd < 0)
return log_error_errno(fd, "Failed to create regular file '%s': %m", path);
CLEANUP_TMPFILE_AT(parent_fd, tmp);
if ((fflags & CHATTR_EARLY_FL) != 0) {
r = chattr_full(fd,
/* path= */ NULL,
@ -250,45 +252,29 @@ static int archive_unpack_regular(
CHATTR_FALLBACK_BITWISE);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
log_warning_errno(r, "Failed to apply chattr of '%s', ignoring: %m", path);
else if (r < 0) {
log_error_errno(r, "Failed to adjust chattr of '%s': %m", path);
goto fail;
}
else if (r < 0)
return log_error_errno(r, "Failed to adjust chattr of '%s': %m", path);
}
r = sym_archive_read_data_into_fd(a, fd);
if (r != ARCHIVE_OK) {
r = log_error_errno(
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to unpack regular file '%s': %s", path, sym_archive_error_string(a));
goto fail;
}
if (r != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to unpack regular file '%s': %s", path, sym_archive_error_string(a));
/* If this is a sparse file, then libarchive's archive_read_data_into_fd() won't insert the final
* hole. We need to manually truncate. */
off_t l = lseek(fd, 0, SEEK_CUR);
if (l < 0) {
r = log_error_errno(errno, "Failed to determine current file position in '%s': %m", path);
goto fail;
}
if (ftruncate(fd, l) < 0) {
r = log_error_errno(errno, "Failed to truncate regular file '%s' to %" PRIu64 ": %m", path, (uint64_t) l);
goto fail;
}
if (l < 0)
return log_error_errno(errno, "Failed to determine current file position in '%s': %m", path);
if (ftruncate(fd, l) < 0)
return log_error_errno(errno, "Failed to truncate regular file '%s' to %" PRIu64 ": %m", path, (uint64_t) l);
r = link_tmpfile_at(fd, parent_fd, tmp, filename, LINK_TMPFILE_REPLACE);
if (r < 0) {
log_error_errno(r, "Failed to install regular file '%s': %m", path);
goto fail;
}
if (r < 0)
return log_error_errno(r, "Failed to install regular file '%s': %m", path);
tmp = mfree(tmp); /* disarm CLEANUP_TMPFILE_AT() */
return TAKE_FD(fd);
fail:
if (tmp)
(void) unlinkat(parent_fd, tmp, /* flags= */ 0);
return r;
}
static int archive_unpack_directory(

View File

@ -4,8 +4,9 @@
#include "varlink-io.systemd.MuteConsole.h"
static SD_VARLINK_DEFINE_METHOD(
static SD_VARLINK_DEFINE_METHOD_FULL(
Mute,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("Whether to mute the kernel's output to the console (defaults to true)."),
SD_VARLINK_DEFINE_INPUT(kernel, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether to mute PID1's output to the console (defaults to true)."),

View File

@ -1,13 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.Network.h"
/* Helper macro to define address fields with both binary and string representation */
#define SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(field_name, comment, flags) \
SD_VARLINK_FIELD_COMMENT(comment), \
SD_VARLINK_DEFINE_FIELD(field_name, SD_VARLINK_INT, SD_VARLINK_ARRAY | (flags)), \
SD_VARLINK_FIELD_COMMENT(comment " (human-readable format)"), \
SD_VARLINK_DEFINE_FIELD(field_name##String, SD_VARLINK_STRING, (flags))
#define VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(field_name, comment, flags) \
SD_VARLINK_FIELD_COMMENT(comment), \
SD_VARLINK_DEFINE_FIELD(field_name, SD_VARLINK_INT, SD_VARLINK_ARRAY | (flags)), \
SD_VARLINK_FIELD_COMMENT(comment " (human-readable format)"), \
SD_VARLINK_DEFINE_FIELD(field_name##String, SD_VARLINK_STRING, (flags))
static SD_VARLINK_DEFINE_ENUM_TYPE(
LinkState,
@ -42,10 +43,10 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
RoutingPolicyRule,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(FromPrefix, "Source address prefix to match", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(FromPrefix, "Source address prefix to match", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of source prefix in bits"),
SD_VARLINK_DEFINE_FIELD(FromPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ToPrefix, "Destination address prefix to match", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ToPrefix, "Destination address prefix to match", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of destination prefix in bits"),
SD_VARLINK_DEFINE_FIELD(ToPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Routing protocol identifier"),
@ -97,14 +98,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
Route,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "Destination network address", 0),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "Destination network address", 0),
SD_VARLINK_FIELD_COMMENT("Destination network prefix length"),
SD_VARLINK_DEFINE_FIELD(DestinationPrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this route", SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Source, "Source address prefix for route selection", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this route", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Source, "Source address prefix for route selection", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Source prefix length"),
SD_VARLINK_DEFINE_FIELD(SourcePrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(PreferredSource, "Preferred source address for outgoing packets", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(PreferredSource, "Preferred source address for outgoing packets", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Type of Service (TOS) field"),
SD_VARLINK_DEFINE_FIELD(TOS, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Route scope (RT_SCOPE_* value)"),
@ -139,7 +140,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this route"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration state of this route"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index for serialization"),
@ -162,7 +163,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this next hop", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this next hop", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Next hop flags (RTNH_F_* values)"),
SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable flags string"),
@ -177,7 +178,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Group, NextHopGroup, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this next hop"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration state of this next hop"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
@ -208,7 +209,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNS,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "DNS server IP address", 0),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "DNS server IP address", 0),
SD_VARLINK_FIELD_COMMENT("DNS server port number"),
SD_VARLINK_DEFINE_FIELD(Port, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index for link-local DNS servers"),
@ -217,29 +218,29 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(ServerName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this DNS server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NTP,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "NTP server IP address", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "NTP server IP address", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("NTP server"),
SD_VARLINK_DEFINE_FIELD(Server, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this NTP server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
SIP,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "SIP server IP address", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "SIP server IP address", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("SIP server domain name"),
SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this SIP server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Domain,
@ -247,7 +248,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Configuration source for this domain"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSSECNegativeTrustAnchor,
@ -279,7 +280,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Lifetime of the prefix in microseconds"),
SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of router that provided this prefix", SD_VARLINK_NULLABLE));
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of router that provided this prefix", SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NDisc,
@ -290,14 +291,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
Address,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "IP address", 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Peer, "Peer address for point-to-point interfaces", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "IP address", 0),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Peer, "Peer address for point-to-point interfaces", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Network prefix length"),
SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Configuration source for this address"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider (DHCP server, router, etc.)", SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Broadcast, "Broadcast address for IPv4 networks", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider (DHCP server, router, etc.)", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Broadcast, "Broadcast address for IPv4 networks", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address scope (RT_SCOPE_* value)"),
SD_VARLINK_DEFINE_FIELD(Scope, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable scope string"),
@ -323,7 +324,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
Neighbor,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "IP address of the neighbor", 0),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "IP address of the neighbor", 0),
SD_VARLINK_FIELD_COMMENT("Link layer (MAC) address of the neighbor"),
SD_VARLINK_DEFINE_FIELD(LinkLayerAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Configuration source for this neighbor entry"),
@ -386,7 +387,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPServerLease,
SD_VARLINK_FIELD_COMMENT("DHCP client identifier"),
SD_VARLINK_DEFINE_FIELD(ClientId, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "Address assigned to the client", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "Address assigned to the client", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hostname provided by the DHCP client"),
SD_VARLINK_DEFINE_FIELD(Hostname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hardware address type (ARPHRD_* value)"),
@ -447,7 +448,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(PermanentHardwareAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Broadcast address for Ethernet interfaces"),
SD_VARLINK_DEFINE_FIELD(BroadcastAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(IPv6LinkLocalAddress, "IPv6 link-local address", SD_VARLINK_NULLABLE),
VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(IPv6LinkLocalAddress, "IPv6 link-local address", SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Wireless LAN interface type (NL80211_IFTYPE_* value)"),
SD_VARLINK_DEFINE_FIELD(WirelessLanInterfaceType, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable wireless LAN interface type"),
@ -593,6 +594,22 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_FIELD_COMMENT("Whether persistent storage is ready and writable"),
SD_VARLINK_DEFINE_INPUT(Ready, SD_VARLINK_BOOL, 0));
static SD_VARLINK_DEFINE_METHOD(
LinkUp,
SD_VARLINK_FIELD_COMMENT("Index of the interface. If specified together with InterfaceName, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Name of the interface. If specified together with InterfaceIndex, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
LinkDown,
SD_VARLINK_FIELD_COMMENT("Index of the interface. If specified together with InterfaceName, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Name of the interface. If specified together with InterfaceIndex, both must reference the same link."),
SD_VARLINK_DEFINE_INPUT(InterfaceName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_ERROR(StorageReadOnly);
SD_VARLINK_DEFINE_INTERFACE(
@ -603,6 +620,10 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_GetNamespaceId,
&vl_method_GetLLDPNeighbors,
&vl_method_SetPersistentStorage,
SD_VARLINK_SYMBOL_COMMENT("Bring the specified link up."),
&vl_method_LinkUp,
SD_VARLINK_SYMBOL_COMMENT("Bring the specified link down."),
&vl_method_LinkDown,
&vl_type_Address,
&vl_type_DHCPLease,
&vl_type_DHCPServer,

View File

@ -59,8 +59,9 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, a progress percentrage (specific to the work done for the specified phase+object is sent in progress updates."),
SD_VARLINK_DEFINE_OUTPUT(progress, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
static SD_VARLINK_DEFINE_METHOD_FULL(
ListCandidateDevices,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("Control whether to include the root disk of the currently booted OS in the list. Defaults to false, i.e. the root disk is included."),
SD_VARLINK_DEFINE_INPUT(ignoreRoot, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Control whether to include block devices with zero size in the list, i.e. typically block devices without any inserted medium. Defaults to false, i.e. empty block devices are included."),

View File

@ -300,7 +300,7 @@ static SD_VARLINK_DEFINE_METHOD(
static SD_VARLINK_DEFINE_METHOD_FULL(
BrowseServices,
SD_VARLINK_SUPPORTS_MORE,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("The domain to browse for services. If null, the default browsing domain local is used."),
SD_VARLINK_DEFINE_INPUT(domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The service type to browse for (e.g., '_http._tcp')."),

View File

@ -179,6 +179,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD_BY_TYPE(SocketBindDeny, CGroupSocketBind, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#RestrictNetworkInterfaces="),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(RestrictNetworkInterfaces, CGroupRestrictNetworkInterfaces, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#BindNetworkInterface="),
SD_VARLINK_DEFINE_FIELD(BindNetworkInterface, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#NFTSet=family:table:set"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(NFTSet, CGroupNFTSet, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),

View File

@ -1,78 +1,73 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-event.h"
#include "alloc-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fdset.h"
#include "log.h"
#include "parse-util.h"
#include "serialize.h"
#include "socket-util.h"
#include "string-util.h"
#include "varlink-internal.h"
#include "varlink-serialize.h"
int varlink_server_serialize(sd_varlink_server *s, FILE *f, FDSet *fds) {
int varlink_server_serialize(sd_varlink_server *s, const char *name, FILE *f, FDSet *fds) {
assert(f);
assert(fds);
if (!s)
return 0;
LIST_FOREACH(sockets, ss, s->sockets) {
int copy;
const char *prefix = name ? strjoina("varlink-server-", name) : "varlink-server";
LIST_FOREACH(sockets, ss, s->sockets) {
assert(ss->address);
assert(ss->fd >= 0);
fprintf(f, "varlink-server-socket-address=%s", ss->address);
/* If we fail to serialize the fd, it will be considered an error during deserialization */
copy = fdset_put_dup(fds, ss->fd);
int copy = fdset_put_dup(fds, ss->fd);
if (copy < 0)
return copy;
fprintf(f, " varlink-server-socket-fd=%i", copy);
fputc('\n', f);
fprintf(f, "%s-socket-address=%s varlink-server-socket-fd=%d\n", prefix, ss->address, copy);
}
return 0;
}
int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSet *fds) {
_cleanup_(varlink_server_socket_freep) VarlinkServerSocket *ss = NULL;
_cleanup_free_ char *address = NULL;
const char *v = ASSERT_PTR(value);
int r, fd = -EBADF;
char *buf;
size_t n;
_cleanup_close_ int fd = -EBADF;
const char *v;
int r;
/* This function expects a serialization line with "varlink-server(-name)-" prefix stripped! */
assert(s);
assert(value);
assert(fds);
n = strcspn(v, " ");
address = strndup(v, n);
if (!address)
return log_oom_debug();
if (v[n] != ' ')
return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EINVAL),
"Failed to deserialize sd_varlink_server_socket: %s", value);
v = startswith(v + n + 1, "varlink-server-socket-fd=");
v = startswith(value, "socket-address=");
if (!v)
return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EINVAL),
"Failed to deserialize VarlinkServerSocket fd: %s", value);
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid varlink server serialization entry: %s", value);
n = strcspn(v, " ");
buf = strndupa_safe(v, n);
fd = parse_fd(buf);
if (fd < 0)
return varlink_server_log_errno(s, fd, "Unable to parse VarlinkServerSocket varlink-server-socket-fd=%s: %m", buf);
if (!fdset_contains(fds, fd))
r = extract_first_word(&v, &address, " ", /* flags = */ 0);
if (r <= 0)
return varlink_server_log_errno(s, r < 0 ? r : SYNTHETIC_ERRNO(ENODATA),
"Failed to extract socket address from varlink serialization: %s", value);
if (v)
v = startswith(v, "varlink-server-socket-fd=");
if (!v)
return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EBADF),
"VarlinkServerSocket varlink-server-socket-fd= has unknown fd: %d", fd);
"Got varlink serialization without socket fd, refusing.");
fd = deserialize_fd(fds, v);
if (fd < 0)
return varlink_server_log_errno(s, fd, "Failed to deserialize varlink socket fd: %m");
/* NB: varlink_server_socket_free() does not close the fd! */
_cleanup_(varlink_server_socket_freep) VarlinkServerSocket *ss = NULL;
ss = new(VarlinkServerSocket, 1);
if (!ss)
return log_oom_debug();
@ -80,14 +75,16 @@ int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSe
*ss = (VarlinkServerSocket) {
.server = s,
.address = TAKE_PTR(address),
.fd = fdset_remove(fds, fd),
.fd = fd,
};
r = varlink_server_add_socket_event_source(s, ss, SD_EVENT_PRIORITY_NORMAL);
r = varlink_server_add_socket_event_source(s, ss);
if (r < 0)
return varlink_server_log_errno(s, r, "Failed to add VarlinkServerSocket event source to the event loop: %m");
LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss));
TAKE_FD(fd); /* ownership is now transferred to varlink server */
return 0;
}

View File

@ -3,7 +3,7 @@
#include "shared-forward.h"
int varlink_server_serialize(sd_varlink_server *s, FILE *f, FDSet *fds);
int varlink_server_serialize(sd_varlink_server *s, const char *name, FILE *f, FDSet *fds);
int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSet *fds);
bool varlink_server_contains_socket(sd_varlink_server *s, const char *address);

View File

@ -2749,6 +2749,7 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
int r;
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
const char *class = NULL;
r = sd_varlink_dispatch(link, parameters, dispatch_table, &class);

View File

@ -149,6 +149,7 @@ simple_tests += files(
'test-mkdir.c',
'test-modhex.c',
'test-mountpoint-util.c',
'test-namespace-util.c',
'test-net-naming-scheme.c',
'test-notify-recv.c',
'test-nsresource.c',

View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "capability-util.h"
#include "errno-util.h"
#include "pidref.h"
#include "process-util.h"
#include "fd-util.h"
#include "namespace-util.h"
#include "tests.h"
TEST(namespace_enter) {
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
r = pidref_safe_fork(
"test-ns-enter-1",
FORK_NEW_USERNS|FORK_NEW_MOUNTNS|FORK_LOG|FORK_FREEZE|FORK_DEATHSIG_SIGKILL,
&pidref);
if (ERRNO_IS_NEG_PRIVILEGE(r))
return (void) log_tests_skipped_errno(r, "Unable to unshare user namespace");
ASSERT_OK(r);
_cleanup_close_ int mntns_fd = -EBADF, userns_fd = -EBADF, root_fd = -EBADF;
ASSERT_OK(pidref_namespace_open(&pidref, NULL, &mntns_fd, NULL, &userns_fd, &root_fd));
r = ASSERT_OK(pidref_safe_fork(
"test-ns-enter-2",
FORK_LOG|FORK_WAIT|FORK_DEATHSIG_SIGKILL,
NULL));
if (r == 0) {
ASSERT_OK(namespace_enter(-EBADF, mntns_fd, -EBADF, userns_fd, root_fd));
_exit(EXIT_SUCCESS);
}
/* Make sure we can enter the namespaces as well if we don't have CAP_SYS_ADMIN. */
r = ASSERT_OK(pidref_safe_fork(
"test-ns-enter-3",
FORK_LOG|FORK_WAIT|FORK_DEATHSIG_SIGKILL,
NULL));
if (r == 0) {
ASSERT_OK(drop_capability(CAP_SYS_ADMIN));
ASSERT_OK(namespace_enter(-EBADF, mntns_fd, -EBADF, userns_fd, root_fd));
_exit(EXIT_SUCCESS);
}
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -15,9 +15,9 @@ TEST(manager_parse_string) {
assert_se(manager_new(&m) == 0);
assert_se(!m->have_fallbacks);
assert_se(!m->fallback_set);
assert_se(manager_parse_server_string(m, SERVER_FALLBACK, NTP_SERVERS) == 0);
assert_se(m->have_fallbacks);
assert_se(m->fallback_set);
assert_se(manager_parse_fallback_string(m, NTP_SERVERS) == 0);
assert_se(manager_parse_server_string(m, SERVER_SYSTEM, "time1.foobar.com time2.foobar.com axrfav.,avf..ra 12345..123") == 0);

View File

@ -20,7 +20,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers;
if (type == SERVER_FALLBACK)
m->have_fallbacks = true;
m->fallback_set = true;
for (;;) {
_cleanup_free_ char *word = NULL;
@ -59,7 +59,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
}
int manager_parse_fallback_string(Manager *m, const char *string) {
if (m->have_fallbacks)
if (m->fallback_set)
return 0;
return manager_parse_server_string(m, SERVER_FALLBACK, string);
@ -84,15 +84,21 @@ int config_parse_servers(
assert(lvalue);
assert(rvalue);
if (isempty(rvalue))
if (isempty(rvalue)) {
manager_flush_server_names(m, ltype);
else {
r = manager_parse_server_string(m, ltype, rvalue);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse NTP server string '%s', ignoring: %m", rvalue);
return 0;
}
/* FallbackNTP= with an empty string disables the built-in fallback servers. */
if (ltype == SERVER_FALLBACK)
m->fallback_set = true;
return 0;
}
r = manager_parse_server_string(m, ltype, rvalue);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse NTP server string '%s', ignoring: %m", rvalue);
return 0;
}
return 0;

View File

@ -33,7 +33,7 @@ typedef struct Manager {
RateLimit ratelimit;
bool exhausted_servers;
bool have_fallbacks;
bool fallback_set; /* Indicate if FallbackNTP= is explicitly configured. */
/* network */
sd_event_source *network_event_source;

View File

@ -1452,6 +1452,7 @@ testcase_delegate() {
[Delegate]
DNS=192.168.77.78
Domains=exercise.test
FirewallMark=42
EOF
systemctl reload systemd-resolved
resolvectl status

View File

@ -573,3 +573,4 @@ loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="rebo
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="reboot"]
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="shutdown"]
varlinkctl.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--system"]
systemd.network.xml ./refsect1[title="[ModemManager] Section Options"]/variablelist/varlistentry[term="SimpleConnectProperties="]