]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #5704 from keszybz/meson
authorEvgeny Vereshchagin <evvers@ya.ru>
Tue, 25 Apr 2017 13:10:15 +0000 (16:10 +0300)
committerGitHub <noreply@github.com>
Tue, 25 Apr 2017 13:10:15 +0000 (16:10 +0300)
meson: build systemd using meson

41 files changed:
Makefile-man.am
Makefile.am
TODO
configure.ac
hwdb/70-mouse.hwdb
man/machinectl.xml
man/sd_bus_message_append.xml
man/sd_id128_randomize.xml
man/systemd.journal-fields.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.service.xml
man/systemd.unit.xml
man/udevadm.xml
src/basic/missing.h
src/core/load-fragment.c
src/core/service.c
src/fstab-generator/fstab-generator.c
src/import/pull-common.c
src/import/pull-job.c
src/import/pull-job.h
src/import/pull-raw.c
src/import/pull-tar.c
src/journal/sd-journal.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-bus/bus-convenience.c
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-message.h
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/network/netdev/geneve.c [new file with mode: 0644]
src/network/netdev/geneve.h [new file with mode: 0644]
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/networkd-network-gperf.gperf
src/network/networkd-route.c
src/network/networkd-route.h
src/shared/pager.c
src/systemd/sd-bus.h
test/test-exec-deserialization.py [new file with mode: 0755]

index d5626411a530a9dafb1dfb00c6159602efd8fef8..f43636107494b0fe79b97b8623c12c425029ae16 100644 (file)
@@ -326,6 +326,7 @@ MANPAGES_ALIAS += \
        man/sd_bus_message_append_array_space.3 \
        man/sd_bus_message_append_string_iovec.3 \
        man/sd_bus_message_append_string_space.3 \
+       man/sd_bus_message_appendv.3 \
        man/sd_bus_message_get_realtime_usec.3 \
        man/sd_bus_message_get_reply_cookie.3 \
        man/sd_bus_message_get_seqnum.3 \
@@ -685,6 +686,7 @@ man/sd_bus_message_append_array_memfd.3: man/sd_bus_message_append_array.3
 man/sd_bus_message_append_array_space.3: man/sd_bus_message_append_array.3
 man/sd_bus_message_append_string_iovec.3: man/sd_bus_message_append_string_memfd.3
 man/sd_bus_message_append_string_space.3: man/sd_bus_message_append_string_memfd.3
+man/sd_bus_message_appendv.3: man/sd_bus_message_append.3
 man/sd_bus_message_get_realtime_usec.3: man/sd_bus_message_get_monotonic_usec.3
 man/sd_bus_message_get_reply_cookie.3: man/sd_bus_message_get_cookie.3
 man/sd_bus_message_get_seqnum.3: man/sd_bus_message_get_monotonic_usec.3
@@ -1322,6 +1324,9 @@ man/sd_bus_message_append_string_iovec.html: man/sd_bus_message_append_string_me
 man/sd_bus_message_append_string_space.html: man/sd_bus_message_append_string_memfd.html
        $(html-alias)
 
+man/sd_bus_message_appendv.html: man/sd_bus_message_append.html
+       $(html-alias)
+
 man/sd_bus_message_get_realtime_usec.html: man/sd_bus_message_get_monotonic_usec.html
        $(html-alias)
 
@@ -2600,16 +2605,6 @@ man/systemd-user-sessions.html: man/systemd-user-sessions.service.html
 
 endif
 
-if HAVE_PYTHON
-MANPAGES += \
-       man/systemd.directives.7 \
-       man/systemd.index.7
-MANPAGES_ALIAS += \
-       #
-
-
-endif
-
 if HAVE_SYSV_COMPAT
 MANPAGES += \
        man/systemd-sysv-generator.8
index ea5883bf0158876b9d63847ef264fad3e0f3a7f5..8339625a622e8ca4fce699e271b5e75c6ddc6bc7 100644 (file)
@@ -5774,6 +5774,8 @@ libnetworkd_core_la_SOURCES = \
        src/network/netdev/veth.c \
        src/network/netdev/vxlan.h \
        src/network/netdev/vxlan.c \
+       src/network/netdev/geneve.h \
+       src/network/netdev/geneve.c \
        src/network/netdev/vlan.h \
        src/network/netdev/vlan.c \
        src/network/netdev/macvlan.h \
@@ -5944,7 +5946,8 @@ EXTRA_DIST += \
        src/network/systemd-networkd.pkla \
        units/systemd-networkd.service.m4.in \
        units/systemd-networkd-wait-online.service.in \
-       test/networkd-test.py
+       test/networkd-test.py \
+       test/test-exec-deserialization.py
 
 # ------------------------------------------------------------------------------
 if ENABLE_LOGIND
diff --git a/TODO b/TODO
index 3cf4ce393c6d7b832f28e0820631622c7e1f8def..bc46e33e4781db6bbe494afa4e5433e59e75605d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -24,6 +24,11 @@ Janitorial Clean-ups:
 
 Features:
 
+* add some optional flag to ReadWritePaths= and friends, that has the effect
+  that we create the dir in question when the service is started. Example:
+
+  ReadWritePaths=:/var/lib/foobar
+
 * sort generated hwdb files alphabetically when we import them, so that git
   diffs remain minimal (in particular: the OUI databases we import are not
   sorted, and not stable)
index 13e758331e0446be112eaa2029acfa6dfffe71ce..f59f3faf38459ffab7681873c0895f0c36ef904f 100644 (file)
@@ -368,6 +368,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
                 IFLA_BOND_AD_INFO,
                 IFLA_VLAN_PROTOCOL,
                 IFLA_VXLAN_GPE,
+                IFLA_GENEVE_LABEL,
                 IFLA_IPTUN_ENCAP_DPORT,
                 IFLA_GRE_ENCAP_DPORT,
                 IFLA_BRIDGE_VLAN_INFO,
index 772534f4958f9f9bd81f9f7e97a69fe12332ebe1..d49c472926a21c5fe77220eac769df955cfb5bbf 100644 (file)
@@ -243,6 +243,14 @@ mouse:usb:v093ap2510:name:PixArt USB Optical Mouse:
 mouse:usb:v093ap2510:name:PIXART USB OPTICAL MOUSE:
  MOUSE_DPI=1000@125
 
+##########################################
+# IBM
+##########################################
+
+# IBM USB Travel Mouse (MO32BO)
+mouse:usb:v04b3p3107:name:*
+ MOUSE_DPI=800@125
+
 ##########################################
 # Lenovo
 ##########################################
index 7a159aecdc782001a231c17bb6d0fc105643e358..46dcb44ca675ab4f058ca61294adf5eb8edaac81 100644 (file)
         is automatically derived from the last component of the URL,
         with its suffix removed.</para>
 
-        <para>The image is verified before it is made available,
-        unless <option>--verify=no</option> is specified. Verification
-        is done via SHA256SUMS and SHA256SUMS.gpg files that need to
-        be made available on the same web server, under the same URL
-        as the <filename>.tar</filename> file, but with the last
-        component (the filename) of the URL replaced. With
-        <option>--verify=checksum</option>, only the SHA256 checksum
-        for the file is verified, based on the
-        <filename>SHA256SUMS</filename> file. With
-        <option>--verify=signature</option>, the SHA256SUMS file is
-        first verified with detached GPG signature file
-        <filename>SHA256SUMS.gpg</filename>. The public key for this
-        verification step needs to be available in
+        <para>The image is verified before it is made available, unless
+        <option>--verify=no</option> is specified.
+        Verification is done either via an inline signed file with the name
+        of the image and the suffix <filename>.sha256</filename> or via
+        separate <filename>SHA256SUMS</filename> and
+        <filename>SHA256SUMS.gpg</filename> files.
+        The signature files need to be made available on the same web
+        server, under the same URL as the <filename>.tar</filename> file.
+        With <option>--verify=checksum</option>, only the SHA256 checksum
+        for the file is verified, based on the <filename>.sha256</filename>
+        suffixed file or the<filename>SHA256SUMS</filename> file.
+        With <option>--verify=signature</option>, the sha checksum file is
+        first verified with the inline signature in the
+        <filename>.sha256</filename> file or the detached GPG signature file
+        <filename>SHA256SUMS.gpg</filename>.
+        The public key for this verification step needs to be available in
         <filename>/usr/lib/systemd/import-pubring.gpg</filename> or
         <filename>/etc/systemd/import-pubring.gpg</filename>.</para>
 
