summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am16
-rw-r--r--NEWS61
-rw-r--r--TODO11
-rw-r--r--configure.ac12
-rw-r--r--hwdb/70-mouse.hwdb4
-rw-r--r--man/coredump.conf.xml2
-rw-r--r--man/custom-html.xsl2
-rw-r--r--man/machinectl.xml4
-rw-r--r--man/nss-mymachines.xml35
-rw-r--r--man/sd-bus-errors.xml4
-rw-r--r--man/sd_bus_message_append_array.xml8
-rw-r--r--man/sd_bus_negotiate_fds.xml2
-rw-r--r--man/systemd-coredump.xml4
-rw-r--r--man/systemd-journald.service.xml2
-rw-r--r--man/systemd.journal-fields.xml2
-rw-r--r--man/systemd.link.xml9
-rw-r--r--man/systemd.netdev.xml39
-rw-r--r--man/systemd.network.xml72
-rw-r--r--man/systemd.preset.xml2
-rw-r--r--man/systemd.socket.xml2
-rw-r--r--src/analyze/analyze.c238
-rw-r--r--src/basic/bitmap.c198
-rw-r--r--src/basic/bitmap.h50
-rw-r--r--src/basic/copy.c6
-rw-r--r--src/basic/exit-status.c3
-rw-r--r--src/basic/fileio.c7
-rw-r--r--src/basic/macro.h21
-rw-r--r--src/basic/missing.h40
-rw-r--r--src/basic/process-util.c52
-rw-r--r--src/basic/util.c369
-rw-r--r--src/basic/util.h5
-rw-r--r--src/basic/virt.c20
-rw-r--r--src/boot/bootctl.c2
-rw-r--r--src/boot/efi/boot.c17
-rw-r--r--src/bootchart/bootchart.c16
-rw-r--r--src/bus-proxyd/driver.c5
-rw-r--r--src/bus-proxyd/driver.h3
-rw-r--r--src/bus-proxyd/proxy.c55
-rw-r--r--src/bus-proxyd/proxy.h3
-rw-r--r--src/bus-proxyd/synthesize.c19
-rw-r--r--src/bus-proxyd/synthesize.h3
-rw-r--r--src/cgls/cgls.c8
-rw-r--r--src/cgtop/cgtop.c1
-rw-r--r--src/core/automount.c34
-rw-r--r--src/core/busname.c3
-rw-r--r--src/core/job.c313
-rw-r--r--src/core/mount.c9
-rw-r--r--src/core/selinux-access.c12
-rw-r--r--src/core/service.c10
-rw-r--r--src/core/slice.c1
-rw-r--r--src/core/socket.c1
-rw-r--r--src/core/swap.c1
-rw-r--r--src/core/target.c1
-rw-r--r--src/core/unit.c81
-rw-r--r--src/core/unit.h1
-rw-r--r--src/import/pull-dkr.c2
-rw-r--r--src/journal/journal-file.c37
-rw-r--r--src/journal/journal-file.h3
-rw-r--r--src/journal/journal-vacuum.c2
-rw-r--r--src/journal/journal-verify.c233
-rw-r--r--src/journal/journalctl.c4
-rw-r--r--src/journal/journald-server.c8
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c16
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c3
-rw-r--r--src/libsystemd/sd-bus/bus-message.c17
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c90
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c21
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c18
-rw-r--r--src/libsystemd/sd-bus/test-bus-proxy.c109
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c45
-rw-r--r--src/login/logind-dbus.c2
-rw-r--r--src/login/logind-seat.c4
-rw-r--r--src/machine/machined-dbus.c231
-rw-r--r--src/machine/org.freedesktop.machine1.conf16
-rw-r--r--src/network/networkd-dhcp4.c41
-rw-r--r--src/network/networkd-link.c23
-rw-r--r--src/network/networkd-netdev-gperf.gperf4
-rw-r--r--src/network/networkd-netdev-tunnel.c71
-rw-r--r--src/network/networkd-netdev-tunnel.h28
-rw-r--r--src/network/networkd-netdev-vxlan.h11
-rw-r--r--src/network/networkd-network-gperf.gperf6
-rw-r--r--src/network/networkd-network.c40
-rw-r--r--src/network/networkd-wait-online.c2
-rw-r--r--src/network/networkd.h32
-rw-r--r--src/nspawn/nspawn.c6
-rw-r--r--src/nss-mymachines/nss-mymachines.c320
-rw-r--r--src/nss-mymachines/nss-mymachines.sym4
-rw-r--r--src/resolve/dns-type.c5
-rw-r--r--src/resolve/dns-type.h1
-rw-r--r--src/resolve/resolved-dns-packet.c435
-rw-r--r--src/resolve/resolved-dns-packet.h2
-rw-r--r--src/resolve/resolved-dns-rr.c112
-rw-r--r--src/resolve/resolved-dns-rr.h24
-rw-r--r--src/resolve/resolved-dns-scope.c70
-rw-r--r--src/resolve/resolved-dns-scope.h4
-rw-r--r--src/resolve/resolved-dns-transaction.c192
-rw-r--r--src/resolve/resolved-dns-transaction.h10
-rw-r--r--src/resolve/resolved-manager.c46
-rw-r--r--src/resolve/resolved-manager.h1
-rw-r--r--src/shared/dns-domain.c95
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/install.c5
-rw-r--r--src/shared/nss-util.h33
-rw-r--r--src/systemd/sd-bus-vtable.h6
-rw-r--r--src/test/test-bitmap.c105
-rw-r--r--src/test/test-dns-domain.c74
-rw-r--r--src/test/test-util.c186
-rw-r--r--src/tmpfiles/tmpfiles.c7
-rw-r--r--src/udev/ata_id/ata_id.c15
-rw-r--r--src/udev/udev-builtin-hwdb.c2
-rw-r--r--src/udev/udevd.c20
-rw-r--r--src/user-sessions/user-sessions.c2
-rw-r--r--tmpfiles.d/systemd.conf.m42
-rw-r--r--units/systemd-machined.service.in2
-rw-r--r--units/systemd-networkd.service.m4.in2
117 files changed, 3849 insertions, 965 deletions
diff --git a/.gitignore b/.gitignore
index 99f361d555..7659e7a645 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,6 +144,7 @@
/test-audit-type
/test-async
/test-barrier
+/test-bitmap
/test-boot-timestamp
/test-btrfs
/test-bus-benchmark
@@ -159,6 +160,7 @@
/test-bus-match
/test-bus-objects
/test-bus-policy
+/test-bus-proxy
/test-bus-server
/test-bus-signature
/test-bus-zero-copy
diff --git a/Makefile.am b/Makefile.am
index 3c0ce32692..d21982285f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -791,6 +791,8 @@ libbasic_la_SOURCES = \
src/basic/siphash24.h \
src/basic/set.h \
src/basic/ordered-set.h \
+ src/basic/bitmap.c \
+ src/basic/bitmap.h \
src/basic/fdset.c \
src/basic/fdset.h \
src/basic/prioq.c \
@@ -1412,6 +1414,7 @@ tests += \
test-time \
test-hashmap \
test-set \
+ test-bitmap \
test-list \
test-unaligned \
test-tables \
@@ -1768,6 +1771,12 @@ test_set_SOURCES = \
test_set_LDADD = \
libshared.la
+test_bitmap_SOURCES = \
+ src/test/test-bitmap.c
+
+test_bitmap_LDADD = \
+ libshared.la
+
test_xml_SOURCES = \
src/test/test-xml.c
@@ -2987,6 +2996,7 @@ tests += \
test-bus-cleanup \
test-bus-server \
test-bus-match \
+ test-bus-proxy \
test-bus-kernel \
test-bus-kernel-bloom \
test-bus-zero-copy \
@@ -3079,6 +3089,12 @@ test_bus_match_SOURCES = \
test_bus_match_LDADD = \
libshared.la
+test_bus_proxy_SOURCES = \
+ src/libsystemd/sd-bus/test-bus-proxy.c
+
+test_bus_proxy_LDADD = \
+ libshared.la
+
test_bus_kernel_SOURCES = \
src/libsystemd/sd-bus/test-bus-kernel.c
diff --git a/NEWS b/NEWS
index 3f80af3783..8e09efcdda 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,66 @@
systemd System and Service Manager
+CHANGES WITH 223:
+
+ * The python-systemd code has been removed from the systemd repository.
+ A new repository has been created which accommodates the code from
+ now on, and we kindly ask distributions to create a separate package
+ for this: https://github.com/systemd/python-systemd
+
+ * The systemd daemon will now reload its main configuration
+ (/etc/systemd/system.conf) on daemon-reload.
+
+ * sd-dhcp now exposes vendor specific extensions via
+ sd_dhcp_lease_get_vendor_specific().
+
+ * systemd-networkd gained a number of new configuration options.
+
+ - A new boolean configuration option for TAP devices called
+ 'VNetHeader='. If set, the IFF_VNET_HDR flag is set for the
+ device, thus allowing to send and receive GSO packets.
+
+ - A new tunnel configuration option called 'CopyDSCP='.
+ If enabled, the DSCP field of ip6 tunnels is copied into the
+ decapsulated packet.
+
+ - A set of boolean bridge configuration options were added.
+ 'UseBPDU=', 'HairPin=', 'FastLeave=', 'AllowPortToBeRoot=',
+ and 'UnicastFlood=' are now parsed by networkd and applied to the
+ respective bridge link device via the respective IFLA_BRPORT_*
+ netlink attribute.
+
+ - A new string configuration option to override the hostname sent
+ to a DHCP server, called 'Hostname='. If set and 'SendHostname='
+ is true, networkd will use the configured hostname instead of the
+ system hostname when sending DHCP requests.
+
+ - A new tunnel configuration option called 'IPv6FlowLabel='. If set,
+ networkd will configure the IPv6 flow-label of the tunnel device
+ according to RFC2460.
+
+ * systemd-resolved now implements RFC5452 to improve resilience against
+ cache poisoning. Additionally, source port randomization is enabled
+ by default to further protect against DNS spoofing attacks.
+
+ * nss-mymachines now supports translating UIDs and GIDs of running
+ containers with user-namespaces enabled. If a container 'foo'
+ translates a host uid 'UID' to the container uid 'TUID', then
+ nss-mymachines will also map uid 'UID' to/from username 'vu-foo-TUID'
+ (with 'foo' and 'TUID' replaced accordingly). Similarly, groups are
+ mapped as 'vg-foo-TGID'.
+
+ Contributions from: Beniamino Galvani, cee1, Christian Hesse, Daniel
+ Buch, Daniel Mack, daurnimator, David Herrmann, Dimitri John Ledkov, Jan
+ Alexander Steffens (heftig), Johan Ouwerkerk, Jose Carlos Venegas Munoz,
+ Kay Sievers, Lennart Poettering, Lidong Zhong, Martin Pitt, Michael
+ Biebl, Michael Olbrich, Michal Schmidt, Mike Gilbert, Namhyung Kim, Nick
+ Owens, Peter Hutterer, Richard Maw, Steven Allen, Sungbae Yoo, Susant
+ Sahani, Thomas Blume, Thomas Hindoe Paaboel Andersen, Tom Gundersen,
+ Umut Tezduyar Lindskog, Vito Caputo, Vivenzio Pagliari, Zbigniew
+ Jędrzejewski-Szmek
+
+ -- Berlin, 2015-XX-XX
+
CHANGES WITH 222:
* udev does not longer support the WAIT_FOR_SYSFS= key in udev rules.
diff --git a/TODO b/TODO
index 3a2b4cf9f0..9514af5a90 100644
--- a/TODO
+++ b/TODO
@@ -51,8 +51,6 @@ Features:
* install: include generator dirs in unit file search paths
-* introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.
-
* stop using off_t, it's a crazy type. Use uint64_t instead.
* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins
@@ -71,8 +69,6 @@ Features:
* log accumulated resource usage after each service invocation
-* networkd: dhcp server: try to assign stable IP addresses based on client's MAC address
-
* nspawn: a nice way to boot up without machine id set, so that it is set at boot automatically for supporting --ephemeral. Maybe hash the host machine id together with the machine name to generate the machine id for the container
* logind: rename session scope so that it includes the UID. THat way
@@ -98,8 +94,6 @@ Features:
* nspawn: as soon as networkd has a bus interface, hook up --network-interface=, --network-bridge= with networkd, to trigger netdev creation should an interface be missing
-* networkd: make DHCP server IP range configurable, including only with a single IP address
-
* rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring
to unicode chars, to make things more expressive.
@@ -318,11 +312,11 @@ Features:
(throughout the codebase, not only PID1)
* networkd:
+ - make DHCP server IP range configurable, including only with a single IP address
+ - dhcp server: try to assign stable IP addresses based on client's MAC address
- add LLDP client side support
- the DHCP lease data (such as NTP/DNS) is still made available when
a carrier is lost on a link. It should be removed instantly.
- - .network setting that allows overriding of the hostname to send to the dhcp server
- http://lists.freedesktop.org/archives/systemd-devel/2014-July/021550.html
- expose in the API the following bits:
- option 15, domain name and/or option 119, search list
- option 12, host name and/or option 81, fqdn
@@ -337,6 +331,7 @@ Features:
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
support Name=foo*|bar*|baz ?
- duplicate address check for static IPs (like ARPCHECK in network-scripts)
+ - allow DUID/IAID to be customized, see issue #394.
* resolved:
- put networkd events and rtnl events at a higher priority, so that
diff --git a/configure.ac b/configure.ac
index 999f9f84d3..2fddf29f36 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,11 @@ AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-di
AM_SILENT_RULES([yes])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
+
+AC_CHECK_TOOLS([AR], [gcc-ar ar], [:])
+AC_CHECK_TOOLS([NM], [gcc-nm nm], [:])
+AC_CHECK_TOOLS([RANLIB], [gcc-ranlib ranlib], [:])
+
LT_PREREQ(2.2)
LT_INIT([disable-static])
@@ -196,7 +201,7 @@ AS_CASE([$CC], [*clang*],
AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
[CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
- -flto -ffat-lto-objects])],
+ -flto])],
[AC_MSG_RESULT([skipping -flto, optimization not enabled])])
AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
@@ -299,9 +304,10 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
IFLA_BOND_AD_INFO,
IFLA_VLAN_PROTOCOL,
IFLA_VXLAN_REMCSUM_NOPARTIAL,
- IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+ IFLA_IPTUN_ENCAP_DPORT,
+ IFLA_GRE_ENCAP_DPORT,
IFLA_BRIDGE_VLAN_INFO,
- IFLA_BRPORT_UNICAST_FLOOD,
+ IFLA_BRPORT_LEARNING_SYNC,
NDA_IFINDEX,
IFA_FLAGS],
[], [], [[
diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb
index 1633321502..bc4b597bbf 100644
--- a/hwdb/70-mouse.hwdb
+++ b/hwdb/70-mouse.hwdb
@@ -247,6 +247,10 @@ mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
MOUSE_DPI=1000@125
+# Logitech MX Master
+mouse:usb:v046dp4041:name:Logitech MX Master:
+ MOUSE_DPI=1000@166
+
# Logitech MK260 Wireless Combo Receiver aka M-R0011
mouse:usb:v046dpc52e:name:Logitech USB Receiver:
MOUSE_DPI=1000@200
diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml
index fd54c59e6b..8e71f7d4ec 100644
--- a/man/coredump.conf.xml
+++ b/man/coredump.conf.xml
@@ -58,7 +58,7 @@
<refsect1>
<title>Description</title>
- <para>These files configure the behaviour of
+ <para>These files configure the behavior of
<citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
a handler for core dumps invoked by the kernel.</para>
</refsect1>
diff --git a/man/custom-html.xsl b/man/custom-html.xsl
index 151276362c..3e266e4a7f 100644
--- a/man/custom-html.xsl
+++ b/man/custom-html.xsl
@@ -125,7 +125,7 @@
<!--
- helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
- - this conflict resolution is necessary to prevent malformed HTML ouput (multiple id attributes with the same value)
+ - this conflict resolution is necessary to prevent malformed HTML output (multiple id attributes with the same value)
- and it fixes xsltproc warnings during compilation of HTML man pages
-
- A simple top-to-bottom numbering scheme is implemented for nodes with the same ID value to derive unique ID values for HTML output.
diff --git a/man/machinectl.xml b/man/machinectl.xml
index 4b87870853..a5eb3f08e4 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -593,7 +593,7 @@
<filename>/var/lib/machines/</filename>, that is named after
the specified URL and its HTTP etag. A writable snapshot is
then taken from this subvolume, and named after the specified
- local name. This behaviour ensures that creating multiple
+ local name. This behavior ensures that creating multiple
container instances of the same URL is efficient, as multiple
downloads are not necessary. In order to create only the
read-only image, and avoid creating its writable snapshot,
@@ -639,7 +639,7 @@
machine name. To omit creation of the local, writable copy
pass <literal>-</literal> as local machine name.</para>
- <para>Similar to the behaviour of <command>pull-tar</command>,
+ <para>Similar to the behavior of <command>pull-tar</command>,
the read-only image is prefixed with
<filename>.raw-</filename>, and thus not shown by
<command>list-images</command>, unless <option>--all</option>
diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml
index eb1ed2592b..41ec458e4b 100644
--- a/man/nss-mymachines.xml
+++ b/man/nss-mymachines.xml
@@ -59,21 +59,26 @@
<para><command>nss-mymachines</command> is a plugin for the GNU
Name Service Switch (NSS) functionality of the GNU C Library
(<command>glibc</command>) providing hostname resolution for
- containers running locally, that are registered with
+ container names of containers running locally, that are registered
+ with
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- The container names are resolved to IP addresses of the specific
- container, ordered by their scope.</para>
+ The container names are resolved to the IP addresses of the
+ specific container, ordered by their scope.</para>
+
+ <para>The module also resolves user IDs used by containers to user
+ names indicating the container name, and back.</para>
<para>To activate the NSS modules, <literal>mymachines</literal>
- has to be added to the line starting with
- <literal>hosts:</literal> in
+ has to be added to the lines starting with
+ <literal>hosts:</literal>, <literal>passwd:</literal> and
+ <literal>group:</literal> in
<filename>/etc/nsswitch.conf</filename>.</para>
<para>It is recommended to place <literal>mymachines</literal>
- near the end of the <filename>nsswitch.conf</filename> line to
- make sure that this mapping is only used as fallback, and any DNS
- or <filename>/etc/hosts</filename> based mapping takes
- precedence.</para>
+ near the end of the <filename>nsswitch.conf</filename> lines to
+ make sure that its mappings are only used as fallback, and any
+ other mappings, such as DNS or <filename>/etc/hosts</filename>
+ based mappings take precedence.</para>
</refsect1>
<refsect1>
@@ -82,17 +87,17 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>mymachines</command> correctly:</para>
-<programlisting>passwd: compat
-group: compat
-shadow: compat
+ <programlisting>passwd: compat <command>mymachines</command>
+group: compat <command>mymachines</command>
+shadow: compat
-hosts: files dns <command>mymachines</command> myhostname
+hosts: files dns <command>mymachines</command> myhostname
networks: files
protocols: db files
services: db files
-ethers: db files
-rpc: db files
+ethers: db files
+rpc: db files
netgroup: nis</programlisting>
diff --git a/man/sd-bus-errors.xml b/man/sd-bus-errors.xml
index d6bbd7fbb2..a1e8462858 100644
--- a/man/sd-bus-errors.xml
+++ b/man/sd-bus-errors.xml
@@ -138,7 +138,7 @@
<term><varname>SD_BUS_ERROR_FAILED</varname></term>
<listitem><para>A generic error indication. See the error
message for further details. This error name should be
- avoided, in favour of a more expressive error
+ avoided, in favor of a more expressive error
name.</para></listitem>
</varlistentry>
@@ -186,7 +186,7 @@
</varlistentry>
<varlistentry>
<term><varname>SD_BUS_ERROR_ACCESS_DENIED</varname></term>
- <listitem><para>Access to a resource has bee denied, due to security restrictions.</para></listitem>
+ <listitem><para>Access to a resource has been denied, due to security restrictions.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SD_BUS_ERROR_AUTH_FAILED</varname></term>
diff --git a/man/sd_bus_message_append_array.xml b/man/sd_bus_message_append_array.xml
index 034466bf9c..37cadb9d0f 100644
--- a/man/sd_bus_message_append_array.xml
+++ b/man/sd_bus_message_append_array.xml
@@ -49,7 +49,7 @@
<refname>sd_bus_message_append_array_iovec</refname>
<refname>sd_bus_message_append_array_space</refname>
- <refpurpose>Appaned an array of fields to a D-Bus
+ <refpurpose>Append an array of fields to a D-Bus
message</refpurpose>
</refnamediv>
@@ -125,7 +125,7 @@
<parameter>m</parameter>, similar to
<function>sd_bus_message_append_array()</function>. The contents
of the memory file descriptor <parameter>memfd</parameter>
- starting at the specified offset and and of the specified size is
+ starting at the specified offset and of the specified size is
used as the contents of the array. The offset and size must be a
multiple of the size of the type
<parameter>type</parameter>. However, as a special exception, if
@@ -173,7 +173,7 @@
<parameter>p</parameter>. The caller should subsequently write the
array contents to this memory. Modifications of the memory
pointed to should only occur until the next operation on the bus
- message is invoked, most imporantly the memory should not be
+ message is invoked, most importantly the memory should not be
altered anymore when another field has been added to the message
or the message has been sealed.</para>
</refsect1>
@@ -182,7 +182,7 @@
<title>Return Value</title>
<para>On success, these calls return 0 or a positive integer. On
- failure, they returns a negative errno-style error code.</para>
+ failure, they return a negative errno-style error code.</para>
</refsect1>
<xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
diff --git a/man/sd_bus_negotiate_fds.xml b/man/sd_bus_negotiate_fds.xml
index 1be44e2785..f53ea9e41a 100644
--- a/man/sd_bus_negotiate_fds.xml
+++ b/man/sd_bus_negotiate_fds.xml
@@ -152,7 +152,7 @@
<refsect1>
<title>Return Value</title>
- <para>On success, these functions returns 0 or a
+ <para>On success, these functions return 0 or a
positive integer. On failure, they return a negative errno-style
error code.</para>
</refsect1>
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 5da3857c08..cb46d41902 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -67,7 +67,7 @@
overridden to use a different setting following normal
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> rules.</para>
- <para>The behaviour of a specific program upon reception of a
+ <para>The behavior of a specific program upon reception of a
signal is governed by a few factors which are described in detail
in <citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
In particular, the coredump will only be processed when the
@@ -81,7 +81,7 @@
including a backtrace if possible, and store the core (contents of
process' memory contents) in an external file on disk in
<filename>/var/lib/systemd/coredump</filename>, or directly in
- the journal. This behaviour may be modified using
+ the journal. This behavior may be modified using
<citerefentry><refentrytitle>coredump.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>Apart from the
diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml
index 8280d6c874..dae6ee6042 100644
--- a/man/systemd-journald.service.xml
+++ b/man/systemd-journald.service.xml
@@ -203,7 +203,7 @@
<listitem><para>Configure
<command>systemd-journald</command>
- behaviour. See
+ behavior. See
<citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml
index afe1200d7e..49f44d2922 100644
--- a/man/systemd.journal-fields.xml
+++ b/man/systemd.journal-fields.xml
@@ -73,7 +73,7 @@
<para>The human-readable message string for this entry. This
is supposed to be the primary text shown to the user. It is
usually not translated (but might be in some cases), and is
- not supposed to be parsed for meta data.</para>
+ not supposed to be parsed for metadata.</para>
</listitem>
</varlistentry>
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index d9b1879c59..b630ef7a17 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -68,11 +68,10 @@
in <filename>/etc</filename> have the highest priority, files in
<filename>/run</filename> take precedence over files with the same
name in <filename>/usr/lib</filename>. This can be used to
- override a system-supplied link file with a local file if needed;
- a symlink in <filename>/etc</filename> with the same name as a
- link file in <filename>/usr/lib</filename>, pointing to
- <filename>/dev/null</filename>, disables the link file
- entirely.</para>
+ override a system-supplied link file with a local file if needed.
+ As a special case, an empty file (file size 0) or symlink with the
+ same name pointing to <filename>/dev/null</filename>, disable the
+ configuration file entirely (it is "masked").</para>
<para>The link file contains a <literal>[Match]</literal> section,
which determines if a given link file may be applied to a given
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index ff7b85453f..298cf0eb84 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -80,11 +80,9 @@
<filename>/run</filename> take precedence over files with the same
name in <filename>/usr/lib</filename>. This can be used to
override a system-supplied configuration file with a local file if
- needed; a symlink in <filename>/etc</filename> with the same name
- as a configuration file in <filename>/usr/lib</filename>, pointing
- to <filename>/dev/null</filename>, disables the configuration file
- entirely.</para>
-
+ needed. As a special case, an empty file (file size 0) or symlink
+ with the same name pointing to <filename>/dev/null</filename>,
+ disable the configuration file entirely (it is "masked").</para>
</refsect1>
<refsect1>
@@ -491,6 +489,31 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>IPv6FlowLabel=</varname></term>
+ <listitem>
+ <para>Configures The 20-bit Flow Label (see <ulink url="https://tools.ietf.org/html/rfc6437">
+ RFC 6437</ulink>) field in the IPv6 header (see <ulink url="https://tools.ietf.org/html/rfc2460">
+ RFC 2460</ulink>), is used by a node to label packets of a flow.
+ It's only used for IPv6 Tunnels.
+ A Flow Label of zero is used to indicate packets that have
+ not been labeled. Takes following values.
+ When <literal>inherit</literal> it uses the original flowlabel,
+ or can be configured to any value between 0 to 0xFFFFF.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>CopyDSCP=</varname></term>
+ <listitem>
+ <para>A boolean. When true, the Differentiated Service Code
+ Point (DSCP) field will be copied to the inner header from
+ outer header during the decapsulation of an IPv6 tunnel
+ packet. DSCP is a field in an IP packet that enables different
+ levels of service to be assigned to network traffic.
+ Defaults to <literal>no</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Mode=</varname></term>
<listitem>
<para>An <literal>ip6tnl</literal> tunnels can have three
@@ -563,7 +586,7 @@
</listitem>
</varlistentry>
<varlistentry>
- <term><varname>VnetHeader=</varname></term>
+ <term><varname>VNetHeader=</varname></term>
<listitem><para>Takes a boolean argument. Configures
IFF_VNET_HDR flag for a tap device. It allows sending
and receiving larger Generic Segmentation Offload (GSO)
@@ -654,7 +677,7 @@
<listitem>
<para>Specifies the frequency that Media Independent
Interface link monitoring will occur. A value of zero
- disables MII link monitoring. This values is rounded down to
+ disables MII link monitoring. This value is rounded down to
the nearest millisecond. The default value is 0.</para>
</listitem>
</varlistentry>
@@ -798,7 +821,7 @@
<listitem>
<para> Specify the number of packets to transmit through a slave before
moving to the next one. When set to 0 then a slave is chosen at
- random.The valid range is (0 - 65535). Defaults to 1. This option
+ random. The valid range is (0 - 65535). Defaults to 1. This option
has effect only in balance-rr mode.
</para>
</listitem>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index ff01da6249..e44491cc2e 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -76,11 +76,9 @@
<filename>/run</filename> take precedence over files with the same
name in <filename>/usr/lib</filename>. This can be used to
override a system-supplied configuration file with a local file if
- needed; a symlink in <filename>/etc</filename> with the same name
- as a configuration file in <filename>/usr/lib</filename>, pointing
- to <filename>/dev/null</filename>, disables the configuration file
- entirely.</para>
-
+ needed. As a special case, an empty file (file size 0) or symlink
+ with the same name pointing to <filename>/dev/null</filename>,
+ disable the configuration file entirely (it is "masked").</para>
</refsect1>
<refsect1>
@@ -288,7 +286,7 @@
<term><varname>BindCarrier=</varname></term>
<listitem>
<para>A port or a list of ports. When set, controls the
- behaviour of the current interface. When all ports in the list
+ behavior of the current interface. When all ports in the list
are in an operational down state, the current interface is brought
down. When at least one port has carrier, the current interface
is brought up.
@@ -576,19 +574,26 @@
<varlistentry>
<term><varname>SendHostname=</varname></term>
<listitem>
- <para>When true (the default), the machine's hostname will be sent to the DHCP
- server</para>
+ <para>When true (the default), the machine's hostname will
+ be sent to the DHCP server.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseHostname=</varname></term>
<listitem>
<para>When true (the default), the hostname received from
- the DHCP server will be used as the transient
- hostname.</para>
+ the DHCP server will be used as the transient hostname.
+ </para>
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>Hostname=</varname></term>
+ <listitem>
+ <para>Use this value for the hostname which is sent to the
+ DHCP server, instead of machine's hostname.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>UseDomains=</varname></term>
<listitem>
<para>When true (not the default), the domain name
@@ -663,16 +668,57 @@
following keys.</para>
<variablelist class='network-directives'>
<varlistentry>
+ <term><varname>UnicastFlood=</varname></term>
+ <listitem>
+ <para>A boolean. Controls whether the bridge should flood
+ traffic for which an FDB entry is missing and the destination
+ is unknown through this port. Defaults to on.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>HairPin=</varname></term>
+ <listitem>
+ <para>A boolean. Configures whether traffic may be sent back
+ out of the port on which it was received. By default, this
+ flag is false, and the bridge will not forward traffic back
+ out of the receiving port.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>UseBPDU=</varname></term>
+ <listitem>
+ <para>A boolean. Configures whether STP Bridge Protocol Data Units will be
+ processed by the bridge port. Defaults to yes.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>FastLeave=</varname></term>
+ <listitem>
+ <para>A boolean. This flag allows the bridge to immediately stop multicast
+ traffic on a port that receives IGMP Leave message. It is only used with
+ IGMP snooping if enabled on the bridge. Defaults to off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>AllowPortToBeRoot=</varname></term>
+ <listitem>
+ <para>A boolean. Configures whether a given port is allowed to
+ become a root port. Only used when STP is enabled on the bridge.
+ Defaults to on.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Cost=</varname></term>
<listitem>
- <para>Each port in a bridge may have different speed. Cost
+ <para>Sets the "cost" of sending packets of this interface.
+ Each port in a bridge may have different speed and the cost
is used to decide which link to use. Faster interfaces
- should have lower costs</para>
+ should have lower costs.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
-
<refsect1>
<title>[BridgeFDB] Section Options</title>
<para>The <literal>[BridgeFDB]</literal> section manages the
diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml
index 2f9add8d6c..b7164014f0 100644
--- a/man/systemd.preset.xml
+++ b/man/systemd.preset.xml
@@ -106,7 +106,7 @@
one takes precedence over all others.</para>
<para>Each preset file shall be named in the style of
- <filename>&lt;priority&gt;-&lt;program&gt;.conf</filename>. Files
+ <filename>&lt;priority&gt;-&lt;policy-name&gt;.preset</filename>. Files
in <filename>/etc/</filename> override files with the same name in
<filename>/usr/lib/</filename> and <filename>/run/</filename>.
Files in <filename>/run/</filename> override files with the same
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 1e9778bc2a..36fa3a86be 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -462,7 +462,7 @@
and the kernel will ignore initial ACK packets without any
data. The argument specifies the approximate amount of time
the kernel should wait for incoming data before falling back
- to the normal behaviour of honouring empty ACK packets. This
+ to the normal behavior of honouring empty ACK packets. This
option is beneficial for protocols where the client sends the
data first (e.g. HTTP, in contrast to SMTP), because the
server process will not be woken up unnecessarily before it
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index c0863e4167..db1e7f3f37 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -88,6 +88,18 @@ struct boot_times {
usec_t generators_finish_time;
usec_t unitsload_start_time;
usec_t unitsload_finish_time;
+
+ /*
+ * If we're analyzing the user instance, all timestamps will be offset
+ * by its own start-up timestamp, which may be arbitrarily big.
+ * With "plot", this causes arbitrarily wide output SVG files which almost
+ * completely consist of empty space. Thus we cancel out this offset.
+ *
+ * This offset is subtracted from times above by acquire_boot_times(),
+ * but it still needs to be subtracted from unit-specific timestamps
+ * (so it is stored here for reference).
+ */
+ usec_t reverse_offset;
};
struct unit_times {
@@ -188,95 +200,13 @@ static void free_unit_times(struct unit_times *t, unsigned n) {
free(t);
}
-static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r, c = 0;
- struct unit_times *unit_times = NULL;
- size_t size = 0;
- UnitInfo u;
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits",
- &error, &reply,
- NULL);
- if (r < 0) {
- log_error("Failed to list units: %s", bus_error_message(&error, -r));
- goto fail;
- }
+static void subtract_timestamp(usec_t *a, usec_t b) {
+ assert(a);
- r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
- if (r < 0) {
- bus_log_parse_error(r);
- goto fail;
+ if (*a > 0) {
+ assert(*a >= b);
+ *a -= b;
}
-
- while ((r = bus_parse_unit_info(reply, &u)) > 0) {
- struct unit_times *t;
-
- if (!GREEDY_REALLOC(unit_times, size, c+1)) {
- r = log_oom();
- goto fail;
- }
-
- t = unit_times+c;
- t->name = NULL;
-
- assert_cc(sizeof(usec_t) == sizeof(uint64_t));
-
- if (bus_get_uint64_property(bus, u.unit_path,
- "org.freedesktop.systemd1.Unit",
- "InactiveExitTimestampMonotonic",
- &t->activating) < 0 ||
- bus_get_uint64_property(bus, u.unit_path,
- "org.freedesktop.systemd1.Unit",
- "ActiveEnterTimestampMonotonic",
- &t->activated) < 0 ||
- bus_get_uint64_property(bus, u.unit_path,
- "org.freedesktop.systemd1.Unit",
- "ActiveExitTimestampMonotonic",
- &t->deactivating) < 0 ||
- bus_get_uint64_property(bus, u.unit_path,
- "org.freedesktop.systemd1.Unit",
- "InactiveEnterTimestampMonotonic",
- &t->deactivated) < 0) {
- r = -EIO;
- goto fail;
- }
-
- if (t->activated >= t->activating)
- t->time = t->activated - t->activating;
- else if (t->deactivated >= t->activating)
- t->time = t->deactivated - t->activating;
- else
- t->time = 0;
-
- if (t->activating == 0)
- continue;
-
- t->name = strdup(u.id);
- if (t->name == NULL) {
- r = log_oom();
- goto fail;
- }
- c++;
- }
- if (r < 0) {
- bus_log_parse_error(r);
- goto fail;
- }
-
- *out = unit_times;
- return c;
-
-fail:
- if (unit_times)
- free_unit_times(unit_times, (unsigned) c);
- return r;
}
static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
@@ -355,10 +285,30 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
return -EINPROGRESS;
}
- if (times.initrd_time)
- times.kernel_done_time = times.initrd_time;
- else
- times.kernel_done_time = times.userspace_time;
+ if (arg_user) {
+ /*
+ * User-instance-specific timestamps processing
+ * (see comment to reverse_offset in struct boot_times).
+ */
+ times.reverse_offset = times.userspace_time;
+
+ times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time = times.userspace_time = 0;
+ subtract_timestamp(&times.finish_time, times.reverse_offset);
+
+ subtract_timestamp(&times.security_start_time, times.reverse_offset);
+ subtract_timestamp(&times.security_finish_time, times.reverse_offset);
+
+ subtract_timestamp(&times.generators_start_time, times.reverse_offset);
+ subtract_timestamp(&times.generators_finish_time, times.reverse_offset);
+
+ subtract_timestamp(&times.unitsload_start_time, times.reverse_offset);
+ subtract_timestamp(&times.unitsload_finish_time, times.reverse_offset);
+ } else {
+ if (times.initrd_time)
+ times.kernel_done_time = times.initrd_time;
+ else
+ times.kernel_done_time = times.userspace_time;
+ }
cached = true;
@@ -378,6 +328,107 @@ static void free_host_info(struct host_info *hi) {
free(hi);
}
+static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r, c = 0;
+ struct boot_times *boot_times = NULL;
+ struct unit_times *unit_times = NULL;
+ size_t size = 0;
+ UnitInfo u;
+
+ r = acquire_boot_times(bus, &boot_times);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnits",
+ &error, &reply,
+ NULL);
+ if (r < 0) {
+ log_error("Failed to list units: %s", bus_error_message(&error, -r));
+ goto fail;
+ }
+
+ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
+ if (r < 0) {
+ bus_log_parse_error(r);
+ goto fail;
+ }
+
+ while ((r = bus_parse_unit_info(reply, &u)) > 0) {
+ struct unit_times *t;
+
+ if (!GREEDY_REALLOC(unit_times, size, c+1)) {
+ r = log_oom();
+ goto fail;
+ }
+
+ t = unit_times+c;
+ t->name = NULL;
+
+ assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+
+ if (bus_get_uint64_property(bus, u.unit_path,
+ "org.freedesktop.systemd1.Unit",
+ "InactiveExitTimestampMonotonic",
+ &t->activating) < 0 ||
+ bus_get_uint64_property(bus, u.unit_path,
+ "org.freedesktop.systemd1.Unit",
+ "ActiveEnterTimestampMonotonic",
+ &t->activated) < 0 ||
+ bus_get_uint64_property(bus, u.unit_path,
+ "org.freedesktop.systemd1.Unit",
+ "ActiveExitTimestampMonotonic",
+ &t->deactivating) < 0 ||
+ bus_get_uint64_property(bus, u.unit_path,
+ "org.freedesktop.systemd1.Unit",
+ "InactiveEnterTimestampMonotonic",
+ &t->deactivated) < 0) {
+ r = -EIO;
+ goto fail;
+ }
+
+ subtract_timestamp(&t->activating, boot_times->reverse_offset);
+ subtract_timestamp(&t->activated, boot_times->reverse_offset);
+ subtract_timestamp(&t->deactivating, boot_times->reverse_offset);
+ subtract_timestamp(&t->deactivated, boot_times->reverse_offset);
+
+ if (t->activated >= t->activating)
+ t->time = t->activated - t->activating;
+ else if (t->deactivated >= t->activating)
+ t->time = t->deactivated - t->activating;
+ else
+ t->time = 0;
+
+ if (t->activating == 0)
+ continue;
+
+ t->name = strdup(u.id);
+ if (t->name == NULL) {
+ r = log_oom();
+ goto fail;
+ }
+ c++;
+ }
+ if (r < 0) {
+ bus_log_parse_error(r);
+ goto fail;
+ }
+
+ *out = unit_times;
+ return c;
+
+fail:
+ if (unit_times)
+ free_unit_times(unit_times, (unsigned) c);
+ return r;
+}
+
static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
int r;
struct host_info *host;
@@ -450,10 +501,7 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
- if (t->kernel_time > 0)
- strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
- else
- strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
+ strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
ptr = strdup(buf);
if (!ptr)
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
new file mode 100644
index 0000000000..bf9d8d4d7c
--- /dev/null
+++ b/src/basic/bitmap.c
@@ -0,0 +1,198 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+#include "bitmap.h"
+
+struct Bitmap {
+ uint64_t *bitmaps;
+ size_t n_bitmaps;
+ size_t bitmaps_allocated;
+};
+
+/* Bitmaps are only meant to store relatively small numbers
+ * (corresponding to, say, an enum), so it is ok to limit
+ * the max entry. 64k should be plenty. */
+#define BITMAPS_MAX_ENTRY 0xffff
+
+/* This indicates that we reached the end of the bitmap */
+#define BITMAP_END ((unsigned) -1)
+
+#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8))
+#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8))
+#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem))
+
+Bitmap *bitmap_new(void) {
+ return new0(Bitmap, 1);
+}
+
+void bitmap_free(Bitmap *b) {
+ if (!b)
+ return;
+
+ free(b->bitmaps);
+ free(b);
+}
+
+int bitmap_ensure_allocated(Bitmap **b) {
+ Bitmap *a;
+
+ assert(b);
+
+ if (*b)
+ return 0;
+
+ a = bitmap_new();
+ if (!a)
+ return -ENOMEM;
+
+ *b = a;
+
+ return 0;
+}
+
+int bitmap_set(Bitmap *b, unsigned n) {
+ uint64_t bitmask;
+ unsigned offset;
+
+ assert(b);
+
+ /* we refuse to allocate huge bitmaps */
+ if (n > BITMAPS_MAX_ENTRY)
+ return -ERANGE;
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps) {
+ if (!GREEDY_REALLOC0(b->bitmaps, b->bitmaps_allocated, offset + 1))
+ return -ENOMEM;
+
+ b->n_bitmaps = offset + 1;
+ }
+
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
+
+ b->bitmaps[offset] |= bitmask;
+
+ return 0;
+}
+
+void bitmap_unset(Bitmap *b, unsigned n) {
+ uint64_t bitmask;
+ unsigned offset;
+
+ if (!b)
+ return;
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps)
+ return;
+
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
+
+ b->bitmaps[offset] &= ~bitmask;
+}
+
+bool bitmap_isset(Bitmap *b, unsigned n) {
+ uint64_t bitmask;
+ unsigned offset;
+
+ if (!b)
+ return false;
+
+ offset = BITMAP_NUM_TO_OFFSET(n);
+
+ if (offset >= b->n_bitmaps)
+ return false;
+
+ bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
+
+ return !!(b->bitmaps[offset] & bitmask);
+}
+
+bool bitmap_isclear(Bitmap *b) {
+ unsigned i;
+
+ assert(b);
+
+ for (i = 0; i < b->n_bitmaps; i++)
+ if (b->bitmaps[i] != 0)
+ return false;
+
+ return true;
+}
+
+void bitmap_clear(Bitmap *b) {
+ assert(b);
+
+ b->n_bitmaps = 0;
+}
+
+bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
+ uint64_t bitmask;
+ unsigned offset, rem;
+
+ assert(i);
+ assert(n);
+
+ if (!b || i->idx == BITMAP_END)
+ return false;
+
+ offset = BITMAP_NUM_TO_OFFSET(i->idx);
+ rem = BITMAP_NUM_TO_REM(i->idx);
+ bitmask = UINT64_C(1) << rem;
+
+ for (; offset < b->n_bitmaps; offset ++) {
+ if (b->bitmaps[offset]) {
+ for (; bitmask; bitmask <<= 1, rem ++) {
+ if (b->bitmaps[offset] & bitmask) {
+ *n = BITMAP_OFFSET_TO_NUM(offset, rem);
+ i->idx = *n + 1;
+
+ return true;
+ }
+ }
+ }
+
+ rem = 0;
+ bitmask = 1;
+ }
+
+ i->idx = BITMAP_END;
+
+ return false;
+}
+
+bool bitmap_equal(Bitmap *a, Bitmap *b) {
+
+ if (!a ^ !b)
+ return false;
+
+ if (!a)
+ return true;
+
+ if (a->n_bitmaps != b->n_bitmaps)
+ return false;
+
+ return memcmp(a->bitmaps, b->bitmaps, sizeof(uint64_t) * a->n_bitmaps) == 0;
+}
diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h
new file mode 100644
index 0000000000..2874bc99f7
--- /dev/null
+++ b/src/basic/bitmap.h
@@ -0,0 +1,50 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+#include "hashmap.h"
+
+typedef struct Bitmap Bitmap;
+
+Bitmap *bitmap_new(void);
+
+void bitmap_free(Bitmap *b);
+
+int bitmap_ensure_allocated(Bitmap **b);
+
+int bitmap_set(Bitmap *b, unsigned n);
+void bitmap_unset(Bitmap *b, unsigned n);
+bool bitmap_isset(Bitmap *b, unsigned n);
+bool bitmap_isclear(Bitmap *b);
+void bitmap_clear(Bitmap *b);
+
+bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n);
+
+bool bitmap_equal(Bitmap *a, Bitmap *b);
+
+#define BITMAP_FOREACH(n, b, i) \
+ for ((i).idx = 0; bitmap_iterate((b), &(i), (unsigned*)&(n)); )
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Bitmap*, bitmap_free);
+
+#define _cleanup_bitmap_free_ _cleanup_(bitmap_freep)
diff --git a/src/basic/copy.c b/src/basic/copy.c
index 230e7e4d3f..e2d356d676 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -24,6 +24,7 @@
#include "util.h"
#include "btrfs-util.h"
+#include "strv.h"
#include "copy.h"
#define COPY_BUFFER_SIZE (16*1024)
@@ -262,10 +263,13 @@ static int fd_copy_directory(
(void) copy_xattr(dirfd(d), fdt);
}
- FOREACH_DIRENT(de, d, return -errno) {
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
struct stat buf;
int q;
+ if (STR_IN_SET(de->d_name, ".", ".."))
+ continue;
+
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
r = -errno;
continue;
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 5ab36825c0..fcff753ada 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -151,6 +151,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
case EXIT_BUS_ENDPOINT:
return "BUS_ENDPOINT";
+
+ case EXIT_SMACK_PROCESS_LABEL:
+ return "SMACK_PROCESS_LABEL";
}
}
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index d592bf5ac9..2216853777 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -786,7 +786,7 @@ int executable_is_script(const char *path, char **interpreter) {
*/
int get_status_field(const char *filename, const char *pattern, char **field) {
_cleanup_free_ char *status = NULL;
- char *t;
+ char *t, *f;
size_t len;
int r;
@@ -820,9 +820,10 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
len = strcspn(t, WHITESPACE);
- *field = strndup(t, len);
- if (!*field)
+ f = strndup(t, len);
+ if (!f)
return -ENOMEM;
+ *field = f;
return 0;
}
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 5fa17ed208..627d768b76 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <inttypes.h>
+#include <stdbool.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -406,12 +407,12 @@ do { \
#define IN_SET(x, y, ...) \
({ \
- const typeof(y) _y = (y); \
- const typeof(_y) _x = (x); \
+ static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \
+ const typeof(y) _x = (x); \
unsigned _i; \
bool _found = false; \
- for (_i = 0; _i < 1 + sizeof((const typeof(_x)[]) { __VA_ARGS__ })/sizeof(const typeof(_x)); _i++) \
- if (((const typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
+ for (_i = 0; _i < ELEMENTSOF(_array); _i++) \
+ if (_array[_i] == _x) { \
_found = true; \
break; \
} \
@@ -461,6 +462,18 @@ do { \
#define GID_INVALID ((gid_t) -1)
#define MODE_INVALID ((mode_t) -1)
+static inline bool UID_IS_INVALID(uid_t uid) {
+ /* We consider both the old 16bit -1 user and the newer 32bit
+ * -1 user invalid, since they are or used to be incompatible
+ * with syscalls such as setresuid() or chown(). */
+
+ return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
+}
+
+static inline bool GID_IS_INVALID(gid_t gid) {
+ return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
+}
+
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
diff --git a/src/basic/missing.h b/src/basic/missing.h
index be7f6186fc..ed6cd80c75 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -772,7 +772,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPTUN_6RD_RELAY_PREFIXLEN
+#if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT
#define IFLA_IPTUN_UNSPEC 0
#define IFLA_IPTUN_LINK 1
#define IFLA_IPTUN_LOCAL 2
@@ -788,11 +788,41 @@ static inline int setns(int fd, int nstype) {
#define IFLA_IPTUN_6RD_RELAY_PREFIX 12
#define IFLA_IPTUN_6RD_PREFIXLEN 13
#define IFLA_IPTUN_6RD_RELAY_PREFIXLEN 14
-#define __IFLA_IPTUN_MAX 15
+#define IFLA_IPTUN_ENCAP_TYPE 15
+#define IFLA_IPTUN_ENCAP_FLAGS 16
+#define IFLA_IPTUN_ENCAP_SPORT 17
+#define IFLA_IPTUN_ENCAP_DPORT 18
+
+#define __IFLA_IPTUN_MAX 19
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_GRE_ENCAP_DPORT
+#define IFLA_GRE_UNSPEC 0
+#define IFLA_GRE_LINK 1
+#define IFLA_GRE_IFLAGS 2
+#define IFLA_GRE_OFLAGS 3
+#define IFLA_GRE_IKEY 4
+#define IFLA_GRE_OKEY 5
+#define IFLA_GRE_LOCAL 6
+#define IFLA_GRE_REMOTE 7
+#define IFLA_GRE_TTL 8
+#define IFLA_GRE_TOS 9
+#define IFLA_GRE_PMTUDISC 10
+#define IFLA_GRE_ENCAP_LIMIT 11
+#define IFLA_GRE_FLOWINFO 12
+#define IFLA_GRE_FLAGS 13
+#define IFLA_GRE_ENCAP_TYPE 14
+#define IFLA_GRE_ENCAP_FLAGS 15
+#define IFLA_GRE_ENCAP_SPORT 16
+#define IFLA_GRE_ENCAP_DPORT 17
+
+#define __IFLA_GRE_MAX 18
+
+#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+#endif
+
#if !HAVE_DECL_IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_FLAGS 0
#define IFLA_BRIDGE_MODE 1
@@ -802,7 +832,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_UNICAST_FLOOD
+#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
#define IFLA_BRPORT_PRIORITY 2
@@ -813,7 +843,9 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRPORT_FAST_LEAVE 7
#define IFLA_BRPORT_LEARNING 8
#define IFLA_BRPORT_UNICAST_FLOOD 9
-#define __IFLA_BRPORT_MAX 10
+#define IFLA_BRPORT_PROXYARP 10
+#define IFLA_BRPORT_LEARNING_SYNC 11
+#define __IFLA_BRPORT_MAX 12
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 2c05f2fee4..61f188467f 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -43,7 +43,10 @@ int get_process_state(pid_t pid) {
assert(pid >= 0);
p = procfs_file_alloca(pid, "stat");
+
r = read_one_line_file(p, &line);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0)
return r;
@@ -87,8 +90,11 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
p = procfs_file_alloca(pid, "cmdline");
f = fopen(p, "re");
- if (!f)
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
return -errno;
+ }
if (max_length == 0) {
size_t len = 0, allocated = 0;
@@ -182,8 +188,11 @@ int is_kernel_thread(pid_t pid) {
p = procfs_file_alloca(pid, "cmdline");
f = fopen(p, "re");
- if (!f)
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
return -errno;
+ }
count = fread(&c, 1, 1, f);
eof = feof(f);
@@ -199,13 +208,18 @@ int is_kernel_thread(pid_t pid) {
int get_process_capeff(pid_t pid, char **capeff) {
const char *p;
+ int r;
assert(capeff);
assert(pid >= 0);
p = procfs_file_alloca(pid, "status");
- return get_status_field(p, "\nCapEff:", capeff);
+ r = get_status_field(p, "\nCapEff:", capeff);
+ if (r == -ENOENT)
+ return -ESRCH;
+
+ return r;
}
static int get_process_link_contents(const char *proc_file, char **name) {
@@ -215,8 +229,10 @@ static int get_process_link_contents(const char *proc_file, char **name) {
assert(name);
r = readlink_malloc(proc_file, name);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
+ return r;
return 0;
}
@@ -253,8 +269,11 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
- if (!f)
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
return -errno;
+ }
FOREACH_LINE(line, f, return -errno) {
char *l;
@@ -316,8 +335,11 @@ int get_process_environ(pid_t pid, char **env) {
p = procfs_file_alloca(pid, "environ");
f = fopen(p, "re");
- if (!f)
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
return -errno;
+ }
while ((c = fgetc(f)) != EOF) {
if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
@@ -329,10 +351,13 @@ int get_process_environ(pid_t pid, char **env) {
sz += cescape_char(c, outcome + sz);
}
- if (sz == 0)
- return -ENOENT;
+ if (!outcome) {
+ outcome = strdup("");
+ if (!outcome)
+ return -ENOMEM;
+ } else
+ outcome[sz] = '\0';
- outcome[sz] = '\0';
*env = outcome;
outcome = NULL;
@@ -355,6 +380,8 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
p = procfs_file_alloca(pid, "stat");
r = read_one_line_file(p, &line);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0)
return r;
@@ -475,8 +502,11 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
path = procfs_file_alloca(pid, "environ");
f = fopen(path, "re");
- if (!f)
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
return -errno;
+ }
l = strlen(field);
r = 0;
@@ -535,7 +565,7 @@ bool pid_is_alive(pid_t pid) {
return false;
r = get_process_state(pid);
- if (r == -ENOENT || r == 'Z')
+ if (r == -ESRCH || r == 'Z')
return false;
return true;
diff --git a/src/basic/util.c b/src/basic/util.c
index a45f5f8e53..1c15fbc172 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -954,6 +954,356 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
return 0;
}
+/* https://tools.ietf.org/html/rfc4648#section-6
+ * Notice that base32hex differs from base32 in the alphabet it uses.
+ * The distinction is that the base32hex representation preserves the
+ * order of the underlying data when compared as bytestrings, this is
+ * useful when representing NSEC3 hashes, as one can then verify the
+ * order of hashes directly from their representation. */
+char base32hexchar(int x) {
+ static const char table[32] = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUV";
+
+ return table[x & 31];
+}
+
+int unbase32hexchar(char c) {
+ unsigned offset;
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ offset = '9' - '0' + 1;
+
+ if (c >= 'A' && c <= 'V')
+ return c - 'A' + offset;
+
+ return -EINVAL;
+}
+
+char *base32hexmem(const void *p, size_t l, bool padding) {
+ char *r, *z;
+ const uint8_t *x;
+ size_t len;
+
+ if (padding)
+ /* five input bytes makes eight output bytes, padding is added so we must round up */
+ len = 8 * (l + 4) / 5;
+ else {
+ /* same, but round down as there is no padding */
+ len = 8 * l / 5;
+
+ switch (l % 5) {
+ case 4:
+ len += 7;
+ break;
+ case 3:
+ len += 5;
+ break;
+ case 2:
+ len += 4;
+ break;
+ case 1:
+ len += 2;
+ break;
+ }
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
+ x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
+ *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
+ }
+
+ switch (l % 5) {
+ case 4:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
+ if (padding)
+ *(z++) = '=';
+
+ break;
+
+ case 3:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 2:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 1:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d, e, f, g, h;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+ unsigned pad = 0;
+
+ assert(p);
+
+ /* padding ensures any base32hex input has input divisible by 8 */
+ if (padding && l % 8 != 0)
+ return -EINVAL;
+
+ if (padding) {
+ /* strip the padding */
+ while (l > 0 && p[l - 1] == '=' && pad < 7) {
+ pad ++;
+ l --;
+ }
+ }
+
+ /* a group of eight input bytes needs five output bytes, in case of
+ padding we need to add some extra bytes */
+ len = (l / 8) * 5;
+
+ switch (l % 8) {
+ case 7:
+ len += 4;
+ break;
+ case 5:
+ len += 3;
+ break;
+ case 4:
+ len += 2;
+ break;
+ case 2:
+ len += 1;
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 8) * 8; x += 8) {
+ /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
+ e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ h = unbase32hexchar(x[7]);
+ if (h < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+ *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
+ }
+
+ switch (l % 8) {
+ case 7:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ /* g == 000VV000 */
+ if (g & 7)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+
+ break;
+ case 5:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ /* e == 000SSSS0 */
+ if (e & 1)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+
+ break;
+ case 4:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ /* d == 000W0000 */
+ if (d & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+
+ break;
+ case 2:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 000YYY00 */
+ if (b & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
/* https://tools.ietf.org/html/rfc4648#section-4 */
char base64char(int x) {
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -1117,6 +1467,11 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
+ case 0:
+
+ break;
+ default:
+ return -EINVAL;
}
*z = 0;
@@ -5379,13 +5734,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case VALUE:
if (c == 0)
goto finish;
- else if (c == '\'')
+ else if (c == '\'') {
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
state = SINGLE_QUOTE;
- else if (c == '\\')
+ } else if (c == '\\')
state = VALUE_ESCAPE;
- else if (c == '\"')
+ else if (c == '\"') {
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
state = DOUBLE_QUOTE;
- else if (strchr(WHITESPACE, c))
+ } else if (strchr(WHITESPACE, c))
state = SPACE;
else {
if (!GREEDY_REALLOC(s, allocated, sz+2))
diff --git a/src/basic/util.h b/src/basic/util.h
index dae43006e4..c2e5cc610b 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -240,6 +240,8 @@ char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
+char base32hexchar(int x) _const_;
+int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
@@ -618,6 +620,9 @@ static inline void *mempset(void *s, int c, size_t n) {
char *hexmem(const void *p, size_t l);
int unhexmem(const char *p, size_t l, void **mem, size_t *len);
+char *base32hexmem(const void *p, size_t l, bool padding);
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
+
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 1299a75ed5..a8d26716a1 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -188,7 +188,7 @@ int detect_vm(const char **id) {
_cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
static thread_local int cached_found = -1;
static thread_local const char *cached_id = NULL;
- const char *_id = NULL;
+ const char *_id = NULL, *_id_cpuid = NULL;
int r;
if (_likely_(cached_found >= 0)) {
@@ -234,10 +234,26 @@ int detect_vm(const char **id) {
/* this will set _id to "other" and return 0 for unknown hypervisors */
r = detect_vm_cpuid(&_id);
- if (r != 0)
+
+ /* finish when found a known hypervisor other than kvm */
+ if (r < 0 || (r > 0 && !streq(_id, "kvm")))
goto finish;
+ _id_cpuid = _id;
+
r = detect_vm_dmi(&_id);
+
+ /* kvm with and without Virtualbox */
+ if (streq_ptr(_id_cpuid, "kvm")) {
+ if (r > 0 && streq(_id, "oracle"))
+ goto finish;
+
+ _id = _id_cpuid;
+ r = 1;
+ goto finish;
+ }
+
+ /* information from dmi */
if (r != 0)
goto finish;
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index faab82dbb8..091ea375d3 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -294,6 +294,8 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
else if (r < 0)
return r;
+ printf("\n");
+
return 0;
}
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 827c11844c..e8cd8abd26 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1495,6 +1495,7 @@ static VOID config_entry_add_osx(Config *config) {
static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) {
EFI_FILE_HANDLE linux_dir;
EFI_STATUS err;
+ ConfigEntry *entry;
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
if (!EFI_ERROR(err)) {
@@ -1504,6 +1505,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
EFI_FILE_INFO *f;
CHAR8 *sections[] = {
(UINT8 *)".osrel",
+ (UINT8 *)".cmdline",
NULL
};
UINTN offs[ELEMENTSOF(sections)-1] = {};
@@ -1535,7 +1537,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
if (StriCmp(f->FileName + len - 4, L".efi") != 0)
continue;
- /* look for an .osrel section in the .efi binary */
+ /* look for .osrel and .cmdline sections in the .efi binary */
err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs);
if (EFI_ERROR(err))
continue;
@@ -1575,10 +1577,21 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
if (os_name && os_id && (os_version || os_build)) {
CHAR16 *conf;
CHAR16 *path;
+ CHAR16 *cmdline;
conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build);
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
- config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
+ entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
+
+ FreePool(content);
+ /* read the embedded cmdline file */
+ len = file_read(linux_dir, f->FileName, offs[1], szs[1] - 1 , &content);
+ if (len > 0) {
+ cmdline = stra_to_str(content);
+ entry->options = cmdline;
+ cmdline = NULL;
+ }
+ FreePool(cmdline);
FreePool(conf);
FreePool(path);
}
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 3360bc85be..1625d51fa8 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -387,9 +387,6 @@ int main(int argc, char *argv[]) {
for (samples = 0; !exiting && samples < arg_samples_len; samples++) {
int res;
double sample_stop;
- struct timespec req;
- time_t newint_s;
- long newint_ns;
double elapsed;
double timeleft;
@@ -427,18 +424,17 @@ int main(int argc, char *argv[]) {
elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0;
timeleft = interval - elapsed;
- newint_s = (time_t)(timeleft / 1000000000.0);
- newint_ns = (long)(timeleft - (newint_s * 1000000000.0));
-
/*
* check if we have not consumed our entire timeslice. If we
* do, don't sleep and take a new sample right away.
* we'll lose all the missed samples and overrun our total
* time
*/
- if (newint_ns > 0 || newint_s > 0) {
- req.tv_sec = newint_s;
- req.tv_nsec = newint_ns;
+ if (timeleft > 0) {
+ struct timespec req;
+
+ req.tv_sec = (time_t)(timeleft / 1000000000.0);
+ req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0));
res = nanosleep(&req, NULL);
if (res) {
@@ -452,7 +448,7 @@ int main(int argc, char *argv[]) {
} else {
overrun++;
/* calculate how many samples we lost and scrap them */
- arg_samples_len -= (int)(newint_ns / interval);
+ arg_samples_len -= (int)(-timeleft / interval);
}
LIST_PREPEND(link, head, sampledata);
}
diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c
index 4ac955da41..1cb5ea5008 100644
--- a/src/bus-proxyd/driver.c
+++ b/src/bus-proxyd/driver.c
@@ -33,6 +33,7 @@
#include "strv.h"
#include "set.h"
#include "driver.h"
+#include "proxy.h"
#include "synthesize.h"
static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
@@ -70,7 +71,7 @@ static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, s
return get_creds_by_name(bus, name, mask, _creds, error);
}
-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
+int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
int r;
assert(a);
@@ -189,7 +190,7 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- r = sd_bus_add_match(a, NULL, match, NULL, NULL);
+ r = sd_bus_add_match(a, NULL, match, proxy_match, p);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h
index b8cedf5ce5..da3834f8b0 100644
--- a/src/bus-proxyd/driver.h
+++ b/src/bus-proxyd/driver.h
@@ -23,5 +23,6 @@
#include "sd-bus.h"
#include "bus-xml-policy.h"
+#include "proxy.h"
-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
+int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c
index 189ee969c7..c37b09b9c0 100644
--- a/src/bus-proxyd/proxy.c
+++ b/src/bus-proxyd/proxy.c
@@ -144,9 +144,17 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd
return 0;
}
+static int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ Proxy *p = userdata;
+
+ p->synthetic_matched = true;
+ return 0; /* make sure to continue processing it in further handlers */
+}
+
/*
- * dbus-1 clients receive NameOwnerChanged and directed signals without
- * subscribing to them; install the matches to receive them on kdbus.
+ * We always need NameOwnerChanged so we can synthesize NameLost and
+ * NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so
+ * subscribe unconditionally.
*/
static int proxy_prepare_matches(Proxy *p) {
_cleanup_free_ char *match = NULL;
@@ -172,7 +180,7 @@ static int proxy_prepare_matches(Proxy *p) {
if (!match)
return log_oom();
- r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+ r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
if (r < 0)
return log_error_errno(r, "Failed to add match for NameLost: %m");
@@ -189,7 +197,7 @@ static int proxy_prepare_matches(Proxy *p) {
if (!match)
return log_oom();
- r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+ r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
if (r < 0)
return log_error_errno(r, "Failed to add match for NameAcquired: %m");
@@ -202,7 +210,7 @@ static int proxy_prepare_matches(Proxy *p) {
if (!match)
return log_oom();
- r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+ r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
if (r < 0)
log_error_errno(r, "Failed to add match for directed signals: %m");
/* FIXME: temporarily ignore error to support older kdbus versions */
@@ -679,11 +687,28 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) {
static int proxy_process_destination_to_local(Proxy *p) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ bool matched, matched_synthetic;
int r;
assert(p);
+ /*
+ * Usually, we would just take any message that the bus passes to us
+ * and forward it to the local connection. However, there are actually
+ * applications that fail if they receive broadcasts that they didn't
+ * subscribe to. Therefore, we actually emulate a real broadcast
+ * matching here, and discard any broadcasts that weren't matched. Our
+ * match-handlers remembers whether a message was matched by any rule,
+ * by marking it in @p->message_matched.
+ */
+
r = sd_bus_process(p->destination_bus, &m);
+
+ matched = p->message_matched;
+ matched_synthetic = p->synthetic_matched;
+ p->message_matched = false;
+ p->synthetic_matched = false;
+
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
return r;
if (r < 0) {
@@ -699,12 +724,21 @@ static int proxy_process_destination_to_local(Proxy *p) {
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
return -ECONNRESET;
- r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
+ r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to synthesize message: %m");
+ /* discard broadcasts that were not matched by any MATCH rule */
+ if (!matched && !sd_bus_message_get_destination(m)) {
+ if (!matched_synthetic)
+ log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s",
+ p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
+ strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
+ return 1;
+ }
+
patch_sender(p->destination_bus, m);
if (p->policy) {
@@ -788,7 +822,7 @@ static int proxy_process_local_to_destination(Proxy *p) {
if (r > 0)
return 1;
- r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
+ r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
@@ -834,6 +868,13 @@ static int proxy_process_local_to_destination(Proxy *p) {
return 1;
}
+int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ Proxy *p = userdata;
+
+ p->message_matched = true;
+ return 0; /* make sure to continue processing it in further handlers */
+}
+
int proxy_run(Proxy *p) {
int r;
diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h
index ff278a2465..ccb951c109 100644
--- a/src/bus-proxyd/proxy.h
+++ b/src/bus-proxyd/proxy.h
@@ -39,6 +39,8 @@ struct Proxy {
bool got_hello : 1;
bool queue_overflow : 1;
+ bool message_matched : 1;
+ bool synthetic_matched : 1;
};
int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
@@ -46,6 +48,7 @@ Proxy *proxy_free(Proxy *p);
int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration);
int proxy_hello_policy(Proxy *p, uid_t original_uid);
+int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error);
int proxy_run(Proxy *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c
index 67bcc7a242..3ecedfd575 100644
--- a/src/bus-proxyd/synthesize.c
+++ b/src/bus-proxyd/synthesize.c
@@ -28,6 +28,7 @@
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
+#include "bus-match.h"
#include "synthesize.h"
int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
@@ -152,11 +153,12 @@ int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
return synthetic_driver_send(call->bus, m);
}
-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
+int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_message_unref_ sd_bus_message *n = NULL;
const char *name, *old_owner, *new_owner;
int r;
+ assert(p);
assert(a);
assert(b);
assert(m);
@@ -216,5 +218,18 @@ int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
if (r < 0)
return r;
- return sd_bus_send(b, n, NULL);
+ /*
+ * Make sure to only forward NameLost/NameAcquired messages if they
+ * match an installed MATCH rule of the local client. We really must
+ * not send messages the client doesn't expect.
+ */
+
+ r = bus_match_run(b, &b->match_callbacks, n);
+ if (r >= 0 && p->message_matched)
+ r = sd_bus_send(b, n, NULL);
+
+ p->message_matched = false;
+ p->synthetic_matched = false;
+
+ return r;
}
diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h
index e850350bc5..b596daddf2 100644
--- a/src/bus-proxyd/synthesize.h
+++ b/src/bus-proxyd/synthesize.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+#include "proxy.h"
int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
@@ -33,4 +34,4 @@ int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const
int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p);
int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4);
-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m);
+int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m);
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 46a444340a..b8d1d2ccaf 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -197,19 +197,19 @@ int main(int argc, char *argv[]) {
if (arg_machine) {
char *m;
const char *cgroup;
- _cleanup_free_ char *scope = NULL;
+ _cleanup_free_ char *unit = NULL;
_cleanup_free_ char *path = NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
m = strjoina("/run/systemd/machines/", arg_machine);
- r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL);
+ r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
if (r < 0) {
log_error_errno(r, "Failed to get machine path: %m");
goto finish;
}
- path = unit_dbus_path_from_name(scope);
+ path = unit_dbus_path_from_name(unit);
if (!path) {
log_oom();
goto finish;
@@ -219,7 +219,7 @@ int main(int argc, char *argv[]) {
bus,
"org.freedesktop.systemd1",
path,
- "org.freedesktop.systemd1.Scope",
+ endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
"ControlGroup",
&error,
&reply,
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index d630e35882..f953c9e624 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <alloca.h>
#include <getopt.h>
+#include <signal.h>
#include "path-util.h"
#include "terminal-util.h"
diff --git a/src/core/automount.c b/src/core/automount.c
index d847dc1629..4af381b4b6 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -471,13 +471,20 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
return r;
}
+static int automount_start_expire(Automount *a);
+
int automount_update_mount(Automount *a, MountState old_state, MountState state) {
+ int r;
+
assert(a);
switch (state) {
case MOUNT_MOUNTED:
case MOUNT_REMOUNTING:
automount_send_ready(a, a->tokens, 0);
+ r = automount_start_expire(a);
+ if (r < 0)
+ log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
break;
case MOUNT_DEAD:
case MOUNT_UNMOUNTING:
@@ -490,6 +497,7 @@ int automount_update_mount(Automount *a, MountState old_state, MountState state)
case MOUNT_FAILED:
if (old_state != state)
automount_send_ready(a, a->tokens, -ENODEV);
+ (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
break;
default:
break;
@@ -633,8 +641,6 @@ static void *expire_thread(void *p) {
return NULL;
}
-static int automount_start_expire(Automount *a);
-
static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
Automount *a = AUTOMOUNT(userdata);
_cleanup_(expire_data_freep) struct expire_data *data = NULL;
@@ -672,7 +678,10 @@ static int automount_start_expire(Automount *a) {
assert(a);
- timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/10, USEC_PER_SEC);
+ if (a->timeout_idle_usec == 0)
+ return 0;
+
+ timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);
if (a->expire_event_source) {
r = sd_event_source_set_time(a->expire_event_source, timeout);
@@ -730,10 +739,6 @@ static void automount_enter_runnning(Automount *a) {
}
}
- r = automount_start_expire(a);
- if (r < 0)
- log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
-
automount_set_state(a, AUTOMOUNT_RUNNING);
return;
@@ -904,6 +909,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
Automount *a = AUTOMOUNT(userdata);
+ struct stat st;
int r;
assert(a);
@@ -963,6 +969,19 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
goto fail;
}
+
+ /* Before we do anything, let's see if somebody is playing games with us? */
+ if (lstat(a->where, &st) < 0) {
+ log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
+ goto fail;
+ }
+
+ if (!S_ISDIR(st.st_mode) || st.st_dev == a->dev_id) {
+ log_unit_info(UNIT(a), "Automount point already unmounted?");
+ automount_send_ready(a, a->expire_tokens, 0);
+ break;
+ }
+
r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
if (r < 0) {
log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
@@ -1066,7 +1085,6 @@ const UnitVTable automount_vtable = {
.finished_start_job = {
[JOB_DONE] = "Set up automount %s.",
[JOB_FAILED] = "Failed to set up automount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Unset automount %s.",
diff --git a/src/core/busname.c b/src/core/busname.c
index 2085721546..9530a87311 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -1065,13 +1065,10 @@ const UnitVTable busname_vtable = {
.finished_start_job = {
[JOB_DONE] = "Listening on %s.",
[JOB_FAILED] = "Failed to listen on %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Closed %s.",
[JOB_FAILED] = "Failed stopping %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
},
},
};
diff --git a/src/core/job.c b/src/core/job.c
index 1448e5b69a..15f5cc0cc9 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -495,10 +495,48 @@ static void job_change_type(Job *j, JobType newtype) {
j->type = newtype;
}
+static int job_perform_on_unit(Job **j) {
+ /* While we execute this operation the job might go away (for
+ * example: because it finishes immediately or is replaced by a new,
+ * conflicting job.) To make sure we don't access a freed job later on
+ * we store the id here, so that we can verify the job is still
+ * valid. */
+ Manager *m = (*j)->manager;
+ Unit *u = (*j)->unit;
+ JobType t = (*j)->type;
+ uint32_t id = (*j)->id;
+ int r;
+
+ switch (t) {
+ case JOB_START:
+ r = unit_start(u);
+ break;
+
+ case JOB_RESTART:
+ t = JOB_STOP;
+ case JOB_STOP:
+ r = unit_stop(u);
+ break;
+
+ case JOB_RELOAD:
+ r = unit_reload(u);
+ break;
+
+ default:
+ assert_not_reached("Invalid job type");
+ }
+
+ /* Log if the job still exists and the start/stop/reload function
+ * actually did something. */
+ *j = manager_get_job(m, id);
+ if (*j && r > 0)
+ unit_status_emit_starting_stopping_reloading(u, t);
+
+ return r;
+}
+
int job_run_and_invalidate(Job *j) {
int r;
- uint32_t id;
- Manager *m = j->manager;
assert(j);
assert(j->installed);
@@ -517,23 +555,9 @@ int job_run_and_invalidate(Job *j) {
job_set_state(j, JOB_RUNNING);
job_add_to_dbus_queue(j);
- /* While we execute this operation the job might go away (for
- * example: because it is replaced by a new, conflicting
- * job.) To make sure we don't access a freed job later on we
- * store the id here, so that we can verify the job is still
- * valid. */
- id = j->id;
switch (j->type) {
- case JOB_START:
- r = unit_start(j->unit);
-
- /* If this unit cannot be started, then simply wait */
- if (r == -EBADR)
- r = 0;
- break;
-
case JOB_VERIFY_ACTIVE: {
UnitActiveState t = unit_active_state(j->unit);
if (UNIT_IS_ACTIVE_OR_RELOADING(t))
@@ -545,17 +569,19 @@ int job_run_and_invalidate(Job *j) {
break;
}
+ case JOB_START:
case JOB_STOP:
case JOB_RESTART:
- r = unit_stop(j->unit);
+ r = job_perform_on_unit(&j);
- /* If this unit cannot stopped, then simply wait. */
+ /* If the unit type does not support starting/stopping,
+ * then simply wait. */
if (r == -EBADR)
r = 0;
break;
case JOB_RELOAD:
- r = unit_reload(j->unit);
+ r = job_perform_on_unit(&j);
break;
case JOB_NOP:
@@ -566,7 +592,6 @@ int job_run_and_invalidate(Job *j) {
assert_not_reached("Unknown job type");
}
- j = manager_get_job(m, id);
if (j) {
if (r == -EALREADY)
r = job_finish_and_invalidate(j, JOB_DONE, true);
@@ -588,161 +613,110 @@ int job_run_and_invalidate(Job *j) {
}
_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
+ const char *format;
const UnitStatusMessageFormats *format_table;
+ static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = "Started %s.",
+ [JOB_TIMEOUT] = "Timed out starting %s.",
+ [JOB_FAILED] = "Failed to start %s.",
+ [JOB_DEPENDENCY] = "Dependency failed for %s.",
+ [JOB_ASSERT] = "Assertion failed for %s.",
+ [JOB_UNSUPPORTED] = "Starting of %s not supported.",
+ };
+ static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = "Stopped %s.",
+ [JOB_FAILED] = "Stopped (with error) %s.",
+ [JOB_TIMEOUT] = "Timed out stoppping %s.",
+ };
+ static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = "Reloaded %s.",
+ [JOB_FAILED] = "Reload failed for %s.",
+ [JOB_TIMEOUT] = "Timed out reloading %s.",
+ };
+ /* When verify-active detects the unit is inactive, report it.
+ * Most likely a DEPEND warning from a requisiting unit will
+ * occur next and it's nice to see what was requisited. */
+ static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = {
+ [JOB_SKIPPED] = "%s is not active.",
+ };
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
+ if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) {
+ format_table = &UNIT_VTABLE(u)->status_message_formats;
+ if (format_table) {
+ format = t == JOB_START ? format_table->finished_start_job[result] :
+ format_table->finished_stop_job[result];
+ if (format)
+ return format;
+ }
+ }
+ /* Return generic strings */
if (t == JOB_START)
- return format_table->finished_start_job[result];
+ return generic_finished_start_job[result];
else if (t == JOB_STOP || t == JOB_RESTART)
- return format_table->finished_stop_job[result];
+ return generic_finished_stop_job[result];
+ else if (t == JOB_RELOAD)
+ return generic_finished_reload_job[result];
+ else if (t == JOB_VERIFY_ACTIVE)
+ return generic_finished_verify_active_job[result];
return NULL;
}
-_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
+static void job_print_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
+ static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF,
+ [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF,
+ [JOB_FAILED] = ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF,
+ [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF,
+ [JOB_SKIPPED] = ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF,
+ [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF,
+ [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF,
+ };
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
format = job_get_status_message_format(u, t, result);
- if (format)
- return format;
-
- /* Return generic strings */
- if (t == JOB_START) {
- if (result == JOB_DONE)
- return "Started %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out starting %s.";
- else if (result == JOB_FAILED)
- return "Failed to start %s.";
- else if (result == JOB_DEPENDENCY)
- return "Dependency failed for %s.";
- else if (result == JOB_ASSERT)
- return "Assertion failed for %s.";
- else if (result == JOB_UNSUPPORTED)
- return "Starting of %s not supported.";
- } else if (t == JOB_STOP || t == JOB_RESTART) {
- if (result == JOB_DONE)
- return "Stopped %s.";
- else if (result == JOB_FAILED)
- return "Stopped (with error) %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out stoppping %s.";
- } else if (t == JOB_RELOAD) {
- if (result == JOB_DONE)
- return "Reloaded %s.";
- else if (result == JOB_FAILED)
- return "Reload failed for %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out reloading %s.";
- }
-
- return NULL;
-}
+ if (!format)
+ return;
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
+ if (result != JOB_DONE)
+ manager_flip_auto_status(u->manager, true);
DISABLE_WARNING_FORMAT_NONLITERAL;
+ unit_status_printf(u, job_result_status_table[result], format);
+ REENABLE_WARNING;
- if (t == JOB_START) {
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_DONE:
- if (u->condition_result)
- unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_TIMEOUT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_FAILED: {
- _cleanup_free_ char *quoted = NULL;
-
- quoted = shell_maybe_quote(u->id);
-
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
- break;
- }
-
- case JOB_DEPENDENCY:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_ASSERT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_UNSUPPORTED:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_STOP || t == JOB_RESTART) {
-
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_TIMEOUT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_DONE:
- case JOB_FAILED:
- unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_VERIFY_ACTIVE) {
+ if (t == JOB_START && result == JOB_FAILED) {
+ _cleanup_free_ char *quoted = shell_maybe_quote(u->id);
- /* When verify-active detects the unit is inactive, report it.
- * Most likely a DEPEND warning from a requisiting unit will
- * occur next and it's nice to see what was requisited. */
- if (result == JOB_SKIPPED)
- unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
+ "See 'systemctl status %s' for details.", strna(quoted));
}
-
- REENABLE_WARNING;
}
static void job_log_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
char buf[LINE_MAX];
+ sd_id128_t mid;
+ static const int job_result_log_level[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = LOG_INFO,
+ [JOB_CANCELED] = LOG_INFO,
+ [JOB_TIMEOUT] = LOG_ERR,
+ [JOB_FAILED] = LOG_ERR,
+ [JOB_DEPENDENCY] = LOG_WARNING,
+ [JOB_SKIPPED] = LOG_NOTICE,
+ [JOB_INVALID] = LOG_INFO,
+ [JOB_ASSERT] = LOG_WARNING,
+ [JOB_UNSUPPORTED] = LOG_WARNING,
+ };
assert(u);
assert(t >= 0);
@@ -754,7 +728,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
if (log_on_console())
return;
- format = job_get_status_message_format_try_harder(u, t, result);
+ format = job_get_status_message_format(u, t, result);
if (!format)
return;
@@ -762,32 +736,40 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
snprintf(buf, sizeof(buf), format, unit_description(u));
REENABLE_WARNING;
- if (t == JOB_START) {
- sd_id128_t mid;
-
+ if (t == JOB_START)
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(mid),
+ else if (t == JOB_STOP || t == JOB_RESTART)
+ mid = SD_MESSAGE_UNIT_STOPPED;
+ else if (t == JOB_RELOAD)
+ mid = SD_MESSAGE_UNIT_RELOADED;
+ else {
+ log_struct(job_result_log_level[result],
LOG_UNIT_ID(u),
LOG_MESSAGE("%s", buf),
"RESULT=%s", job_result_to_string(result),
NULL);
+ return;
+ }
- } else if (t == JOB_STOP)
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
- LOG_UNIT_ID(u),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
+ log_struct(job_result_log_level[result],
+ LOG_MESSAGE_ID(mid),
+ LOG_UNIT_ID(u),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
+}
- else if (t == JOB_RELOAD)
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
- LOG_UNIT_ID(u),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
+static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+
+ /* No message if the job did not actually do anything due to failed condition. */
+ if (t == JOB_START && result == JOB_DONE && !u->condition_result)
+ return;
+
+ job_log_status_message(u, t, result);
+
+ /* Reload status messages have traditionally not been printed to console. */
+ if (t != JOB_RELOAD)
+ job_print_status_message(u, t, result);
}
static void job_fail_dependencies(Unit *u, UnitDependency d) {
@@ -825,8 +807,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
- job_print_status_message(u, t, result);
- job_log_status_message(u, t, result);
+ job_emit_status_message(u, t, result);
job_add_to_dbus_queue(j);
diff --git a/src/core/mount.c b/src/core/mount.c
index 851b41351e..c0d1cdfbd4 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -834,8 +834,6 @@ static void mount_enter_unmounting(Mount *m) {
m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
r = exec_command_set(m->control_command, UMOUNT_PATH, m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
if (r < 0)
goto fail;
@@ -886,8 +884,6 @@ static void mount_enter_mounting(Mount *m) {
r = exec_command_set(m->control_command, MOUNT_PATH,
m->parameters_fragment.what, m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
if (r >= 0 && m->parameters_fragment.fstype)
@@ -934,8 +930,6 @@ static void mount_enter_remounting(Mount *m) {
r = exec_command_set(m->control_command, MOUNT_PATH,
m->parameters_fragment.what, m->where,
"-o", o, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
if (r >= 0 && m->parameters_fragment.fstype)
@@ -1025,7 +1019,7 @@ static int mount_reload(Unit *u) {
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
- return 0;
+ return 1;
}
static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
@@ -1897,7 +1891,6 @@ const UnitVTable mount_vtable = {
.finished_start_job = {
[JOB_DONE] = "Mounted %s.",
[JOB_FAILED] = "Failed to mount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
[JOB_TIMEOUT] = "Timed out mounting %s.",
},
.finished_stop_job = {
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index e9a9a020de..50a90b0bac 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -302,12 +302,12 @@ int mac_selinux_unit_access_check_strv(
int r;
STRV_FOREACH(i, units) {
- u = manager_get_unit(m, *i);
- if (u) {
- r = mac_selinux_unit_access_check(u, message, permission, error);
- if (r < 0)
- return r;
- }
+ r = manager_load_unit(m, *i, NULL, error, &u);
+ if (r < 0)
+ return r;
+ r = mac_selinux_unit_access_check(u, message, permission, error);
+ if (r < 0)
+ return r;
}
#endif
return 0;
diff --git a/src/core/service.c b/src/core/service.c
index d72ff54daa..b790ec98be 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -401,7 +401,6 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
r = service_add_fd_store(s, fd);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
-
if (r > 0) {
log_unit_debug(UNIT(s), "Added fd to fd store.");
fd = -1;
@@ -576,8 +575,10 @@ static int service_add_extras(Service *s) {
return r;
r = unit_watch_bus_name(UNIT(s), s->bus_name);
+ if (r == -EEXIST)
+ return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
if (r < 0)
- return r;
+ return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
}
if (UNIT(s)->default_dependencies) {
@@ -1974,7 +1975,7 @@ static int service_reload(Unit *u) {
assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
service_enter_reload(s);
- return 0;
+ return 1;
}
_pure_ static bool service_can_reload(Unit *u) {
@@ -3229,13 +3230,10 @@ const UnitVTable service_vtable = {
.finished_start_job = {
[JOB_DONE] = "Started %s.",
[JOB_FAILED] = "Failed to start %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Stopped %s.",
[JOB_FAILED] = "Stopped (with error) %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
},
},
};
diff --git a/src/core/slice.c b/src/core/slice.c
index e52bf71515..064eb5d933 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -297,7 +297,6 @@ const UnitVTable slice_vtable = {
.status_message_formats = {
.finished_start_job = {
[JOB_DONE] = "Created slice %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Removed slice %s.",
diff --git a/src/core/socket.c b/src/core/socket.c
index 693cbc6080..87631f8753 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2722,7 +2722,6 @@ const UnitVTable socket_vtable = {
.finished_start_job = {
[JOB_DONE] = "Listening on %s.",
[JOB_FAILED] = "Failed to listen on %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
[JOB_TIMEOUT] = "Timed out starting %s.",
},
.finished_stop_job = {
diff --git a/src/core/swap.c b/src/core/swap.c
index 193c8c3767..0bc3827ff0 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1505,7 +1505,6 @@ const UnitVTable swap_vtable = {
.finished_start_job = {
[JOB_DONE] = "Activated swap %s.",
[JOB_FAILED] = "Failed to activate swap %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
[JOB_TIMEOUT] = "Timed out activating swap %s.",
},
.finished_stop_job = {
diff --git a/src/core/target.c b/src/core/target.c
index 8817ef21c4..b492a7c4c7 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -227,7 +227,6 @@ const UnitVTable target_vtable = {
.status_message_formats = {
.finished_start_job = {
[JOB_DONE] = "Reached target %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Stopped target %s.",
diff --git a/src/core/unit.c b/src/core/unit.c
index fac017c57d..dd5e801285 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1318,42 +1318,28 @@ static bool unit_assert_test(Unit *u) {
}
_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (t != JOB_START && t != JOB_STOP)
- return NULL;
-
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
-
- return format_table->starting_stopping[t == JOB_STOP];
-}
-
-_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
const char *format;
+ const UnitStatusMessageFormats *format_table;
assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
+ assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD);
- format = unit_get_status_message_format(u, t);
- if (format)
- return format;
+ if (t != JOB_RELOAD) {
+ format_table = &UNIT_VTABLE(u)->status_message_formats;
+ if (format_table) {
+ format = format_table->starting_stopping[t == JOB_STOP];
+ if (format)
+ return format;
+ }
+ }
/* Return generic strings */
if (t == JOB_START)
return "Starting %s.";
else if (t == JOB_STOP)
return "Stopping %s.";
- else if (t == JOB_RELOAD)
+ else
return "Reloading %s.";
-
- return NULL;
}
static void unit_status_print_starting_stopping(Unit *u, JobType t) {
@@ -1361,12 +1347,7 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
assert(u);
- /* We only print status messages for selected units on
- * selected operations. */
-
format = unit_get_status_message_format(u, t);
- if (!format)
- return;
DISABLE_WARNING_FORMAT_NONLITERAL;
unit_status_printf(u, "", format);
@@ -1388,9 +1369,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
/* We log status messages for all units and all operations. */
- format = unit_get_status_message_format_try_harder(u, t);
- if (!format)
- return;
+ format = unit_get_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
snprintf(buf, sizeof(buf), format, unit_description(u));
@@ -1413,6 +1392,15 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
NULL);
}
+void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
+
+ unit_status_log_starting_stopping_reloading(u, t);
+
+ /* Reload status messages have traditionally not been printed to console. */
+ if (t != JOB_RELOAD)
+ unit_status_print_starting_stopping(u, t);
+}
+
/* Errors:
* -EBADR: This unit type does not support starting.
* -EALREADY: Unit is already started.
@@ -1423,7 +1411,6 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
- int r;
assert(u);
@@ -1477,14 +1464,7 @@ int unit_start(Unit *u) {
unit_add_to_dbus_queue(u);
- r = UNIT_VTABLE(u)->start(u);
- if (r <= 0)
- return r;
-
- /* Log if the start function actually did something */
- unit_status_log_starting_stopping_reloading(u, JOB_START);
- unit_status_print_starting_stopping(u, JOB_START);
- return r;
+ return UNIT_VTABLE(u)->start(u);
}
bool unit_can_start(Unit *u) {
@@ -1508,7 +1488,6 @@ bool unit_can_isolate(Unit *u) {
int unit_stop(Unit *u) {
UnitActiveState state;
Unit *following;
- int r;
assert(u);
@@ -1527,13 +1506,7 @@ int unit_stop(Unit *u) {
unit_add_to_dbus_queue(u);
- r = UNIT_VTABLE(u)->stop(u);
- if (r <= 0)
- return r;
-
- unit_status_log_starting_stopping_reloading(u, JOB_STOP);
- unit_status_print_starting_stopping(u, JOB_STOP);
- return r;
+ return UNIT_VTABLE(u)->stop(u);
}
/* Errors:
@@ -1544,7 +1517,6 @@ int unit_stop(Unit *u) {
int unit_reload(Unit *u) {
UnitActiveState state;
Unit *following;
- int r;
assert(u);
@@ -1571,12 +1543,7 @@ int unit_reload(Unit *u) {
unit_add_to_dbus_queue(u);
- r = UNIT_VTABLE(u)->reload(u);
- if (r <= 0)
- return r;
-
- unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
- return r;
+ return UNIT_VTABLE(u)->reload(u);
}
bool unit_can_reload(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index 9491ef64f9..e60168267f 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -544,6 +544,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants);
int unit_coldplug(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
+void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);
bool unit_need_daemon_reload(Unit *u);
diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c
index 78e3184c42..67ca1ce8e4 100644
--- a/src/import/pull-dkr.c
+++ b/src/import/pull-dkr.c
@@ -793,7 +793,7 @@ static void dkr_pull_job_on_finished_v2(PullJob *j) {
} else if (i->tags_job == j) {
const char *url;
- _cleanup_free_ const char *buf;
+ _cleanup_free_ char *buf;
_cleanup_json_variant_unref_ JsonVariant *doc = NULL;
JsonVariant *e = NULL;
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index be6a5522fa..f7815b2796 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -656,13 +656,16 @@ static int journal_file_setup_field_hash_table(JournalFile *f) {
return 0;
}
-static int journal_file_map_data_hash_table(JournalFile *f) {
+int journal_file_map_data_hash_table(JournalFile *f) {
uint64_t s, p;
void *t;
int r;
assert(f);
+ if (f->data_hash_table)
+ return 0;
+
p = le64toh(f->header->data_hash_table_offset);
s = le64toh(f->header->data_hash_table_size);
@@ -678,13 +681,16 @@ static int journal_file_map_data_hash_table(JournalFile *f) {
return 0;
}
-static int journal_file_map_field_hash_table(JournalFile *f) {
+int journal_file_map_field_hash_table(JournalFile *f) {
uint64_t s, p;
void *t;
int r;
assert(f);
+ if (f->field_hash_table)
+ return 0;
+
p = le64toh(f->header->field_hash_table_offset);
s = le64toh(f->header->field_hash_table_size);
@@ -803,10 +809,18 @@ int journal_file_find_field_object_with_hash(
assert(f);
assert(field && size > 0);
+ /* If the field hash table is empty, we can't find anything */
+ if (le64toh(f->header->field_hash_table_size) <= 0)
+ return 0;
+
+ /* Map the field hash table, if it isn't mapped yet. */
+ r = journal_file_map_field_hash_table(f);
+ if (r < 0)
+ return r;
+
osize = offsetof(Object, field.payload) + size;
m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
-
if (m <= 0)
return -EBADMSG;
@@ -866,6 +880,15 @@ int journal_file_find_data_object_with_hash(
assert(f);
assert(data || size == 0);
+ /* If there's no data hash table, then there's no entry. */
+ if (le64toh(f->header->data_hash_table_size) <= 0)
+ return 0;
+
+ /* Map the data hash table, if it isn't mapped yet. */
+ r = journal_file_map_data_hash_table(f);
+ if (r < 0)
+ return r;
+
osize = offsetof(Object, data.payload) + size;
m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
@@ -2731,14 +2754,6 @@ int journal_file_open(
#endif
}
- r = journal_file_map_field_hash_table(f);
- if (r < 0)
- goto fail;
-
- r = journal_file_map_data_hash_table(f);
- if (r < 0)
- goto fail;
-
if (mmap_cache_got_sigbus(f->mmap, f->fd)) {
r = -EIO;
goto fail;
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 403c8f760c..e92b75eabe 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -229,3 +229,6 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
+
+int journal_file_map_data_hash_table(JournalFile *f);
+int journal_file_map_field_hash_table(JournalFile *f);
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 81a577ea27..17499bbc30 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -72,7 +72,7 @@ static void patch_realtime(
const struct stat *st,
unsigned long long *realtime) {
- _cleanup_free_ const char *path = NULL;
+ _cleanup_free_ char *path = NULL;
usec_t x, crtime = 0;
/* The timestamp was determined by the file name, but let's
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index ce734d8df7..eaf006db7a 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -69,6 +69,16 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
fflush(stdout);
}
+static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) {
+
+ /* Calculates scale * p / m, but handles m == 0 safely, and saturates */
+
+ if (p >= m || m == 0)
+ return scale;
+
+ return scale * p / m;
+}
+
static void flush_progress(void) {
unsigned n, i;
@@ -113,8 +123,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
* other objects. */
if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
- o->object.type != OBJECT_DATA)
+ o->object.type != OBJECT_DATA) {
+ error(offset, "Found compressed object that isn't of type DATA, which is not allowed.");
return -EBADMSG;
+ }
switch (o->object.type) {
@@ -123,15 +135,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
int compression, r;
if (le64toh(o->data.entry_offset) == 0)
- warning(offset, "unused data (entry_offset==0)");
+ warning(offset, "Unused data (entry_offset==0)");
if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
- error(offset, "bad n_entries: %"PRIu64, o->data.n_entries);
+ error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries);
return -EBADMSG;
}
if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
- error(offset, "bad object size (<= %zu): %"PRIu64,
+ error(offset, "Bad object size (<= %zu): %"PRIu64,
offsetof(DataObject, payload),
le64toh(o->object.size));
return -EBADMSG;
@@ -159,7 +171,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
if (h1 != h2) {
- error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
+ error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
return -EBADMSG;
}
@@ -167,7 +179,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
!VALID64(o->data.next_field_offset) ||
!VALID64(o->data.entry_offset) ||
!VALID64(o->data.entry_array_offset)) {
- error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
+ error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
o->data.next_hash_offset,
o->data.next_field_offset,
o->data.entry_offset,
@@ -181,7 +193,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
case OBJECT_FIELD:
if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
error(offset,
- "bad field size (<= %zu): %"PRIu64,
+ "Bad field size (<= %zu): %"PRIu64,
offsetof(FieldObject, payload),
le64toh(o->object.size));
return -EBADMSG;
@@ -190,7 +202,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if (!VALID64(o->field.next_hash_offset) ||
!VALID64(o->field.head_data_offset)) {
error(offset,
- "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
+ "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
o->field.next_hash_offset,
o->field.head_data_offset);
return -EBADMSG;
@@ -200,7 +212,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
case OBJECT_ENTRY:
if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
error(offset,
- "bad entry size (<= %zu): %"PRIu64,
+ "Bad entry size (<= %zu): %"PRIu64,
offsetof(EntryObject, items),
le64toh(o->object.size));
return -EBADMSG;
@@ -208,28 +220,28 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
error(offset,
- "invalid number items in entry: %"PRIu64,
+ "Invalid number items in entry: %"PRIu64,
(le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
return -EBADMSG;
}
if (le64toh(o->entry.seqnum) <= 0) {
error(offset,
- "invalid entry seqnum: %"PRIx64,
+ "Invalid entry seqnum: %"PRIx64,
le64toh(o->entry.seqnum));
return -EBADMSG;
}
if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
error(offset,
- "invalid entry realtime timestamp: %"PRIu64,
+ "Invalid entry realtime timestamp: %"PRIu64,
le64toh(o->entry.realtime));
return -EBADMSG;
}
if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
error(offset,
- "invalid entry monotonic timestamp: %"PRIu64,
+ "Invalid entry monotonic timestamp: %"PRIu64,
le64toh(o->entry.monotonic));
return -EBADMSG;
}
@@ -238,7 +250,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if (o->entry.items[i].object_offset == 0 ||
!VALID64(o->entry.items[i].object_offset)) {
error(offset,
- "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
+ "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
i, journal_file_entry_n_items(o),
o->entry.items[i].object_offset);
return -EBADMSG;
@@ -252,7 +264,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
(le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
error(offset,
- "invalid %s hash table size: %"PRIu64,
+ "Invalid %s hash table size: %"PRIu64,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
le64toh(o->object.size));
return -EBADMSG;
@@ -262,7 +274,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if (o->hash_table.items[i].head_hash_offset != 0 &&
!VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
error(offset,
- "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
+ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
i, journal_file_hash_table_n_items(o),
le64toh(o->hash_table.items[i].head_hash_offset));
@@ -271,7 +283,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if (o->hash_table.items[i].tail_hash_offset != 0 &&
!VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
error(offset,
- "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
+ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
i, journal_file_hash_table_n_items(o),
le64toh(o->hash_table.items[i].tail_hash_offset));
@@ -281,7 +293,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if ((o->hash_table.items[i].head_hash_offset != 0) !=
(o->hash_table.items[i].tail_hash_offset != 0)) {
error(offset,
- "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
+ "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
i, journal_file_hash_table_n_items(o),
le64toh(o->hash_table.items[i].head_hash_offset),
@@ -296,14 +308,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
(le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
error(offset,
- "invalid object entry array size: %"PRIu64,
+ "Invalid object entry array size: %"PRIu64,
le64toh(o->object.size));
return -EBADMSG;
}
if (!VALID64(o->entry_array.next_entry_array_offset)) {
error(offset,
- "invalid object entry array next_entry_array_offset: "OFSfmt,
+ "Invalid object entry array next_entry_array_offset: "OFSfmt,
o->entry_array.next_entry_array_offset);
return -EBADMSG;
}
@@ -312,7 +324,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
if (le64toh(o->entry_array.items[i]) != 0 &&
!VALID64(le64toh(o->entry_array.items[i]))) {
error(offset,
- "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
+ "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
i, journal_file_entry_array_n_items(o),
le64toh(o->entry_array.items[i]));
return -EBADMSG;
@@ -323,14 +335,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
case OBJECT_TAG:
if (le64toh(o->object.size) != sizeof(TagObject)) {
error(offset,
- "invalid object tag size: %"PRIu64,
+ "Invalid object tag size: %"PRIu64,
le64toh(o->object.size));
return -EBADMSG;
}
if (!VALID_EPOCH(o->tag.epoch)) {
error(offset,
- "invalid object tag epoch: %"PRIu64,
+ "Invalid object tag epoch: %"PRIu64,
o->tag.epoch);
return -EBADMSG;
}
@@ -403,8 +415,7 @@ static int entry_points_to_data(
assert(entry_fd >= 0);
if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
- error(data_p,
- "data object references invalid entry at "OFSfmt, entry_p);
+ error(data_p, "Data object references invalid entry at "OFSfmt, entry_p);
return -EBADMSG;
}
@@ -420,8 +431,7 @@ static int entry_points_to_data(
}
if (!found) {
- error(entry_p,
- "data object at "OFSfmt" not referenced by linked entry", data_p);
+ error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p);
return -EBADMSG;
}
@@ -464,7 +474,7 @@ static int entry_points_to_data(
x = z;
}
- error(entry_p, "entry object doesn't exist in main entry array");
+ error(entry_p, "Entry object doesn't exist in main entry array");
return -EBADMSG;
}
@@ -494,9 +504,7 @@ static int verify_data(
/* Entry array means at least two objects */
if (a && n < 2) {
- error(p,
- "entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")",
- a, n);
+ error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n);
return -EBADMSG;
}
@@ -516,12 +524,12 @@ static int verify_data(
uint64_t next, m, j;
if (a == 0) {
- error(p, "array chain too short");
+ error(p, "Array chain too short");
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
- error(p, "invalid array offset "OFSfmt, a);
+ error(p, "Invalid array offset "OFSfmt, a);
return -EBADMSG;
}
@@ -531,8 +539,7 @@ static int verify_data(
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
- error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")",
- a, next);
+ error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next);
return -EBADMSG;
}
@@ -541,7 +548,7 @@ static int verify_data(
q = le64toh(o->entry_array.items[j]);
if (q <= last) {
- error(p, "data object's entry array not sorted");
+ error(p, "Data object's entry array not sorted");
return -EBADMSG;
}
last = q;
@@ -580,11 +587,18 @@ static int verify_hash_table(
assert(last_usec);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
+ if (n <= 0)
+ return 0;
+
+ r = journal_file_map_data_hash_table(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to map data hash table: %m");
+
for (i = 0; i < n; i++) {
uint64_t last = 0, p;
if (show_progress)
- draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
+ draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec);
p = le64toh(f->data_hash_table[i].head_hash_offset);
while (p != 0) {
@@ -592,8 +606,7 @@ static int verify_hash_table(
uint64_t next;
if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
- error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64,
- i, n);
+ error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
@@ -603,14 +616,12 @@ static int verify_hash_table(
next = le64toh(o->data.next_hash_offset);
if (next != 0 && next <= p) {
- error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
- i, n);
+ error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
if (le64toh(o->data.hash) % n != i) {
- error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
- i, n);
+ error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
@@ -623,7 +634,7 @@ static int verify_hash_table(
}
if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
- error(p, "tail hash pointer mismatch in hash table");
+ error(p, "Tail hash pointer mismatch in hash table");
return -EBADMSG;
}
}
@@ -637,6 +648,13 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p)
assert(f);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
+ if (n <= 0)
+ return 0;
+
+ r = journal_file_map_data_hash_table(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to map data hash table: %m");
+
h = hash % n;
q = le64toh(f->data_hash_table[h].head_hash_offset);
@@ -677,16 +695,16 @@ static int verify_entry(
h = le64toh(o->entry.items[i].hash);
if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
- error(p, "invalid data object of entry");
- return -EBADMSG;
- }
+ error(p, "Invalid data object of entry");
+ return -EBADMSG;
+ }
r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
if (r < 0)
return r;
if (le64toh(u->data.hash) != h) {
- error(p, "hash mismatch for data object of entry");
+ error(p, "Hash mismatch for data object of entry");
return -EBADMSG;
}
@@ -694,7 +712,7 @@ static int verify_entry(
if (r < 0)
return r;
if (r == 0) {
- error(p, "data object missing from hash table");
+ error(p, "Data object missing from hash table");
return -EBADMSG;
}
}
@@ -726,15 +744,15 @@ static int verify_entry_array(
Object *o;
if (show_progress)
- draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
+ draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec);
if (a == 0) {
- error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n);
+ error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
- error(a, "invalid array %"PRIu64" of %"PRIu64, i, n);
+ error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
@@ -744,9 +762,7 @@ static int verify_entry_array(
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
- error(a,
- "array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")",
- i, n, next);
+ error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next);
return -EBADMSG;
}
@@ -756,15 +772,13 @@ static int verify_entry_array(
p = le64toh(o->entry_array.items[j]);
if (p <= last) {
- error(a, "entry array not sorted at %"PRIu64" of %"PRIu64,
- i, n);
+ error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
last = p;
if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
- error(a, "invalid array entry at %"PRIu64" of %"PRIu64,
- i, n);
+ error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
@@ -852,7 +866,7 @@ int journal_file_verify(
for (i = 0; i < sizeof(f->header->reserved); i++)
if (f->header->reserved[i] != 0) {
- error(offsetof(Header, reserved[i]), "reserved field is non-zero");
+ error(offsetof(Header, reserved[i]), "Reserved field is non-zero");
r = -EBADMSG;
goto fail;
}
@@ -861,36 +875,37 @@ int journal_file_verify(
* superficial structure, headers, hashes. */
p = le64toh(f->header->header_size);
- while (p != 0) {
+ for (;;) {
+ /* Early exit if there are no objects in the file, at all */
+ if (le64toh(f->header->tail_object_offset) == 0)
+ break;
+
if (show_progress)
- draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
+ draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec);
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0) {
- error(p, "invalid object");
+ error(p, "Invalid object");
goto fail;
}
if (p > le64toh(f->header->tail_object_offset)) {
- error(offsetof(Header, tail_object_offset), "invalid tail object pointer");
+ error(offsetof(Header, tail_object_offset), "Invalid tail object pointer");
r = -EBADMSG;
goto fail;
}
- if (p == le64toh(f->header->tail_object_offset))
- found_last = true;
-
n_objects ++;
r = journal_file_object_verify(f, p, o);
if (r < 0) {
- error(p, "invalid object contents: %s", strerror(-r));
+ error(p, "Envalid object contents: %s", strerror(-r));
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
(o->object.flags & OBJECT_COMPRESSED_LZ4)) {
- error(p, "objected with double compression");
+ error(p, "Objected with double compression");
r = -EINVAL;
goto fail;
}
@@ -923,7 +938,7 @@ int journal_file_verify(
case OBJECT_ENTRY:
if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
- error(p, "first entry before first tag");
+ error(p, "First entry before first tag");
r = -EBADMSG;
goto fail;
}
@@ -933,21 +948,21 @@ int journal_file_verify(
goto fail;
if (le64toh(o->entry.realtime) < last_tag_realtime) {
- error(p, "older entry after newer tag");
+ error(p, "Older entry after newer tag");
r = -EBADMSG;
goto fail;
}
if (!entry_seqnum_set &&
le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
- error(p, "head entry sequence number incorrect");
+ error(p, "Head entry sequence number incorrect");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum >= le64toh(o->entry.seqnum)) {
- error(p, "entry sequence number out of synchronization");
+ error(p, "Entry sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
@@ -958,7 +973,7 @@ int journal_file_verify(
if (entry_monotonic_set &&
sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
entry_monotonic > le64toh(o->entry.monotonic)) {
- error(p, "entry timestamp out of synchronization");
+ error(p, "Entry timestamp out of synchronization");
r = -EBADMSG;
goto fail;
}
@@ -969,7 +984,7 @@ int journal_file_verify(
if (!entry_realtime_set &&
le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
- error(p, "head entry realtime timestamp incorrect");
+ error(p, "Head entry realtime timestamp incorrect");
r = -EBADMSG;
goto fail;
}
@@ -982,7 +997,7 @@ int journal_file_verify(
case OBJECT_DATA_HASH_TABLE:
if (n_data_hash_tables > 1) {
- error(p, "more than one data hash table");
+ error(p, "More than one data hash table");
r = -EBADMSG;
goto fail;
}
@@ -999,14 +1014,14 @@ int journal_file_verify(
case OBJECT_FIELD_HASH_TABLE:
if (n_field_hash_tables > 1) {
- error(p, "more than one field hash table");
+ error(p, "More than one field hash table");
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
- error(p, "header fields for field hash table invalid");
+ error(p, "Header fields for field hash table invalid");
r = -EBADMSG;
goto fail;
}
@@ -1021,7 +1036,7 @@ int journal_file_verify(
if (p == le64toh(f->header->entry_array_offset)) {
if (found_main_entry_array) {
- error(p, "more than one main entry array");
+ error(p, "More than one main entry array");
r = -EBADMSG;
goto fail;
}
@@ -1034,19 +1049,19 @@ int journal_file_verify(
case OBJECT_TAG:
if (!JOURNAL_HEADER_SEALED(f->header)) {
- error(p, "tag object in file without sealing");
+ error(p, "Tag object in file without sealing");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.seqnum) != n_tags + 1) {
- error(p, "tag sequence number out of synchronization");
+ error(p, "Tag sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.epoch) < last_epoch) {
- error(p, "epoch sequence out of synchronization");
+ error(p, "Epoch sequence out of synchronization");
r = -EBADMSG;
goto fail;
}
@@ -1055,7 +1070,7 @@ int journal_file_verify(
if (f->seal) {
uint64_t q, rt;
- debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
+ debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
@@ -1102,7 +1117,7 @@ int journal_file_verify(
goto fail;
if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
- error(p, "tag failed verification");
+ error(p, "Tag failed verification");
r = -EBADMSG;
goto fail;
}
@@ -1124,79 +1139,69 @@ int journal_file_verify(
n_weird ++;
}
- if (p == le64toh(f->header->tail_object_offset))
- p = 0;
- else
- p = p + ALIGN64(le64toh(o->object.size));
- }
+ if (p == le64toh(f->header->tail_object_offset)) {
+ found_last = true;
+ break;
+ }
- if (!found_last) {
- error(le64toh(f->header->tail_object_offset), "tail object pointer dead");
+ p = p + ALIGN64(le64toh(o->object.size));
+ };
+
+ if (!found_last && le64toh(f->header->tail_object_offset) != 0) {
+ error(le64toh(f->header->tail_object_offset), "Tail object pointer dead");
r = -EBADMSG;
goto fail;
}
if (n_objects != le64toh(f->header->n_objects)) {
- error(offsetof(Header, n_objects), "object number mismatch");
+ error(offsetof(Header, n_objects), "Object number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_entries != le64toh(f->header->n_entries)) {
- error(offsetof(Header, n_entries), "entry number mismatch");
+ error(offsetof(Header, n_entries), "Entry number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
n_data != le64toh(f->header->n_data)) {
- error(offsetof(Header, n_data), "data number mismatch");
+ error(offsetof(Header, n_data), "Data number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
n_fields != le64toh(f->header->n_fields)) {
- error(offsetof(Header, n_fields), "field number mismatch");
+ error(offsetof(Header, n_fields), "Field number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
n_tags != le64toh(f->header->n_tags)) {
- error(offsetof(Header, n_tags), "tag number mismatch");
+ error(offsetof(Header, n_tags), "Tag number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
- error(offsetof(Header, n_entry_arrays), "entry array number mismatch");
- r = -EBADMSG;
- goto fail;
- }
-
- if (n_data_hash_tables != 1) {
- error(0, "missing data hash table");
- r = -EBADMSG;
- goto fail;
- }
-
- if (n_field_hash_tables != 1) {
- error(0, "missing field hash table");
+ error(offsetof(Header, n_entry_arrays), "Entry array number mismatch");
r = -EBADMSG;
goto fail;
}
- if (!found_main_entry_array) {
- error(0, "missing entry array");
+ if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) {
+ error(0, "Missing entry array");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
- error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum");
+ error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum");
r = -EBADMSG;
goto fail;
}
@@ -1204,13 +1209,13 @@ int journal_file_verify(
if (entry_monotonic_set &&
(!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
- error(0, "invalid tail monotonic timestamp");
+ error(0, "Invalid tail monotonic timestamp");
r = -EBADMSG;
goto fail;
}
if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
- error(0, "invalid tail realtime timestamp");
+ error(0, "Invalid tail realtime timestamp");
r = -EBADMSG;
goto fail;
}
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 2d6ecfb750..073cc77711 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2066,6 +2066,10 @@ int main(int argc, char *argv[]) {
log_error_errno(r, "Failed to iterate through journal: %m");
goto finish;
}
+ if (r == 0) {
+ printf("-- No entries --\n");
+ goto finish;
+ }
if (!arg_follow)
pager_open_if_enabled();
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 46358e1c1a..28b1472ac8 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -175,9 +175,11 @@ static uint64_t available_space(Server *s, bool verbose) {
fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
- "%s journal is using %s (max allowed %s, "
- "trying to leave %s free of %s available → current limit %s).",
- s->system_journal ? "Permanent" : "Runtime",
+ "%s is currently using %s.\n"
+ "Maximum allowed usage is set to %s.\n"
+ "Leaving at least %s free (of currently available %s of space).\n"
+ "Enforced usage limit is thus %s.",
+ s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)",
format_bytes(fb1, sizeof(fb1), sum),
format_bytes(fb2, sizeof(fb2), m->max_use),
format_bytes(fb3, sizeof(fb3), m->keep_free),
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 0dbfbddcf6..f2092795f4 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -46,6 +46,8 @@
#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"
#define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking"
+#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping"
+#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping"
#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession"
#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID"
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index a38c5c50fc..c53666ddd0 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -1131,7 +1131,7 @@ static int add_name_change_match(sd_bus *bus,
/* If the old name is unset or empty, then
* this can match against added names */
- if (!old_owner || old_owner[0] == 0) {
+ if (isempty(old_owner)) {
item->type = KDBUS_ITEM_NAME_ADD;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
@@ -1141,7 +1141,7 @@ static int add_name_change_match(sd_bus *bus,
/* If the new name is unset or empty, then
* this can match against removed names */
- if (!new_owner || new_owner[0] == 0) {
+ if (isempty(new_owner)) {
item->type = KDBUS_ITEM_NAME_REMOVE;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
@@ -1185,8 +1185,10 @@ static int add_name_change_match(sd_bus *bus,
/* If the old name is unset or empty, then this can
* match against added ids */
- if (!old_owner || old_owner[0] == 0) {
+ if (isempty(old_owner)) {
item->type = KDBUS_ITEM_ID_ADD;
+ if (!isempty(new_owner))
+ item->id_change.id = new_owner_id;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
@@ -1195,8 +1197,10 @@ static int add_name_change_match(sd_bus *bus,
/* If thew new name is unset or empty, then this can
* match against removed ids */
- if (!new_owner || new_owner[0] == 0) {
+ if (isempty(new_owner)) {
item->type = KDBUS_ITEM_ID_REMOVE;
+ if (!isempty(old_owner))
+ item->id_change.id = old_owner_id;
r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
if (r < 0)
@@ -1345,6 +1349,10 @@ int bus_add_match_internal_kernel(
else if (r > 0)
sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
+ /* if not a broadcast, it cannot be a name-change */
+ if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
+ matches_name_change = false;
+
break;
}
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index e3fac01f92..6ac5ebc3da 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -1332,8 +1332,7 @@ static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
KDBUS_ITEM_FOREACH(d, k, items) {
if (d->type == KDBUS_ITEM_TIMESTAMP)
ts = &d->timestamp;
-
- if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
+ else if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
if (found)
return -EBADMSG;
found = d;
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 983e2f62cd..18685be8ff 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -2161,6 +2161,7 @@ static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c)
}
static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
+ bool fixed_size = true;
size_t n_variable = 0;
unsigned i = 0;
const char *p;
@@ -2196,6 +2197,8 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
/* We need to add an offset for each item that has a
* variable size and that is not the last one in the
* list */
+ if (r == 0)
+ fixed_size = false;
if (r == 0 && p[n] != 0)
n_variable++;
@@ -2207,7 +2210,19 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
assert(c->need_offsets || n_variable == 0);
if (n_variable <= 0) {
- a = message_extend_body(m, 1, 0, add_offset, false);
+ int alignment = 1;
+
+ /* Structures with fixed-size members only have to be
+ * fixed-size themselves. But gvariant requires all fixed-size
+ * elements to be sized a multiple of their alignment. Hence,
+ * we must *always* add final padding after the last member so
+ * the overall size of the structure is properly aligned. */
+ if (fixed_size)
+ alignment = bus_gvariant_get_alignment(strempty(c->signature));
+
+ assert(alignment > 0);
+
+ a = message_extend_body(m, alignment, 0, add_offset, false);
if (!a)
return -ENOMEM;
} else {
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index cbdf6552f9..c25293e5e9 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -68,6 +68,12 @@ static int node_vtable_get_userdata(
return 1;
}
+static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
+ assert(p);
+
+ return (uint8_t*) u + p->x.method.offset;
+}
+
static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
@@ -167,6 +173,7 @@ static int add_subtree_to_set(
sd_bus *bus,
const char *prefix,
struct node *n,
+ bool skip_subhierarchies,
Set *s,
sd_bus_error *error) {
@@ -198,11 +205,13 @@ static int add_subtree_to_set(
if (r < 0 && r != -EEXIST)
return r;
- r = add_subtree_to_set(bus, prefix, i, s, error);
- if (r < 0)
- return r;
- if (bus->nodes_modified)
- return 0;
+ if (!skip_subhierarchies || !i->object_managers) {
+ r = add_subtree_to_set(bus, prefix, i, skip_subhierarchies, s, error);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified)
+ return 0;
+ }
}
return 0;
@@ -212,6 +221,7 @@ static int get_child_nodes(
sd_bus *bus,
const char *prefix,
struct node *n,
+ bool skip_subhierarchies,
Set **_s,
sd_bus_error *error) {
@@ -227,7 +237,7 @@ static int get_child_nodes(
if (!s)
return -ENOMEM;
- r = add_subtree_to_set(bus, prefix, n, s, error);
+ r = add_subtree_to_set(bus, prefix, n, skip_subhierarchies, s, error);
if (r < 0) {
set_free_free(s);
return r;
@@ -360,6 +370,8 @@ static int method_callbacks_run(
if (bus->nodes_modified)
return 0;
+ u = vtable_method_convert_userdata(c->vtable, u);
+
*found_object = true;
if (c->last_iteration == bus->iteration_counter)
@@ -892,7 +904,7 @@ static int process_introspect(
assert(n);
assert(found_object);
- r = get_child_nodes(bus, m->path, n, &s, &error);
+ r = get_child_nodes(bus, m->path, n, false, &s, &error);
if (r < 0)
return bus_maybe_reply_error(m, r, &error);
if (bus->nodes_modified)
@@ -1158,7 +1170,7 @@ static int process_get_managed_objects(
if (require_fallback || !n->object_managers)
return 0;
- r = get_child_nodes(bus, m->path, n, &s, &error);
+ r = get_child_nodes(bus, m->path, n, true, &s, &error);
if (r < 0)
return r;
if (bus->nodes_modified)
@@ -1467,6 +1479,32 @@ void bus_node_gc(sd_bus *b, struct node *n) {
free(n);
}
+static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
+ struct node *n;
+
+ assert(bus);
+ assert(path);
+
+ n = hashmap_get(bus->nodes, path);
+ if (!n) {
+ char *prefix;
+
+ prefix = alloca(strlen(path) + 1);
+ OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+ n = hashmap_get(bus->nodes, prefix);
+ if (n)
+ break;
+ }
+ }
+
+ while (n && !n->object_managers)
+ n = n->parent;
+
+ if (out)
+ *out = n;
+ return !!n;
+}
+
static int bus_add_object(
sd_bus *bus,
sd_bus_slot **slot,
@@ -2269,6 +2307,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
BUS_DONT_DESTROY(bus);
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
/*
@@ -2289,11 +2328,17 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
+ r = bus_find_parent_object_manager(bus, &object_manager, path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
if (r < 0)
return r;
@@ -2432,6 +2477,7 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
BUS_DONT_DESTROY(bus);
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
/*
@@ -2452,11 +2498,17 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
+ r = bus_find_parent_object_manager(bus, &object_manager, path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
if (r < 0)
return r;
@@ -2588,6 +2640,7 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch
BUS_DONT_DESTROY(bus);
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ struct node *object_manager;
char **i;
int r;
@@ -2601,11 +2654,17 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch
if (strv_isempty(interfaces))
return 0;
+ r = bus_find_parent_object_manager(bus, &object_manager, path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
do {
bus->nodes_modified = false;
m = sd_bus_message_unref(m);
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
if (r < 0)
return r;
@@ -2665,6 +2724,7 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c
_public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ struct node *object_manager;
int r;
assert_return(bus, -EINVAL);
@@ -2677,7 +2737,13 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path,
if (strv_isempty(interfaces))
return 0;
- r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
+ r = bus_find_parent_object_manager(bus, &object_manager, path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ESRCH;
+
+ r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index a866a56179..59deaea89f 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -131,6 +131,9 @@ int main(int argc, char *argv[]) {
r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
assert_se(r >= 0);
+ r = sd_bus_message_append(m, "y(ty)y(yt)y", 8, 777ULL, 7, 9, 77, 7777ULL, 10);
+ assert_se(r >= 0);
+
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
assert_se(r >= 0);
@@ -252,6 +255,22 @@ int main(int argc, char *argv[]) {
assert_se(v == 5);
assert_se(streq(y, "waldo"));
+ r = sd_bus_message_read(m, "y(ty)", &v, &u64, &u);
+ assert_se(r > 0);
+ assert_se(v == 8);
+ assert_se(u64 == 777);
+ assert_se(u == 7);
+
+ r = sd_bus_message_read(m, "y(yt)", &v, &u, &u64);
+ assert_se(r > 0);
+ assert_se(v == 9);
+ assert_se(u == 77);
+ assert_se(u64 == 7777);
+
+ r = sd_bus_message_read(m, "y", &v);
+ assert_se(r > 0);
+ assert_se(v == 10);
+
r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
assert_se(r > 0);
assert_se(boolean);
@@ -331,7 +350,7 @@ int main(int argc, char *argv[]) {
assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
- r = sd_bus_message_skip(m, "a{yv}");
+ r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y");
assert_se(r >= 0);
assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index 1db67ecfac..359984c7f3 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -153,7 +153,7 @@ static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error)
static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+ assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -164,7 +164,7 @@ static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error
static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+ assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -175,7 +175,7 @@ static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_err
static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), m->path) >= 0);
+ assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -186,7 +186,7 @@ static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *er
static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), m->path) >= 0);
+ assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -228,6 +228,14 @@ static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, ch
return 1;
}
+static int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+
+ if (object_path_startswith("/value/a", path))
+ assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL));
+
+ return 1;
+}
+
static void *server(void *p) {
struct context *c = p;
sd_bus *bus = NULL;
@@ -246,7 +254,9 @@ static void *server(void *p) {
assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
+ assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value/a", enumerator2_callback, NULL) >= 0);
assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
+ assert_se(sd_bus_add_object_manager(bus, NULL, "/value/a") >= 0);
assert_se(sd_bus_start(bus) >= 0);
diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c
new file mode 100644
index 0000000000..369c2f331c
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-proxy.c
@@ -0,0 +1,109 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "log.h"
+
+#include "sd-bus.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+#include "bus-dump.h"
+
+typedef struct {
+ const char *sender;
+ int matched_acquired;
+} TestProxyMatch;
+
+static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ TestProxyMatch *match = userdata;
+ const char *name;
+ int r;
+
+ r = sd_bus_message_read(m, "s", &name);
+ assert_se(r >= 0);
+
+ if (!streq_ptr(match->sender, name))
+ return 0;
+
+ ++match->matched_acquired;
+ return 1;
+}
+
+static void test_proxy_matched(void) {
+ _cleanup_bus_flush_close_unref_ sd_bus *a = NULL;
+ TestProxyMatch match = {};
+ int r;
+
+ /* open bus 'a' */
+
+ r = sd_bus_new(&a);
+ assert_se(r >= 0);
+
+ r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket");
+ assert_se(r >= 0);
+
+ r = sd_bus_set_bus_client(a, true);
+ assert_se(r >= 0);
+
+ r = sd_bus_start(a);
+ assert_se(r >= 0);
+
+ r = sd_bus_add_match(a, NULL,
+ "type='signal',"
+ "member='NameAcquired'",
+ test_proxy_acquired, &match);
+ assert_se(r >= 0);
+
+ r = sd_bus_get_unique_name(a, &match.sender);
+ assert_se(r >= 0);
+
+ /* barrier to guarantee proxy/dbus-daemon handled the previous data */
+ r = sd_bus_call_method(a,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetId",
+ NULL, NULL, NULL);
+ assert_se(r >= 0);
+
+ /* now we can be sure the Name* signals were sent */
+ do {
+ r = sd_bus_process(a, NULL);
+ } while (r > 0);
+ assert_se(r == 0);
+
+ assert_se(match.matched_acquired == 1);
+}
+
+int main(int argc, char **argv) {
+ if (access("/var/run/dbus/system_bus_socket", F_OK) < 0)
+ return EXIT_TEST_SKIP;
+
+ log_parse_environment();
+
+ test_proxy_matched();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 74ac2ab344..9b68935245 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -196,27 +196,37 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 },
[IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
+ [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
};
static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
@@ -227,7 +237,7 @@ static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 },
[IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
[IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32},
+ [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
};
/* these strings must match the .kind entries in the kernel */
@@ -319,8 +329,11 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1]
[IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 },
};
static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
@@ -362,9 +375,9 @@ static const NLTypeSystem rtnl_af_spec_type_system = {
};
static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
- [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR, },
- [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR, },
- [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, },
+ [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR },
+ [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR },
+ [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
[IFLA_MTU] = { .type = NETLINK_TYPE_U32 },
[IFLA_LINK] = { .type = NETLINK_TYPE_U32 },
/*
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 049e33e2a6..e6371ff04d 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1774,7 +1774,7 @@ static int nologin_timeout_handler(
log_info("Creating /run/nologin, blocking further logins...");
- r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC);
+ r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
if (r < 0)
log_error_errno(r, "Failed to create /run/nologin: %m");
else
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 9d5287ad35..495ec50be0 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -486,7 +486,7 @@ void seat_evict_position(Seat *s, Session *session) {
* position (eg., during gdm->session transition), so let's look
* for it and set it on the free slot. */
LIST_FOREACH(sessions_by_seat, iter, s->sessions) {
- if (iter->position == pos) {
+ if (iter->position == pos && session_get_state(iter) != SESSION_CLOSING) {
s->positions[pos] = iter;
break;
}
@@ -505,7 +505,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) {
seat_evict_position(s, session);
session->position = pos;
- if (pos > 0 && !s->positions[pos])
+ if (pos > 0)
s->positions[pos] = session;
}
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 0e971a6789..3637815fc9 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -31,12 +31,13 @@
#include "bus-common-errors.h"
#include "cgroup-util.h"
#include "btrfs-util.h"
+#include "formats-util.h"
+#include "process-util.h"
#include "machine-image.h"
#include "machine-pool.h"
#include "image-dbus.h"
#include "machined.h"
#include "machine-dbus.h"
-#include "formats-util.h"
static int property_get_pool_path(
sd_bus *bus,
@@ -840,6 +841,230 @@ static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bu
return bus_image_method_set_limit(message, i, error);
}
+static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_fclose_ FILE *f = NULL;
+ Manager *m = userdata;
+ const char *name, *p;
+ Machine *machine;
+ uint32_t uid;
+ int r;
+
+ r = sd_bus_message_read(message, "su", &name, &uid);
+ if (r < 0)
+ return r;
+
+ if (UID_IS_INVALID(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ p = procfs_file_alloca(machine->leader, "uid_map");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ uid_t uid_base, uid_shift, uid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (uid < uid_base || uid >= uid_base + uid_range)
+ continue;
+
+ converted = uid - uid_base + uid_shift;
+ if (UID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
+}
+
+static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ uid_t uid;
+ Iterator i;
+ int r;
+
+ r = sd_bus_message_read(message, "u", &uid);
+ if (r < 0)
+ return r;
+ if (UID_IS_INVALID(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+ if (uid < 0x10000)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
+
+ HASHMAP_FOREACH(machine, m->machines, i) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+ xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
+ f = fopen(p, "re");
+ if (!f) {
+ log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+ continue;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *o = NULL;
+ uid_t uid_base, uid_shift, uid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (uid < uid_shift || uid >= uid_shift + uid_range)
+ continue;
+
+ converted = (uid - uid_shift + uid_base);
+ if (UID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+ o = machine_bus_path(machine);
+ if (!o)
+ return -ENOMEM;
+
+ return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+ }
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
+}
+
+static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+ _cleanup_fclose_ FILE *f = NULL;
+ Manager *m = groupdata;
+ const char *name, *p;
+ Machine *machine;
+ uint32_t gid;
+ int r;
+
+ r = sd_bus_message_read(message, "su", &name, &gid);
+ if (r < 0)
+ return r;
+
+ if (GID_IS_INVALID(gid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ p = procfs_file_alloca(machine->leader, "gid_map");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ gid_t gid_base, gid_shift, gid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (gid < gid_base || gid >= gid_base + gid_range)
+ continue;
+
+ converted = gid - gid_base + gid_shift;
+ if (GID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
+}
+
+static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+ Manager *m = groupdata;
+ Machine *machine;
+ gid_t gid;
+ Iterator i;
+ int r;
+
+ r = sd_bus_message_read(message, "u", &gid);
+ if (r < 0)
+ return r;
+ if (GID_IS_INVALID(gid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+ if (gid < 0x10000)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
+
+ HASHMAP_FOREACH(machine, m->machines, i) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+ xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
+ f = fopen(p, "re");
+ if (!f) {
+ log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+ continue;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *o = NULL;
+ gid_t gid_base, gid_shift, gid_range, converted;
+ int k;
+
+ errno = 0;
+ k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+ if (k < 0 && feof(f))
+ break;
+ if (k != 3) {
+ if (ferror(f) && errno != 0)
+ return -errno;
+
+ return -EIO;
+ }
+
+ if (gid < gid_shift || gid >= gid_shift + gid_range)
+ continue;
+
+ converted = (gid - gid_shift + gid_base);
+ if (GID_IS_INVALID(converted))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+ o = machine_bus_path(machine);
+ if (!o)
+ return -ENOMEM;
+
+ return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+ }
+ }
+
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
+}
+
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
@@ -869,6 +1094,10 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("MachineNew", "so", 0),
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
SD_BUS_VTABLE_END
diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf
index 93aaf6a377..d58f01507b 100644
--- a/src/machine/org.freedesktop.machine1.conf
+++ b/src/machine/org.freedesktop.machine1.conf
@@ -113,6 +113,22 @@
send_member="SetImageLimit"/>
<allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapFromMachineUser"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapToMachineUser"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapFromMachineGroup"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MapToMachineGroup"/>
+
+ <allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Machine"
send_member="GetAddresses"/>
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index d446bfa8b3..4aa301b112 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -270,12 +270,18 @@ static int dhcp_lease_lost(Link *link) {
if (link->network->dhcp_hostname) {
const char *hostname = NULL;
- r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
- if (r >= 0 && hostname) {
- r = link_set_hostname(link, "");
+ if (!link->network->hostname)
+ r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
+ else
+ hostname = link->network->hostname;
+
+ if (r >= 0 || hostname) {
+ r = link_set_hostname(link, hostname);
if (r < 0)
- log_link_error(link,
- "Failed to reset transient hostname");
+ log_link_error_errno(link, r,
+ "Failed to set transient hostname to '%s': %m",
+ hostname);
+
}
}
@@ -464,8 +470,12 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (link->network->dhcp_hostname) {
const char *hostname;
- r = sd_dhcp_lease_get_hostname(lease, &hostname);
- if (r >= 0) {
+ if (!link->network->hostname)
+ r = sd_dhcp_lease_get_hostname(lease, &hostname);
+ else
+ hostname = link->network->hostname;
+
+ if (r >= 0 || hostname) {
r = link_set_hostname(link, hostname);
if (r < 0)
log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
@@ -616,14 +626,19 @@ int dhcp4_configure(Link *link) {
if (link->network->dhcp_sendhost) {
_cleanup_free_ char *hostname = NULL;
+ const char *hn = NULL;
+
+ if (!link->network->hostname) {
+ hostname = gethostname_malloc();
+ if (!hostname)
+ return -ENOMEM;
- hostname = gethostname_malloc();
- if (!hostname)
- return -ENOMEM;
+ hn = hostname;
+ } else
+ hn = link->network->hostname;
- if (!is_localhost(hostname)) {
- r = sd_dhcp_client_set_hostname(link->dhcp_client,
- hostname);
+ if (!is_localhost(hn)) {
+ r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
if (r < 0)
return r;
}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 9550e89a15..f20f68b482 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -846,9 +846,6 @@ static int link_set_bridge(Link *link) {
assert(link);
assert(link->network);
- if(link->network->cost == 0)
- return 0;
-
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
@@ -861,6 +858,26 @@ static int link_set_bridge(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, !link->network->use_bpdu);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, !link->network->allow_port_to_be_root);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
+
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
+
if(link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 010c106610..fa3ba38a3b 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -36,6 +36,8 @@ Tunnel.TOS, config_parse_unsigned, 0,
Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
+Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel)
+Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
@@ -59,7 +61,7 @@ Tun.Group, config_parse_string, 0,
Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
-Tap.VnetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
+Tap.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 5533fb5c7b..7fd9ef584b 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -33,6 +33,7 @@
#include "conf-parser.h"
#define DEFAULT_TNL_HOP_LIMIT 64
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
[NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
@@ -184,6 +185,16 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
+ if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
+ }
+
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m");
+
return r;
}
@@ -264,6 +275,19 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
+ if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
+ }
+
+ if (t->copy_dscp)
+ t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
+
switch (t->ip6tnl_mode) {
case NETDEV_IP6_TNL_MODE_IP6IP6:
proto = IPPROTO_IPV6;
@@ -380,6 +404,52 @@ int config_parse_tunnel_address(const char *unit,
return 0;
}
+static const char* const ipv6_flowlabel_table[_NETDEV_IPV6_FLOWLABEL_MAX] = {
+ [NETDEV_IPV6_FLOWLABEL_INHERIT] = "inherit",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipv6_flowlabel, IPv6FlowLabel);
+
+int config_parse_ipv6_flowlabel(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) {
+ IPv6FlowLabel *ipv6_flowlabel = data;
+ Tunnel *t = userdata;
+ IPv6FlowLabel s;
+ int k = 0;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(ipv6_flowlabel);
+
+ s = ipv6_flowlabel_from_string(rvalue);
+ if (s != _NETDEV_IPV6_FLOWLABEL_INVALID) {
+ *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
+ t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ } else {
+ r = config_parse_unsigned(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
+ if (r >= 0) {
+ if (k > 0xFFFFF)
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
+ else {
+ *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
+ t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ }
+ }
+ }
+
+ return 0;
+}
+
static void ipip_init(NetDev *n) {
Tunnel *t = IPIP(n);
@@ -452,6 +522,7 @@ static void ip6tnl_init(NetDev *n) {
t->ttl = DEFAULT_TNL_HOP_LIMIT;
t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
+ t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
}
const NetDevVTable ipip_vtable = {
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index 88f57ac105..1fd2b94ae1 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -33,6 +33,12 @@ typedef enum Ip6TnlMode {
_NETDEV_IP6_TNL_MODE_INVALID = -1,
} Ip6TnlMode;
+typedef enum IPv6FlowLabel {
+ NETDEV_IPV6_FLOWLABEL_INHERIT = 0xFFFFF + 1,
+ _NETDEV_IPV6_FLOWLABEL_MAX,
+ _NETDEV_IPV6_FLOWLABEL_INVALID = -1,
+} IPv6FlowLabel;
+
struct Tunnel {
NetDev meta;
@@ -48,8 +54,10 @@ struct Tunnel {
union in_addr_union remote;
Ip6TnlMode ip6tnl_mode;
+ IPv6FlowLabel ipv6_flowlabel;
bool pmtudisc;
+ bool copy_dscp;
};
extern const NetDevVTable ipip_vtable;
@@ -70,3 +78,23 @@ int config_parse_ip6tnl_mode(const char *unit, const char *filename,
unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data,
void *userdata);
+
+int config_parse_tunnel_address(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);
+
+const char *ipv6_flowlabel_to_string(IPv6FlowLabel d) _const_;
+IPv6FlowLabel ipv6_flowlabel_from_string(const char *d) _pure_;
+
+int config_parse_ipv6_flowlabel(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);
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index fe5254e91f..e7d1306f13 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -53,3 +53,14 @@ struct VxLan {
};
extern const NetDevVTable vxlan_vtable;
+
+int config_parse_vxlan_group_address(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);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 787fc2ff5b..83224d7109 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -67,11 +67,17 @@ DHCP.UseHostname, config_parse_bool, 0
DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost)
+DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
+Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu)
+Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin)
+Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave)
+Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root)
+Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
/* backwards compatibility: do not add new entries to this section */
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index a8e9ef909c..d8f42621af 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -107,6 +107,10 @@ static int network_load_one(Manager *manager, const char *filename) {
network->dhcp_route_metric = DHCP_ROUTE_METRIC;
network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
+ network->use_bpdu = true;
+ network->allow_port_to_be_root = true;
+ network->unicast_flood = true;
+
network->llmnr = LLMNR_SUPPORT_YES;
network->link_local = ADDRESS_FAMILY_IPV6;
@@ -207,6 +211,7 @@ void network_free(Network *network) {
free(network->description);
free(network->dhcp_vendor_class_identifier);
+ free(network->hostname);
free(network->mac);
@@ -809,3 +814,38 @@ int config_parse_ipv6_privacy_extensions(
return 0;
}
+
+int config_parse_hostname(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) {
+ char **hostname = data;
+ char *hn = NULL;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = config_parse_string(unit, filename, line, section, section_line,
+ lvalue, ltype, rvalue, &hn, userdata);
+ if (r < 0)
+ return r;
+
+ if (!hostname_is_valid(hn)) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "hostname is not valid, ignoring assignment: %s", rvalue);
+
+ free(hn);
+ return 0;
+ }
+
+ *hostname = hn;
+
+ return 0;
+}
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index 32c31fdf3d..d958b48771 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -66,7 +66,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hiq", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hi:q", options, NULL)) >= 0)
switch (c) {
diff --git a/src/network/networkd.h b/src/network/networkd.h
index f98c640822..a285a4b08f 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -133,6 +133,7 @@ struct Network {
AddressFamilyBoolean dhcp;
DCHPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
+ char *hostname;
bool dhcp_dns;
bool dhcp_ntp;
bool dhcp_mtu;
@@ -149,6 +150,11 @@ struct Network {
bool dhcp_server;
+ bool use_bpdu;
+ bool hairpin;
+ bool fast_leave;
+ bool allow_port_to_be_root;
+ bool unicast_flood;
unsigned cost;
AddressFamilyBoolean ip_forward;
@@ -319,28 +325,6 @@ int config_parse_tunnel(const char *unit,
void *data,
void *userdata);
-int config_parse_tunnel_address(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);
-
-int config_parse_vxlan_group_address(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);
-
extern const sd_bus_vtable network_vtable[];
int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
@@ -473,3 +457,7 @@ const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
int config_parse_ipv6_privacy_extensions(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);
+
+
+/* Hostname */
+int config_parse_hostname(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);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 3428109da4..65b9a5071b 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1785,15 +1785,13 @@ static int setup_pts(const char *dest) {
#ifdef HAVE_SELINUX
if (arg_selinux_apifs_context)
(void) asprintf(&options,
- "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT ",context=\"%s\"",
- arg_uid_shift,
+ "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT ",context=\"%s\"",
arg_uid_shift + TTY_GID,
arg_selinux_apifs_context);
else
#endif
(void) asprintf(&options,
- "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT,
- arg_uid_shift,
+ "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT,
arg_uid_shift + TTY_GID);
if (!options)
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index f712033e6c..cdec83d074 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -28,9 +28,12 @@
#include "util.h"
#include "nss-util.h"
#include "bus-util.h"
+#include "bus-common-errors.h"
#include "in-addr-util.h"
NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
+NSS_GETPW_PROTOTYPES(mymachines);
+NSS_GETGR_PROTOTYPES(mymachines);
static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
unsigned c = 0;
@@ -380,4 +383,319 @@ fail:
return NSS_STATUS_UNAVAIL;
}
-NSS_GETHOSTBYNAME_FALLBACKS(mymachines)
+NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
+
+enum nss_status _nss_mymachines_getpwnam_r(
+ const char *name,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *p, *e, *machine;
+ uint32_t mapped;
+ uid_t uid;
+ size_t l;
+ int r;
+
+ assert(name);
+ assert(pwd);
+
+ p = startswith(name, "vu-");
+ if (!p)
+ goto not_found;
+
+ e = strrchr(p, '-');
+ if (!e || e == p)
+ goto not_found;
+
+ r = parse_uid(e + 1, &uid);
+ if (r < 0)
+ goto not_found;
+
+ machine = strndupa(p, e - p);
+ if (!machine_name_is_valid(machine))
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapFromMachineUser",
+ &error,
+ &reply,
+ "su",
+ machine, (uint32_t) uid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &mapped);
+ if (r < 0)
+ goto fail;
+
+ l = strlen(name);
+ if (buflen < l+1) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy(buffer, name, l+1);
+
+ pwd->pw_name = buffer;
+ pwd->pw_uid = mapped;
+ pwd->pw_gid = 65534; /* nobody */
+ pwd->pw_gecos = buffer;
+ pwd->pw_passwd = (char*) "*"; /* locked */
+ pwd->pw_dir = (char*) "/";
+ pwd->pw_shell = (char*) "/sbin/nologin";
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getpwuid_r(
+ uid_t uid,
+ struct passwd *pwd,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *machine, *object;
+ uint32_t mapped;
+ int r;
+
+ if (UID_IS_INVALID(uid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* We consider all uids < 65536 host uids */
+ if (uid < 0x10000)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapToMachineUser",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) uid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+ if (r < 0)
+ goto fail;
+
+ if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ pwd->pw_name = buffer;
+ pwd->pw_uid = uid;
+ pwd->pw_gid = 65534; /* nobody */
+ pwd->pw_gecos = buffer;
+ pwd->pw_passwd = (char*) "*"; /* locked */
+ pwd->pw_dir = (char*) "/";
+ pwd->pw_shell = (char*) "/sbin/nologin";
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getgrnam_r(
+ const char *name,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *p, *e, *machine;
+ uint32_t mapped;
+ uid_t gid;
+ size_t l;
+ int r;
+
+ assert(name);
+ assert(gr);
+
+ p = startswith(name, "vg-");
+ if (!p)
+ goto not_found;
+
+ e = strrchr(p, '-');
+ if (!e || e == p)
+ goto not_found;
+
+ r = parse_gid(e + 1, &gid);
+ if (r < 0)
+ goto not_found;
+
+ machine = strndupa(p, e - p);
+ if (!machine_name_is_valid(machine))
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapFromMachineGroup",
+ &error,
+ &reply,
+ "su",
+ machine, (uint32_t) gid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "u", &mapped);
+ if (r < 0)
+ goto fail;
+
+ l = sizeof(char*) + strlen(name) + 1;
+ if (buflen < l) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memzero(buffer, sizeof(char*));
+ strcpy(buffer + sizeof(char*), name);
+
+ gr->gr_name = buffer + sizeof(char*);
+ gr->gr_gid = gid;
+ gr->gr_passwd = (char*) "*"; /* locked */
+ gr->gr_mem = (char**) buffer;
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
+
+enum nss_status _nss_mymachines_getgrgid_r(
+ gid_t gid,
+ struct group *gr,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ const char *machine, *object;
+ uint32_t mapped;
+ int r;
+
+ if (GID_IS_INVALID(gid)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* We consider all gids < 65536 host gids */
+ if (gid < 0x10000)
+ goto not_found;
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "MapToMachineGroup",
+ &error,
+ &reply,
+ "u",
+ (uint32_t) gid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
+ goto not_found;
+
+ goto fail;
+ }
+
+ r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
+ if (r < 0)
+ goto fail;
+
+ if (buflen < sizeof(char*) + 1) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memzero(buffer, sizeof(char*));
+ if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ gr->gr_name = buffer + sizeof(char*);
+ gr->gr_gid = gid;
+ gr->gr_passwd = (char*) "*"; /* locked */
+ gr->gr_mem = (char**) buffer;
+
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+
+not_found:
+ *errnop = 0;
+ return NSS_STATUS_NOTFOUND;
+
+fail:
+ *errnop = -r;
+ return NSS_STATUS_UNAVAIL;
+}
diff --git a/src/nss-mymachines/nss-mymachines.sym b/src/nss-mymachines/nss-mymachines.sym
index f80b51c1aa..0728ac3ba7 100644
--- a/src/nss-mymachines/nss-mymachines.sym
+++ b/src/nss-mymachines/nss-mymachines.sym
@@ -13,5 +13,9 @@ global:
_nss_mymachines_gethostbyname2_r;
_nss_mymachines_gethostbyname3_r;
_nss_mymachines_gethostbyname4_r;
+ _nss_mymachines_getpwnam_r;
+ _nss_mymachines_getpwuid_r;
+ _nss_mymachines_getgrnam_r;
+ _nss_mymachines_getgrgid_r;
local: *;
};
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
index a3e740896f..e1087b3219 100644
--- a/src/resolve/dns-type.c
+++ b/src/resolve/dns-type.c
@@ -43,3 +43,8 @@ int dns_type_from_string(const char *s) {
return sc->id;
}
+
+/* XXX: find an authorotative list of all pseudo types? */
+bool dns_type_is_pseudo(int n) {
+ return IN_SET(n, DNS_TYPE_ANY, DNS_TYPE_AXFR, DNS_TYPE_IXFR, DNS_TYPE_OPT);
+}
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
index 86951d233a..950af36ee3 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -25,6 +25,7 @@
const char *dns_type_to_string(int type);
int dns_type_from_string(const char *s);
+bool dns_type_is_pseudo(int n);
/* DNS record types, taken from
* http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml.
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 1ebebf8ea4..649e8b74e1 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -275,7 +275,7 @@ static void dns_packet_truncate(DnsPacket *p, size_t sz) {
if (p->size <= sz)
return;
- HASHMAP_FOREACH_KEY(s, n, p->names, i) {
+ HASHMAP_FOREACH_KEY(n, s, p->names, i) {
if (PTR_TO_SIZE(n) < sz)
continue;
@@ -502,6 +502,90 @@ fail:
return r;
}
+static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) {
+ size_t saved_size;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ saved_size = p->size;
+
+ if (length != 0) {
+
+ r = dns_packet_append_uint8(p, window, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, length, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, types, length, NULL);
+ if (r < 0)
+ goto fail;
+ }
+
+ if (start)
+ *start = saved_size;
+
+ return 0;
+fail:
+ dns_packet_truncate(p, saved_size);
+ return r;
+}
+
+static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
+ Iterator i;
+ uint8_t window = 0;
+ uint8_t len = 0;
+ uint8_t bitmaps[32] = {};
+ unsigned n;
+ size_t saved_size;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ saved_size = p->size;
+
+ BITMAP_FOREACH(n, types, i) {
+ uint8_t entry;
+
+ assert(n <= 0xffff);
+
+ if ((n << 8) != window) {
+ r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (len > 0) {
+ len = 0;
+ zero(bitmaps);
+ }
+ }
+
+ window = n << 8;
+ len ++;
+
+ entry = n & 255;
+
+ bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
+ }
+
+ r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (start)
+ *start = saved_size;
+
+ return 0;
+fail:
+ dns_packet_truncate(p, saved_size);
+ return r;
+}
+
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
size_t saved_size, rdlength_offset, end, rdlength;
int r;
@@ -677,7 +761,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
if (r < 0)
goto fail;
- r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
+ r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL);
break;
case DNS_TYPE_DNSKEY:
@@ -732,6 +816,50 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
break;
+ case DNS_TYPE_NSEC:
+ r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_types(p, rr->nsec.types, NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
+ case DNS_TYPE_NSEC3:
+ r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_types(p, rr->nsec3.types, NULL);
+ if (r < 0)
+ goto fail;
+
+ break;
case _DNS_TYPE_INVALID: /* unparseable */
default:
@@ -805,6 +933,42 @@ int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
return 0;
}
+static int dns_packet_read_memdup(
+ DnsPacket *p, size_t size,
+ void **ret, size_t *ret_size,
+ size_t *ret_start) {
+
+ const void *src;
+ size_t start;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ r = dns_packet_read(p, size, &src, &start);
+ if (r < 0)
+ return r;
+
+ if (size <= 0)
+ *ret = NULL;
+ else {
+ void *copy;
+
+ copy = memdup(src, size);
+ if (!copy)
+ return -ENOMEM;
+
+ *ret = copy;
+ }
+
+ if (ret_size)
+ *ret_size = size;
+ if (ret_start)
+ *ret_start = start;
+
+ return 0;
+}
+
int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
const void *d;
int r;
@@ -996,6 +1160,114 @@ fail:
return r;
}
+static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
+ uint8_t window;
+ uint8_t length;
+ const uint8_t *bitmap;
+ unsigned i;
+ bool found = false;
+ size_t saved_rindex;
+ int r;
+
+ assert(p);
+ assert(types);
+
+ saved_rindex = p->rindex;
+
+ r = bitmap_ensure_allocated(types);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &window, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &length, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (length == 0 || length > 32)
+ return -EBADMSG;
+
+ r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
+ if (r < 0)
+ goto fail;
+
+ for (i = 0; i < length; i++) {
+ uint8_t bitmask = 1 << 7;
+ uint8_t bit = 0;
+
+ if (!bitmap[i]) {
+ found = false;
+ continue;
+ }
+
+ found = true;
+
+ while (bitmask) {
+ if (bitmap[i] & bitmask) {
+ uint16_t n;
+
+ n = (uint16_t) window << 8 | (uint16_t) bit;
+
+ /* Ignore pseudo-types. see RFC4034 section 4.1.2 */
+ if (dns_type_is_pseudo(n))
+ continue;
+
+ r = bitmap_set(*types, n);
+ if (r < 0)
+ goto fail;
+ }
+
+ bit ++;
+ bitmask >>= 1;
+ }
+ }
+
+ if (!found)
+ return -EBADMSG;
+
+ if (start)
+ *start = saved_rindex;
+
+ return 0;
+fail:
+ dns_packet_rewind(p, saved_rindex);
+ return r;
+}
+
+static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
+ size_t saved_rindex;
+ int r;
+
+ saved_rindex = p->rindex;
+
+ while (p->rindex < saved_rindex + size) {
+ r = dns_packet_read_type_window(p, types, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* don't read past end of current RR */
+ if (p->rindex > saved_rindex + size) {
+ r = -EBADMSG;
+ goto fail;
+ }
+ }
+
+ if (p->rindex != saved_rindex + size) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ if (start)
+ *start = saved_rindex;
+
+ return 0;
+fail:
+ dns_packet_rewind(p, saved_rindex);
+ return r;
+}
+
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
_cleanup_free_ char *name = NULL;
uint16_t class, type;
@@ -1038,26 +1310,6 @@ fail:
return r;
}
-static int dns_packet_read_public_key(DnsPacket *p, size_t length,
- void **dp, size_t *lengthp,
- size_t *start) {
- int r;
- const void *d;
- void *d2;
-
- r = dns_packet_read(p, length, &d, NULL);
- if (r < 0)
- return r;
-
- d2 = memdup(d, length);
- if (!d2)
- return -ENOMEM;
-
- *dp = d2;
- *lengthp = length;
- return 0;
-}
-
static bool loc_size_ok(uint8_t size) {
uint8_t m = size >> 4, e = size & 0xF;
@@ -1080,7 +1332,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
size_t saved_rindex, offset;
uint16_t rdlength;
- const void *d;
int r;
assert(p);
@@ -1291,12 +1542,19 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 4,
- &rr->ds.digest, &rr->ds.digest_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 4,
+ &rr->ds.digest, &rr->ds.digest_size,
+ NULL);
if (r < 0)
goto fail;
+ if (rr->ds.digest_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
@@ -1307,9 +1565,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 2,
- &rr->sshfp.key, &rr->sshfp.key_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 2,
+ &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
+ NULL);
+
+ if (rr->sshfp.fingerprint_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
case DNS_TYPE_DNSKEY: {
@@ -1338,9 +1604,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, rdlength - 4,
- &rr->dnskey.key, &rr->dnskey.key_size,
- NULL);
+ r = dns_packet_read_memdup(p, rdlength - 4,
+ &rr->dnskey.key, &rr->dnskey.key_size,
+ NULL);
+
+ if (rr->dnskey.key_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
}
@@ -1377,24 +1651,83 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- r = dns_packet_read_public_key(p, offset + rdlength - p->rindex,
- &rr->rrsig.signature, &rr->rrsig.signature_size,
- NULL);
+ r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
+ &rr->rrsig.signature, &rr->rrsig.signature_size,
+ NULL);
+
+ if (rr->rrsig.signature_size <= 0) {
+ /* the accepted size depends on the algorithm, but for now
+ just ensure that the value is greater than zero */
+ r = -EBADMSG;
+ goto fail;
+ }
+
break;
- default:
- unparseable:
- r = dns_packet_read(p, rdlength, &d, NULL);
+ case DNS_TYPE_NSEC:
+ r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL);
if (r < 0)
goto fail;
- rr->generic.data = memdup(d, rdlength);
- if (!rr->generic.data) {
- r = -ENOMEM;
+ r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* NSEC RRs with empty bitmpas makes no sense, but the RFC does not explicitly forbid them
+ so we allow it */
+
+ break;
+
+ case DNS_TYPE_NSEC3: {
+ uint8_t size;
+
+ r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* this may be zero */
+ r = dns_packet_read_uint8(p, &size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_uint8(p, &size, NULL);
+ if (r < 0)
+ goto fail;
+
+ if (size <= 0) {
+ r = -EBADMSG;
goto fail;
}
- rr->generic.size = rdlength;
+ r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
+ if (r < 0)
+ goto fail;
+
+ /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
+
+ break;
+ }
+ default:
+ unparseable:
+ r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL);
+ if (r < 0)
+ goto fail;
break;
}
if (r < 0)
@@ -1516,13 +1849,15 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
- [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
- [DNSSEC_ALGORITHM_DH] = "DH",
- [DNSSEC_ALGORITHM_DSA] = "DSA",
- [DNSSEC_ALGORITHM_ECC] = "ECC",
- [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
- [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
- [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
- [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
+ [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
+ [DNSSEC_ALGORITHM_DH] = "DH",
+ [DNSSEC_ALGORITHM_DSA] = "DSA",
+ [DNSSEC_ALGORITHM_ECC] = "ECC",
+ [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
+ [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
+ [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
+ [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
+ [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
+ [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 6588ed9df5..58559c85df 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -223,6 +223,8 @@ enum {
DNSSEC_ALGORITHM_DSA,
DNSSEC_ALGORITHM_ECC,
DNSSEC_ALGORITHM_RSASHA1,
+ DNSSEC_ALGORITHM_DSA_NSEC3_SHA1,
+ DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
DNSSEC_ALGORITHM_INDIRECT = 252,
DNSSEC_ALGORITHM_PRIVATEDNS,
DNSSEC_ALGORITHM_PRIVATEOID,
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 676b77713e..ad7ca26cfe 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -276,7 +276,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
break;
case DNS_TYPE_SSHFP:
- free(rr->sshfp.key);
+ free(rr->sshfp.fingerprint);
break;
case DNS_TYPE_DNSKEY:
@@ -288,6 +288,17 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
free(rr->rrsig.signature);
break;
+ case DNS_TYPE_NSEC:
+ free(rr->nsec.next_domain_name);
+ bitmap_free(rr->nsec.types);
+ break;
+
+ case DNS_TYPE_NSEC3:
+ free(rr->nsec3.next_hashed_name);
+ free(rr->nsec3.salt);
+ bitmap_free(rr->nsec3.types);
+ break;
+
case DNS_TYPE_LOC:
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
@@ -423,8 +434,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
case DNS_TYPE_SSHFP:
return a->sshfp.algorithm == b->sshfp.algorithm &&
a->sshfp.fptype == b->sshfp.fptype &&
- a->sshfp.key_size == b->sshfp.key_size &&
- memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
+ a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
+ memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
case DNS_TYPE_DNSKEY:
return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
@@ -448,6 +459,19 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
+ case DNS_TYPE_NSEC:
+ return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
+ bitmap_equal(a->nsec.types, b->nsec.types);
+
+ case DNS_TYPE_NSEC3:
+ return a->nsec3.algorithm == b->nsec3.algorithm &&
+ a->nsec3.flags == b->nsec3.flags &&
+ a->nsec3.iterations == b->nsec3.iterations &&
+ a->nsec3.salt_size == b->nsec3.salt_size &&
+ memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
+ memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
+ bitmap_equal(a->nsec3.types, b->nsec3.types);
+
default:
return a->generic.size == b->generic.size &&
memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@@ -500,6 +524,38 @@ static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
return 0;
}
+static char *format_types(Bitmap *types) {
+ _cleanup_strv_free_ char **strv = NULL;
+ _cleanup_free_ char *str = NULL;
+ Iterator i;
+ unsigned type;
+ int r;
+
+ BITMAP_FOREACH(type, types, i) {
+ if (dns_type_to_string(type)) {
+ r = strv_extend(&strv, dns_type_to_string(type));
+ if (r < 0)
+ return NULL;
+ } else {
+ char *t;
+
+ r = asprintf(&t, "TYPE%u", type);
+ if (r < 0)
+ return NULL;
+
+ r = strv_consume(&strv, t);
+ if (r < 0)
+ return NULL;
+ }
+ }
+
+ str = strv_join(strv, " ");
+ if (!str)
+ return NULL;
+
+ return strjoin("( ", str, " )", NULL);
+}
+
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
_cleanup_free_ char *k = NULL, *t = NULL;
char *s;
@@ -631,7 +687,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
break;
case DNS_TYPE_SSHFP:
- t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
+ t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!t)
return -ENOMEM;
@@ -704,12 +760,56 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
break;
}
+ case DNS_TYPE_NSEC:
+ t = format_types(rr->nsec.types);
+ if (!t)
+ return -ENOMEM;
+
+ r = asprintf(&s, "%s %s %s",
+ k,
+ rr->nsec.next_domain_name,
+ t);
+ if (r < 0)
+ return -ENOMEM;
+ break;
+
+ case DNS_TYPE_NSEC3: {
+ _cleanup_free_ char *salt = NULL, *hash = NULL;
+
+ if (rr->nsec3.salt_size > 0) {
+ salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
+ if (!salt)
+ return -ENOMEM;
+ }
+
+ hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
+ if (!hash)
+ return -ENOMEM;
+
+ t = format_types(rr->nsec3.types);
+ if (!t)
+ return -ENOMEM;
+
+ r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
+ k,
+ rr->nsec3.algorithm,
+ rr->nsec3.flags,
+ rr->nsec3.iterations,
+ rr->nsec3.salt_size > 0 ? salt : "-",
+ hash,
+ t);
+ if (r < 0)
+ return -ENOMEM;
+
+ break;
+ }
+
default:
t = hexmem(rr->generic.data, rr->generic.size);
if (!t)
return -ENOMEM;
- r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
+ r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
if (r < 0)
return -ENOMEM;
break;
@@ -740,7 +840,7 @@ int dns_class_from_string(const char *s, uint16_t *class) {
if (strcaseeq(s, "IN"))
*class = DNS_CLASS_IN;
else if (strcaseeq(s, "ANY"))
- *class = DNS_TYPE_ANY;
+ *class = DNS_CLASS_ANY;
else
return -EINVAL;
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index b375d6b9fc..0f40f3ceef 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -23,6 +23,7 @@
#include <netinet/in.h>
+#include "bitmap.h"
#include "hashmap.h"
#include "in-addr-util.h"
#include "dns-type.h"
@@ -52,7 +53,7 @@ struct DnsResourceRecord {
union {
struct {
void *data;
- uint16_t size;
+ size_t size;
} generic;
struct {
@@ -116,11 +117,12 @@ struct DnsResourceRecord {
size_t digest_size;
} ds;
+ /* https://tools.ietf.org/html/rfc4255#section-3.1 */
struct {
uint8_t algorithm;
uint8_t fptype;
- void *key;
- size_t key_size;
+ void *fingerprint;
+ size_t fingerprint_size;
} sshfp;
/* http://tools.ietf.org/html/rfc4034#section-2.1 */
@@ -145,6 +147,22 @@ struct DnsResourceRecord {
void *signature;
size_t signature_size;
} rrsig;
+
+ struct {
+ char *next_domain_name;
+ Bitmap *types;
+ } nsec;
+
+ struct {
+ uint8_t algorithm;
+ uint8_t flags;
+ uint16_t iterations;
+ void *salt;
+ size_t salt_size;
+ void *next_hashed_name;
+ size_t next_hashed_name_size;
+ Bitmap *types;
+ } nsec3;
};
};
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 7b72c090c2..927a1ddc26 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -125,18 +125,17 @@ void dns_scope_next_dns_server(DnsScope *s) {
manager_next_dns_server(s->manager);
}
-int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) {
- DnsServer *srv = NULL;
+int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
union in_addr_union addr;
int ifindex = 0, r;
int family;
uint16_t port;
uint32_t mtu;
- int fd;
assert(s);
assert(p);
assert(p->protocol == s->protocol);
+ assert((s->protocol == DNS_PROTOCOL_DNS) != (fd < 0));
if (s->link) {
mtu = s->link->mtu;
@@ -148,28 +147,15 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser
if (DNS_PACKET_QDCOUNT(p) > 1)
return -EOPNOTSUPP;
- srv = dns_scope_get_dns_server(s);
- if (!srv)
- return -ESRCH;
-
- family = srv->family;
- addr = srv->address;
- port = 53;
-
if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
return -EMSGSIZE;
if (p->size + UDP_PACKET_HEADER_SIZE > mtu)
return -EMSGSIZE;
- if (family == AF_INET)
- fd = transaction_dns_ipv4_fd(t);
- else if (family == AF_INET6)
- fd = transaction_dns_ipv6_fd(t);
- else
- return -EAFNOSUPPORT;
- if (fd < 0)
- return fd;
+ r = manager_write(s->manager, fd, p);
+ if (r < 0)
+ return r;
} else if (s->protocol == DNS_PROTOCOL_LLMNR) {
@@ -192,20 +178,17 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser
return -EAFNOSUPPORT;
if (fd < 0)
return fd;
+
+ r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
+ if (r < 0)
+ return r;
} else
return -EAFNOSUPPORT;
- r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
- if (r < 0)
- return r;
-
- if (server)
- *server = srv;
-
return 1;
}
-int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
+static int dns_scope_socket(DnsScope *s, int type, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
DnsServer *srv = NULL;
_cleanup_close_ int fd = -1;
union sockaddr_union sa = {};
@@ -249,13 +232,15 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
return -EAFNOSUPPORT;
}
- fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ fd = socket(sa.sa.sa_family, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
- r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
- if (r < 0)
- return -errno;
+ if (type == SOCK_STREAM) {
+ r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
+ if (r < 0)
+ return -errno;
+ }
if (s->link) {
uint32_t ifindex = htobe32(s->link->ifindex);
@@ -298,6 +283,14 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
return ret;
}
+int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server) {
+ return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, 53, server);
+}
+
+int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
+ return dns_scope_socket(s, SOCK_STREAM, family, address, port, server);
+}
+
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
char **i;
@@ -420,19 +413,6 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
return 0;
}
-int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
- assert(s);
- assert(address);
-
- if (s->protocol != DNS_PROTOCOL_DNS)
- return 1;
-
- if (s->link)
- return !!link_find_dns_server(s->link, family, address);
- else
- return !!manager_find_dns_server(s->manager, family, address);
-}
-
static int dns_scope_make_reply_packet(
DnsScope *s,
uint16_t id,
@@ -700,7 +680,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
return 0;
}
- r = dns_scope_emit(scope, NULL, p, NULL);
+ r = dns_scope_emit(scope, -1, p);
if (r < 0)
log_debug_errno(r, "Failed to send conflict packet: %m");
}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 5c5ccc71c5..29479ad550 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -65,12 +65,12 @@ struct DnsScope {
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
DnsScope* dns_scope_free(DnsScope *s);
-int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server);
+int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p);
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
+int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server);
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
-int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address);
DnsServer *dns_scope_get_dns_server(DnsScope *s);
void dns_scope_next_dns_server(DnsScope *s);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index e468f245f7..b235fda3d2 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -39,10 +39,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
dns_packet_unref(t->received);
dns_answer_unref(t->cached);
- sd_event_source_unref(t->dns_ipv4_event_source);
- sd_event_source_unref(t->dns_ipv6_event_source);
- safe_close(t->dns_ipv4_fd);
- safe_close(t->dns_ipv6_fd);
+ sd_event_source_unref(t->dns_event_source);
+ safe_close(t->dns_fd);
dns_server_unref(t->server);
dns_stream_free(t->stream);
@@ -94,7 +92,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
if (!t)
return -ENOMEM;
- t->dns_ipv4_fd = t->dns_ipv6_fd = -1;
+ t->dns_fd = -1;
t->question = dns_question_ref(q);
@@ -245,7 +243,7 @@ static int on_stream_complete(DnsStream *s, int error) {
}
static int dns_transaction_open_tcp(DnsTransaction *t) {
- _cleanup_(dns_server_unrefp) DnsServer *server = NULL;
+ DnsServer *server = NULL;
_cleanup_close_ int fd = -1;
int r;
@@ -310,6 +308,16 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
return 0;
}
+static void dns_transaction_next_dns_server(DnsTransaction *t) {
+ assert(t);
+
+ t->server = dns_server_unref(t->server);
+ t->dns_event_source = sd_event_source_unref(t->dns_event_source);
+ t->dns_fd = safe_close(t->dns_fd);
+
+ dns_scope_next_dns_server(t->scope);
+}
+
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
int r;
@@ -342,24 +350,6 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
}
}
- if (t->scope->protocol == DNS_PROTOCOL_DNS) {
-
- /* For DNS we are fine with accepting packets on any
- * interface, but the source IP address must be the
- * one of the DNS server we queried */
-
- assert(t->server);
-
- if (t->server->family != p->family)
- return;
-
- if (!in_addr_equal(p->family, &p->sender, &t->server->address))
- return;
-
- if (p->sender_port != 53)
- return;
- }
-
if (t->received != p) {
dns_packet_unref(t->received);
t->received = dns_packet_ref(p);
@@ -396,7 +386,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
}
/* On DNS, couldn't send? Try immediately again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
r = dns_transaction_go(t);
if (r < 0) {
@@ -417,8 +407,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
/* Only consider responses with equivalent query section to the request */
if (!dns_question_is_superset(p->question, t->question) ||
- !dns_question_is_superset(t->question, p->question))
+ !dns_question_is_superset(t->question, p->question)) {
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
+ return;
+ }
/* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
@@ -429,6 +421,56 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
}
+static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+ DnsTransaction *t = userdata;
+ int r;
+
+ assert(t);
+ assert(t->scope);
+
+ r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
+ if (r <= 0)
+ return r;
+
+ if (dns_packet_validate_reply(p) > 0 &&
+ DNS_PACKET_ID(p) == t->id) {
+ dns_transaction_process_reply(t, p);
+ } else
+ log_debug("Invalid DNS packet.");
+
+ return 0;
+}
+
+static int dns_transaction_emit(DnsTransaction *t) {
+ int r;
+
+ assert(t);
+
+ if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) {
+ DnsServer *server = NULL;
+ _cleanup_close_ int fd = -1;
+
+ fd = dns_scope_udp_dns_socket(t->scope, &server);
+ if (fd < 0)
+ return fd;
+
+ r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, fd, EPOLLIN, on_dns_packet, t);
+ if (r < 0)
+ return r;
+
+ t->dns_fd = fd;
+ fd = -1;
+ t->server = dns_server_ref(server);
+ }
+
+ r = dns_scope_emit(t->scope, t->dns_fd, t->sent);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
DnsTransaction *t = userdata;
int r;
@@ -437,7 +479,7 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat
assert(t);
/* Timeout reached? Try again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
r = dns_transaction_go(t);
if (r < 0)
@@ -514,7 +556,6 @@ int dns_transaction_go(DnsTransaction *t) {
}
t->n_attempts++;
- t->server = dns_server_unref(t->server);
t->received = dns_packet_unref(t->received);
t->cached = dns_answer_unref(t->cached);
t->cached_rcode = 0;
@@ -594,13 +635,9 @@ int dns_transaction_go(DnsTransaction *t) {
* always be made via TCP on LLMNR */
r = dns_transaction_open_tcp(t);
} else {
- DnsServer *server;
-
/* Try via UDP, and if that fails due to large size try via TCP */
- r = dns_scope_emit(t->scope, t, t->sent, &server);
- if (r >= 0)
- t->server = dns_server_ref(server);
- else if (r == -EMSGSIZE)
+ r = dns_transaction_emit(t);
+ if (r == -EMSGSIZE)
r = dns_transaction_open_tcp(t);
}
if (r == -ESRCH) {
@@ -614,7 +651,7 @@ int dns_transaction_go(DnsTransaction *t) {
}
/* Couldn't send? Try immediately again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
return dns_transaction_go(t);
}
@@ -632,91 +669,6 @@ int dns_transaction_go(DnsTransaction *t) {
return 1;
}
-static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- DnsTransaction *t = userdata;
- int r;
-
- assert(t);
- assert(t->scope);
-
- r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
- if (r <= 0)
- return r;
-
- if (dns_packet_validate_reply(p) > 0 &&
- DNS_PACKET_ID(p) == t->id) {
- dns_transaction_process_reply(t, p);
- } else
- log_debug("Invalid DNS packet.");
-
- return 0;
-}
-
-int transaction_dns_ipv4_fd(DnsTransaction *t) {
- const int one = 1;
- int r;
-
- assert(t);
- assert(t->scope);
- assert(t->scope->manager);
-
- if (t->dns_ipv4_fd >= 0)
- return t->dns_ipv4_fd;
-
- t->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (t->dns_ipv4_fd < 0)
- return -errno;
-
- r = setsockopt(t->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
- if (r < 0) {
- r = -errno;
- goto fail;
- }
-
- r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv4_event_source, t->dns_ipv4_fd, EPOLLIN, on_dns_packet, t);
- if (r < 0)
- goto fail;
-
- return t->dns_ipv4_fd;
-
-fail:
- t->dns_ipv4_fd = safe_close(t->dns_ipv4_fd);
- return r;
-}
-
-int transaction_dns_ipv6_fd(DnsTransaction *t) {
- const int one = 1;
- int r;
-
- assert(t);
- assert(t->scope);
- assert(t->scope->manager);
-
- if (t->dns_ipv6_fd >= 0)
- return t->dns_ipv6_fd;
-
- t->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (t->dns_ipv6_fd < 0)
- return -errno;
-
- r = setsockopt(t->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
- if (r < 0) {
- r = -errno;
- goto fail;
- }
-
- r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv6_event_source, t->dns_ipv6_fd, EPOLLIN, on_dns_packet, t);
- if (r < 0)
- goto fail;
-
- return t->dns_ipv6_fd;
-
-fail:
- t->dns_ipv6_fd = safe_close(t->dns_ipv6_fd);
- return r;
-}
-
static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
[DNS_TRANSACTION_NULL] = "null",
[DNS_TRANSACTION_PENDING] = "pending",
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 87f342ca11..a8f4267bc8 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -61,11 +61,8 @@ struct DnsTransaction {
sd_event_source *timeout_event_source;
unsigned n_attempts;
- int dns_ipv4_fd;
- int dns_ipv6_fd;
-
- sd_event_source *dns_ipv4_event_source;
- sd_event_source *dns_ipv6_event_source;
+ int dns_fd;
+ sd_event_source *dns_event_source;
/* the active server */
DnsServer *server;
@@ -95,9 +92,6 @@ int dns_transaction_go(DnsTransaction *t);
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p);
void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state);
-int transaction_dns_ipv4_fd(DnsTransaction *t);
-int transaction_dns_ipv6_fd(DnsTransaction *t);
-
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 17de14bae1..5be01d3cb8 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -912,10 +912,12 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (p->ifindex == LOOPBACK_IFINDEX)
p->ifindex = 0;
- /* If we don't know the interface index still, we look for the
- * first local interface with a matching address. Yuck! */
- if (p->ifindex <= 0)
- p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
+ if (protocol != DNS_PROTOCOL_DNS) {
+ /* If we don't know the interface index still, we look for the
+ * first local interface with a matching address. Yuck! */
+ if (p->ifindex <= 0)
+ p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
+ }
*ret = p;
p = NULL;
@@ -947,6 +949,42 @@ static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
}
}
+static int write_loop(int fd, void *message, size_t length) {
+ int r;
+
+ assert(fd >= 0);
+ assert(message);
+
+ for (;;) {
+ if (write(fd, message, length) >= 0)
+ return 0;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != EAGAIN)
+ return -errno;
+
+ r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ETIMEDOUT;
+ }
+}
+
+int manager_write(Manager *m, int fd, DnsPacket *p) {
+ int r;
+
+ log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
+
+ r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 005f844df2..53b5acb33c 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -119,6 +119,7 @@ void manager_next_dns_server(Manager *m);
uint32_t manager_find_mtu(Manager *m);
+int manager_write(Manager *m, int fd, DnsPacket *p);
int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p);
int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret);
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 20a44ce4e1..8a0dec1540 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -114,6 +114,68 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
return r;
}
+/* @label_terminal: terminal character of a label, updated to point to the terminal character of
+ * the previous label (always skipping one dot) or to NULL if there are no more
+ * labels. */
+int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
+ const char *terminal;
+ int r;
+
+ assert(name);
+ assert(label_terminal);
+ assert(dest);
+
+ /* no more labels */
+ if (!*label_terminal) {
+ if (sz >= 1)
+ *dest = 0;
+
+ return 0;
+ }
+
+ assert(**label_terminal == '.' || **label_terminal == 0);
+
+ /* skip current terminal character */
+ terminal = *label_terminal - 1;
+
+ /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
+ for (;;) {
+ if (terminal < name) {
+ /* reached the first label, so indicate that there are no more */
+ terminal = NULL;
+ break;
+ }
+
+ /* find the start of the last label */
+ if (*terminal == '.') {
+ const char *y;
+ unsigned slashes = 0;
+
+ for (y = terminal - 1; y >= name && *y == '\\'; y--)
+ slashes ++;
+
+ if (slashes % 2 == 0) {
+ /* the '.' was not escaped */
+ name = terminal + 1;
+ break;
+ } else {
+ terminal = y;
+ continue;
+ }
+ }
+
+ terminal --;
+ }
+
+ r = dns_label_unescape(&name, dest, sz);
+ if (r < 0)
+ return r;
+
+ *label_terminal = terminal;
+
+ return r;
+}
+
int dns_label_escape(const char *p, size_t l, char **ret) {
_cleanup_free_ char *s = NULL;
char *q;
@@ -338,20 +400,23 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
}
int dns_name_compare_func(const void *a, const void *b) {
- const char *x = a, *y = b;
+ const char *x, *y;
int r, q, k, w;
assert(a);
assert(b);
+ x = (const char *) a + strlen(a);
+ y = (const char *) b + strlen(b);
+
for (;;) {
char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
- if (*x == 0 && *y == 0)
+ if (x == NULL && y == NULL)
return 0;
- r = dns_label_unescape(&x, la, sizeof(la));
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
+ q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
if (r < 0 || q < 0)
return r - q;
@@ -464,6 +529,28 @@ int dns_name_endswith(const char *name, const char *suffix) {
}
}
+int dns_name_between(const char *a, const char *b, const char *c) {
+ int n;
+
+ /* Determine if b is strictly greater than a and strictly smaller than c.
+ We consider the order of names to be circular, so that if a is
+ strictly greater than c, we consider b to be between them if it is
+ either greater than a or smaller than c. This is how the canonical
+ DNS name order used in NSEC records work. */
+
+ n = dns_name_compare_func(a, c);
+ if (n == 0)
+ return -EINVAL;
+ else if (n < 0)
+ /* a<---b--->c */
+ return dns_name_compare_func(a, b) < 0 &&
+ dns_name_compare_func(b, c) < 0;
+ else
+ /* <--b--c a--b--> */
+ return dns_name_compare_func(b, c) < 0 ||
+ dns_name_compare_func(a, b) < 0;
+}
+
int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
const uint8_t *p;
int r;
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 00caf5d700..bd50ad3e6d 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -29,6 +29,7 @@
#define DNS_NAME_MAX 255
int dns_label_unescape(const char **name, char *dest, size_t sz);
+int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
int dns_label_escape(const char *p, size_t l, char **ret);
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
@@ -49,6 +50,7 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
int dns_name_compare_func(const void *a, const void *b);
extern const struct hash_ops dns_name_hash_ops;
+int dns_name_between(const char *a, const char *b, const char *c);
int dns_name_equal(const char *x, const char *y);
int dns_name_endswith(const char *name, const char *suffix);
diff --git a/src/shared/install.c b/src/shared/install.c
index c37cf1948a..3d2b5ae77f 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -2190,6 +2190,7 @@ int unit_file_get_list(
_cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
struct dirent *de;
_cleanup_free_ char *path = NULL;
+ bool also = false;
errno = 0;
de = readdir(d);
@@ -2243,7 +2244,7 @@ int unit_file_get_list(
if (!path)
return -ENOMEM;
- r = unit_file_can_install(&paths, root_dir, path, true, NULL);
+ r = unit_file_can_install(&paths, root_dir, path, true, &also);
if (r == -EINVAL || /* Invalid setting? */
r == -EBADMSG || /* Invalid format? */
r == -ENOENT /* Included file not found? */)
@@ -2253,7 +2254,7 @@ int unit_file_get_list(
else if (r > 0)
f->state = UNIT_FILE_DISABLED;
else
- f->state = UNIT_FILE_STATIC;
+ f->state = also ? UNIT_FILE_INDIRECT : UNIT_FILE_STATIC;
found:
r = hashmap_put(h, basename(f->path), f);
diff --git a/src/shared/nss-util.h b/src/shared/nss-util.h
index 230a986040..3657aa5d9c 100644
--- a/src/shared/nss-util.h
+++ b/src/shared/nss-util.h
@@ -24,6 +24,9 @@
#include <nss.h>
#include <netdb.h>
#include <resolv.h>
+#include <pwd.h>
+#include <grp.h>
+
#define NSS_GETHOSTBYNAME_PROTOTYPES(module) \
enum nss_status _nss_##module##_gethostbyname4_r( \
@@ -109,7 +112,8 @@ enum nss_status _nss_##module##_gethostbyname_r( \
NULL, \
NULL); \
return ret; \
-}
+} \
+struct __useless_struct_to_allow_trailing_semicolon__
#define NSS_GETHOSTBYADDR_FALLBACKS(module) \
enum nss_status _nss_##module##_gethostbyaddr_r( \
@@ -125,4 +129,29 @@ enum nss_status _nss_##module##_gethostbyaddr_r( \
buffer, buflen, \
errnop, h_errnop, \
NULL); \
-}
+} \
+struct __useless_struct_to_allow_trailing_semicolon__
+
+#define NSS_GETPW_PROTOTYPES(module) \
+enum nss_status _nss_##module##_getpwnam_r( \
+ const char *name, \
+ struct passwd *pwd, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_; \
+enum nss_status _nss_mymachines_getpwuid_r( \
+ uid_t uid, \
+ struct passwd *pwd, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_
+
+#define NSS_GETGR_PROTOTYPES(module) \
+enum nss_status _nss_##module##_getgrnam_r( \
+ const char *name, \
+ struct group *gr, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_; \
+enum nss_status _nss_##module##_getgrgid_r( \
+ gid_t gid, \
+ struct group *gr, \
+ char *buffer, size_t buflen, \
+ int *errnop) _public_
diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h
index a03221502a..bb4b1eb748 100644
--- a/src/systemd/sd-bus-vtable.h
+++ b/src/systemd/sd-bus-vtable.h
@@ -67,6 +67,7 @@ struct sd_bus_vtable {
const char *signature;
const char *result;
sd_bus_message_handler_t handler;
+ size_t offset;
} method;
struct {
const char *member;
@@ -89,7 +90,7 @@ struct sd_bus_vtable {
.x.start.element_size = sizeof(sd_bus_vtable), \
}
-#define SD_BUS_METHOD(_member, _signature, _result, _handler, _flags) \
+#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags) \
{ \
.type = _SD_BUS_VTABLE_METHOD, \
.flags = _flags, \
@@ -97,7 +98,10 @@ struct sd_bus_vtable {
.x.method.signature = _signature, \
.x.method.result = _result, \
.x.method.handler = _handler, \
+ .x.method.offset = _offset, \
}
+#define SD_BUS_METHOD(_member, _signature, _result, _handler, _flags) \
+ SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, 0, _flags)
#define SD_BUS_SIGNAL(_member, _signature, _flags) \
{ \
diff --git a/src/test/test-bitmap.c b/src/test/test-bitmap.c
new file mode 100644
index 0000000000..96deeded7e
--- /dev/null
+++ b/src/test/test-bitmap.c
@@ -0,0 +1,105 @@
+/***
+ This file is part of systemd
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "bitmap.h"
+
+int main(int argc, const char *argv[]) {
+ _cleanup_bitmap_free_ Bitmap *b = NULL;
+ Iterator it;
+ unsigned n = (unsigned) -1, i = 0;
+
+ b = bitmap_new();
+ assert_se(b);
+
+ assert_se(bitmap_ensure_allocated(&b) == 0);
+ bitmap_free(b);
+ b = NULL;
+ assert_se(bitmap_ensure_allocated(&b) == 0);
+
+ assert_se(bitmap_isset(b, 0) == false);
+ assert_se(bitmap_isset(b, 1) == false);
+ assert_se(bitmap_isset(b, 256) == false);
+ assert_se(bitmap_isclear(b) == true);
+
+ assert_se(bitmap_set(b, 0) == 0);
+ assert_se(bitmap_isset(b, 0) == true);
+ assert_se(bitmap_isclear(b) == false);
+ bitmap_unset(b, 0);
+ assert_se(bitmap_isset(b, 0) == false);
+ assert_se(bitmap_isclear(b) == true);
+
+ assert_se(bitmap_set(b, 1) == 0);
+ assert_se(bitmap_isset(b, 1) == true);
+ assert_se(bitmap_isclear(b) == false);
+ bitmap_unset(b, 1);
+ assert_se(bitmap_isset(b, 1) == false);
+ assert_se(bitmap_isclear(b) == true);
+
+ assert_se(bitmap_set(b, 256) == 0);
+ assert_se(bitmap_isset(b, 256) == true);
+ assert_se(bitmap_isclear(b) == false);
+ bitmap_unset(b, 256);
+ assert_se(bitmap_isset(b, 256) == false);
+ assert_se(bitmap_isclear(b) == true);
+
+ assert_se(bitmap_set(b, 32) == 0);
+ bitmap_unset(b, 0);
+ assert_se(bitmap_isset(b, 32) == true);
+ bitmap_unset(b, 32);
+
+ BITMAP_FOREACH(n, NULL, it)
+ assert_not_reached("NULL bitmap");
+
+ assert_se(bitmap_set(b, 0) == 0);
+ assert_se(bitmap_set(b, 1) == 0);
+ assert_se(bitmap_set(b, 256) == 0);
+
+ BITMAP_FOREACH(n, b, it) {
+ assert_se(n == i);
+ if (i == 0)
+ i = 1;
+ else if (i == 1)
+ i = 256;
+ else if (i == 256)
+ i = (unsigned) -1;
+ }
+
+ assert_se(i == (unsigned) -1);
+
+ i = 0;
+
+ BITMAP_FOREACH(n, b, it) {
+ assert_se(n == i);
+ if (i == 0)
+ i = 1;
+ else if (i == 1)
+ i = 256;
+ else if (i == 256)
+ i = (unsigned) -1;
+ }
+
+ assert_se(i == (unsigned) -1);
+
+ bitmap_clear(b);
+ assert_se(bitmap_isclear(b) == true);
+
+ assert_se(bitmap_set(b, (unsigned) -1) == -ERANGE);
+
+ return 0;
+}
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 527cdd3b54..31e110cf0d 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -50,6 +50,46 @@ static void test_dns_label_unescape(void) {
test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
}
+static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) {
+ char buffer[buffer_sz];
+ const char *label;
+ int r;
+
+ label = what + strlen(what);
+
+ r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
+ assert_se(r == ret1);
+ if (r >= 0)
+ assert_se(streq(buffer, expect1));
+
+ r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
+ assert_se(r == ret2);
+ if (r >= 0)
+ assert_se(streq(buffer, expect2));
+}
+
+static void test_dns_label_unescape_suffix(void) {
+ test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0);
+ test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOSPC, -ENOSPC);
+ test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);
+ test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0);
+ test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5);
+ test_dns_label_unescape_suffix_one("hallo.foobar\n", "foobar", "foobar", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_suffix_one("hallo\\", "hallo", "hallo", 20, -EINVAL, -EINVAL);
+ test_dns_label_unescape_suffix_one("hallo\\032 ", "hallo ", "", 20, 7, 0);
+ test_dns_label_unescape_suffix_one(".", "", "", 20, 0, 0);
+ test_dns_label_unescape_suffix_one("..", "", "", 20, 0, 0);
+ test_dns_label_unescape_suffix_one(".foobar", "foobar", "", 20, 6, -EINVAL);
+ test_dns_label_unescape_suffix_one("foobar.", "", "foobar", 20, 0, 6);
+ test_dns_label_unescape_suffix_one("foo\\\\bar", "foo\\bar", "", 20, 7, 0);
+ test_dns_label_unescape_suffix_one("foo.bar", "bar", "foo", 20, 3, 3);
+ test_dns_label_unescape_suffix_one("foo..bar", "bar", "", 20, 3, -EINVAL);
+ test_dns_label_unescape_suffix_one("foo...bar", "bar", "", 20, 3, -EINVAL);
+ test_dns_label_unescape_suffix_one("foo\\.bar", "foo.bar", "", 20, 7, 0);
+ test_dns_label_unescape_suffix_one("foo\\\\.bar", "bar", "foo\\", 20, 3, 4);
+ test_dns_label_unescape_suffix_one("foo\\\\\\.bar", "foo\\.bar", "", 20, 8, 0);
+}
+
static void test_dns_label_escape_one(const char *what, size_t l, const char *expect, int ret) {
_cleanup_free_ char *t = NULL;
int r;
@@ -120,6 +160,38 @@ static void test_dns_name_equal(void) {
test_dns_name_equal_one("..", "..", -EINVAL);
}
+static void test_dns_name_between_one(const char *a, const char *b, const char *c, int ret) {
+ int r;
+
+ r = dns_name_between(a, b, c);
+ assert_se(r == ret);
+
+ r = dns_name_between(c, b, a);
+ if (ret >= 0)
+ assert_se(r == 0);
+ else
+ assert_se(r == ret);
+}
+
+static void test_dns_name_between(void) {
+ /* see https://tools.ietf.org/html/rfc4034#section-6.1
+ Note that we use "\033.z.example" in stead of "\001.z.example" as we
+ consider the latter invalid */
+ test_dns_name_between_one("example", "a.example", "yljkjljk.a.example", true);
+ test_dns_name_between_one("a.example", "yljkjljk.a.example", "Z.a.example", true);
+ test_dns_name_between_one("yljkjljk.a.example", "Z.a.example", "zABC.a.EXAMPLE", true);
+ test_dns_name_between_one("Z.a.example", "zABC.a.EXAMPLE", "z.example", true);
+ test_dns_name_between_one("zABC.a.EXAMPLE", "z.example", "\\033.z.example", true);
+ test_dns_name_between_one("z.example", "\\033.z.example", "*.z.example", true);
+ test_dns_name_between_one("\\033.z.example", "*.z.example", "\\200.z.example", true);
+ test_dns_name_between_one("*.z.example", "\\200.z.example", "example", true);
+ test_dns_name_between_one("\\200.z.example", "example", "a.example", true);
+
+ test_dns_name_between_one("example", "a.example", "example", -EINVAL);
+ test_dns_name_between_one("example", "example", "yljkjljk.a.example", false);
+ test_dns_name_between_one("example", "yljkjljk.a.example", "yljkjljk.a.example", false);
+}
+
static void test_dns_name_endswith_one(const char *a, const char *b, int ret) {
assert_se(dns_name_endswith(a, b) == ret);
}
@@ -180,10 +252,12 @@ static void test_dns_name_reverse(void) {
int main(int argc, char *argv[]) {
test_dns_label_unescape();
+ test_dns_label_unescape_suffix();
test_dns_label_escape();
test_dns_name_normalize();
test_dns_name_equal();
test_dns_name_endswith();
+ test_dns_name_between();
test_dns_name_root();
test_dns_name_single_label();
test_dns_name_reverse();
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 72fbc345c2..f43433baa1 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -390,6 +390,21 @@ static void test_unhexchar(void) {
assert_se(unhexchar('0') == 0x0);
}
+static void test_base32hexchar(void) {
+ assert_se(base32hexchar(0) == '0');
+ assert_se(base32hexchar(9) == '9');
+ assert_se(base32hexchar(10) == 'A');
+ assert_se(base32hexchar(31) == 'V');
+}
+
+static void test_unbase32hexchar(void) {
+ assert_se(unbase32hexchar('0') == 0);
+ assert_se(unbase32hexchar('9') == 9);
+ assert_se(unbase32hexchar('A') == 10);
+ assert_se(unbase32hexchar('V') == 31);
+ assert_se(unbase32hexchar('=') == -EINVAL);
+}
+
static void test_base64char(void) {
assert_se(base64char(0) == 'A');
assert_se(base64char(26) == 'a');
@@ -453,6 +468,162 @@ static void test_unhexmem(void) {
}
/* https://tools.ietf.org/html/rfc4648#section-10 */
+static void test_base32hexmem(void) {
+ char *b32;
+
+ b32 = base32hexmem("", strlen(""), true);
+ assert_se(b32);
+ assert_se(streq(b32, ""));
+ free(b32);
+
+ b32 = base32hexmem("f", strlen("f"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CO======"));
+ free(b32);
+
+ b32 = base32hexmem("fo", strlen("fo"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNG===="));
+ free(b32);
+
+ b32 = base32hexmem("foo", strlen("foo"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMU==="));
+ free(b32);
+
+ b32 = base32hexmem("foob", strlen("foob"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOG="));
+ free(b32);
+
+ b32 = base32hexmem("fooba", strlen("fooba"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1"));
+ free(b32);
+
+ b32 = base32hexmem("foobar", strlen("foobar"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1E8======"));
+ free(b32);
+
+ b32 = base32hexmem("", strlen(""), false);
+ assert_se(b32);
+ assert_se(streq(b32, ""));
+ free(b32);
+
+ b32 = base32hexmem("f", strlen("f"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CO"));
+ free(b32);
+
+ b32 = base32hexmem("fo", strlen("fo"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNG"));
+ free(b32);
+
+ b32 = base32hexmem("foo", strlen("foo"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMU"));
+ free(b32);
+
+ b32 = base32hexmem("foob", strlen("foob"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOG"));
+ free(b32);
+
+ b32 = base32hexmem("fooba", strlen("fooba"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1"));
+ free(b32);
+
+ b32 = base32hexmem("foobar", strlen("foobar"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1E8"));
+ free(b32);
+}
+
+static void test_unbase32hexmem(void) {
+ void *mem;
+ size_t len;
+
+ assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), ""));
+ free(mem);
+
+ assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "f"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foob"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fooba"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foobar"));
+ free(mem);
+
+ assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL);
+
+ assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), ""));
+ free(mem);
+
+ assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "f"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foob"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fooba"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foobar"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL);
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-10 */
static void test_base64mem(void) {
char *b64;
@@ -1518,6 +1689,17 @@ static void test_unquote_first_word(void) {
assert_se(streq(t, "\\w+\b"));
free(t);
assert_se(p == original + 5);
+
+ p = original = "-N ''";
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
+ assert_se(streq(t, "-N"));
+ free(t);
+ assert_se(p == original + 3);
+
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
+ assert_se(streq(t, ""));
+ free(t);
+ assert_se(p == original + 5);
}
static void test_unquote_first_word_and_warn(void) {
@@ -1924,6 +2106,8 @@ int main(int argc, char *argv[]) {
test_in_charset();
test_hexchar();
test_unhexchar();
+ test_base32hexchar();
+ test_unbase32hexchar();
test_base64char();
test_unbase64char();
test_octchar();
@@ -1931,6 +2115,8 @@ int main(int argc, char *argv[]) {
test_decchar();
test_undecchar();
test_unhexmem();
+ test_base32hexmem();
+ test_unbase32hexmem();
test_base64mem();
test_unbase64mem();
test_cescape();
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 42f757c4b7..271984b5a8 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -955,9 +955,10 @@ static int path_set_attribute(Item *item, const char *path) {
r = chattr_fd(fd, f, item->attribute_mask);
if (r < 0)
- return log_error_errno(r,
- "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
- path, item->attribute_value, item->attribute_mask);
+ log_full_errno(r == -ENOTTY ? LOG_DEBUG : LOG_WARNING,
+ r,
+ "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
+ path, item->attribute_value, item->attribute_mask);
return 0;
}
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index 7ba0b7fc8f..c6a2c56e77 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -409,7 +409,6 @@ int main(int argc, char *argv[])
union {
uint8_t byte[512];
uint16_t wyde[256];
- uint64_t octa[64];
} identify;
char model[41];
char model_enc[256];
@@ -638,10 +637,20 @@ int main(int argc, char *argv[])
* All other values are reserved.
*/
word = identify.wyde[108];
- if ((word & 0xf000) == 0x5000)
+ if ((word & 0xf000) == 0x5000) {
+ uint64_t wwwn;
+
+ wwwn = identify.wyde[108];
+ wwwn <<= 16;
+ wwwn |= identify.wyde[109];
+ wwwn <<= 16;
+ wwwn |= identify.wyde[110];
+ wwwn <<= 16;
+ wwwn |= identify.wyde[111];
printf("ID_WWN=0x%1$" PRIx64 "\n"
"ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n",
- identify.octa[108/4]);
+ wwwn);
+ }
/* from Linux's include/linux/ata.h */
if (identify.wyde[0] == 0x848a ||
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index b656204c46..72109d93d2 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -33,7 +33,7 @@ static sd_hwdb *hwdb;
int udev_builtin_hwdb_lookup(struct udev_device *dev,
const char *prefix, const char *modalias,
const char *filter, bool test) {
- _cleanup_free_ const char *lookup = NULL;
+ _cleanup_free_ char *lookup = NULL;
const char *key, *value;
int n = 0;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 0661f7be00..d0b8bad48e 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1358,6 +1358,7 @@ static int listen_fds(int *rctrl, int *rnetlink) {
* udev.event-timeout=<number of seconds> seconds to wait before terminating an event
*/
static int parse_proc_cmdline_item(const char *key, const char *value) {
+ const char *full_key = key;
int r;
assert(key);
@@ -1377,26 +1378,29 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
int prio;
prio = util_log_priority(value);
+ if (prio < 0)
+ goto invalid;
log_set_max_level(prio);
} else if (streq(key, "children-max")) {
r = safe_atou(value, &arg_children_max);
if (r < 0)
- log_warning("invalid udev.children-max ignored: %s", value);
+ goto invalid;
} else if (streq(key, "exec-delay")) {
r = safe_atoi(value, &arg_exec_delay);
if (r < 0)
- log_warning("invalid udev.exec-delay ignored: %s", value);
+ goto invalid;
} else if (streq(key, "event-timeout")) {
r = safe_atou64(value, &arg_event_timeout_usec);
if (r < 0)
- log_warning("invalid udev.event-timeout ignored: %s", value);
- else {
- arg_event_timeout_usec *= USEC_PER_SEC;
- arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
- }
+ goto invalid;
+ arg_event_timeout_usec *= USEC_PER_SEC;
+ arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
return 0;
+invalid:
+ log_warning("invalid %s ignored: %s", full_key, value);
+ return 0;
}
static void help(void) {
@@ -1432,7 +1436,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
int r;
switch (c) {
diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c
index ddeb310c3c..e80a7771de 100644
--- a/src/user-sessions/user-sessions.c
+++ b/src/user-sessions/user-sessions.c
@@ -65,7 +65,7 @@ int main(int argc, char*argv[]) {
} else if (streq(argv[1], "stop")) {
int r;
- r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC);
+ r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
if (r < 0) {
log_error_errno(r, "Failed to create /run/nologin: %m");
return EXIT_FAILURE;
diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
index b447b01f58..d9d51af929 100644
--- a/tmpfiles.d/systemd.conf.m4
+++ b/tmpfiles.d/systemd.conf.m4
@@ -35,7 +35,7 @@ z /var/log/journal 2755 root systemd-journal - -
z /var/log/journal/%m 2755 root systemd-journal - -
m4_ifdef(`HAVE_ACL',``
a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
-A+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
'')m4_dnl
d /var/lib/systemd 0755 root root -
diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in
index 19c33959d6..fb1f383cdc 100644
--- a/units/systemd-machined.service.in
+++ b/units/systemd-machined.service.in
@@ -15,7 +15,7 @@ After=machine.slice
[Service]
ExecStart=@rootlibexecdir@/systemd-machined
BusName=org.freedesktop.machine1
-CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
+CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID
WatchdogSec=1min
# Note that machined cannot be placed in a mount namespace, since it
diff --git a/units/systemd-networkd.service.m4.in b/units/systemd-networkd.service.m4.in
index 64d9130c24..35be713ade 100644
--- a/units/systemd-networkd.service.m4.in
+++ b/units/systemd-networkd.service.m4.in
@@ -12,7 +12,7 @@ ConditionCapability=CAP_NET_ADMIN
DefaultDependencies=no
# dbus.service can be dropped once on kdbus, and systemd-udevd.service can be
# dropped once tuntap is moved to netlink
-After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service
+After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service systemd-sysctl.service
Before=network.target multi-user.target shutdown.target
Conflicts=shutdown.target
Wants=network.target