index 132ce66434626bb836d45b86918f4a755fcf8625..2c28ee715433fb654fd741017a9eaea9f9640a5a 100644 (file)
@@ -45,6 +45,7 @@
 
   <refnamediv>
     <refname>sd_bus_message_append</refname>
+    <refname>sd_bus_message_appendv</refname>
 
     <refpurpose>Attach fields to a D-Bus message based on a type
     string</refpurpose>
         <paramdef>const char *<parameter>types</parameter></paramdef>
         <paramdef>…</paramdef>
       </funcprototype>
+
+      <funcprototype>
+          <funcdef>int sd_bus_message_appendv</funcdef>
+          <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+          <paramdef>const char *<parameter>types</parameter></paramdef>
+          <paramdef>va_list <parameter>ap</parameter></paramdef>
+      </funcprototype>
+
     </funcsynopsis>
   </refsynopsisdiv>
 
     values for each entry matching the element type of
     the dictionary entries.</para>
 
+    <para>The <function>sd_bus_message_appendv()</function> is equivalent to
+    the function <function>sd_bus_message_append()</function>,
+    except that it is called with a <literal>va_list</literal> instead of
+    a variable number of arguments. This function does not call the
+    <function>va_end()</function> macro. Because it invokes the
+    <function>va_arg()</function> macro, the value of ap
+    is undefined after the call.</para>
+
     <para>For further details on the D-Bus type system, please consult
     the <ulink
     url="http://dbus.freedesktop.org/doc/dbus-specification.html#type-system">D-Bus
@@ -238,8 +255,8 @@ sd_bus_message_append(m, "ynqiuxtd", y, n, q, i, u, x, t, d);</programlisting>
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, this call returns 0 or a positive
-    integer. On failure, this call returns a negative
+    <para>On success, these functions return 0 or a positive
+    integer. On failure, these functions return a negative
     errno-style error code.</para>
   </refsect1>
 
index ab449d29378cd6c38d9f55db2e55093a23d4d4ac..852a9fd7ebbb5ebbdac2a88e591569d3de6e7808 100644 (file)
@@ -77,7 +77,7 @@
     <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
     <para><citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
-    <option>--new-id</option> option may be used as a command line
+    <option>--new-id128</option> option may be used as a command line
     front-end for <function>sd_id128_randomize()</function>.</para>
   </refsect1>
 
index 747d985aa11deb1547818d2849ccc5fd286d6aea..b82c1300ca056e316f36bed7727d9874ede71c62 100644 (file)
@@ -87,7 +87,7 @@
           recommended to be a UUID-compatible ID, but this is not
           enforced, and formatted differently. Developers can generate
           a new ID for this purpose with <command>journalctl
-          <option>--new-id</option></command>.
+          <option>--new-id128</option></command>.
           </para>
         </listitem>
       </varlistentry>
         <listitem>
           <para>The process, user, and group ID of the process the
           journal entry originates from formatted as a decimal
-          string.</para>
+          string. Note that entries obtained via <literal>stdout</literal> or
+          <literal>stderr</literal> of forked processes will contain credentials valid for a parent
+          process (that initiated the connection to <command>systemd-journald</command>).</para>
         </listitem>
       </varlistentry>
 
index 4ec672fe51c0422c75cd62ec1089f464bd283f6e..cb2bd23f7133d2665a23f38edf6c6155b11a527b 100644 (file)
           <row><entry><varname>vxlan</varname></entry>
           <entry>A virtual extensible LAN (vxlan), for connecting Cloud computing deployments.</entry></row>
 
+          <row><entry><varname>geneve</varname></entry>
+          <entry>A GEneric NEtwork Virtualization Encapsulation (GENEVE) netdev driver.</entry></row>
+
           <row><entry><varname>vrf</varname></entry>
           <entry>A Virtual Routing and Forwarding (<ulink url="https://www.kernel.org/doc/Documentation/networking/vrf.txt">VRF</ulink>) interface to create separate routing and forwarding domains.</entry></row>
 
       </varlistentry>
     </variablelist>
   </refsect1>
+  <refsect1>
+    <title>[GENEVE] Section Options</title>
+    <para>The <literal>[GENEVE]</literal> section only applies for
+    netdevs of kind <literal>geneve</literal>, and accepts the
+    following keys:</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>Id=</varname></term>
+        <listitem>
+          <para>Specifies the Virtual Network Identifer (VNI) to use. Ranges [0-16777215].</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>Remote=</varname></term>
+        <listitem>
+          <para>Specifies the unicast destination IP address to use in outgoing packets.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>TOS=</varname></term>
+        <listitem>
+          <para>Specifies the TOS value to use in outgoing packets. Ranges [1-255]. </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>TTL=</varname></term>
+        <listitem>
+          <para>Specifies the TTL value to use in outgoing packets. Ranges [1-255]. </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDPChecksum=</varname></term>
+        <listitem>
+          <para>A boolean. When true, specifies if UDP checksum is calculated for transmitted packets over IPv4.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDP6ZeroChecksumTx=</varname></term>
+        <listitem>
+          <para>A boolean. When true, skip UDP checksum calculation for transmitted packets over IPv6.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDP6ZeroChecksumRx=</varname></term>
+        <listitem>
+          <para>A boolean. When true, allows incoming UDP packets over IPv6 with zero checksum field.</para>
+        </listitem>
+      </varlistentry>
+    <varlistentry>
+      <term><varname>DestinationPort=</varname></term>
+      <listitem>
+        <para>Specifies destination port. Defaults to 6081.</para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term><varname>FlowLabel=</varname></term>
+        <listitem>
+          <para>Specifies the flow label to use in outgoing packets.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
   <refsect1>
     <title>[Tunnel] Section Options</title>
 
index fdf7d5caaf95c92ccfb878ccdc5249ccb1b191c5..4b80578333f7073d14b863ddcfdcd7019eb70ed7 100644 (file)
             <para>The metric of the route (an unsigned integer).</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>IPv6Preference=</varname></term>
+          <listitem>
+            <para>Specifies the route preference as defined in <ulink
+            url="https://tools.ietf.org/html/rfc4191">RFC4191</ulink> for Router Discovery messages.
+            Which can be one of <literal>low</literal> the route has a lowest priority,
+            <literal>medium</literal> the route has a default priority or
+            <literal>high</literal> the route has a highest priority.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>Scope=</varname></term>
           <listitem>
index a452e3a67205a6e678769315cac292954474acda..51617f27cc73ec28815eb67c6639b3bea96ece11 100644 (file)
         multiple command lines, following the same scheme as described
         for <varname>ExecStart=</varname> above. Use of this setting
         is optional. After the commands configured in this option are
-        run, all processes remaining for a service are terminated
+        run, it is implied that the service is stopped, and any processes
+        remaining for it are terminated
         according to the <varname>KillMode=</varname> setting (see
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
         If this option is not specified, the process is terminated by
index 44841ac7dd6c732907d247e13d5c34cb31f2dbb5..68bf0b2407648fb8673d083125085dab2a3a3b4a 100644 (file)
@@ -1384,7 +1384,7 @@ WantedBy=multi-user.target</programlisting>
       ordered appropriately (<varname>After=</varname>). Thirdly, in
       order to harden the service a bit more, the administrator would
       like to set the <varname>PrivateTmp=</varname> setting (see
-      <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
       for details). And lastly, the administrator would like to reset
       the niceness of the service to its default value of 0.</para>
 
index 1c7921f5bdd853a0ba6bc78096825dc940bc06a4..8d4fe31ec1c3a3b3060818a07a454c0b7ea81538 100644 (file)
           <term><option>-s</option></term>
           <term><option>--subsystem-match=<replaceable>string[/string]</replaceable></option></term>
           <listitem>
-            <para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
+            <para>Filter kernel uevents and udev events by subsystem[/devtype]. Only events with a matching subsystem value will pass.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>-t</option></term>
           <term><option>--tag-match=<replaceable>string</replaceable></option></term>
           <listitem>
-            <para>Filter events by property. Only udev events with a given tag attached will pass.</para>
+            <para>Filter udev events by tag. Only udev events with a given tag attached will pass.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
index e860fa7c2c47f2360ce348710b934519fa27a1a9..55028754cdc0deb75f9bcccf3de183be0b1191a5 100644 (file)
@@ -759,6 +759,25 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IFLA_VXLAN_MAX  (__IFLA_VXLAN_MAX - 1)
 #endif
 
+#if !HAVE_DECL_IFLA_GENEVE_LABEL
+#define IFLA_GENEVE_UNSPEC 0
+#define IFLA_GENEVE_ID 1
+#define IFLA_GENEVE_REMOTE 2
+#define IFLA_GENEVE_TTL 3
+#define IFLA_GENEVE_TOS 4
+#define IFLA_GENEVE_PORT 5
+#define IFLA_GENEVE_COLLECT_METADATA 6
+#define IFLA_GENEVE_REMOTE6 7
+#define IFLA_GENEVE_UDP_CSUM 8
+#define IFLA_GENEVE_UDP_ZERO_CSUM6_TX 9
+#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
+#define IFLA_GENEVE_LABEL 11
+
+#define __IFLA_GENEVE_MAX 12
+
+#define IFLA_GENEVE_MAX  (__IFLA_GENEVE_MAX - 1)
+#endif
+
 #if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT
 #define IFLA_IPTUN_UNSPEC 0
 #define IFLA_IPTUN_LINK 1
index 5b7471c0d0d202b45a28c138ec9f862c8128c6c8..af3c6a46068b3a8f5d8a2ba55088a8a0b4ba7706 100644 (file)
@@ -392,7 +392,9 @@ int config_parse_socket_listen(const char *unit,
 
                 r = socket_address_parse_and_warn(&p->address, k);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
+                        if (r != -EAFNOSUPPORT)
+                                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
+
                         return 0;
                 }
 
@@ -3907,6 +3909,7 @@ int config_parse_bind_paths(
                 void *userdata) {
 
         ExecContext *c = data;
+        Unit *u = userdata;
         const char *p;
         int r;
 
@@ -3926,6 +3929,7 @@ int config_parse_bind_paths(
         p = rvalue;
         for (;;) {
                 _cleanup_free_ char *source = NULL, *destination = NULL;
+                _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
                 char *s = NULL, *d = NULL;
                 bool rbind = true, ignore_enoent = false;
 
@@ -3939,7 +3943,14 @@ int config_parse_bind_paths(
                         return 0;
                 }
 
-                s = source;
+                r = unit_full_printf(u, source, &sresolved);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
+                        return 0;
+                }
+
+                s = sresolved;
                 if (s[0] == '-') {
                         ignore_enoent = true;
                         s++;
@@ -3970,16 +3981,23 @@ int config_parse_bind_paths(
                                 return 0;
                         }
 
-                        if (!utf8_is_valid(destination)) {
-                                log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, destination);
+                        r = unit_full_printf(u, destination, &dresolved);
+                        if (r < 0) {
+                                log_syntax(unit, LOG_ERR, filename, line, r,
+                                           "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
+                                return 0;
+                        }
+
+                        if (!utf8_is_valid(dresolved)) {
+                                log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
                                 return 0;
                         }
-                        if (!path_is_absolute(destination)) {
-                                log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", destination);
+                        if (!path_is_absolute(dresolved)) {
+                                log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
                                 return 0;
                         }
 
-                        d = path_kill_slashes(destination);
+                        d = path_kill_slashes(dresolved);
 
                         /* Optionally, there's also a short option string specified */
                         if (p && p[-1] == ':') {
index 185173a5423ff3c20240bb8a49dc941b4fb44466..a63c6d8bc392425ccc738abbb41181ed037b098a 100644 (file)
@@ -45,6 +45,7 @@
 #include "service.h"
 #include "signal-util.h"
 #include "special.h"
+#include "stdio-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
@@ -2140,6 +2141,80 @@ _pure_ static bool service_can_reload(Unit *u) {
         return !!s->exec_command[SERVICE_EXEC_RELOAD];
 }
 
+static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) {
+        Service *s = SERVICE(u);
+        unsigned idx = 0;
+        ExecCommand *first, *c;
+
+        assert(s);
+
+        first = s->exec_command[id];
+
+        /* Figure out where we are in the list by walking back to the beginning */
+        for (c = current; c != first; c = c->command_prev)
+                idx++;
+
+        return idx;
+}
+
+static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command) {
+        Service *s = SERVICE(u);
+        ServiceExecCommand id;
+        unsigned idx;
+        const char *type;
+        char **arg;
+        _cleanup_strv_free_ char **escaped_args = NULL;
+        _cleanup_free_ char *args = NULL, *p = NULL;
+        size_t allocated = 0, length = 0;
+
+        assert(s);
+        assert(f);
+
+        if (!command)
+                return 0;
+
+        if (command == s->control_command) {
+                type = "control";
+                id = s->control_command_id;
+        } else {
+                type = "main";
+                id = SERVICE_EXEC_START;
+        }
+
+        idx = service_exec_command_index(u, id, command);
+
+        STRV_FOREACH(arg, command->argv) {
+                size_t n;
+                _cleanup_free_ char *e = NULL;
+
+                e = xescape(*arg, WHITESPACE);
+                if (!e)
+                        return -ENOMEM;
+
+                n = strlen(e);
+                if (!GREEDY_REALLOC(args, allocated, length + 1 + n + 1))
+                        return -ENOMEM;
+
+                if (length > 0)
+                        args[length++] = ' ';
+
+                memcpy(args + length, e, n);
+                length += n;
+        }
+
+        if (!GREEDY_REALLOC(args, allocated, length + 1))
+                return -ENOMEM;
+        args[length++] = 0;
+
+        p = xescape(command->path, WHITESPACE);
+        if (!p)
+                return -ENOMEM;
+
+        fprintf(f, "%s-command=%s %u %s %s\n", type, service_exec_command_to_string(id), idx, p, args);
+
+        return 0;
+}
+
 static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         Service *s = SERVICE(u);
         ServiceFDStore *fs;
@@ -2167,11 +2242,8 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         if (r < 0)
                 return r;
 
-        /* FIXME: There's a minor uncleanliness here: if there are
-         * multiple commands attached here, we will start from the
-         * first one again */
-        if (s->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
+        service_serialize_exec_command(u, f, s->control_command);
+        service_serialize_exec_command(u, f, s->main_command);
 
         r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
         if (r < 0)
@@ -2227,6 +2299,106 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         return 0;
 }
 
+static int service_deserialize_exec_command(Unit *u, const char *key, const char *value) {
+        Service *s = SERVICE(u);
+        int r;
+        unsigned idx = 0, i;
+        bool control, found = false;
+        ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID;
+        ExecCommand *command = NULL;
+        _cleanup_free_ char *args = NULL, *path = NULL;
+        _cleanup_strv_free_ char **argv = NULL;
+
+        enum ExecCommandState {
+                STATE_EXEC_COMMAND_TYPE,
+                STATE_EXEC_COMMAND_INDEX,
+                STATE_EXEC_COMMAND_PATH,
+                STATE_EXEC_COMMAND_ARGS,
+                _STATE_EXEC_COMMAND_MAX,
+                _STATE_EXEC_COMMAND_INVALID = -1,
+        } state;
+
+        assert(s);
+        assert(key);
+        assert(value);
+
+        control = streq(key, "control-command");
+
+        state = STATE_EXEC_COMMAND_TYPE;
+
+        for (;;) {
+                _cleanup_free_ char *arg = NULL;
+
+                r = extract_first_word(&value, &arg, NULL, EXTRACT_CUNESCAPE);
+                if (r == 0)
+                        break;
+                else if (r < 0)
+                        return r;
+
+                switch (state) {
+                case STATE_EXEC_COMMAND_TYPE:
+                        id = service_exec_command_from_string(arg);
+                        if (id < 0)
+                                return -EINVAL;
+
+                        state = STATE_EXEC_COMMAND_INDEX;
+                        break;
+                case STATE_EXEC_COMMAND_INDEX:
+                        r = safe_atou(arg, &idx);
+                        if (r < 0)
+                                return -EINVAL;
+
+                        state = STATE_EXEC_COMMAND_PATH;
+                        break;
+                case STATE_EXEC_COMMAND_PATH:
+                        path = arg;
+                        arg = NULL;
+                        state = STATE_EXEC_COMMAND_ARGS;
+
+                        if (!path_is_absolute(path))
+                                return -EINVAL;
+                        break;
+                case STATE_EXEC_COMMAND_ARGS:
+                        r = strv_extend(&argv, arg);
+                        if (r < 0)
+                                return -ENOMEM;
+                        break;
+                default:
+                        assert_not_reached("Unknown error at deserialization of exec command");
+                        break;
+                }
+        }
+
+        if (state != STATE_EXEC_COMMAND_ARGS)
+                return -EINVAL;
+
+        /* Let's check whether exec command on given offset matches data that we just deserialized */
+        for (command = s->exec_command[id], i = 0; command; command = command->command_next, i++) {
+                if (i != idx)
+                        continue;
+
+                found = strv_equal(argv, command->argv) && streq(command->path, path);
+                break;
+        }
+
+        if (!found) {
+                /* Command at the index we serialized is different, let's look for command that exactly
+                 * matches but is on different index. If there is no such command we will not resume execution. */
+                for (command = s->exec_command[id]; command; command = command->command_next)
+                        if (strv_equal(command->argv, argv) && streq(command->path, path))
+                                break;
+        }
+
+        if (command && control)
+                s->control_command = command;
+        else if (command)
+                s->main_command = command;
+        else
+                log_unit_warning(u, "Current command vanished from the unit file, execution of the command list won't be resumed.");
+
+        return 0;
+}
+
 static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
         Service *s = SERVICE(u);
         int r;
@@ -2309,16 +2481,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                         s->status_text = t;
                 }
 
-        } else if (streq(key, "control-command")) {
-                ServiceExecCommand id;
-
-                id = service_exec_command_from_string(value);
-                if (id < 0)
-                        log_unit_debug(u, "Failed to parse exec-command value: %s", value);
-                else {
-                        s->control_command_id = id;
-                        s->control_command = s->exec_command[id];
-                }
         } else if (streq(key, "accept-socket")) {
                 Unit *socket;
 
@@ -2437,6 +2599,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                         s->watchdog_override_enable = true;
                         s->watchdog_override_usec = watchdog_override_usec;
                 }
+        } else if (STR_IN_SET(key, "main-command", "control-command")) {
+                r = service_deserialize_exec_command(u, key, value);
+                if (r < 0)
+                        log_unit_debug_errno(u, r, "Failed to parse serialized command \"%s\": %m", value);
         } else
                 log_unit_debug(u, "Unknown serialization key: %s", key);
 
index 2677a3fb3212b78686efaba623303d315d310ca4..50d350fce89a59bb089e7dd9a71caf6ce36aa196 100644 (file)
@@ -358,7 +358,7 @@ static int add_mount(
                 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
                 source);
 
-        if (!noauto && !nofail && !automount)
+        if (!nofail && !automount)
                 fprintf(f, "Before=%s\n", post);
 
         if (!automount && opts) {
index 62a9195cc49dad4574340d9756ae8376b3bb3050..4c745288f57c7400cbfb2598fb067d314a4e3095 100644 (file)
@@ -275,6 +275,7 @@ int pull_make_verification_jobs(
 
         _cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL;
         int r;
+        const char *chksums = NULL;
 
         assert(ret_checksum_job);
         assert(ret_signature_job);
@@ -284,10 +285,16 @@ int pull_make_verification_jobs(
         assert(glue);
 
         if (verify != IMPORT_VERIFY_NO) {
-                _cleanup_free_ char *checksum_url = NULL;
+                _cleanup_free_ char *checksum_url = NULL, *fn = NULL;
 
-                /* Queue job for the SHA256SUMS file for the image */
-                r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url);
+                /* Queue jobs for the checksum file for the image. */
+                r = import_url_last_component(url, &fn);
+                if (r < 0)
+                        return r;
+
+                chksums = strjoina(fn, ".sha256");
+
+                r = import_url_change_last_component(url, chksums, &checksum_url);
                 if (r < 0)
                         return r;
 
@@ -362,6 +369,15 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
                    line,
                    strlen(line));
 
+        if (!p) {
+                line = strjoina(job->checksum, "  ", fn, "\n");
+
+                p = memmem(checksum_job->payload,
+                        checksum_job->payload_size,
+                        line,
+                        strlen(line));
+        }
+
         if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
                 log_error("DOWNLOAD INVALID: Checksum of %s file did not checkout, file has been tampered with.", fn);
                 return -EBADMSG;
@@ -416,6 +432,9 @@ int pull_verify(PullJob *main_job,
         if (!signature_job)
                 return 0;
 
+        if (checksum_job->style == VERIFICATION_PER_FILE)
+                signature_job = checksum_job;
+
         assert(signature_job->state == PULL_JOB_DONE);
 
         if (!signature_job->payload || signature_job->payload_size <= 0) {
@@ -507,9 +526,11 @@ int pull_verify(PullJob *main_job,
                         cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
 
                 cmd[k++] = "--verify";
-                cmd[k++] = sig_file_path;
-                cmd[k++] = "-";
-                cmd[k++] = NULL;
+                if (checksum_job->style == VERIFICATION_PER_DIRECTORY) {
+                        cmd[k++] = sig_file_path;
+                        cmd[k++] = "-";
+                        cmd[k++] = NULL;
+                }
 
                 stdio_unset_cloexec();
 
index 70aaa5c291946f8fd07e0cb1ccd97d77dea823b1..8eabb09eed2444855a52899e96a0ad1ad7790a2d 100644 (file)
@@ -29,6 +29,8 @@
 #include "string-util.h"
 #include "strv.h"
 #include "xattr-util.h"
+#include "pull-common.h"
+#include "import-util.h"
 
 PullJob* pull_job_unref(PullJob *j) {
         if (!j)
@@ -73,6 +75,33 @@ static void pull_job_finish(PullJob *j, int ret) {
                 j->on_finished(j);
 }
 
+static int pull_job_restart(PullJob *j) {
+        int r;
+        char *chksum_url = NULL;
+
+        r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url);
+        if (r < 0)
+                return r;
+
+        free(j->url);
+        free(j->payload);
+        j->url = chksum_url;
+        j->state = PULL_JOB_INIT;
+        j->payload = NULL;
+        j->payload_size = 0;
+        j->payload_allocated = 0;
+        j->written_compressed = 0;
+        j->written_uncompressed = 0;
+        j->written_since_last_grow = 0;
+
+        r = pull_job_begin(j);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+
 void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
         PullJob *j = NULL;
         CURLcode code;
@@ -102,6 +131,26 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
                 r = 0;
                 goto finish;
         } else if (status >= 300) {
+                if (status == 404 && j->style == VERIFICATION_PER_FILE) {
+
+                        /* retry pull job with SHA256SUMS file */
+                        r = pull_job_restart(j);
+                        if (r < 0)
+                                goto finish;
+
+                        code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
+                        if (code != CURLE_OK) {
+                                log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
+                                r = -EIO;
+                                goto finish;
+                        }
+
+                        if (status == 0) {
+                                j->style = VERIFICATION_PER_DIRECTORY;
+                                return;
+                        }
+                }
+
                 log_error("HTTP request to %s failed with code %li.", j->url, status);
                 r = -EIO;
                 goto finish;
@@ -528,6 +577,7 @@ int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata)
         j->content_length = (uint64_t) -1;
         j->start_usec = now(CLOCK_MONOTONIC);
         j->compressed_max = j->uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU; /* 64GB safety limit */
+        j->style = VERIFICATION_STYLE_UNSET;
 
         j->url = strdup(url);
         if (!j->url)
index 3a152a50e3e88b592ffdabecb326f17b729d33f2..412b66cf22eb41b93d6075587135b739198b5452 100644 (file)
@@ -42,6 +42,12 @@ typedef enum PullJobState {
         _PULL_JOB_STATE_INVALID = -1,
 } PullJobState;
 
+typedef enum VerificationStyle {
+        VERIFICATION_STYLE_UNSET,
+        VERIFICATION_PER_FILE,        /* SuSE-style ".sha256" files with inline signature */
+        VERIFICATION_PER_DIRECTORY,   /* Ubuntu-style SHA256SUM files with detach SHA256SUM.gpg signatures */
+} VerificationStyle;
+
 #define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
 
 struct PullJob {
@@ -94,6 +100,8 @@ struct PullJob {
 
         bool grow_machine_directory;
         uint64_t written_since_last_grow;
+
+        VerificationStyle style;
 };
 
 int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata);
index 60a769e94438724e31362f95468ab68dd337fe0a..fd2e472f092ba4df60cbb32dc77f712849861f91 100644 (file)
@@ -478,11 +478,9 @@ static void raw_pull_job_on_finished(PullJob *j) {
         } else if (j == i->settings_job) {
                 if (j->error != 0)
                         log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
-        } else if (j->error != 0) {
+        } else if (j->error != 0 && j != i->signature_job) {
                 if (j == i->checksum_job)
                         log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
-                else if (j == i->signature_job)
-                        log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
                 else
                         log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
 
@@ -500,6 +498,13 @@ static void raw_pull_job_on_finished(PullJob *j) {
         if (!raw_pull_is_done(i))
                 return;
 
+        if (i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
+                log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+
+                r = i->signature_job->error;
+                goto finish;
+        }
+
         if (i->roothash_job)
                 i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd);
         if (i->settings_job)
@@ -744,6 +749,7 @@ int raw_pull_start(
 
         if (i->checksum_job) {
                 i->checksum_job->on_progress = raw_pull_job_on_progress;
+                i->checksum_job->style = VERIFICATION_PER_FILE;
 
                 r = pull_job_begin(i->checksum_job);
                 if (r < 0)
index 91833d61747e4e1f3c3218bd3a3c99db4a653651..d4b599ba95144b7ff097dd04a07ac0d9c82e8a32 100644 (file)
@@ -298,11 +298,9 @@ static void tar_pull_job_on_finished(PullJob *j) {
         if (j == i->settings_job) {
                 if (j->error != 0)
                         log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
-        } else if (j->error != 0) {
+        } else if (j->error != 0 && j != i->signature_job) {
                 if (j == i->checksum_job)
                         log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
-                else if (j == i->signature_job)
-                        log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
                 else
                         log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
 
@@ -317,6 +315,13 @@ static void tar_pull_job_on_finished(PullJob *j) {
         if (!tar_pull_is_done(i))
                 return;
 
+        if (i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
+                log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+
+                r = i->signature_job->error;
+                goto finish;
+        }
+
         i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd);
         if (i->settings_job)
                 i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
@@ -547,6 +552,7 @@ int tar_pull_start(
 
         if (i->checksum_job) {
                 i->checksum_job->on_progress = tar_pull_job_on_progress;
+                i->checksum_job->style = VERIFICATION_PER_FILE;
 
                 r = pull_job_begin(i->checksum_job);
                 if (r < 0)
index 71967a0f3330573056a50a26eb0ada690435ae7e..86afb4985d8381ebda98a4091391fd65890e1fb3 100644 (file)
@@ -2424,6 +2424,7 @@ _public_ int sd_journal_process(sd_journal *j) {
         assert_return(!journal_pid_changed(j), -ECHILD);
 
         j->last_process_usec = now(CLOCK_MONOTONIC);
+        j->last_invalidate_counter = j->current_invalidate_counter;
 
         for (;;) {
                 union inotify_event_buffer buffer;
index c1135ffa226ec1ff52deda9055819529ebd5463a..92cb790d499fd4ad3444874461cc09498445bc9b 100644 (file)
@@ -517,3 +517,8 @@ global:
         sd_id128_get_machine_app_specific;
         sd_is_socket_sockaddr;
 } LIBSYSTEMD_232;
+
+LIBSYSTEMD_234 {
+global:
+        sd_bus_message_appendv;
+} LIBSYSTEMD_233;
index 2d06bf541f7df9a4963d499f09f062c365e9ad72..04158cae4d3ccfc718a00b403f926e5140e0f1db 100644 (file)
@@ -48,7 +48,7 @@ _public_ int sd_bus_emit_signal(
                 va_list ap;
 
                 va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
+                r = sd_bus_message_appendv(m, types, ap);
                 va_end(ap);
                 if (r < 0)
                         return r;
@@ -85,7 +85,7 @@ _public_ int sd_bus_call_method_async(
                 va_list ap;
 
                 va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
+                r = sd_bus_message_appendv(m, types, ap);
                 va_end(ap);
                 if (r < 0)
                         return r;
@@ -123,7 +123,7 @@ _public_ int sd_bus_call_method(
                 va_list ap;
 
                 va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
+                r = sd_bus_message_appendv(m, types, ap);
                 va_end(ap);
                 if (r < 0)
                         goto fail;
@@ -162,7 +162,7 @@ _public_ int sd_bus_reply_method_return(
                 va_list ap;
 
                 va_start(ap, types);
-                r = bus_message_append_ap(m, types, ap);
+                r = sd_bus_message_appendv(m, types, ap);
                 va_end(ap);
                 if (r < 0)
                         return r;
@@ -493,7 +493,7 @@ _public_ int sd_bus_set_property(
                 goto fail;
 
         va_start(ap, type);
-        r = bus_message_append_ap(m, type, ap);
+        r = sd_bus_message_appendv(m, type, ap);
         va_end(ap);
         if (r < 0)
                 goto fail;
index 5cec804e326145773e17af103802e74dedd00b16..da6fd3b89664d647a1c93a143d3efdf6f07df301 100644 (file)
@@ -2341,7 +2341,7 @@ static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const cha
         return 1;
 }
 
-int bus_message_append_ap(
+_public_ int sd_bus_message_appendv(
                 sd_bus_message *m,
                 const char *types,
                 va_list ap) {
@@ -2351,10 +2351,10 @@ int bus_message_append_ap(
         unsigned stack_ptr = 0;
         int r;
 
-        assert(m);
-
-        if (!types)
-                return 0;
+        assert_return(m, -EINVAL);
+        assert_return(types, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->poisoned, -ESTALE);
 
         n_array = (unsigned) -1;
         n_struct = strlen(types);
@@ -2555,7 +2555,7 @@ _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
         assert_return(!m->poisoned, -ESTALE);
 
         va_start(ap, types);
-        r = bus_message_append_ap(m, types, ap);
+        r = sd_bus_message_appendv(m, types, ap);
         va_end(ap);
 
         return r;
index 4710c106b95293e054396aa9df400a4bb0239809..a59aa73833c80a9ea12a4554f6769ce6e07c02be 100644 (file)
@@ -220,8 +220,6 @@ int bus_message_from_malloc(
 int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str);
 int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv);
 
-int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
-
 int bus_message_parse_fields(sd_bus_message *m);
 
 struct bus_body_part *message_append_part(sd_bus_message *m);
index fc13a4ce143b468b475d577089935925e3eea878..248bc90788e117ffbda13bd4fa04fba434c0f4c9 100644 (file)
@@ -286,6 +286,19 @@ static const NLType rtnl_link_info_data_vrf_types[] = {
         [IFLA_VRF_TABLE]                 = { .type = NETLINK_TYPE_U32 },
 };
 
+static const NLType rtnl_link_info_data_geneve_types[] = {
+        [IFLA_GENEVE_ID]                = { .type = NETLINK_TYPE_U32 },
+        [IFLA_GENEVE_TTL]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_GENEVE_TOS]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_GENEVE_PORT]              = { .type = NETLINK_TYPE_U16 },
+        [IFLA_GENEVE_REMOTE]            = { .type = NETLINK_TYPE_IN_ADDR },
+        [IFLA_GENEVE_REMOTE6]           = { .type = NETLINK_TYPE_IN_ADDR },
+        [IFLA_GENEVE_UDP_CSUM]          = { .type = NETLINK_TYPE_U8 },
+        [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 },
+        [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 },
+        [IFLA_GENEVE_LABEL]             = { .type = NETLINK_TYPE_U32 },
+};
+
 /* these strings must match the .kind entries in the kernel */
 static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
@@ -308,6 +321,7 @@ static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
         [NL_UNION_LINK_INFO_DATA_VRF] = "vrf",
         [NL_UNION_LINK_INFO_DATA_VCAN] = "vcan",
+        [NL_UNION_LINK_INFO_DATA_GENEVE] = "geneve",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
@@ -349,6 +363,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
                                                        .types = rtnl_link_info_data_ip6tnl_types },
         [NL_UNION_LINK_INFO_DATA_VRF] =              { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types),
                                                        .types = rtnl_link_info_data_vrf_types },
+        [NL_UNION_LINK_INFO_DATA_GENEVE] =           { .count = ELEMENTSOF(rtnl_link_info_data_geneve_types),
+                                                       .types = rtnl_link_info_data_geneve_types },
 };
 
 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
index 42e96173de84dd3c8b1082439bba9e71c05852ff..ae65c1d8e4fbe83d6977aac9d028a48a7f30f971 100644 (file)
@@ -88,6 +88,7 @@ typedef enum NLUnionLinkInfoData {
         NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
         NL_UNION_LINK_INFO_DATA_VRF,
         NL_UNION_LINK_INFO_DATA_VCAN,
+        NL_UNION_LINK_INFO_DATA_GENEVE,
         _NL_UNION_LINK_INFO_DATA_MAX,
         _NL_UNION_LINK_INFO_DATA_INVALID = -1
 } NLUnionLinkInfoData;
diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c
new file mode 100644 (file)
index 0000000..bb9807b
--- /dev/null
@@ -0,0 +1,394 @@
+/***
+    This file is part of systemd.
+
+    Copyright 2017 Susant Sahani
+
+    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 <net/if.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "extract-word.h"
+#include "geneve.h"
+#include "parse-util.h"
+#include "sd-netlink.h"
+#include "string-util.h"
+#include "strv.h"
+#include "missing.h"
+#include "networkd-manager.h"
+
+#define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU
+#define DEFAULT_GENEVE_DESTINATION_PORT 6081
+
+/* callback for geneve netdev's created without a backing Link */
+static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        _cleanup_netdev_unref_ NetDev *netdev = userdata;
+        int r;
+
+        assert(netdev->state != _NETDEV_STATE_INVALID);
+
+        r = sd_netlink_message_get_errno(m);
+        if (r == -EEXIST)
+                log_netdev_info(netdev, "Geneve netdev exists, using existing without changing its parameters");
+        else if (r < 0) {
+                log_netdev_warning_errno(netdev, r, "Geneve netdev could not be created: %m");
+                netdev_drop(netdev);
+
+                return 1;
+        }
+
+        log_netdev_debug(netdev, "Geneve created");
+
+        return 1;
+}
+
+static int netdev_geneve_create(NetDev *netdev) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        Geneve *v;
+        int r;
+
+        assert(netdev);
+
+        v = GENEVE(netdev);
+
+        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
+
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
+
+        if (netdev->mac) {
+                r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
+        }
+
+        if (netdev->mtu) {
+                r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
+        }
+
+        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+        r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+        if (v->id <= GENEVE_VID_MAX) {
+                r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m");
+        }
+
+        if (!in_addr_is_null(v->remote_family, &v->remote)) {
+
+                if (v->remote_family == AF_INET)
+                        r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in);
+                else
+                        r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6);
+
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_GROUP attribute: %m");
+
+        }
+
+        if (v->ttl) {
+                r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL attribute: %m");
+        }
+
+        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TOS attribute: %m");
+
+        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_CSUM attribute: %m");
+
+        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_TX attribute: %m");
+
+        r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_RX attribute: %m");
+
+        if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) {
+                r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port));
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_PORT attribute: %m");
+        }
+
+        if (v->flow_label > 0) {
+                r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label));
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_LABEL attribute: %m");
+        }
+
+        r = sd_netlink_message_close_container(m);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+        r = sd_netlink_message_close_container(m);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+        r = sd_netlink_call_async(netdev->manager->rtnl, m, geneve_netdev_create_handler, netdev, 0, NULL);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
+
+        netdev_ref(netdev);
+
+        netdev->state = NETDEV_STATE_CREATING;
+
+        log_netdev_debug(netdev, "Creating");
+
+
+        return r;
+}
+
+int config_parse_geneve_vni(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) {
+        Geneve *v = userdata;
+        uint32_t f;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou32(rvalue, &f);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve VNI '%s'.", rvalue);
+                return 0;
+        }
+
+        if (f > GENEVE_VID_MAX){
+                log_syntax(unit, LOG_ERR, filename, line, r, "Geneve VNI out is of range '%s'.", rvalue);
+                return 0;
+        }
+
+        v->id = f;
+
+        return 0;
+}
+
+int config_parse_geneve_tos(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) {
+        Geneve *v = userdata;
+        uint8_t f;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou8(rvalue, &f);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TOS '%s'.", rvalue);
+                return 0;
+        }
+
+        v->tos = f;
+
+        return 0;
+}
+
+int config_parse_geneve_ttl(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) {
+        Geneve *v = userdata;
+        uint8_t f;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou8(rvalue, &f);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TTL '%s'.", rvalue);
+                return 0;
+        }
+
+        if (f == 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Geneve TTL '%s'.", rvalue);
+                return 0;
+        }
+
+        v->ttl = f;
+
+        return 0;
+}
+
+int config_parse_geneve_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) {
+        Geneve *v = userdata;
+        union in_addr_union *addr = data, buffer;
+        int r, f;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = in_addr_from_string_auto(rvalue, &f, &buffer);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        r = in_addr_is_multicast(f, &buffer);
+        if (r > 0) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        v->remote_family = f;
+        *addr = buffer;
+
+        return 0;
+}
+
+int config_parse_geneve_destination_port(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) {
+        Geneve *v = userdata;
+        uint16_t port;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = parse_ip_port(rvalue, &port);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve destination port '%s'.", rvalue);
+                return 0;
+        }
+
+        v->dest_port = port;
+
+        return 0;
+}
+
+int config_parse_geneve_flow_label(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) {
+        Geneve *v = userdata;
+        uint32_t f;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou32(rvalue, &f);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue);
+                return 0;
+        }
+
+        if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue);
+                return 0;
+        }
+
+        v->flow_label = f;
+
+        return 0;
+}
+
+static void geneve_init(NetDev *netdev) {
+        Geneve *v;
+
+        assert(netdev);
+
+        v = GENEVE(netdev);
+
+        assert(v);
+
+        v->id = GENEVE_VID_MAX + 1;
+        v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT;
+        v->udpcsum = false;
+        v->udp6zerocsumtx = false;
+        v->udp6zerocsumrx = false;
+}
+
+const NetDevVTable geneve_vtable = {
+        .object_size = sizeof(Geneve),
+        .init = geneve_init,
+        .sections = "Match\0NetDev\0GENEVE\0",
+        .create = netdev_geneve_create,
+        .create_type = NETDEV_CREATE_INDEPENDENT,
+};
diff --git a/src/network/netdev/geneve.h b/src/network/netdev/geneve.h
new file mode 100644 (file)
index 0000000..3ba599a
--- /dev/null
@@ -0,0 +1,119 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2017 Susant Sahani
+
+  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/>.
+***/
+
+typedef struct Geneve Geneve;
+
+#include "in-addr-util.h"
+#include "netdev.h"
+#include "networkd-link.h"
+#include "networkd-network.h"
+#include "netdev.h"
+
+#define GENEVE_VID_MAX (1u << 24) - 1
+
+struct Geneve {
+        NetDev meta;
+
+        uint32_t id;
+        uint32_t flow_label;
+
+        int remote_family;
+
+        uint8_t tos;
+        uint8_t ttl;
+
+        uint16_t dest_port;
+
+        bool udpcsum;
+        bool udp6zerocsumtx;
+        bool udp6zerocsumrx;
+
+        union in_addr_union remote;
+};
+
+DEFINE_NETDEV_CAST(GENEVE, Geneve);
+extern const NetDevVTable geneve_vtable;
+
+int config_parse_geneve_vni(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_geneve_tos(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_geneve_ttl(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_geneve_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_geneve_destination_port(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_geneve_flow_label(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);
index 077fbc1d5c9156bff1eecf0dd4c17eabca585764..a27a3d5562e7f95a911960f55bd8fd44dac3841b 100644 (file)
@@ -4,6 +4,7 @@
 #include "network-internal.h"
 #include "netdev/bond.h"
 #include "netdev/bridge.h"
+#include "netdev/geneve.h"
 #include "netdev/ipvlan.h"
 #include "netdev/macvlan.h"
 #include "netdev/tunnel.h"
@@ -80,6 +81,15 @@ VXLAN.MaximumFDBEntries,     config_parse_unsigned,                0,
 VXLAN.PortRange,             config_parse_port_range,              0,                             0
 VXLAN.DestinationPort,       config_parse_destination_port,        0,                             offsetof(VxLan, dest_port)
 VXLAN.FlowLabel,             config_parse_flow_label,              0,                             0
+GENEVE.Id,                   config_parse_geneve_vni,              0,                             offsetof(Geneve, id)
+GENEVE.Remote,               config_parse_geneve_address,          0,                             offsetof(Geneve, remote)
+GENEVE.TOS,                  config_parse_geneve_tos,              0,                             offsetof(Geneve, tos)
+GENEVE.TTL,                  config_parse_geneve_ttl,              0,                             offsetof(Geneve, ttl)
+GENEVE.UDPChecksum,          config_parse_bool,                    0,                             offsetof(Geneve, udpcsum)
+GENEVE.UDP6ZeroCheckSumRx,   config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumrx)
+GENEVE.UDP6ZeroCheckSumTx,   config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumtx)
+GENEVE.DestinationPort,      config_parse_geneve_destination_port, 0,                             offsetof(Geneve, dest_port)
+GENEVE.FlowLabel,            config_parse_geneve_flow_label,       0,                             0
 Tun.OneQueue,                config_parse_bool,                    0,                             offsetof(TunTap, one_queue)
 Tun.MultiQueue,              config_parse_bool,                    0,                             offsetof(TunTap, multi_queue)
 Tun.PacketInfo,              config_parse_bool,                    0,                             offsetof(TunTap, packet_info)
index 9b9e83d9db4242751532c1a9e0ba1cb7c8c054ae..3848c863c5da77dbd067e0ede5cf26e9593dc9c4 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "netdev/bridge.h"
 #include "netdev/bond.h"
+#include "netdev/geneve.h"
 #include "netdev/vlan.h"
 #include "netdev/macvlan.h"
 #include "netdev/ipvlan.h"
@@ -69,6 +70,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
         [NETDEV_KIND_VRF] = &vrf_vtable,
         [NETDEV_KIND_VCAN] = &vcan_vtable,
+        [NETDEV_KIND_GENEVE] = &geneve_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -94,6 +96,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_IP6TNL] = "ip6tnl",
         [NETDEV_KIND_VRF] = "vrf",
         [NETDEV_KIND_VCAN] = "vcan",
+        [NETDEV_KIND_GENEVE] = "geneve",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
index 37c74312132bc0948b52c690c16ea9f377bb5533..a961e2ac3b44189c0cabca88f00213798432e662 100644 (file)
@@ -57,6 +57,7 @@ typedef enum NetDevKind {
         NETDEV_KIND_TAP,
         NETDEV_KIND_VRF,
         NETDEV_KIND_VCAN,
+        NETDEV_KIND_GENEVE,
         _NETDEV_KIND_MAX,
         _NETDEV_KIND_INVALID = -1
 } NetDevKind;
index abd921ee1aedaab225a96d0fdd6db8f8de2b6f3f..374311382527afe51b5bf681640e0c9ae498178b 100644 (file)
@@ -87,6 +87,7 @@ Route.Scope,                            config_parse_route_scope,
 Route.PreferredSource,                  config_parse_preferred_src,                     0,                             0
 Route.Table,                            config_parse_route_table,                       0,                             0
 Route.GatewayOnlink,                    config_parse_gateway_onlink,                    0,                             0
+Route.IPv6Preference,                   config_parse_ipv6_route_preference,             0,                             0
 DHCP.ClientIdentifier,                  config_parse_dhcp_client_identifier,            0,                             offsetof(Network, dhcp_client_identifier)
 DHCP.UseDNS,                            config_parse_bool,                              0,                             offsetof(Network, dhcp_use_dns)
 DHCP.UseNTP,                            config_parse_bool,                              0,                             offsetof(Network, dhcp_use_ntp)
index e2a5c77ed196853d6af0306693e09e9285dbfe8b..56f831628caa6bdf240e89c152aef9f6c494aae6 100644 (file)
@@ -17,6 +17,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <linux/icmpv6.h>
+
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "in-addr-util.h"
@@ -975,6 +977,35 @@ int config_parse_gateway_onlink(const char *unit,
                 n->flags |= RTNH_F_ONLINK;
         else
                 n->flags &= ~RTNH_F_ONLINK;
+        n = NULL;
+
+        return 0;
+}
+
+int config_parse_ipv6_route_preference(const char *unit,
+                                       const char *filename,
+                                       unsigned line,
+                                       const char *section,
+                                       unsigned section_line,
+                                       const char *lvalue,
+                                       int ltype,
+                                       const char *rvalue,
+                                       void *data,
+                                       void *userdata) {
+        Network *network = userdata;
+        _cleanup_route_free_ Route *n = NULL;
+        int r;
+
+        if (streq(rvalue, "low"))
+                n->pref = ICMPV6_ROUTER_PREF_LOW;
+        else if (streq(rvalue, "medium"))
+                n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
+        else if (streq(rvalue, "high"))
+                n->pref = ICMPV6_ROUTER_PREF_HIGH;
+        else {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
+                return 0;
+        }
 
         n = NULL;
 
index e2446b3e9210ffd2d8b97c1cd2a7a430f815b4e3..47ff6f28a097a5282f4a40151976aa264505729b 100644 (file)
@@ -76,3 +76,4 @@ int config_parse_route_priority(const char *unit, const char *filename, unsigned
 int config_parse_route_scope(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_route_table(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_gateway_onlink(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_ipv6_route_preference(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);
index c1480a718b431669d16ad672cfb52e23396e0ed2..22d7603ec69be3fa788d51d264c24e3fee435f5d 100644 (file)
@@ -53,6 +53,11 @@ noreturn static void pager_fallback(void) {
         _exit(EXIT_SUCCESS);
 }
 
+static int stored_stdout = -1;
+static int stored_stderr = -1;
+static bool stdout_redirected = false;
+static bool stderr_redirected = false;
+
 int pager_open(bool no_pager, bool jump_to_end) {
         _cleanup_close_pair_ int fd[2] = { -1, -1 };
         const char *pager;
@@ -147,10 +152,19 @@ int pager_open(bool no_pager, bool jump_to_end) {
         }
 
         /* Return in the parent */
-        if (dup2(fd[1], STDOUT_FILENO) < 0)
+        stored_stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3);
+        if (dup2(fd[1], STDOUT_FILENO) < 0) {
+                stored_stdout = safe_close(stored_stdout);
                 return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
-        if (dup2(fd[1], STDERR_FILENO) < 0)
+        }
+        stdout_redirected = true;
+
+        stored_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
+        if (dup2(fd[1], STDERR_FILENO) < 0) {
+                stored_stderr = safe_close(stored_stderr);
                 return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
+        }
+        stderr_redirected = true;
 
         return 1;
 }
@@ -161,8 +175,15 @@ void pager_close(void) {
                 return;
 
         /* Inform pager that we are done */
-        safe_fclose(stdout);
-        safe_fclose(stderr);
+        (void) fflush(stdout);
+        if (stdout_redirected && ((stored_stdout < 0) || (dup2(stored_stdout, STDOUT_FILENO) < 0)))
+                (void) close(STDOUT_FILENO);
+        stored_stdout = safe_close(stored_stdout);
+        (void) fflush(stderr);
+        if (stderr_redirected && ((stored_stderr < 0) || (dup2(stored_stderr, STDERR_FILENO) < 0)))
+                (void) close(STDERR_FILENO);
+        stored_stderr = safe_close(stored_stderr);
+        stdout_redirected = stderr_redirected = false;
 
         (void) kill(pager_pid, SIGCONT);
         (void) wait_for_terminate(pager_pid, NULL);
index c47459c9adbb1fff848623f0caccf9eee63ef53a..2b6aeb79896e6fb7b8f6e6315e537cb362a1216c 100644 (file)
@@ -266,6 +266,7 @@ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination);
 int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority);
 
 int sd_bus_message_append(sd_bus_message *m, const char *types, ...);
+int sd_bus_message_appendv(sd_bus_message *m, const char *types, va_list ap);
 int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p);
 int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size);
 int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, void **ptr);
diff --git a/test/test-exec-deserialization.py b/test/test-exec-deserialization.py
new file mode 100755 (executable)
index 0000000..b974b1c
--- /dev/null
@@ -0,0 +1,192 @@
+#!/usr/bin/python3
+
+#
+#  Copyright 2017 Michal Sekletar <msekleta@redhat.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/>.
+
+# ATTENTION: This uses the *installed* systemd, not the one from the built
+# source tree.
+
+import unittest
+import time
+import os
+import tempfile
+import subprocess
+
+from enum import Enum
+
+class UnitFileChange(Enum):
+    NO_CHANGE = 0
+    LINES_SWAPPED = 1
+    COMMAND_ADDED_BEFORE = 2
+    COMMAND_ADDED_AFTER = 3
+    COMMAND_INTERLEAVED = 4
+    REMOVAL = 5
+
+class ExecutionResumeTest(unittest.TestCase):
+    def setUp(self):
+        self.unit = 'test-issue-518.service'
+        self.unitfile_path = '/run/systemd/system/{0}'.format(self.unit)
+        self.output_file = tempfile.mktemp()
+        self.unit_files = {}
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/sleep 2
+        ExecStart=/bin/bash -c "echo foo >> {0}"
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.NO_CHANGE] = unit_file_content
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/bash -c "echo foo >> {0}"
+        ExecStart=/bin/sleep 2
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.LINES_SWAPPED] = unit_file_content
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/bash -c "echo bar >> {0}"
+        ExecStart=/bin/sleep 2
+        ExecStart=/bin/bash -c "echo foo >> {0}"
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.COMMAND_ADDED_BEFORE] = unit_file_content
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/sleep 2
+        ExecStart=/bin/bash -c "echo foo >> {0}"
+        ExecStart=/bin/bash -c "echo bar >> {0}"
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.COMMAND_ADDED_AFTER] = unit_file_content
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/bash -c "echo baz >> {0}"
+        ExecStart=/bin/sleep 2
+        ExecStart=/bin/bash -c "echo foo >> {0}"
+        ExecStart=/bin/bash -c "echo bar >> {0}"
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.COMMAND_INTERLEAVED] = unit_file_content
+
+        unit_file_content = '''
+        [Service]
+        Type=oneshot
+        ExecStart=/bin/bash -c "echo bar >> {0}"
+        ExecStart=/bin/bash -c "echo baz >> {0}"
+        '''.format(self.output_file)
+        self.unit_files[UnitFileChange.REMOVAL] = unit_file_content
+
+    def reload(self):
+        subprocess.check_call(['systemctl', 'daemon-reload'])
+
+    def write_unit_file(self, unit_file_change):
+        if not isinstance(unit_file_change, UnitFileChange):
+            raise ValueError('Unknown unit file change')
+
+        content = self.unit_files[unit_file_change]
+
+        with open(self.unitfile_path, 'w') as f:
+            f.write(content)
+
+        self.reload()
+
+    def check_output(self, expected_output):
+        try:
+            with open(self.output_file, 'r') as log:
+                output = log.read()
+        except IOError:
+            self.fail()
+
+        self.assertEqual(output, expected_output)
+
+    def setup_unit(self):
+        self.write_unit_file(UnitFileChange.NO_CHANGE)
+        subprocess.check_call(['systemctl', '--job-mode=replace', '--no-block', 'start', self.unit])
+
+    def test_no_change(self):
+        expected_output = 'foo\n'
+
+        self.setup_unit()
+        self.reload()
+        time.sleep(4)
+
+        self.check_output(expected_output)
+
+    def test_swapped(self):
+        expected_output = ''
+
+        self.setup_unit()
+        self.write_unit_file(UnitFileChange.LINES_SWAPPED)
+        self.reload()
+        time.sleep(4)
+
+        self.assertTrue(not os.path.exists(self.output_file))
+
+    def test_added_before(self):
+        expected_output = 'foo\n'
+
+        self.setup_unit()
+        self.write_unit_file(UnitFileChange.COMMAND_ADDED_BEFORE)
+        self.reload()
+        time.sleep(4)
+
+        self.check_output(expected_output)
+
+    def test_added_after(self):
+        expected_output = 'foo\nbar\n'
+
+        self.setup_unit()
+        self.write_unit_file(UnitFileChange.COMMAND_ADDED_AFTER)
+        self.reload()
+        time.sleep(4)
+
+        self.check_output(expected_output)
+
+    def test_interleaved(self):
+        expected_output = 'foo\nbar\n'
+
+        self.setup_unit()
+        self.write_unit_file(UnitFileChange.COMMAND_INTERLEAVED)
+        self.reload()
+        time.sleep(4)
+
+        self.check_output(expected_output)
+
+    def test_removal(self):
+        self.setup_unit()
+        self.write_unit_file(UnitFileChange.REMOVAL)
+        self.reload()
+        time.sleep(4)
+
+        self.assertTrue(not os.path.exists(self.output_file))
+
+    def tearDown(self):
+        for f in [self.output_file, self.unitfile_path]:
+            try:
+                os.remove(f)
+            except OSError:
+                # ignore error if log file doesn't exist
+                pass
+
+        self.reload()
+
+if __name__ == '__main__':
+    unittest.main()