[systemd-commits] 15 commits - Makefile.am Makefile-man.am man/systemd-udevd.service.xml man/udevadm.xml man/udev.conf.xml man/udev.xml src/activate src/analyze src/bootchart src/core src/cryptsetup src/delta src/getty-generator src/journal src/journal-remote src/libsystemd src/libsystemd-network src/locale src/login src/machine src/notify src/nspawn src/python-systemd src/readahead src/resolve src/resolve-host src/shared src/shutdownd src/systemctl src/sysv-generator src/test src/timesync src/udev sysusers.d/systemd.conf sysusers.d/systemd-remote.conf

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Thu Jul 31 06:02:55 PDT 2014


 Makefile-man.am                           |    2 
 Makefile.am                               |    9 
 man/systemd-udevd.service.xml             |   44 +---
 man/udev.conf.xml                         |   88 ++++++++
 man/udev.xml                              |    2 
 man/udevadm.xml                           |    1 
 src/activate/activate.c                   |    2 
 src/analyze/analyze.c                     |    1 
 src/bootchart/bootchart.c                 |   32 +-
 src/core/device.c                         |   24 +-
 src/core/load-fragment.c                  |  328 ++++++++++++++++++------------
 src/core/machine-id-setup.c               |    2 
 src/core/main.c                           |   19 +
 src/core/transaction.c                    |    2 
 src/cryptsetup/cryptsetup.c               |    6 
 src/delta/delta.c                         |   18 -
 src/getty-generator/getty-generator.c     |   12 -
 src/journal-remote/journal-remote.c       |   10 
 src/journal/cat.c                         |    2 
 src/journal/coredump.c                    |    4 
 src/journal/coredumpctl.c                 |    2 
 src/journal/journal-def.h                 |    2 
 src/journal/journal-file.h                |    2 
 src/journal/journal-internal.h            |    2 
 src/journal/journal-qrcode.h              |    2 
 src/journal/journalctl.c                  |    2 
 src/journal/journald-kmsg.c               |    2 
 src/journal/journald-server.c             |    3 
 src/journal/journald.c                    |    6 
 src/journal/sd-journal.c                  |   20 -
 src/journal/test-journal-init.c           |    2 
 src/journal/test-journal-interleaving.c   |    2 
 src/journal/test-journal-match.c          |    2 
 src/journal/test-journal-send.c           |    2 
 src/journal/test-journal-stream.c         |    2 
 src/journal/test-journal.c                |    2 
 src/libsystemd-network/network-internal.c |    6 
 src/libsystemd/sd-login/sd-login.c        |   22 --
 src/libsystemd/sd-login/test-login.c      |    2 
 src/locale/localed.c                      |   18 -
 src/login/logind-inhibit.c                |   18 -
 src/machine/machine.c                     |    6 
 src/notify/notify.c                       |    2 
 src/nspawn/nspawn.c                       |    9 
 src/python-systemd/_daemon.c              |    2 
 src/python-systemd/_journal.c             |    2 
 src/python-systemd/_reader.c              |    2 
 src/python-systemd/id128.c                |    2 
 src/readahead/readahead-collect.c         |    2 
 src/readahead/readahead-replay.c          |    2 
 src/resolve-host/resolve-host.c           |   46 ++++
 src/resolve/resolved-dns-packet.c         |  121 ++++++++++-
 src/resolve/resolved-dns-rr.c             |  136 +++++++++++-
 src/resolve/resolved-dns-rr.h             |   29 ++
 src/resolve/resolved-manager.c            |    3 
 src/shared/cgroup-util.c                  |   12 -
 src/shared/condition-util.c               |    7 
 src/shared/conf-parser.c                  |   10 
 src/shared/conf-parser.h                  |    6 
 src/shared/install.c                      |   10 
 src/shared/log.c                          |    8 
 src/shared/logs-show.h                    |    2 
 src/shared/path-util.c                    |    6 
 src/shared/sleep-config.c                 |   19 +
 src/shared/strv.c                         |   30 +-
 src/shared/strv.h                         |    2 
 src/shared/util.c                         |   83 ++++---
 src/shared/util.h                         |    4 
 src/shutdownd/shutdownd.c                 |    4 
 src/systemctl/systemctl.c                 |   13 -
 src/sysv-generator/sysv-generator.c       |   21 +
 src/test/test-daemon.c                    |    2 
 src/test/test-id128.c                     |    2 
 src/test/test-strv.c                      |   53 +++-
 src/test/test-util.c                      |   16 -
 src/timesync/timesyncd.c                  |    8 
 src/udev/net/link-config.c                |    6 
 src/udev/udev-builtin-uaccess.c           |    2 
 src/udev/udev.conf                        |    2 
 src/udev/udevd.c                          |    6 
 sysusers.d/systemd-remote.conf            |   10 
 sysusers.d/systemd.conf                   |    2 
 82 files changed, 997 insertions(+), 442 deletions(-)

New commits:
commit 0dae31d468b1a0e22d98921f7b0dbd92fd217167
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 04:19:43 2014 -0400

    resolved: LOC records
    
    LOC records have a version field. So far only version 0 has been
    published, but if a record with a different version was encountered,
    our only recourse is to treat it as an unknown type. This is
    implemented with the 'unparseable' flag, which causes the
    serialization/deserialization and printing function to cause the
    record as a blob. The flag can be used if other packet types cannot be
    parsed for whatever reason.

diff --git a/Makefile.am b/Makefile.am
index 2e982f5..94eeb11 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4775,7 +4775,8 @@ systemd_resolved_LDADD = \
 	libsystemd-network.la \
 	libsystemd-label.la \
 	libsystemd-internal.la \
-	libsystemd-shared.la
+	libsystemd-shared.la \
+	-lm
 
 rootlibexec_PROGRAMS += \
 	systemd-resolved
@@ -4863,7 +4864,8 @@ systemd_resolve_host_SOURCES = \
 
 systemd_resolve_host_LDADD = \
 	libsystemd-internal.la \
-	libsystemd-shared.la
+	libsystemd-shared.la \
+	-lm
 
 rootlibexec_PROGRAMS += \
 	systemd-resolve-host
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index f225829..fae105d 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -497,7 +497,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
         if (r < 0)
                 goto fail;
 
-        switch (rr->key->type) {
+        switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
 
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
@@ -570,10 +570,40 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_name(p, rr->mx.exchange, NULL);
                 break;
 
+        case DNS_TYPE_LOC:
+                r = dns_packet_append_uint8(p, rr->loc.version, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->loc.size, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint16(p, rr->loc.latitude, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint16(p, rr->loc.longitude, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint16(p, rr->loc.altitude, NULL);
+                break;
+
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
+        case _DNS_TYPE_INVALID: /* unparseable */
         default:
+
                 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
                 break;
         }
@@ -994,6 +1024,49 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
                 break;
 
+        case DNS_TYPE_LOC: {
+                uint8_t t;
+                size_t pos;
+
+                r = dns_packet_read_uint8(p, &t, &pos);
+                if (r < 0)
+                        goto fail;
+
+                if (t == 0) {
+                        rr->loc.version = t;
+
+                        r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        break;
+                } else {
+                        dns_packet_rewind(p, pos);
+                        rr->unparseable = true;
+                        /* fall through */
+                }
+        }
+
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 1ee93fe..b6a2c04 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -19,6 +19,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <math.h>
+
 #include "strv.h"
 
 #include "resolved-dns-domain.h"
@@ -252,6 +254,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                 case DNS_TYPE_MX:
                         free(rr->mx.exchange);
                         break;
+                case DNS_TYPE_LOC:
                 case DNS_TYPE_A:
                 case DNS_TYPE_AAAA:
                         break;
@@ -357,12 +360,54 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
 
                 return dns_name_equal(a->mx.exchange, b->mx.exchange);
 
+        case DNS_TYPE_LOC:
+                assert(a->loc.version == b->loc.version);
+
+                return a->loc.size == b->loc.size &&
+                       a->loc.horiz_pre == b->loc.horiz_pre &&
+                       a->loc.vert_pre == b->loc.vert_pre &&
+                       a->loc.latitude == b->loc.latitude &&
+                       a->loc.longitude == b->loc.longitude &&
+                       a->loc.altitude == b->loc.altitude;
+
         default:
                 return a->generic.size == b->generic.size &&
                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
         }
 }
 
+static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
+                             uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
+        char *s;
+        char NS = latitude >= 1U<<31 ? 'N' : 'S';
+        char EW = longitude >= 1U<<31 ? 'E' : 'W';
+
+        int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
+        int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
+        double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
+        double siz = (size >> 4) * exp10((double) (size & 0xF));
+        double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
+        double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
+
+        if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
+                     (lat / 60000 / 60),
+                     (lat / 60000) % 60,
+                     (lat % 60000) / 1000.,
+                     NS,
+                     (lon / 60000 / 60),
+                     (lon / 60000) % 60,
+                     (lon % 60000) / 1000.,
+                     EW,
+                     alt / 100.,
+                     siz / 100.,
+                     hor / 100.,
+                     ver / 100.) < 0)
+                return NULL;
+
+        return s;
+}
+
+
 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
         _cleanup_free_ char *k = NULL;
         char *s;
@@ -374,7 +419,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
         if (r < 0)
                 return r;
 
-        switch (rr->key->type) {
+        switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
 
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
@@ -455,6 +500,26 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
+        case DNS_TYPE_LOC: {
+                _cleanup_free_ char *loc;
+                assert(rr->loc.version == 0);
+
+                loc = format_location(rr->loc.latitude,
+                                      rr->loc.longitude,
+                                      rr->loc.altitude,
+                                      rr->loc.size,
+                                      rr->loc.horiz_pre,
+                                      rr->loc.vert_pre);
+                if (!loc)
+                        return -ENOMEM;
+
+                s = strjoin(k, " ", loc, NULL);
+                if (!s)
+                        return -ENOMEM;
+
+                break;
+        }
+
         default: {
                 _cleanup_free_ char *x = NULL;
 
@@ -513,6 +578,7 @@ static const struct {
         { DNS_TYPE_MX,    "MX"    },
         { DNS_TYPE_TXT,   "TXT"   },
         { DNS_TYPE_AAAA,  "AAAA"  },
+        { DNS_TYPE_LOC,   "LOC"   },
         { DNS_TYPE_SRV,   "SRV"   },
         { DNS_TYPE_SSHFP, "SSHFP" },
         { DNS_TYPE_SPF,   "SPF"   },
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index afd623a..8fb4639 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -51,6 +51,7 @@ enum {
         DNS_TYPE_MX    = 0x0F,
         DNS_TYPE_TXT   = 0x10,
         DNS_TYPE_AAAA  = 0x1C,
+        DNS_TYPE_LOC   = 0x1D,
         DNS_TYPE_SRV   = 0x21,
         DNS_TYPE_DNAME = 0x27,
         DNS_TYPE_SSHFP = 0x2C,
@@ -78,6 +79,7 @@ struct DnsResourceRecord {
         unsigned n_ref;
         DnsResourceKey *key;
         uint32_t ttl;
+        bool unparseable;
         union {
                 struct {
                         void *data;
@@ -126,6 +128,16 @@ struct DnsResourceRecord {
                         uint16_t priority;
                         char *exchange;
                 } mx;
+
+                struct {
+                        uint8_t version;
+                        uint8_t size;
+                        uint8_t horiz_pre;
+                        uint8_t vert_pre;
+                        uint32_t latitude;
+                        uint32_t longitude;
+                        uint32_t altitude;
+                } loc;
         };
 };
 

commit 9de3e3294065e8697ff10130b53f274319cdcf6f
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 21:47:51 2014 -0400

    resolved: SPF records

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 3d64c27..f225829 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -513,6 +513,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
                 break;
 
+        case DNS_TYPE_SPF: /* exactly the same as TXT */
         case DNS_TYPE_TXT: {
                 char **s;
 
@@ -933,6 +934,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
                 break;
 
+        case DNS_TYPE_SPF: /* exactly the same as TXT */
         case DNS_TYPE_TXT: {
                 char *s;
 
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 9131b4b..1ee93fe 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -231,20 +231,33 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
         }
 
         if (rr->key) {
-                if (IN_SET(rr->key->type, DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME))
+                switch(rr->key->type) {
+                case DNS_TYPE_PTR:
+                case DNS_TYPE_NS:
+                case DNS_TYPE_CNAME:
                         free(rr->ptr.name);
-                else if (rr->key->type == DNS_TYPE_HINFO) {
+                        break;
+                case DNS_TYPE_HINFO:
                         free(rr->hinfo.cpu);
                         free(rr->hinfo.os);
-                } else if (rr->key->type == DNS_TYPE_TXT) {
+                        break;
+                case DNS_TYPE_SPF:
+                case DNS_TYPE_TXT:
                         strv_free(rr->txt.strings);
-                } else if (rr->key->type == DNS_TYPE_SOA) {
+                        break;
+                case DNS_TYPE_SOA:
                         free(rr->soa.mname);
                         free(rr->soa.rname);
-                } else if (rr->key->type == DNS_TYPE_MX) {
+                        break;
+                case DNS_TYPE_MX:
                         free(rr->mx.exchange);
-                } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
+                        break;
+                case DNS_TYPE_A:
+                case DNS_TYPE_AAAA:
+                        break;
+                default:
                         free(rr->generic.data);
+                }
 
                 dns_resource_key_unref(rr->key);
         }
@@ -309,6 +322,7 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
                        strcaseeq(a->hinfo.os, b->hinfo.os);
 
+        case DNS_TYPE_SPF: /* exactly the same as TXT */
         case DNS_TYPE_TXT: {
                 int i;
 
@@ -377,6 +391,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
+        case DNS_TYPE_SPF: /* exactly the same as TXT */
         case DNS_TYPE_TXT: {
                 _cleanup_free_ char *t;
 
@@ -500,6 +515,7 @@ static const struct {
         { DNS_TYPE_AAAA,  "AAAA"  },
         { DNS_TYPE_SRV,   "SRV"   },
         { DNS_TYPE_SSHFP, "SSHFP" },
+        { DNS_TYPE_SPF,   "SPF"   },
         { DNS_TYPE_DNAME, "DNAME" },
         { DNS_TYPE_ANY,   "ANY"   },
         { DNS_TYPE_OPT,   "OPT"   },
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 92ffeab..afd623a 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -55,6 +55,8 @@ enum {
         DNS_TYPE_DNAME = 0x27,
         DNS_TYPE_SSHFP = 0x2C,
 
+        DNS_TYPE_SPF   = 0x63,
+
         /* Special records */
         DNS_TYPE_ANY   = 0xFF,
         DNS_TYPE_OPT   = 0x29,      /* EDNS0 option */

commit 2e276efc7b0398a3086629a52970bdd4ab7252f9
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 21:36:58 2014 -0400

    resolved: TXT records

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 217bdaf..3d64c27 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -21,6 +21,7 @@
 
 #include "utf8.h"
 #include "util.h"
+#include "strv.h"
 #include "resolved-dns-domain.h"
 #include "resolved-dns-packet.h"
 
@@ -512,6 +513,18 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
                 break;
 
+        case DNS_TYPE_TXT: {
+                char **s;
+
+                STRV_FOREACH(s, rr->txt.strings) {
+                        r = dns_packet_append_string(p, *s, NULL);
+                        if (r < 0)
+                                goto fail;
+                }
+
+                break;
+        }
+
         case DNS_TYPE_A:
                 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
                 break;
@@ -556,7 +569,6 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_name(p, rr->mx.exchange, NULL);
                 break;
 
-        case DNS_TYPE_TXT:
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
@@ -921,6 +933,21 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
                 break;
 
+        case DNS_TYPE_TXT: {
+                char *s;
+
+                while (p->rindex < p->size) {
+                        r = dns_packet_read_string(p, &s, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        r = strv_consume(&rr->txt.strings, s);
+                        if (r < 0)
+                                goto fail;
+                };
+                break;
+        }
+
         case DNS_TYPE_A:
                 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
                 break;
@@ -965,7 +992,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
                 break;
 
-        case DNS_TYPE_TXT:
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 2e13b9c..9131b4b 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -19,6 +19,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "strv.h"
+
 #include "resolved-dns-domain.h"
 #include "resolved-dns-rr.h"
 
@@ -234,6 +236,8 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                 else if (rr->key->type == DNS_TYPE_HINFO) {
                         free(rr->hinfo.cpu);
                         free(rr->hinfo.os);
+                } else if (rr->key->type == DNS_TYPE_TXT) {
+                        strv_free(rr->txt.strings);
                 } else if (rr->key->type == DNS_TYPE_SOA) {
                         free(rr->soa.mname);
                         free(rr->soa.rname);
@@ -305,6 +309,15 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
                        strcaseeq(a->hinfo.os, b->hinfo.os);
 
+        case DNS_TYPE_TXT: {
+                int i;
+
+                for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
+                        if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
+                                return false;
+                return true;
+        }
+
         case DNS_TYPE_A:
                 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
 
@@ -364,6 +377,20 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
+        case DNS_TYPE_TXT: {
+                _cleanup_free_ char *t;
+
+                t = strv_join_quoted(rr->txt.strings);
+                if (!t)
+                        return -ENOMEM;
+
+                s = strjoin(k, " ", t, NULL);
+                if (!s)
+                        return -ENOMEM;
+
+                break;
+        }
+
         case DNS_TYPE_A: {
                 _cleanup_free_ char *x = NULL;
 
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 359d662..92ffeab 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -98,9 +98,9 @@ struct DnsResourceRecord {
                         char *os;
                 } hinfo;
 
-                /* struct { */
-                /*         char **list; */
-                /* } txt; */
+                struct {
+                        char **strings;
+                } txt;
 
                 struct {
                         struct in_addr in_addr;

commit 946c70944ebdf428ffeb9991a7449edbd4011461
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 21:06:00 2014 -0400

    resolved: MX records

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 3e6c9a4..217bdaf 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -549,6 +549,13 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 break;
 
         case DNS_TYPE_MX:
+                r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_name(p, rr->mx.exchange, NULL);
+                break;
+
         case DNS_TYPE_TXT:
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
@@ -951,6 +958,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 break;
 
         case DNS_TYPE_MX:
+                r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
+                break;
+
         case DNS_TYPE_TXT:
         case DNS_TYPE_SRV:
         case DNS_TYPE_DNAME:
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index e1200c9..2e13b9c 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -237,6 +237,8 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                 } else if (rr->key->type == DNS_TYPE_SOA) {
                         free(rr->soa.mname);
                         free(rr->soa.rname);
+                } else if (rr->key->type == DNS_TYPE_MX) {
+                        free(rr->mx.exchange);
                 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
                         free(rr->generic.data);
 
@@ -322,6 +324,12 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                        a->soa.retry   == b->soa.retry &&
                        a->soa.expire  == b->soa.expire &&
                        a->soa.minimum == b->soa.minimum;
+        case DNS_TYPE_MX:
+                if (a->mx.priority != b->mx.priority)
+                        return 0;
+
+                return dns_name_equal(a->mx.exchange, b->mx.exchange);
+
         default:
                 return a->generic.size == b->generic.size &&
                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@@ -396,6 +404,15 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
+        case DNS_TYPE_MX:
+                r = asprintf(&s, "%s %u %s",
+                             k,
+                             rr->mx.priority,
+                             rr->mx.exchange);
+                if (r < 0)
+                        return -ENOMEM;
+                break;
+
         default: {
                 _cleanup_free_ char *x = NULL;
 
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 7b73cdc..359d662 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -119,6 +119,11 @@ struct DnsResourceRecord {
                         uint32_t expire;
                         uint32_t minimum;
                 } soa;
+
+                struct {
+                        uint16_t priority;
+                        char *exchange;
+                } mx;
         };
 };
 

commit b93312f5960b276bae915906ccde36f545bae3e0
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 20:06:30 2014 -0400

    resolve-host: list types and classes
    
    Also update systemctl to similar style.

diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 1b1edaf..1063790 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -39,6 +39,7 @@ static int arg_family = AF_UNSPEC;
 static int arg_ifindex = 0;
 static uint16_t arg_type = 0;
 static uint16_t arg_class = 0;
+static bool arg_legend = true;
 
 static int resolve_host(sd_bus *bus, const char *name) {
 
@@ -387,6 +388,32 @@ static int resolve_record(sd_bus *bus, const char *name) {
         return 0;
 }
 
+static void help_dns_types(void) {
+        int i;
+        const char *t;
+
+        if (arg_legend)
+                puts("Known dns types:");
+        for (i = 0; i < _DNS_TYPE_MAX; i++) {
+                t = dns_type_to_string(i);
+                if (t)
+                        puts(t);
+        }
+}
+
+static void help_dns_classes(void) {
+        int i;
+        const char *t;
+
+        if (arg_legend)
+                puts("Known dns classes:");
+        for (i = 0; i < _DNS_CLASS_MAX; i++) {
+                t = dns_class_to_string(i);
+                if (t)
+                        puts(t);
+        }
+}
+
 static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Resolve IPv4 or IPv6 addresses.\n\n"
@@ -397,12 +424,14 @@ static void help(void) {
                "  -i INTERFACE          Filter by interface\n"
                "  -t --type=TYPE        Query RR with DNS type\n"
                "  -c --class=CLASS      Query RR with DNS class\n"
+               "  --no-legend           Do not print column headers\n"
                , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_VERSION = 0x100,
+                ARG_NO_LEGEND,
         };
 
         static const struct option options[] = {
@@ -410,6 +439,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",     no_argument,       NULL, ARG_VERSION   },
                 { "type",        no_argument,       NULL, 't'           },
                 { "class",       no_argument,       NULL, 'c'           },
+                { "no-legend",   no_argument,       NULL, ARG_NO_LEGEND },
                 {}
         };
 
@@ -447,19 +477,35 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case 't':
+                        if (streq(optarg, "help")) {
+                                help_dns_types();
+                                return 0;
+                        }
+
                         r = dns_type_from_string(optarg, &arg_type);
                         if (r < 0) {
                                 log_error("Failed to parse RR record type %s", optarg);
                                 return r;
                         }
+
                         break;
 
                 case 'c':
+                        if (streq(optarg, "help")) {
+                                help_dns_classes();
+                                return 0;
+                        }
+
                         r = dns_class_from_string(optarg, &arg_class);
                         if (r < 0) {
                                 log_error("Failed to parse RR record class %s", optarg);
                                 return r;
                         }
+
+                        break;
+
+                case ARG_NO_LEGEND:
+                        arg_legend = false;
                         break;
 
                 case '?':
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 5246300..7b73cdc 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -35,6 +35,8 @@ typedef struct DnsResourceRecord DnsResourceRecord;
 enum {
         DNS_CLASS_IN   = 0x01,
         DNS_CLASS_ANY  = 0xFF,
+        _DNS_CLASS_MAX,
+        _DNS_CLASS_INVALID = -1
 };
 
 /* DNS record types, see RFC 1035 */
@@ -60,6 +62,8 @@ enum {
         DNS_TYPE_TSIG  = 0xFA,
         DNS_TYPE_IXFR  = 0xFB,
         DNS_TYPE_AXFR  = 0xFC,
+        _DNS_TYPE_MAX,
+        _DNS_TYPE_INVALID = -1
 };
 
 struct DnsResourceKey {
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 21e33d5..8ec0db2 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -5627,18 +5627,17 @@ static int runlevel_help(void) {
         return 0;
 }
 
-static int help_types(void) {
+static void help_types(void) {
         int i;
         const char *t;
 
-        puts("Available unit types:");
+        if (!arg_no_legend)
+                puts("Available unit types:");
         for (i = 0; i < _UNIT_TYPE_MAX; i++) {
                 t = unit_type_to_string(i);
                 if (t)
                         puts(t);
         }
-
-        return 0;
 }
 
 static int systemctl_parse_argv(int argc, char *argv[]) {

commit 73f860db9893deab6aebceb53dd7d0deb662e832
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 04:15:29 2014 -0400

    Always prefer our headers to system headers
    
    In practice this shouldn't make much difference, but
    sometimes our headers might be newer, and we want to
    test them.

diff --git a/src/activate/activate.c b/src/activate/activate.c
index 8c58273..c3309a8 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -27,7 +27,7 @@
 #include <sys/wait.h>
 #include <getopt.h>
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 
 #include "socket-util.h"
 #include "build.h"
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 692cbb9..0ae72c2 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -48,7 +48,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "util.h"
 #include "fileio.h"
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index f154800..712f60c 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -27,7 +27,7 @@
 #include <fcntl.h>
 #include <sys/mount.h>
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 #include "machine-id-setup.h"
 #include "macro.h"
diff --git a/src/journal/cat.c b/src/journal/cat.c
index 60625cb..a525bcf 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -27,7 +27,7 @@
 #include <errno.h>
 #include <fcntl.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "util.h"
 #include "build.h"
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index fee0a90..db51098 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -26,8 +26,8 @@
 #include <sys/types.h>
 #include <sys/xattr.h>
 
-#include <systemd/sd-journal.h>
-#include <systemd/sd-login.h>
+#include "systemd/sd-journal.h"
+#include "systemd/sd-login.h"
 
 #include "log.h"
 #include "util.h"
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index e5f4d45..2bc9021 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -26,7 +26,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "build.h"
 #include "set.h"
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 089dd98..e55fa19 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -23,7 +23,7 @@
 
 #include "sparse-endian.h"
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 #include "macro.h"
 
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index b0c28b5..6703b93 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -27,7 +27,7 @@
 #include <gcrypt.h>
 #endif
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 #include "sparse-endian.h"
 #include "journal-def.h"
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index 2c401e3..2f1f7fc 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -25,7 +25,7 @@
 #include <inttypes.h>
 #include <stdbool.h>
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 #include "journal-def.h"
 #include "list.h"
diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h
index da6244c..c527e65 100644
--- a/src/journal/journal-qrcode.h
+++ b/src/journal/journal-qrcode.h
@@ -25,6 +25,6 @@
 #include <sys/types.h>
 #include <stdio.h>
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 78495f8..52fd8be 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -40,7 +40,7 @@
 #include "acl-util.h"
 #endif
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "log.h"
 #include "logs-show.h"
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index bb62a76..9935986 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -25,7 +25,7 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 
-#include <systemd/sd-messages.h>
+#include "systemd/sd-messages.h"
 #include <libudev.h>
 
 #include "journald-server.h"
diff --git a/src/journal/journald.c b/src/journal/journald.c
index d6b235c..b1a0e25 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -24,9 +24,9 @@
 #include <errno.h>
 #include <unistd.h>
 
-#include <systemd/sd-journal.h>
-#include <systemd/sd-messages.h>
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-journal.h"
+#include "systemd/sd-messages.h"
+#include "systemd/sd-daemon.h"
 
 #include "journal-authenticate.h"
 #include "journald-server.h"
diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c
index 58f260d..ada2f6c 100644
--- a/src/journal/test-journal-init.c
+++ b/src/journal/test-journal-init.c
@@ -19,7 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "log.h"
 #include "util.h"
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 5c96044..6c5995e 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -23,7 +23,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "journal-file.h"
 #include "journal-internal.h"
diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c
index 37bffc1..a318705 100644
--- a/src/journal/test-journal-match.c
+++ b/src/journal/test-journal-match.c
@@ -21,7 +21,7 @@
 
 #include <stdio.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "journal-internal.h"
 #include "util.h"
diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c
index 45eb327..81ca47e 100644
--- a/src/journal/test-journal-send.c
+++ b/src/journal/test-journal-send.c
@@ -19,7 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 #include <stdlib.h>
 #include <unistd.h>
 
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index 8e1d08d..8ccd813 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -22,7 +22,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "journal-file.h"
 #include "journal-internal.h"
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 85b4cf7..6025d04 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -22,7 +22,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "log.h"
 #include "journal-file.h"
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index ccf2c95..28f88a1 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -22,7 +22,7 @@
 #include <sys/poll.h>
 #include <string.h>
 
-#include <systemd/sd-login.h>
+#include "systemd/sd-login.h"
 
 #include "util.h"
 #include "strv.h"
diff --git a/src/notify/notify.c b/src/notify/notify.c
index 0b7f3b1..f463c4d 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -27,7 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 
 #include "strv.h"
 #include "util.h"
diff --git a/src/python-systemd/_daemon.c b/src/python-systemd/_daemon.c
index 7756a78..65cfec7 100644
--- a/src/python-systemd/_daemon.c
+++ b/src/python-systemd/_daemon.c
@@ -29,7 +29,7 @@
 #include <assert.h>
 #include <sys/socket.h>
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 #include "pyutil.h"
 #include "macro.h"
 
diff --git a/src/python-systemd/_journal.c b/src/python-systemd/_journal.c
index cbc661d..456e4a2 100644
--- a/src/python-systemd/_journal.c
+++ b/src/python-systemd/_journal.c
@@ -25,7 +25,7 @@
 #include "util.h"
 
 #define SD_JOURNAL_SUPPRESS_LOCATION
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 PyDoc_STRVAR(journal_sendv__doc__,
              "sendv('FIELD=value', 'FIELD=value', ...) -> None\n\n"
diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c
index 9a19a10..d17aa83 100644
--- a/src/python-systemd/_reader.c
+++ b/src/python-systemd/_reader.c
@@ -25,7 +25,7 @@
 #include <time.h>
 #include <stdio.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "pyutil.h"
 #include "macro.h"
diff --git a/src/python-systemd/id128.c b/src/python-systemd/id128.c
index 6dadf7b..5ec7309 100644
--- a/src/python-systemd/id128.c
+++ b/src/python-systemd/id128.c
@@ -21,7 +21,7 @@
 
 #include <Python.h>
 
-#include <systemd/sd-messages.h>
+#include "systemd/sd-messages.h"
 
 #include "pyutil.h"
 #include "log.h"
diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
index c1afd0d..1592cc8 100644
--- a/src/readahead/readahead-collect.c
+++ b/src/readahead/readahead-collect.c
@@ -52,7 +52,7 @@
 #include <sys/fanotify.h>
 #endif
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 
 #include "missing.h"
 #include "util.h"
diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c
index f46dc3b..f81e0fe 100644
--- a/src/readahead/readahead-replay.c
+++ b/src/readahead/readahead-replay.c
@@ -35,7 +35,7 @@
 #include <getopt.h>
 #include <sys/inotify.h>
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 
 #include "missing.h"
 #include "util.h"
diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c
index b52dcc5..ff4a8ec 100644
--- a/src/shared/condition-util.c
+++ b/src/shared/condition-util.c
@@ -26,7 +26,7 @@
 #include <sys/statvfs.h>
 #include <fnmatch.h>
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 #include "util.h"
 #include "condition-util.h"
 #include "virt.h"
diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h
index 3a99160..187ee59 100644
--- a/src/shared/logs-show.h
+++ b/src/shared/logs-show.h
@@ -25,7 +25,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 
-#include <systemd/sd-journal.h>
+#include "systemd/sd-journal.h"
 
 #include "util.h"
 #include "output-mode.h"
diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c
index 25427d6..9290749 100644
--- a/src/shutdownd/shutdownd.c
+++ b/src/shutdownd/shutdownd.c
@@ -30,8 +30,8 @@
 #include <fcntl.h>
 #include <stddef.h>
 
-#include <systemd/sd-daemon.h>
-#include <systemd/sd-shutdown.h>
+#include "systemd/sd-daemon.h"
+#include "systemd/sd-shutdown.h"
 
 #include "log.h"
 #include "macro.h"
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
index 3215f0c..bcc049b 100644
--- a/src/test/test-daemon.c
+++ b/src/test/test-daemon.c
@@ -21,7 +21,7 @@
 
 #include <unistd.h>
 
-#include <systemd/sd-daemon.h>
+#include "systemd/sd-daemon.h"
 
 int main(int argc, char*argv[]) {
 
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 7b92758..a6a0cd7 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -21,7 +21,7 @@
 
 #include <string.h>
 
-#include <systemd/sd-id128.h>
+#include "systemd/sd-id128.h"
 
 #include "util.h"
 #include "macro.h"
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index e2b276e..6964fb5 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -29,7 +29,7 @@
 #include <dirent.h>
 #include <getopt.h>
 
-#include <systemd/sd-login.h>
+#include "systemd/sd-login.h"
 #include "logind-acl.h"
 #include "udev.h"
 #include "util.h"

commit 5d459d6b07206963a022e9a95ea9d8c18dc0eab8
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jul 30 15:38:54 2014 -0400

    Constify option table and add missing option

diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 453ad33..888f6b7 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -1244,6 +1244,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "to-pattern",   required_argument, NULL, ARG_DOT_TO_PATTERN   },
                 { "fuzz",         required_argument, NULL, ARG_FUZZ             },
                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER         },
+                { "no-man",       no_argument,       NULL, ARG_NO_MAN           },
                 { "host",         required_argument, NULL, 'H'                  },
                 { "machine",      required_argument, NULL, 'M'                  },
                 {}
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index cbfc28d..692cbb9 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -164,21 +164,21 @@ static void help(void) {
 }
 
 static int parse_args(int argc, char *argv[]) {
-        static struct option options[] = {
-                {"rel",       no_argument,        NULL,  'r'},
-                {"freq",      required_argument,  NULL,  'f'},
-                {"samples",   required_argument,  NULL,  'n'},
-                {"pss",       no_argument,        NULL,  'p'},
-                {"output",    required_argument,  NULL,  'o'},
-                {"init",      required_argument,  NULL,  'i'},
-                {"no-filter", no_argument,        NULL,  'F'},
-                {"cmdline",   no_argument,        NULL,  'C'},
-                {"control-group", no_argument,    NULL,  'c'},
-                {"help",      no_argument,        NULL,  'h'},
-                {"scale-x",   required_argument,  NULL,  'x'},
-                {"scale-y",   required_argument,  NULL,  'y'},
-                {"entropy",   no_argument,        NULL,  'e'},
-                {NULL, 0, NULL, 0}
+        static const struct option options[] = {
+                {"rel",           no_argument,        NULL,  'r'},
+                {"freq",          required_argument,  NULL,  'f'},
+                {"samples",       required_argument,  NULL,  'n'},
+                {"pss",           no_argument,        NULL,  'p'},
+                {"output",        required_argument,  NULL,  'o'},
+                {"init",          required_argument,  NULL,  'i'},
+                {"no-filter",     no_argument,        NULL,  'F'},
+                {"cmdline",       no_argument,        NULL,  'C'},
+                {"control-group", no_argument,        NULL,  'c'},
+                {"help",          no_argument,        NULL,  'h'},
+                {"scale-x",       required_argument,  NULL,  'x'},
+                {"scale-y",       required_argument,  NULL,  'y'},
+                {"entropy",       no_argument,        NULL,  'e'},
+                {}
         };
         int c;
 

commit 6fc5a40438dee0972cf1dedca9d4fd1c257c8f91
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 04:01:19 2014 -0400

    man: add udev.conf(5)
    
    We generally have separate man pages for all configuration files.
    In this case udev.conf was already described in systemd-udevd.service(8),
    but it was hard to find. Docbook makes it hard to add a .so link from
    a different section, so describe udev.conf in its own page.

diff --git a/Makefile-man.am b/Makefile-man.am
index 4339e50..c790946 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -118,6 +118,7 @@ MANPAGES += \
 	man/telinit.8 \
 	man/tmpfiles.d.5 \
 	man/udev.7 \
+	man/udev.conf.5 \
 	man/udevadm.8
 MANPAGES_ALIAS += \
 	man/SD_ALERT.3 \
@@ -1688,6 +1689,7 @@ EXTRA_DIST += \
 	man/telinit.xml \
 	man/timedatectl.xml \
 	man/tmpfiles.d.xml \
+	man/udev.conf.xml \
 	man/udev.xml \
 	man/udevadm.xml \
 	man/user-system-options.xml \
diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml
index 3053dc7..049a440 100644
--- a/man/systemd-udevd.service.xml
+++ b/man/systemd-udevd.service.xml
@@ -22,7 +22,6 @@
   <refmeta>
     <refentrytitle>systemd-udevd.service</refentrytitle>
     <manvolnum>8</manvolnum>
-    <refmiscinfo class="version"></refmiscinfo>
   </refmeta>
 
   <refnamediv>
@@ -54,12 +53,16 @@
 
   <refsect1><title>Description</title>
     <para><command>systemd-udevd</command> listens to kernel uevents.
-      For every event, systemd-udevd executes matching instructions
-      specified in udev rules. See <citerefentry>
-      <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
-      </citerefentry>.</para>
-    <para>The behavior of the running daemon can be changed with
-    <command>udevadm control</command>.</para>
+    For every event, systemd-udevd executes matching instructions
+    specified in udev rules. See <citerefentry>
+    <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
+    </citerefentry>.</para>
+
+    <para>The behavior of the running daemon can be changed
+    dynamically with <command>udevadm control</command>, or
+    configured using
+    <citerefentry><refentrytitle>udev.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    </para>
   </refsect1>
 
   <refsect1><title>Options</title>
@@ -185,29 +188,12 @@
          in kernel-command-line.xml -->
  </refsect1>
 
- <refsect1><title>Configuration file</title>
-   <para>udev expects its main configuration file at <filename>/etc/udev/udev.conf</filename>.
-   It consists of a set of variables allowing the user to override default udev values. All
-   empty lines or lines beginning with '#' are ignored. The following variables can be
-   set:</para>
-   <variablelist>
-     <varlistentry>
-       <term><varname>udev_log</varname></term>
-       <listitem>
-         <para>The logging priority. Valid values are the numerical syslog priorities
-         or their textual representations: <option>err</option>, <option>info</option>
-         and <option>debug</option>.</para>
-       </listitem>
-     </varlistentry>
-   </variablelist>
- </refsect1>
-
   <refsect1>
     <title>See Also</title>
-    <para><citerefentry>
-        <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
-      </citerefentry>, <citerefentry>
-        <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
-    </citerefentry></para>
+    <para>
+      <citerefentry><refentrytitle>udev.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    </para>
   </refsect1>
 </refentry>
diff --git a/man/udev.conf.xml b/man/udev.conf.xml
new file mode 100644
index 0000000..de84b91
--- /dev/null
+++ b/man/udev.conf.xml
@@ -0,0 +1,88 @@
+<?xml version='1.0'?>
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Zbigniew Jędrzejewski-Szmek
+
+  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/>.
+-->
+
+<refentry id="udev.conf"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>udev.conf</title>
+    <productname>systemd</productname>
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Kay</firstname>
+        <surname>Sievers</surname>
+        <email>kay at vrfy.org</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>udev.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>udev.conf</refname>
+    <refpurpose>Configuration for device event managing daemon</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/udev/udev.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd-udevd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      expects its main configuration file at
+      <filename>/etc/udev/udev.conf</filename>. It consists of a set
+      of variables allowing the user to override default udev
+      values. All empty lines or lines beginning with '#' are
+      ignored. The following variables can be set:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>udev_log</varname></term>
+
+          <listitem>
+            <para>The logging priority. Valid values are the numerical
+            syslog priorities or their textual representations:
+            <option>err</option>, <option>info</option> and
+            <option>debug</option>.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd-udevd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
diff --git a/man/udevadm.xml b/man/udevadm.xml
index fbfa85a..749144d 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -20,7 +20,6 @@
   <refmeta>
     <refentrytitle>udevadm</refentrytitle>
     <manvolnum>8</manvolnum>
-    <refmiscinfo class="version"></refmiscinfo>
   </refmeta>
 
   <refnamediv>
diff --git a/src/udev/udev.conf b/src/udev/udev.conf
index f39253e..47d1433 100644
--- a/src/udev/udev.conf
+++ b/src/udev/udev.conf
@@ -1,3 +1,3 @@
-# see udev(7) for details
+# see udev.conf(5) for details
 
 #udev_log="info"

commit 2b09983f94feeb04abde32e54a50fe80fc44b397
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 04:01:01 2014 -0400

    man: add missing comma

diff --git a/man/udev.xml b/man/udev.xml
index 123c073..db72937 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -763,7 +763,7 @@
       </citerefentry>,
       <citerefentry>
         <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>
+      </citerefentry>,
       <citerefentry>
         <refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum>
       </citerefentry>

commit a4892054059c483a695e4250713b5ed8948a1c2f
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 03:45:05 2014 -0400

    sysusers: split users for remote into separate file
    
    This mirrors the setup for tmpfiles.d done in ad95fd1d2b9.

diff --git a/Makefile.am b/Makefile.am
index bc16ce3..2e982f5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1936,7 +1936,8 @@ SYSINIT_TARGET_WANTS += \
 	systemd-sysusers.service
 
 dist_sysusers_DATA = \
-	sysusers.d/systemd.conf
+	sysusers.d/systemd.conf \
+	sysusers.d/systemd-remote.conf
 
 nodist_sysusers_DATA = \
 	sysusers.d/basic.conf
diff --git a/sysusers.d/systemd-remote.conf b/sysusers.d/systemd-remote.conf
new file mode 100644
index 0000000..c03b862
--- /dev/null
+++ b/sysusers.d/systemd-remote.conf
@@ -0,0 +1,10 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+u systemd-journal-gateway       -               "systemd Journal Gateway"
+u systemd-journal-remote        -               "systemd Journal Remote"
+u systemd-journal-upload        -               "systemd Journal Upload"
diff --git a/sysusers.d/systemd.conf b/sysusers.d/systemd.conf
index 4c4bd4a..2dd4274 100644
--- a/sysusers.d/systemd.conf
+++ b/sysusers.d/systemd.conf
@@ -6,8 +6,6 @@
 #  (at your option) any later version.
 
 g systemd-journal               -               -
-u systemd-journal-gateway       -               "systemd Journal Gateway"
-u systemd-journal-remote        -               "systemd Journal Remote"
 u systemd-bus-proxy             -               "systemd Bus Proxy"
 u systemd-network               -               "systemd Network Management"
 u systemd-resolve               -               "systemd Resolver"

commit d8aa69b9c89b1309041ca3dc1c5a050fefab64ae
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 03:42:19 2014 -0400

    systemd-analyze verify: improve error message
    
    There's little sense in telling the user to look at the logs...

diff --git a/src/core/transaction.c b/src/core/transaction.c
index 805d40a..1f4c9ce 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -870,7 +870,7 @@ int transaction_add_job_and_dependencies(
         }
 
         if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
-                if (unit->load_error == -ENOENT)
+                if (unit->load_error == -ENOENT || unit->manager->test_run)
                         sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
                                           "Unit %s failed to load: %s.",
                                           unit->id,

commit 1e2fd62d70ff1a960551d28fce745847a9dbd3b7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 03:38:05 2014 -0400

    core/load-fragment.c: correct argument sign and split up long lines
    
    With everything on one line they are just harder to read.

diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index d60e283..fda27be 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -84,7 +84,7 @@ int config_parse_warn_compat(
 }
 #endif
 
-int config_parse_unit_deps(const char* unit,
+int config_parse_unit_deps(const char *unit,
                            const char *filename,
                            unsigned line,
                            const char *section,
@@ -1202,7 +1202,8 @@ int config_parse_exec_mount_flags(const char *unit,
                 else if (streq(word, "private"))
                         flags = MS_PRIVATE;
                 else {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
                         return 0;
                 }
         }
@@ -1252,7 +1253,8 @@ int config_parse_exec_selinux_context(
 
         r = unit_name_printf(u, rvalue, &k);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to resolve specifiers, ignoring: %s", strerror(-r));
                 return 0;
         }
 
@@ -1301,7 +1303,8 @@ int config_parse_exec_apparmor_profile(
 
         r = unit_name_printf(u, rvalue, &k);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to resolve specifiers, ignoring: %s", strerror(-r));
                 return 0;
         }
 
@@ -1523,18 +1526,21 @@ int config_parse_socket_service(const char *unit,
 
         r = unit_name_printf(UNIT(s), rvalue, &p);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to resolve specifiers, ignoring: %s", rvalue);
                 return 0;
         }
 
         if (!endswith(p, ".service")) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Unit must be of type service, ignoring: %s", rvalue);
                 return 0;
         }
 
         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
                 return 0;
         }
 
@@ -1657,18 +1663,21 @@ int config_parse_busname_service(
 
         r = unit_name_printf(UNIT(n), rvalue, &p);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to resolve specifiers, ignoring: %s", rvalue);
                 return 0;
         }
 
         if (!endswith(p, ".service")) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Unit must be of type service, ignoring: %s", rvalue);
                 return 0;
         }
 
         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
                 return 0;
         }
 
@@ -1718,7 +1727,8 @@ int config_parse_bus_policy(
 
         access_str = strpbrk(id_str, WHITESPACE);
         if (!access_str) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid busname policy value '%s'", rvalue);
                 return 0;
         }
 
@@ -1728,7 +1738,8 @@ int config_parse_bus_policy(
 
         p->access = busname_policy_access_from_string(access_str);
         if (p->access < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid busname policy access type '%s'", access_str);
                 return 0;
         }
 
@@ -1772,7 +1783,7 @@ int config_parse_unit_env_file(const char *unit,
 
         r = unit_full_printf(u, rvalue, &n);
         if (r < 0)
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_ERR, filename, line, -r,
                            "Failed to resolve specifiers, ignoring: %s", rvalue);
 
         s = n ?: rvalue;
@@ -2100,7 +2111,7 @@ int config_parse_unit_requires_mounts_for(
 
                 r = unit_require_mounts_for(u, n);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
+                        log_syntax(unit, LOG_ERR, filename, line, -r,
                                    "Failed to add required mount for, ignoring: %s", rvalue);
                         continue;
                 }
@@ -2246,7 +2257,8 @@ int config_parse_syscall_filter(
 
                 id = seccomp_syscall_resolve_name(t);
                 if (id < 0)  {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Failed to parse system call, ignoring: %s", t);
                         continue;
                 }
 
@@ -2311,7 +2323,8 @@ int config_parse_syscall_archs(
 
                 r = seccomp_arch_from_string(t, &a);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Failed to parse system call architecture, ignoring: %s", t);
                         continue;
                 }
 
@@ -2355,7 +2368,8 @@ int config_parse_syscall_errno(
 
         e = errno_from_name(rvalue);
         if (e < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Failed to parse error number, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -2418,7 +2432,8 @@ int config_parse_address_families(
 
                 af = af_from_name(t);
                 if (af <= 0)  {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Failed to parse address family, ignoring: %s", t);
                         continue;
                 }
 
@@ -2518,7 +2533,8 @@ int config_parse_cpu_shares(
 
         r = safe_atolu(rvalue, &lu);
         if (r < 0 || lu <= 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "CPU shares '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2552,12 +2568,14 @@ int config_parse_cpu_quota(
 
         if (!endswith(rvalue, "%")) {
 
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
                 return 0;
         }
 
         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "CPU quota '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2591,7 +2609,8 @@ int config_parse_memory_limit(
 
         r = parse_size(rvalue, 1024, &bytes);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Memory limit '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2632,7 +2651,8 @@ int config_parse_device_allow(
         if (!startswith(path, "/dev/") &&
             !startswith(path, "block-") &&
             !startswith(path, "char-")) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid device node path '%s'. Ignoring.", path);
                 return 0;
         }
 
@@ -2641,7 +2661,8 @@ int config_parse_device_allow(
                 m = "rwm";
 
         if (!in_charset(m, "rwm")) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid device rights '%s'. Ignoring.", m);
                 return 0;
         }
 
@@ -2685,7 +2706,8 @@ int config_parse_blockio_weight(
 
         r = safe_atolu(rvalue, &lu);
         if (r < 0 || lu < 10 || lu > 1000) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Block IO weight '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2727,7 +2749,8 @@ int config_parse_blockio_device_weight(
         n = strcspn(rvalue, WHITESPACE);
         weight = rvalue + n;
         if (!*weight) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Expected block device and device weight. Ignoring.");
                 return 0;
         }
 
@@ -2736,14 +2759,16 @@ int config_parse_blockio_device_weight(
                 return log_oom();
 
         if (!path_startswith(path, "/dev")) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid device node path '%s'. Ignoring.", path);
                 return 0;
         }
 
         weight += strspn(weight, WHITESPACE);
         r = safe_atolu(weight, &lu);
         if (r < 0 || lu < 10 || lu > 1000) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Block IO weight '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2819,7 +2844,8 @@ int config_parse_blockio_bandwidth(
 
         r = parse_size(bandwidth, 1000, &bytes);
         if (r < 0 || bytes <= 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
                 return 0;
         }
 
@@ -2860,7 +2886,8 @@ int config_parse_job_mode_isolate(
 
         r = parse_boolean(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Failed to parse boolean, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -2935,7 +2962,8 @@ int config_parse_runtime_directory(
                         return log_oom();
 
                 if (!filename_is_safe(n)) {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Runtime directory is not valid, ignoring assignment: %s", rvalue);
                         continue;
                 }
 
@@ -2992,35 +3020,29 @@ int config_parse_set_status(
                 if (r < 0) {
                         val = signal_from_string_try_harder(temp);
 
-                        if (val > 0) {
-                                r = set_ensure_allocated(&status_set->signal, NULL, NULL);
-                                if (r < 0)
-                                        return log_oom();
-
-                                r = set_put(status_set->signal, INT_TO_PTR(val));
-                                if (r < 0) {
-                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
-                                        return r;
-                                }
-                        } else {
-                                log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", word);
+                        if (val <= 0) {
+                                log_syntax(unit, LOG_ERR, filename, line, -val,
+                                           "Failed to parse value, ignoring: %s", word);
                                 return 0;
                         }
                 } else {
-                        if (val < 0 || val > 255)
-                                log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
-                        else {
-                                r = set_ensure_allocated(&status_set->status, NULL, NULL);
-                                if (r < 0)
-                                        return log_oom();
-
-                                r = set_put(status_set->status, INT_TO_PTR(val));
-                                if (r < 0) {
-                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
-                                        return r;
-                                }
+                        if (val < 0 || val > 255) {
+                                log_syntax(unit, LOG_ERR, filename, line, ERANGE,
+                                           "Value %d is outside range 0-255, ignoring", val);
+                                continue;
                         }
                 }
+
+                r = set_ensure_allocated(&status_set->status, NULL, NULL);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put(status_set->status, INT_TO_PTR(val));
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, -r,
+                                   "Unable to store: %s", word);
+                        return r;
+                }
         }
         if (!isempty(state))
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
@@ -3073,7 +3095,8 @@ int config_parse_namespace_path_strv(
 
                 offset = n[0] == '-';
                 if (!path_is_absolute(n + offset)) {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Not an absolute path, ignoring: %s", rvalue);
                         continue;
                 }
 
@@ -3114,7 +3137,8 @@ int config_parse_no_new_privileges(
 
         k = parse_boolean(rvalue);
         if (k < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, -k,
+                           "Failed to parse boolean value, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -3157,7 +3181,8 @@ int config_parse_protect_home(
 
                 h = protect_home_from_string(rvalue);
                 if (h < 0){
-                        log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, -h,
+                                   "Failed to parse protect home value, ignoring: %s", rvalue);
                         return 0;
                 }
 
@@ -3200,7 +3225,8 @@ int config_parse_protect_system(
 
                 s = protect_system_from_string(rvalue);
                 if (s < 0){
-                        log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, -s,
+                                   "Failed to parse protect system value, ignoring: %s", rvalue);
                         return 0;
                 }
 
diff --git a/src/shared/util.c b/src/shared/util.c
index 76cee19..4c30a98 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1230,7 +1230,7 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
 
         r = new(char, pl+length+1);
         if (!r)
-                return r;
+                return NULL;
 
         if (prefix)
                 memcpy(r, prefix, pl);

commit b2fadec6048adb3596f2633cb7fe7a49f5937a18
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jul 31 03:28:37 2014 -0400

    Properly report invalid quoted strings
    
    $ systemd-analyze verify trailing-g.service
    [./trailing-g.service:2] Trailing garbage, ignoring.
    trailing-g.service lacks ExecStart setting. Refusing.
    Error: org.freedesktop.systemd1.LoadFailed: Unit trailing-g.service failed to load: Invalid argument.
    Failed to create trailing-g.service/start: Invalid argument

diff --git a/src/core/device.c b/src/core/device.c
index 2c41c7b..0f28a16 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -223,14 +223,13 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
         const char *word, *state;
         size_t l;
         int r;
+        const char *property;
 
         assert(u);
         assert(dev);
 
-        wants = udev_device_get_property_value(
-                        dev,
-                        u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS");
-
+        property = u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
+        wants = udev_device_get_property_value(dev, property);
         if (!wants)
                 return 0;
 
@@ -249,6 +248,9 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
                 if (r < 0)
                         return r;
         }
+        if (!isempty(state))
+                log_warning_unit(u->id, "Property %s on %s has trailing garbage, ignoring.",
+                                 property, strna(udev_device_get_syspath(dev)));
 
         return 0;
 }
@@ -407,6 +409,8 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
                         else
                                 log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
                 }
+                if (!isempty(state))
+                        log_warning("SYSTEMD_ALIAS for %s has trailing garbage, ignoring.", sysfs);
         }
 
         return 0;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index b0448e2..d60e283 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -124,6 +124,8 @@ int config_parse_unit_deps(const char* unit,
                         log_syntax(unit, LOG_ERR, filename, line, -r,
                                    "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
 
         return 0;
 }
@@ -269,6 +271,8 @@ int config_parse_unit_path_strv_printf(
 
                 k = NULL;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
 
         return 0;
 }
@@ -568,11 +572,17 @@ int config_parse_exec(const char *unit,
                 k = 0;
                 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                         if (strneq(word, ";", MAX(l, 1U)))
-                                break;
+                                goto found;
 
                         k++;
                 }
+                if (!isempty(state)) {
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Trailing garbage, ignoring.");
+                        return 0;
+                }
 
+        found:
                 n = new(char*, k + !honour_argv0);
                 if (!n)
                         return log_oom();
@@ -895,6 +905,9 @@ int config_parse_exec_cpu_affinity(const char *unit,
 
                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -977,6 +990,9 @@ int config_parse_exec_secure_bits(const char *unit,
                         return 0;
                 }
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid syntax, garbage at the end, ignoring.");
 
         return 0;
 }
@@ -1031,6 +1047,9 @@ int config_parse_bounding_set(const char *unit,
 
                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         if (invert)
                 *capability_bounding_set_drop |= sum;
@@ -1187,6 +1206,9 @@ int config_parse_exec_mount_flags(const char *unit,
                         return 0;
                 }
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         c->mount_flags = flags;
         return 0;
@@ -1570,6 +1592,9 @@ int config_parse_service_sockets(const char *unit,
                 if (r < 0)
                         return r;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -1827,6 +1852,9 @@ int config_parse_environ(const char *unit,
                 strv_free(*env);
                 *env = x;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2077,6 +2105,9 @@ int config_parse_unit_requires_mounts_for(
                         continue;
                 }
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2231,6 +2262,9 @@ int config_parse_syscall_filter(
                 } else
                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         /* Turn on NNP, but only if it wasn't configured explicitly
          * before, and only if we are in user mode. */
@@ -2287,6 +2321,9 @@ int config_parse_syscall_archs(
                 if (r < 0)
                         return log_oom();
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2397,6 +2434,9 @@ int config_parse_address_families(
                 } else
                         set_remove(c->address_families, INT_TO_PTR(af));
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2905,6 +2945,9 @@ int config_parse_runtime_directory(
 
                 n = NULL;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2979,6 +3022,9 @@ int config_parse_set_status(
                         }
                 }
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -3039,6 +3085,9 @@ int config_parse_namespace_path_strv(
 
                 n = NULL;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
diff --git a/src/core/main.c b/src/core/main.c
index fad15c7..e9909de 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -488,6 +488,9 @@ static int config_parse_cpu_affinity2(
 
                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         if (c) {
                 if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
@@ -636,6 +639,9 @@ static int config_parse_join_controllers(const char *unit,
                         arg_join_controllers = t;
                 }
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 3249027..bc36efa 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -149,9 +149,11 @@ static int spawn_getter(const char *getter, const char *url) {
         _cleanup_strv_free_ char **words = NULL;
 
         assert(getter);
-        words = strv_split_quoted(getter);
-        if (!words)
-                return log_oom();
+        r = strv_split_quoted(&words, getter);
+        if (r < 0) {
+                log_error("Failed to split getter option: %s", strerror(-r));
+                return r;
+        }
 
         r = strv_extend(&words, url);
         if (r < 0) {
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index eac0a4c..01da38b 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1326,6 +1326,7 @@ static int server_parse_proc_cmdline(Server *s) {
                 } else if (startswith(word, "systemd.journald"))
                         log_warning("Invalid systemd.journald parameter. Ignoring.");
         }
+        /* do not warn about state here, since probably systemd already did */
 
         return 0;
 }
diff --git a/src/locale/localed.c b/src/locale/localed.c
index d6ffe67..bce99b8 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -210,6 +210,7 @@ static int x11_read_data(Context *c) {
         FILE *f;
         char line[LINE_MAX];
         bool in_section = false;
+        int r;
 
         context_free_x11(c);
 
@@ -229,10 +230,10 @@ static int x11_read_data(Context *c) {
                 if (in_section && first_word(l, "Option")) {
                         char **a;
 
-                        a = strv_split_quoted(l);
-                        if (!a) {
+                        r = strv_split_quoted(&a, l);
+                        if (r < 0) {
                                 fclose(f);
-                                return -ENOMEM;
+                                return r;
                         }
 
                         if (strv_length(a) == 3) {
@@ -256,8 +257,8 @@ static int x11_read_data(Context *c) {
                 } else if (!in_section && first_word(l, "Section")) {
                         char **a;
 
-                        a = strv_split_quoted(l);
-                        if (!a) {
+                        r = strv_split_quoted(&a, l);
+                        if (r < 0) {
                                 fclose(f);
                                 return -ENOMEM;
                         }
@@ -533,6 +534,7 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
         for (;;) {
                 char line[LINE_MAX];
                 char *l, **b;
+                int r;
 
                 errno = 0;
                 if (!fgets(line, sizeof(line), f)) {
@@ -549,9 +551,9 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
                 if (l[0] == 0 || l[0] == '#')
                         continue;
 
-                b = strv_split_quoted(l);
-                if (!b)
-                        return -ENOMEM;
+                r = strv_split_quoted(&b, l);
+                if (r < 0)
+                        return r;
 
                 if (strv_length(b) < 5) {
                         log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 995621c..fecd7ea 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -333,6 +333,7 @@ static int parse_dns_server_string(Manager *m, const char *string) {
                 if (r < 0)
                         return r;
         }
+        /* do not warn about state here, since probably systemd already did */
 
         return 0;
 }
diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c
index f88ddc1..b52dcc5 100644
--- a/src/shared/condition-util.c
+++ b/src/shared/condition-util.c
@@ -114,6 +114,8 @@ bool condition_test_kernel_command_line(Condition *c) {
                 }
 
         }
+        if (!isempty(state))
+                log_warning("Trailing garbage and the end of kernel commandline, ignoring.");
 
         free(word);
         free(line);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index cd189ad..439cfc5 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -717,6 +717,9 @@ int config_parse_strv(const char *unit,
                 if (r < 0)
                         return log_oom();
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
diff --git a/src/shared/install.c b/src/shared/install.c
index c32d659..276ca3e 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -966,6 +966,9 @@ static int config_parse_also(
                 if (r < 0)
                         return r;
         }
+        if (!isempty(state))
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Trailing garbage, ignoring.");
 
         return 0;
 }
diff --git a/src/shared/log.c b/src/shared/log.c
index a7c3195..078ccdc 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -880,6 +880,8 @@ void log_parse_environment(void) {
                                 break;
                         }
                 }
+                if (!isempty(state))
+                        log_warning("Trailing garbage and the end of kernel commandline, ignoring.");
         }
 
         e = secure_getenv("SYSTEMD_LOG_TARGET");
diff --git a/src/shared/strv.c b/src/shared/strv.c
index 0ac66b9..6448f31 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -231,7 +231,7 @@ char **strv_split(const char *s, const char *separator) {
         return r;
 }
 
-char **strv_split_quoted(const char *s) {
+int strv_split_quoted(char ***t, const char *s) {
         const char *word, *state;
         size_t l;
         unsigned n, i;
@@ -242,26 +242,27 @@ char **strv_split_quoted(const char *s) {
         n = 0;
         FOREACH_WORD_QUOTED(word, l, s, state)
                 n++;
-        if (*state)
+        if (!isempty(state))
                 /* bad syntax */
-                return NULL;
+                return -EINVAL;
 
         r = new(char*, n+1);
         if (!r)
-                return NULL;
+                return -ENOMEM;
 
         i = 0;
         FOREACH_WORD_QUOTED(word, l, s, state) {
                 r[i] = cunescape_length(word, l);
                 if (!r[i]) {
                         strv_free(r);
-                        return NULL;
+                        return -ENOMEM;
                 }
                 i++;
         }
 
         r[i] = NULL;
-        return r;
+        *t = r;
+        return 0;
 }
 
 char **strv_split_newlines(const char *s) {
diff --git a/src/shared/strv.h b/src/shared/strv.h
index 3034073..ee55c14 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -62,7 +62,7 @@ static inline bool strv_isempty(char * const *l) {
 }
 
 char **strv_split(const char *s, const char *separator);
-char **strv_split_quoted(const char *s);
+int strv_split_quoted(char ***t, const char *s);
 char **strv_split_newlines(const char *s);
 
 char *strv_join(char **l, const char *separator);
diff --git a/src/shared/util.c b/src/shared/util.c
index cb9687c..76cee19 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3163,12 +3163,13 @@ fail:
 }
 
 char **replace_env_argv(char **argv, char **env) {
-        char **r, **i;
+        char **ret, **i;
         unsigned k = 0, l = 0;
 
         l = strv_length(argv);
 
-        if (!(r = new(char*, l+1)))
+        ret = new(char*, l+1);
+        if (!ret)
                 return NULL;
 
         STRV_FOREACH(i, argv) {
@@ -3181,10 +3182,12 @@ char **replace_env_argv(char **argv, char **env) {
 
                         e = strv_env_get(env, *i+1);
                         if (e) {
+                                int r;
 
-                                if (!(m = strv_split_quoted(e))) {
-                                        r[k] = NULL;
-                                        strv_free(r);
+                                r = strv_split_quoted(&m, e);
+                                if (r < 0) {
+                                        ret[k] = NULL;
+                                        strv_free(ret);
                                         return NULL;
                                 }
                         } else
@@ -3193,16 +3196,17 @@ char **replace_env_argv(char **argv, char **env) {
                         q = strv_length(m);
                         l = l + q - 1;
 
-                        if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
-                                r[k] = NULL;
-                                strv_free(r);
+                        w = realloc(ret, sizeof(char*) * (l+1));
+                        if (!w) {
+                                ret[k] = NULL;
+                                strv_free(ret);
                                 strv_free(m);
                                 return NULL;
                         }
 
-                        r = w;
+                        ret = w;
                         if (m) {
-                                memcpy(r + k, m, q * sizeof(char*));
+                                memcpy(ret + k, m, q * sizeof(char*));
                                 free(m);
                         }
 
@@ -3211,14 +3215,16 @@ char **replace_env_argv(char **argv, char **env) {
                 }
 
                 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
-                if (!(r[k++] = replace_env(*i, env))) {
-                        strv_free(r);
+                ret[k] = replace_env(*i, env);
+                if (!ret[k]) {
+                        strv_free(ret);
                         return NULL;
                 }
+                k++;
         }
 
-        r[k] = NULL;
-        return r;
+        ret[k] = NULL;
+        return ret;
 }
 
 int fd_columns(int fd) {
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index cfae1d7..368d420 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -494,6 +494,10 @@ static int load_sysv(SysvStub *s) {
                                                                "[%s:%u] Failed to add LSB Provides name %s, ignoring: %s",
                                                                s->path, line, m, strerror(-r));
                                 }
+                                if (!isempty(state_))
+                                        log_error_unit(s->name,
+                                                       "[%s:%u] Trailing garbage in Provides, ignoring.",
+                                                       s->path, line);
 
                         } else if (startswith_no_case(t, "Required-Start:") ||
                                    startswith_no_case(t, "Should-Start:") ||
@@ -552,6 +556,11 @@ static int load_sysv(SysvStub *s) {
                                                                "[%s:%u] Failed to add dependency on %s, ignoring: %s",
                                                                s->path, line, m, strerror(-r));
                                 }
+                                if (!isempty(state_))
+                                        log_error_unit(s->name,
+                                                       "[%s:%u] Trailing garbage in %*s, ignoring.",
+                                                       s->path, line,
+                                                       (int)(strchr(t, ':') - t), t);
 
                         } else if (startswith_no_case(t, "Description:")) {
                                 char *d, *j;
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index cdd2a53..7ba4c36 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -141,6 +141,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
         _cleanup_free_ char *p;
         _cleanup_strv_free_ char **s;
         char **t;
+        int r;
 
         p = strv_join_quoted((char **)split);
         assert_se(p);
@@ -148,7 +149,8 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
         assert_se(p);
         assert_se(streq(p, quoted));
 
-        s = strv_split_quoted(quoted);
+        r = strv_split_quoted(&s, quoted);
+        assert_se(r == 0);
         assert_se(s);
         STRV_FOREACH(t, s) {
                 assert_se(*t);
@@ -162,8 +164,10 @@ static void test_strv_unquote(const char *quoted, const char **list) {
         _cleanup_free_ char *j;
         unsigned i = 0;
         char **t;
+        int r;
 
-        s = strv_split_quoted(quoted);
+        r = strv_split_quoted(&s, quoted);
+        assert_se(r == 0);
         assert_se(s);
         j = strv_join(s, " | ");
         assert(j);
@@ -176,10 +180,12 @@ static void test_strv_unquote(const char *quoted, const char **list) {
 }
 
 static void test_invalid_unquote(const char *quoted) {
-        char **s;
+        char **s = NULL;
+        int r;
 
-        s = strv_split_quoted(quoted);
+        r = strv_split_quoted(&s, quoted);
         assert(s == NULL);
+        assert(r == -EINVAL);
 }
 
 static void test_strv_split(void) {
@@ -441,6 +447,9 @@ int main(int argc, char *argv[]) {
         test_invalid_unquote("a  --b='c \"d e\"'");
         test_invalid_unquote("a  --b='c \"d e\" '");
         test_invalid_unquote("a  --b='c \"d e\"garbage");
+        test_invalid_unquote("'");
+        test_invalid_unquote("\"");
+        test_invalid_unquote("'x'y");
 
         test_strv_split();
         test_strv_split_newlines();
diff --git a/src/test/test-util.c b/src/test/test-util.c
index a56b355..470475a 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -358,6 +358,7 @@ static void test_foreach_word_quoted(void) {
                 assert_se(strneq(expected[i++], word, l));
                 printf("<%s>\n", t);
         }
+        assert(isempty(state));
 }
 
 static void test_default_term_for_tty(void) {
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 8bb79fb..1bd8cf5 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -1001,6 +1001,8 @@ static int manager_add_server_string(Manager *m, const char *string) {
                 if (r < 0)
                         log_error("Failed to add server %s to configuration, ignoring: %s", t, strerror(-r));
         }
+        if (!isempty(state))
+                log_warning("Trailing garbage at the end of server list, ignoring.");
 
         return 0;
 }

commit a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Jul 29 22:01:36 2014 -0400

    Reject invalid quoted strings
    
    String which ended in an unfinished quote were accepted, potentially
    with bad memory accesses.
    
    Reject anything which ends in a unfished quote, or contains
    non-whitespace characters right after the closing quote.
    
    _FOREACH_WORD now returns the invalid character in *state. But this return
    value is not checked anywhere yet.
    
    Also, make 'word' and 'state' variables const pointers, and rename 'w'
    to 'word' in various places. Things are easier to read if the same name
    is used consistently.
    
    mbiebl_> am I correct that something like this doesn't work
    mbiebl_> ExecStart=/usr/bin/encfs --extpass='/bin/systemd-ask-passwd "Unlock EncFS"'
    mbiebl_> systemd seems to strip of the quotes
    mbiebl_> systemctl status shows
    mbiebl_> ExecStart=/usr/bin/encfs --extpass='/bin/systemd-ask-password Unlock EncFS  $RootDir $MountPoint
    mbiebl_> which is pretty weird

diff --git a/src/core/device.c b/src/core/device.c
index 444286e..2c41c7b 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -220,7 +220,7 @@ static int device_make_description(Unit *u, struct udev_device *dev, const char
 
 static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
         const char *wants;
-        char *state, *w;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -234,11 +234,11 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
         if (!wants)
                 return 0;
 
-        FOREACH_WORD_QUOTED(w, l, wants, state) {
+        FOREACH_WORD_QUOTED(word, l, wants, state) {
                 _cleanup_free_ char *n = NULL;
                 char e[l+1];
 
-                memcpy(e, w, l);
+                memcpy(e, word, l);
                 e[l] = 0;
 
                 n = unit_name_mangle(e, MANGLE_NOGLOB);
@@ -393,13 +393,13 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
          * aliases */
         alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
         if (alias) {
-                char *state, *w;
+                const char *word, *state;
                 size_t l;
 
-                FOREACH_WORD_QUOTED(w, l, alias, state) {
+                FOREACH_WORD_QUOTED(word, l, alias, state) {
                         char e[l+1];
 
-                        memcpy(e, w, l);
+                        memcpy(e, word, l);
                         e[l] = 0;
 
                         if (path_is_absolute(e))
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 6d84310..b0448e2 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -97,18 +97,18 @@ int config_parse_unit_deps(const char* unit,
 
         UnitDependency d = ltype;
         Unit *u = userdata;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL, *k = NULL;
                 int r;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -227,7 +227,8 @@ int config_parse_unit_path_strv_printf(
                 void *data,
                 void *userdata) {
 
-        char *w, *state, ***x = data;
+        char ***x = data;
+        const char *word, *state;
         Unit *u = userdata;
         size_t l;
         int r;
@@ -237,11 +238,11 @@ int config_parse_unit_path_strv_printf(
         assert(rvalue);
         assert(u);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *k = NULL;
                 char t[l+1];
 
-                memcpy(t, w, l);
+                memcpy(t, word, l);
                 t[l] = 0;
 
                 r = unit_full_printf(u, t, &k);
@@ -533,9 +534,8 @@ int config_parse_exec(const char *unit,
          * overriding of argv[0]. */
         for (;;) {
                 int i;
-                char *w;
+                const char *word, *state;
                 size_t l;
-                char *state;
                 bool honour_argv0 = false, ignore = false;
 
                 path = NULL;
@@ -566,8 +566,8 @@ int config_parse_exec(const char *unit,
                 }
 
                 k = 0;
-                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                        if (strneq(w, ";", MAX(l, 1U)))
+                FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+                        if (strneq(word, ";", MAX(l, 1U)))
                                 break;
 
                         k++;
@@ -578,16 +578,16 @@ int config_parse_exec(const char *unit,
                         return log_oom();
 
                 k = 0;
-                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                        if (strneq(w, ";", MAX(l, 1U)))
+                FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+                        if (strneq(word, ";", MAX(l, 1U)))
                                 break;
-                        else if (strneq(w, "\\;", MAX(l, 1U)))
-                                w ++;
+                        else if (strneq(word, "\\;", MAX(l, 1U)))
+                                word ++;
 
-                        if (honour_argv0 && w == rvalue) {
+                        if (honour_argv0 && word == rvalue) {
                                 assert(!path);
 
-                                path = strndup(w, l);
+                                path = strndup(word, l);
                                 if (!path) {
                                         r = log_oom();
                                         goto fail;
@@ -602,7 +602,7 @@ int config_parse_exec(const char *unit,
                         } else {
                                 char *c;
 
-                                c = n[k++] = cunescape_length(w, l);
+                                c = n[k++] = cunescape_length(word, l);
                                 if (!c) {
                                         r = log_oom();
                                         goto fail;
@@ -854,9 +854,8 @@ int config_parse_exec_cpu_affinity(const char *unit,
                                    void *userdata) {
 
         ExecContext *c = data;
-        char *w;
+        const char *word, *state;
         size_t l;
-        char *state;
 
         assert(filename);
         assert(lvalue);
@@ -871,12 +870,12 @@ int config_parse_exec_cpu_affinity(const char *unit,
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
                 int r;
                 unsigned cpu;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -945,9 +944,8 @@ int config_parse_exec_secure_bits(const char *unit,
                                   void *userdata) {
 
         ExecContext *c = data;
-        char *w;
         size_t l;
-        char *state;
+        const char *word, *state;
 
         assert(filename);
         assert(lvalue);
@@ -960,18 +958,18 @@ int config_parse_exec_secure_bits(const char *unit,
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                if (first_word(w, "keep-caps"))
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+                if (first_word(word, "keep-caps"))
                         c->secure_bits |= 1<<SECURE_KEEP_CAPS;
-                else if (first_word(w, "keep-caps-locked"))
+                else if (first_word(word, "keep-caps-locked"))
                         c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
-                else if (first_word(w, "no-setuid-fixup"))
+                else if (first_word(word, "no-setuid-fixup"))
                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
-                else if (first_word(w, "no-setuid-fixup-locked"))
+                else if (first_word(word, "no-setuid-fixup-locked"))
                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
-                else if (first_word(w, "noroot"))
+                else if (first_word(word, "noroot"))
                         c->secure_bits |= 1<<SECURE_NOROOT;
-                else if (first_word(w, "noroot-locked"))
+                else if (first_word(word, "noroot-locked"))
                         c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
                 else {
                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
@@ -995,9 +993,8 @@ int config_parse_bounding_set(const char *unit,
                               void *userdata) {
 
         uint64_t *capability_bounding_set_drop = data;
-        char *w;
+        const char *word, *state;
         size_t l;
-        char *state;
         bool invert = false;
         uint64_t sum = 0;
 
@@ -1016,12 +1013,12 @@ int config_parse_bounding_set(const char *unit,
          * non-inverted everywhere to have a fully normalized
          * interface. */
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
                 int r;
                 cap_value_t cap;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -1163,9 +1160,8 @@ int config_parse_exec_mount_flags(const char *unit,
                                   void *userdata) {
 
         ExecContext *c = data;
-        char *w;
+        const char *word, *state;
         size_t l;
-        char *state;
         unsigned long flags = 0;
 
         assert(filename);
@@ -1173,10 +1169,10 @@ int config_parse_exec_mount_flags(const char *unit,
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
+        FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
                 _cleanup_free_ char *t;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -1184,7 +1180,7 @@ int config_parse_exec_mount_flags(const char *unit,
                         flags = MS_SHARED;
                 else if (streq(t, "slave"))
                         flags = MS_SLAVE;
-                else if (streq(w, "private"))
+                else if (streq(word, "private"))
                         flags = MS_PRIVATE;
                 else {
                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
@@ -1538,7 +1534,7 @@ int config_parse_service_sockets(const char *unit,
 
         Service *s = data;
         int r;
-        char *state, *w;
+        const char *word, *state;
         size_t l;
 
         assert(filename);
@@ -1546,10 +1542,10 @@ int config_parse_service_sockets(const char *unit,
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL, *k = NULL;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -1780,7 +1776,8 @@ int config_parse_environ(const char *unit,
                          void *userdata) {
 
         Unit *u = userdata;
-        char*** env = data, *w, *state;
+        char*** env = data;
+        const char *word, *state;
         size_t l;
         _cleanup_free_ char *k = NULL;
         int r;
@@ -1809,11 +1806,11 @@ int config_parse_environ(const char *unit,
         if (!k)
                 return log_oom();
 
-        FOREACH_WORD_QUOTED(w, l, k, state) {
+        FOREACH_WORD_QUOTED(word, l, k, state) {
                 _cleanup_free_ char *n;
                 char **x;
 
-                n = cunescape_length(w, l);
+                n = cunescape_length(word, l);
                 if (!n)
                         return log_oom();
 
@@ -2052,20 +2049,19 @@ int config_parse_unit_requires_mounts_for(
                 void *userdata) {
 
         Unit *u = userdata;
-        char *state;
+        const char *word, *state;
         size_t l;
-        char *w;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 int r;
                 _cleanup_free_ char *n;
 
-                n = strndup(w, l);
+                n = strndup(word, l);
                 if (!n)
                         return log_oom();
 
@@ -2156,7 +2152,7 @@ int config_parse_syscall_filter(
         ExecContext *c = data;
         Unit *u = userdata;
         bool invert = false;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -2209,11 +2205,11 @@ int config_parse_syscall_filter(
                 }
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
                 int id;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -2257,7 +2253,7 @@ int config_parse_syscall_archs(
                 void *userdata) {
 
         Set **archs = data;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -2271,11 +2267,11 @@ int config_parse_syscall_archs(
         if (r < 0)
                 return log_oom();
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
                 uint32_t a;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -2345,7 +2341,7 @@ int config_parse_address_families(
         ExecContext *c = data;
         Unit *u = userdata;
         bool invert = false;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -2375,11 +2371,11 @@ int config_parse_address_families(
                 c->address_families_whitelist = !invert;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
                 int af;
 
-                t = strndup(w, l);
+                t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
@@ -2874,7 +2870,8 @@ int config_parse_runtime_directory(
                 void *data,
                 void *userdata) {
 
-        char***rt = data, *w, *state;
+        char***rt = data;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -2890,10 +2887,10 @@ int config_parse_runtime_directory(
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *n;
 
-                n = strndup(w, l);
+                n = strndup(word, l);
                 if (!n)
                         return log_oom();
 
@@ -2924,9 +2921,8 @@ int config_parse_set_status(
                 void *data,
                 void *userdata) {
 
-        char *w;
         size_t l;
-        char *state;
+        const char *word, *state;
         int r;
         ExitStatusSet *status_set = data;
 
@@ -2941,11 +2937,11 @@ int config_parse_set_status(
                 return 0;
         }
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD(word, l, rvalue, state) {
                 _cleanup_free_ char *temp;
                 int val;
 
-                temp = strndup(w, l);
+                temp = strndup(word, l);
                 if (!temp)
                         return log_oom();
 
@@ -2960,11 +2956,11 @@ int config_parse_set_status(
 
                                 r = set_put(status_set->signal, INT_TO_PTR(val));
                                 if (r < 0) {
-                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
+                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
                                         return r;
                                 }
                         } else {
-                                log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
+                                log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", word);
                                 return 0;
                         }
                 } else {
@@ -2977,7 +2973,7 @@ int config_parse_set_status(
 
                                 r = set_put(status_set->status, INT_TO_PTR(val));
                                 if (r < 0) {
-                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
+                                        log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
                                         return r;
                                 }
                         }
@@ -2999,7 +2995,8 @@ int config_parse_namespace_path_strv(
                 void *data,
                 void *userdata) {
 
-        char*** sv = data, *w, *state;
+        char*** sv = data;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -3015,11 +3012,11 @@ int config_parse_namespace_path_strv(
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *n;
                 int offset;
 
-                n = strndup(w, l);
+                n = strndup(word, l);
                 if (!n)
                         return log_oom();
 
diff --git a/src/core/main.c b/src/core/main.c
index 2741989..fad15c7 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -455,9 +455,8 @@ static int config_parse_cpu_affinity2(
                 void *data,
                 void *userdata) {
 
-        char *w;
+        const char *word, *state;
         size_t l;
-        char *state;
         cpu_set_t *c = NULL;
         unsigned ncpus = 0;
 
@@ -465,12 +464,12 @@ static int config_parse_cpu_affinity2(
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 char *t;
                 int r;
                 unsigned cpu;
 
-                if (!(t = strndup(w, l)))
+                if (!(t = strndup(word, l)))
                         return log_oom();
 
                 r = safe_atou(t, &cpu);
@@ -559,7 +558,7 @@ static int config_parse_join_controllers(const char *unit,
                                          void *userdata) {
 
         unsigned n = 0;
-        char *state, *w;
+        const char *word, *state;
         size_t length;
 
         assert(filename);
@@ -568,10 +567,10 @@ static int config_parse_join_controllers(const char *unit,
 
         free_join_controllers();
 
-        FOREACH_WORD_QUOTED(w, length, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, length, rvalue, state) {
                 char *s, **l;
 
-                s = strndup(w, length);
+                s = strndup(word, length);
                 if (!s)
                         return log_oom();
 
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 67dc88f..94570eb 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -175,16 +175,16 @@ static int parse_one_option(const char *option) {
 }
 
 static int parse_options(const char *options) {
-        char *state, *w;
+        const char *word, *state;
         size_t l;
         int r;
 
         assert(options);
 
-        FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
+        FOREACH_WORD_SEPARATOR(word, l, options, ",", state) {
                 _cleanup_free_ char *o;
 
-                o = strndup(w, l);
+                o = strndup(word, l);
                 if (!o)
                         return -ENOMEM;
                 r = parse_one_option(o);
diff --git a/src/delta/delta.c b/src/delta/delta.c
index 96a9fa5..dd7523d 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -488,23 +488,23 @@ static int help(void) {
 }
 
 static int parse_flags(const char *flag_str, int flags) {
-        char *w, *state;
+        const char *word, *state;
         size_t l;
 
-        FOREACH_WORD(w, l, flag_str, state) {
-                if (strneq("masked", w, l))
+        FOREACH_WORD(word, l, flag_str, state) {
+                if (strneq("masked", word, l))
                         flags |= SHOW_MASKED;
-                else if (strneq ("equivalent", w, l))
+                else if (strneq ("equivalent", word, l))
                         flags |= SHOW_EQUIVALENT;
-                else if (strneq("redirected", w, l))
+                else if (strneq("redirected", word, l))
                         flags |= SHOW_REDIRECTED;
-                else if (strneq("overridden", w, l))
+                else if (strneq("overridden", word, l))
                         flags |= SHOW_OVERRIDDEN;
-                else if (strneq("unchanged", w, l))
+                else if (strneq("unchanged", word, l))
                         flags |= SHOW_UNCHANGED;
-                else if (strneq("extended", w, l))
+                else if (strneq("extended", word, l))
                         flags |= SHOW_EXTENDED;
-                else if (strneq("default", w, l))
+                else if (strneq("default", word, l))
                         flags |= SHOW_DEFAULTS;
                 else
                         return -EINVAL;
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index 7d4b546..c78a511 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -154,14 +154,14 @@ int main(int argc, char *argv[]) {
 
                 r = getenv_for_pid(1, "container_ttys", &container_ttys);
                 if (r > 0) {
-                        char *w, *state;
+                        const char *word, *state;
                         size_t l;
 
-                        FOREACH_WORD(w, l, container_ttys, state) {
+                        FOREACH_WORD(word, l, container_ttys, state) {
                                 const char *t;
                                 char tty[l + 1];
 
-                                memcpy(tty, w, l);
+                                memcpy(tty, word, l);
                                 tty[l] = 0;
 
                                 /* First strip off /dev/ if it is specified */
@@ -184,15 +184,15 @@ int main(int argc, char *argv[]) {
         }
 
         if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
-                char *w, *state;
+                const char *word, *state;
                 size_t l;
 
                 /* Automatically add in a serial getty on all active
                  * kernel consoles */
-                FOREACH_WORD(w, l, active, state) {
+                FOREACH_WORD(word, l, active, state) {
                         _cleanup_free_ char *tty = NULL;
 
-                        tty = strndup(w, l);
+                        tty = strndup(word, l);
                         if (!tty) {
                                 log_oom();
                                 return EXIT_FAILURE;
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 37ad902..3249027 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -1344,7 +1344,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_GNUTLS_LOG: {
 #ifdef HAVE_GNUTLS
-                        char *word, *state;
+                        const char *word, *state;
                         size_t size;
 
                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 4ea9d43..eac0a4c 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1282,7 +1282,7 @@ static int setup_signals(Server *s) {
 
 static int server_parse_proc_cmdline(Server *s) {
         _cleanup_free_ char *line = NULL;
-        char *w, *state;
+        const char *w, *state;
         size_t l;
         int r;
 
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 6349aeb..01c91e4 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -997,7 +997,7 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
 }
 
 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         unsigned long long seqnum, monotonic, realtime, xor_hash;
         bool
@@ -1013,18 +1013,18 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
         assert_return(!journal_pid_changed(j), -ECHILD);
         assert_return(!isempty(cursor), -EINVAL);
 
-        FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
+        FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
                 char *item;
                 int k = 0;
 
-                if (l < 2 || w[1] != '=')
+                if (l < 2 || word[1] != '=')
                         return -EINVAL;
 
-                item = strndup(w, l);
+                item = strndup(word, l);
                 if (!item)
                         return -ENOMEM;
 
-                switch (w[0]) {
+                switch (word[0]) {
 
                 case 's':
                         seqnum_id_set = true;
@@ -1103,7 +1103,7 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
 
 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         int r;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         Object *o;
 
@@ -1118,20 +1118,20 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         if (r < 0)
                 return r;
 
-        FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
+        FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
                 _cleanup_free_ char *item = NULL;
                 sd_id128_t id;
                 unsigned long long ll;
                 int k = 0;
 
-                if (l < 2 || w[1] != '=')
+                if (l < 2 || word[1] != '=')
                         return -EINVAL;
 
-                item = strndup(w, l);
+                item = strndup(word, l);
                 if (!item)
                         return -ENOMEM;
 
-                switch (w[0]) {
+                switch (word[0]) {
 
                 case 's':
                         k = sd_id128_from_string(item+2, &id);
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 603ee6d..7f74421 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -354,7 +354,7 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
         _cleanup_free_ struct in_addr *addresses = NULL;
         int size = 0;
-        char *word, *state;
+        const char *word, *state;
         size_t len;
 
         assert(ret);
@@ -391,7 +391,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
         _cleanup_free_ struct in6_addr *addresses = NULL;
         int size = 0;
-        char *word, *state;
+        const char *word, *state;
         size_t len;
 
         assert(ret);
@@ -446,7 +446,7 @@ void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *route
 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
         size_t size = 0, allocated = 0;
-        char *word, *state;
+        const char *word, *state;
         size_t len;
 
         assert(ret);
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 38ff944..95cb6ff 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -226,11 +226,10 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
 }
 
 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
-        char *w, *state;
         _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
         size_t l;
         int r;
-        const char *variable;
+        const char *word, *variable, *state;
 
         assert_return(seat, -EINVAL);
 
@@ -251,8 +250,8 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat)
         if (asprintf(&t, UID_FMT, uid) < 0)
                 return -ENOMEM;
 
-        FOREACH_WORD(w, l, s, state) {
-                if (strneq(t, w, l))
+        FOREACH_WORD(word, l, s, state) {
+                if (strneq(t, word, l))
                         return 1;
         }
 
@@ -587,10 +586,10 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
         }
 
         if (uids && t) {
-                char *w, *state;
+                const char *word, *state;
                 size_t l;
 
-                FOREACH_WORD(w, l, t, state)
+                FOREACH_WORD(word, l, t, state)
                         n++;
 
                 if (n > 0) {
@@ -600,10 +599,10 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
                         if (!b)
                                 return -ENOMEM;
 
-                        FOREACH_WORD(w, l, t, state) {
+                        FOREACH_WORD(word, l, t, state) {
                                 _cleanup_free_ char *k = NULL;
 
-                                k = strndup(w, l);
+                                k = strndup(word, l);
                                 if (!k)
                                         return -ENOMEM;
 
@@ -789,9 +788,8 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
         _cleanup_free_ char *netif = NULL;
         size_t l, allocated = 0, nr = 0;
-        char *w, *state;
         int *ni = NULL;
-        const char *p;
+        const char *p, *word, *state;
         int r;
 
         assert_return(machine_name_is_valid(machine), -EINVAL);
@@ -806,11 +804,11 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
                 return 0;
         }
 
-        FOREACH_WORD(w, l, netif, state) {
+        FOREACH_WORD(word, l, netif, state) {
                 char buf[l+1];
                 int ifi;
 
-                *(char*) (mempcpy(buf, w, l)) = 0;
+                *(char*) (mempcpy(buf, word, l)) = 0;
 
                 if (safe_atoi(buf, &ifi) < 0)
                         continue;
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 64a62ff..a9e14af 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -439,23 +439,23 @@ const char *inhibit_what_to_string(InhibitWhat w) {
 
 InhibitWhat inhibit_what_from_string(const char *s) {
         InhibitWhat what = 0;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
 
-        FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
-                if (l == 8 && strneq(w, "shutdown", l))
+        FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
+                if (l == 8 && strneq(word, "shutdown", l))
                         what |= INHIBIT_SHUTDOWN;
-                else if (l == 5 && strneq(w, "sleep", l))
+                else if (l == 5 && strneq(word, "sleep", l))
                         what |= INHIBIT_SLEEP;
-                else if (l == 4 && strneq(w, "idle", l))
+                else if (l == 4 && strneq(word, "idle", l))
                         what |= INHIBIT_IDLE;
-                else if (l == 16 && strneq(w, "handle-power-key", l))
+                else if (l == 16 && strneq(word, "handle-power-key", l))
                         what |= INHIBIT_HANDLE_POWER_KEY;
-                else if (l == 18 && strneq(w, "handle-suspend-key", l))
+                else if (l == 18 && strneq(word, "handle-suspend-key", l))
                         what |= INHIBIT_HANDLE_SUSPEND_KEY;
-                else if (l == 20 && strneq(w, "handle-hibernate-key", l))
+                else if (l == 20 && strneq(word, "handle-hibernate-key", l))
                         what |= INHIBIT_HANDLE_HIBERNATE_KEY;
-                else if (l == 17 && strneq(w, "handle-lid-switch", l))
+                else if (l == 17 && strneq(word, "handle-lid-switch", l))
                         what |= INHIBIT_HANDLE_LID_SWITCH;
                 else
                         return _INHIBIT_WHAT_INVALID;
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 0ed18d7..1c9177e 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -291,14 +291,14 @@ int machine_load(Machine *m) {
 
         if (netif) {
                 size_t l, allocated = 0, nr = 0;
-                char *w, *state;
+                const char *word, *state;
                 int *ni = NULL;
 
-                FOREACH_WORD(w, l, netif, state) {
+                FOREACH_WORD(word, l, netif, state) {
                         char buf[l+1];
                         int ifi;
 
-                        *(char*) (mempcpy(buf, w, l)) = 0;
+                        *(char*) (mempcpy(buf, word, l)) = 0;
 
                         if (safe_atoi(buf, &ifi) < 0)
                                 continue;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 7c47f6e..ddf1c37 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -395,7 +395,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_CAPABILITY:
                 case ARG_DROP_CAPABILITY: {
-                        char *state, *word;
+                        const char *state, *word;
                         size_t length;
 
                         FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
@@ -2602,7 +2602,8 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
 }
 
 static int change_uid_gid(char **_home) {
-        char line[LINE_MAX], *w, *x, *state, *u, *g, *h;
+        char line[LINE_MAX], *x, *u, *g, *h;
+        const char *word, *state;
         _cleanup_free_ uid_t *uids = NULL;
         _cleanup_free_ char *home = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -2752,10 +2753,10 @@ static int change_uid_gid(char **_home) {
         x += strcspn(x, WHITESPACE);
         x += strspn(x, WHITESPACE);
 
-        FOREACH_WORD(w, l, x, state) {
+        FOREACH_WORD(word, l, x, state) {
                 char c[l+1];
 
-                memcpy(c, w, l);
+                memcpy(c, word, l);
                 c[l] = 0;
 
                 if (!GREEDY_REALLOC(uids, sz, n_uids+1))
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 319baf7..995621c 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -304,7 +304,7 @@ static int manager_network_monitor_listen(Manager *m) {
 }
 
 static int parse_dns_server_string(Manager *m, const char *string) {
-        char *word, *state;
+        const char *word, *state;
         size_t length;
         int r;
 
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index c1c4d40..f683ae9 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -753,9 +753,9 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         cs = strlen(controller);
 
         FOREACH_LINE(line, f, return -errno) {
-                char *l, *p, *w, *e;
+                char *l, *p, *e;
                 size_t k;
-                char *state;
+                const char *word, *state;
                 bool found = false;
 
                 truncate_nl(line);
@@ -771,16 +771,16 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
 
                 *e = 0;
 
-                FOREACH_WORD_SEPARATOR(w, k, l, ",", state) {
+                FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
 
-                        if (k == cs && memcmp(w, controller, cs) == 0) {
+                        if (k == cs && memcmp(word, controller, cs) == 0) {
                                 found = true;
                                 break;
                         }
 
                         if (k == 5 + cs &&
-                            memcmp(w, "name=", 5) == 0 &&
-                            memcmp(w+5, controller, cs) == 0) {
+                            memcmp(word, "name=", 5) == 0 &&
+                            memcmp(word+5, controller, cs) == 0) {
                                 found = true;
                                 break;
                         }
diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c
index 928edee..f88ddc1 100644
--- a/src/shared/condition-util.c
+++ b/src/shared/condition-util.c
@@ -74,7 +74,8 @@ void condition_free_list(Condition *first) {
 }
 
 bool condition_test_kernel_command_line(Condition *c) {
-        char *line, *w, *state, *word = NULL;
+        char *line, *word = NULL;
+        const char *w, *state;
         bool equal;
         int r;
         size_t l, pl;
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 0be7226..cd189ad 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -675,7 +675,8 @@ int config_parse_strv(const char *unit,
                       void *data,
                       void *userdata) {
 
-        char *** sv = data, *w, *state;
+        char ***sv = data;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -700,10 +701,10 @@ int config_parse_strv(const char *unit,
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 char *n;
 
-                n = strndup(w, l);
+                n = strndup(word, l);
                 if (!n)
                         return log_oom();
 
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index ea7b710..a17dde9 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -170,7 +170,7 @@ int log_syntax_internal(const char *unit, int level,
                      void *userdata) {                                         \
                                                                                \
                 type **enums = data, *xs, x, *ys;                              \
-                char *w, *state;                                               \
+                const char *word, *state;                                      \
                 size_t l, i = 0;                                               \
                                                                                \
                 assert(filename);                                              \
@@ -181,10 +181,10 @@ int log_syntax_internal(const char *unit, int level,
                 xs = new0(type, 1);                                            \
                 *xs = invalid;                                                 \
                                                                                \
-                FOREACH_WORD(w, l, rvalue, state) {                            \
+                FOREACH_WORD(word, l, rvalue, state) {                         \
                         _cleanup_free_ char *en = NULL;                        \
                                                                                \
-                        en = strndup(w, l);                                    \
+                        en = strndup(word, l);                                 \
                         if (!en)                                               \
                                 return -ENOMEM;                                \
                                                                                \
diff --git a/src/shared/install.c b/src/shared/install.c
index cc61c01..c32d659 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -946,20 +946,19 @@ static int config_parse_also(
                 void *data,
                 void *userdata) {
 
-        char *w;
         size_t l;
-        char *state;
+        const char *word, *state;
         InstallContext *c = data;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *n;
                 int r;
 
-                n = strndup(w, l);
+                n = strndup(word, l);
                 if (!n)
                         return -ENOMEM;
 
diff --git a/src/shared/log.c b/src/shared/log.c
index 3941e3e..a7c3195 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -871,11 +871,11 @@ void log_parse_environment(void) {
         if (r < 0)
                 log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r));
         else if (r > 0) {
-                char *w, *state;
+                const char *word, *state;
                 size_t l;
 
-                FOREACH_WORD_QUOTED(w, l, line, state) {
-                        if (l == 5 && startswith(w, "debug")) {
+                FOREACH_WORD_QUOTED(word, l, line, state) {
+                        if (l == 5 && startswith(word, "debug")) {
                                 log_set_max_level(LOG_DEBUG);
                                 break;
                         }
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 5bc5012..57554cd 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -574,7 +574,7 @@ int find_binary(const char *name, char **filename) {
                 return 0;
         } else {
                 const char *path;
-                char *state, *w;
+                const char *word, *state;
                 size_t l;
 
                 /**
@@ -585,10 +585,10 @@ int find_binary(const char *name, char **filename) {
                 if (!path)
                         path = DEFAULT_PATH;
 
-                FOREACH_WORD_SEPARATOR(w, l, path, ":", state) {
+                FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
                         _cleanup_free_ char *p = NULL;
 
-                        if (asprintf(&p, "%.*s/%s", (int) l, w, name) < 0)
+                        if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
                                 return -ENOMEM;
 
                         if (access(p, X_OK) < 0)
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 16a488d..d8de644 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -98,7 +98,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
 }
 
 int can_sleep_state(char **types) {
-        char *w, *state, **type;
+        char **type;
         int r;
         _cleanup_free_ char *p = NULL;
 
@@ -114,11 +114,12 @@ int can_sleep_state(char **types) {
                 return false;
 
         STRV_FOREACH(type, types) {
+                const char *word, *state;
                 size_t l, k;
 
                 k = strlen(*type);
-                FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
-                        if (l == k && memcmp(w, *type, l) == 0)
+                FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state)
+                        if (l == k && memcmp(word, *type, l) == 0)
                                 return true;
         }
 
@@ -126,7 +127,7 @@ int can_sleep_state(char **types) {
 }
 
 int can_sleep_disk(char **types) {
-        char *w, *state, **type;
+        char **type;
         int r;
         _cleanup_free_ char *p = NULL;
 
@@ -142,14 +143,18 @@ int can_sleep_disk(char **types) {
                 return false;
 
         STRV_FOREACH(type, types) {
+                const char *word, *state;
                 size_t l, k;
 
                 k = strlen(*type);
-                FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
-                        if (l == k && memcmp(w, *type, l) == 0)
+                FOREACH_WORD_SEPARATOR(word, l, p, WHITESPACE, state) {
+                        if (l == k && memcmp(word, *type, l) == 0)
                                 return true;
 
-                        if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
+                        if (l == k + 2 &&
+                            word[0] == '[' &&
+                            memcmp(word + 1, *type, l - 2) == 0 &&
+                            word[l-1] == ']')
                                 return true;
                 }
         }
diff --git a/src/shared/strv.c b/src/shared/strv.c
index b4c476e..0ac66b9 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -201,8 +201,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
 }
 
 char **strv_split(const char *s, const char *separator) {
-        char *state;
-        char *w;
+        const char *word, *state;
         size_t l;
         unsigned n, i;
         char **r;
@@ -210,7 +209,7 @@ char **strv_split(const char *s, const char *separator) {
         assert(s);
 
         n = 0;
-        FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
+        FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
                 n++;
 
         r = new(char*, n+1);
@@ -218,8 +217,8 @@ char **strv_split(const char *s, const char *separator) {
                 return NULL;
 
         i = 0;
-        FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
-                r[i] = strndup(w, l);
+        FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
+                r[i] = strndup(word, l);
                 if (!r[i]) {
                         strv_free(r);
                         return NULL;
@@ -233,8 +232,7 @@ char **strv_split(const char *s, const char *separator) {
 }
 
 char **strv_split_quoted(const char *s) {
-        char *state;
-        char *w;
+        const char *word, *state;
         size_t l;
         unsigned n, i;
         char **r;
@@ -242,16 +240,19 @@ char **strv_split_quoted(const char *s) {
         assert(s);
 
         n = 0;
-        FOREACH_WORD_QUOTED(w, l, s, state)
+        FOREACH_WORD_QUOTED(word, l, s, state)
                 n++;
+        if (*state)
+                /* bad syntax */
+                return NULL;
 
         r = new(char*, n+1);
         if (!r)
                 return NULL;
 
         i = 0;
-        FOREACH_WORD_QUOTED(w, l, s, state) {
-                r[i] = cunescape_length(w, l);
+        FOREACH_WORD_QUOTED(word, l, s, state) {
+                r[i] = cunescape_length(word, l);
                 if (!r[i]) {
                         strv_free(r);
                         return NULL;
diff --git a/src/shared/util.c b/src/shared/util.c
index d8a75bd..cb9687c 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -415,37 +415,50 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
                 else if (s[n] == '\\')
                         escaped = true;
                 else if (strchr(reject, s[n]))
-                        return n;
+                        break;
         }
-        return n;
+        /* if s ends in \, return index of previous char */
+        return n - escaped;
 }
 
 /* Split a string into words. */
-char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state) {
-        char *current;
+const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+        const char *current;
 
-        current = *state ? *state : (char*) c;
+        current = *state;
 
-        if (!*current || *c == 0)
+        if (!*current) {
+                assert(**state == '\0');
                 return NULL;
+        }
 
         current += strspn(current, separator);
-        if (!*current)
+        if (!*current) {
+                *state = current;
                 return NULL;
+        }
 
         if (quoted && strchr("\'\"", *current)) {
-                char quotechar = *(current++);
-                *l = strcspn_escaped(current, (char[]){quotechar, '\0'});
-                *state = current+*l+1;
+                char quotechars[2] = {*current, '\0'};
+
+                *l = strcspn_escaped(current + 1, quotechars);
+                if (current[*l + 1] == '\0' ||
+                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+                        /* right quote missing or garbage at the end*/
+                        *state = current;
+                        return NULL;
+                }
+                assert(current[*l + 1] == quotechars[0]);
+                *state = current++ + *l + 2;
         } else if (quoted) {
                 *l = strcspn_escaped(current, separator);
-                *state = current+*l;
+                *state = current + *l;
         } else {
                 *l = strcspn(current, separator);
-                *state = current+*l;
+                *state = current + *l;
         }
 
-        return (char*) current;
+        return current;
 }
 
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
@@ -6059,7 +6072,7 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
 
 int shall_restore_state(void) {
         _cleanup_free_ char *line = NULL;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -6071,12 +6084,12 @@ int shall_restore_state(void) {
 
         r = 1;
 
-        FOREACH_WORD_QUOTED(w, l, line, state) {
+        FOREACH_WORD_QUOTED(word, l, line, state) {
                 const char *e;
                 char n[l+1];
                 int k;
 
-                memcpy(n, w, l);
+                memcpy(n, word, l);
                 n[l] = 0;
 
                 e = startswith(n, "systemd.restore_state=");
@@ -6120,7 +6133,7 @@ int proc_cmdline(char **ret) {
 
 int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
         _cleanup_free_ char *line = NULL;
-        char *w, *state;
+        const char *w, *state;
         size_t l;
         int r;
 
diff --git a/src/shared/util.h b/src/shared/util.h
index 81da59b..4529480 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -234,7 +234,7 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
         return safe_atolli(s, (long long int*) ret_i);
 }
 
-char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state);
+const char* split(const char **state, size_t *l, const char *separator, bool quoted);
 
 #define FOREACH_WORD(word, length, s, state)                            \
         _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
@@ -249,7 +249,7 @@ char *split(const char *c, size_t *l, const char *separator, bool quoted, char *
         _FOREACH_WORD(word, length, s, separator, true, state)
 
 #define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
-        for ((state) = NULL, (word) = split((s), &(length), (separator), (quoted), &(state)); (word); (word) = split((s), &(length), (separator), (quoted), &(state)))
+        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
 
 pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
 int get_starttime_of_pid(pid_t pid, unsigned long long *st);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 4699a67..21e33d5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -5733,7 +5733,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         return 0;
 
                 case 't': {
-                        char *word, *state;
+                        const char *word, *state;
                         size_t size;
 
                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
@@ -5782,7 +5782,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 if (!arg_properties)
                                         return log_oom();
                         } else {
-                                char *word, *state;
+                                const char *word, *state;
                                 size_t size;
 
                                 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
@@ -5952,7 +5952,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_STATE: {
-                        char *word, *state;
+                        const char *word, *state;
                         size_t size;
 
                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 9a869ba..cfae1d7 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -442,15 +442,15 @@ static int load_sysv(SysvStub *s) {
                 } else if (state == LSB || state == LSB_DESCRIPTION) {
 
                         if (startswith_no_case(t, "Provides:")) {
-                                char *i, *w;
+                                const char *word, *state_;
                                 size_t z;
 
                                 state = LSB;
 
-                                FOREACH_WORD_QUOTED(w, z, t+9, i) {
+                                FOREACH_WORD_QUOTED(word, z, t+9, state_) {
                                         _cleanup_free_ char *n = NULL, *m = NULL;
 
-                                        n = strndup(w, z);
+                                        n = strndup(word, z);
                                         if (!n)
                                                 return -ENOMEM;
 
@@ -499,16 +499,16 @@ static int load_sysv(SysvStub *s) {
                                    startswith_no_case(t, "Should-Start:") ||
                                    startswith_no_case(t, "X-Start-Before:") ||
                                    startswith_no_case(t, "X-Start-After:")) {
-                                char *i, *w;
+                                const char *word, *state_;
                                 size_t z;
 
                                 state = LSB;
 
-                                FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
+                                FOREACH_WORD_QUOTED(word, z, strchr(t, ':')+1, state_) {
                                         _cleanup_free_ char *n = NULL, *m = NULL;
                                         bool is_before;
 
-                                        n = strndup(w, z);
+                                        n = strndup(word, z);
                                         if (!n)
                                                 return -ENOMEM;
 
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 3702191..cdd2a53 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -159,12 +159,15 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
 
 static void test_strv_unquote(const char *quoted, const char **list) {
         _cleanup_strv_free_ char **s;
+        _cleanup_free_ char *j;
         unsigned i = 0;
         char **t;
 
         s = strv_split_quoted(quoted);
         assert_se(s);
-        strv_print(s);
+        j = strv_join(s, " | ");
+        assert(j);
+        puts(j);
 
         STRV_FOREACH(t, s)
                 assert_se(streq(list[i++], *t));
@@ -172,6 +175,13 @@ static void test_strv_unquote(const char *quoted, const char **list) {
         assert_se(list[i] == NULL);
 }
 
+static void test_invalid_unquote(const char *quoted) {
+        char **s;
+
+        s = strv_split_quoted(quoted);
+        assert(s == NULL);
+}
+
 static void test_strv_split(void) {
         char **s;
         unsigned i = 0;
@@ -428,7 +438,9 @@ int main(int argc, char *argv[]) {
         test_strv_unquote("  \"x'\"   ", (const char*[]) { "x'", NULL });
         test_strv_unquote("a  '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL });
 
-        test_strv_unquote("a  --b='c \"d e\"'", (const char*[]) { "a", "--b='c", "\"d", "e\"'", NULL });
+        test_invalid_unquote("a  --b='c \"d e\"'");
+        test_invalid_unquote("a  --b='c \"d e\" '");
+        test_invalid_unquote("a  --b='c \"d e\"garbage");
 
         test_strv_split();
         test_strv_split_newlines();
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 9a28ef9..a56b355 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -311,7 +311,7 @@ static void test_cunescape(void) {
 }
 
 static void test_foreach_word(void) {
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int i = 0;
         const char test[] = "test abc d\te   f   ";
@@ -325,13 +325,12 @@ static void test_foreach_word(void) {
                 NULL
         };
 
-        FOREACH_WORD(w, l, test, state) {
-                assert_se(strneq(expected[i++], w, l));
-        }
+        FOREACH_WORD(word, l, test, state)
+                assert_se(strneq(expected[i++], word, l));
 }
 
 static void test_foreach_word_quoted(void) {
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int i = 0;
         const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\"";
@@ -352,11 +351,11 @@ static void test_foreach_word_quoted(void) {
         };
 
         printf("<%s>\n", test);
-        FOREACH_WORD_QUOTED(w, l, test, state) {
+        FOREACH_WORD_QUOTED(word, l, test, state) {
                 _cleanup_free_ char *t = NULL;
 
-                assert_se(t = strndup(w, l));
-                assert_se(strneq(expected[i++], w, l));
+                assert_se(t = strndup(word, l));
+                assert_se(strneq(expected[i++], word, l));
                 printf("<%s>\n", t);
         }
 }
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index b80e03b..8bb79fb 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -984,17 +984,17 @@ static int manager_add_server(Manager *m, const char *server) {
 }
 
 static int manager_add_server_string(Manager *m, const char *string) {
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
         assert(m);
         assert(string);
 
-        FOREACH_WORD_QUOTED(w, l, string, state) {
+        FOREACH_WORD_QUOTED(word, l, string, state) {
                 char t[l+1];
 
-                memcpy(t, w, l);
+                memcpy(t, word, l);
                 t[l] = 0;
 
                 r = manager_add_server(m, t);
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 512885f..946715c 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -193,7 +193,7 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
 
 static bool enable_name_policy(void) {
         _cleanup_free_ char *line = NULL;
-        char *w, *state;
+        const char *word, *state;
         int r;
         size_t l;
 
@@ -203,8 +203,8 @@ static bool enable_name_policy(void) {
         if (r <= 0)
                 return true;
 
-        FOREACH_WORD_QUOTED(w, l, line, state)
-                if (strneq(w, "net.ifnames=0", l))
+        FOREACH_WORD_QUOTED(word, l, line, state)
+                if (strneq(word, "net.ifnames=0", l))
                         return false;
 
         return true;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index b75145e..f882cfb 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -956,7 +956,7 @@ static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
  */
 static void kernel_cmdline_options(struct udev *udev) {
         _cleanup_free_ char *line = NULL;
-        char *w, *state;
+        const char *word, *state;
         size_t l;
         int r;
 
@@ -966,10 +966,10 @@ static void kernel_cmdline_options(struct udev *udev) {
         if (r <= 0)
                 return;
 
-        FOREACH_WORD_QUOTED(w, l, line, state) {
+        FOREACH_WORD_QUOTED(word, l, line, state) {
                 char *s, *opt;
 
-                s = strndup(w, l);
+                s = strndup(word, l);
                 if (!s)
                         break;
 

commit 73381fcf54e38456067f0e87b8611a21eff99169
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Mon Jul 28 20:01:56 2014 -0400

    test-strv: add test which shows access to random memory

diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 24ed681..3702191 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -157,13 +157,14 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
         }
 }
 
-static void test_strv_quote_unquote2(const char *quoted, const char ** list) {
+static void test_strv_unquote(const char *quoted, const char **list) {
         _cleanup_strv_free_ char **s;
         unsigned i = 0;
         char **t;
 
         s = strv_split_quoted(quoted);
         assert_se(s);
+        strv_print(s);
 
         STRV_FOREACH(t, s)
                 assert_se(streq(list[i++], *t));
@@ -414,17 +415,20 @@ int main(int argc, char *argv[]) {
         test_strv_quote_unquote(input_table_quotes, QUOTES_STRING);
         test_strv_quote_unquote(input_table_spaces, SPACES_STRING);
 
-        test_strv_quote_unquote2("    foo=bar     \"waldo\"    zzz    ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL });
-        test_strv_quote_unquote2("", (const char*[]) { NULL });
-        test_strv_quote_unquote2(" ", (const char*[]) { NULL });
-        test_strv_quote_unquote2("   ", (const char*[]) { NULL });
-        test_strv_quote_unquote2("   x", (const char*[]) { "x", NULL });
-        test_strv_quote_unquote2("x   ", (const char*[]) { "x", NULL });
-        test_strv_quote_unquote2("  x   ", (const char*[]) { "x", NULL });
-        test_strv_quote_unquote2("  \"x\"   ", (const char*[]) { "x", NULL });
-        test_strv_quote_unquote2("  \'x\'   ", (const char*[]) { "x", NULL });
-        test_strv_quote_unquote2("  \'x\"\'   ", (const char*[]) { "x\"", NULL });
-        test_strv_quote_unquote2("  \"x\'\"   ", (const char*[]) { "x\'", NULL });
+        test_strv_unquote("    foo=bar     \"waldo\"    zzz    ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL });
+        test_strv_unquote("", (const char*[]) { NULL });
+        test_strv_unquote(" ", (const char*[]) { NULL });
+        test_strv_unquote("   ", (const char*[]) { NULL });
+        test_strv_unquote("   x", (const char*[]) { "x", NULL });
+        test_strv_unquote("x   ", (const char*[]) { "x", NULL });
+        test_strv_unquote("  x   ", (const char*[]) { "x", NULL });
+        test_strv_unquote("  \"x\"   ", (const char*[]) { "x", NULL });
+        test_strv_unquote("  'x'   ", (const char*[]) { "x", NULL });
+        test_strv_unquote("  'x\"'   ", (const char*[]) { "x\"", NULL });
+        test_strv_unquote("  \"x'\"   ", (const char*[]) { "x'", NULL });
+        test_strv_unquote("a  '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL });
+
+        test_strv_unquote("a  --b='c \"d e\"'", (const char*[]) { "a", "--b='c", "\"d", "e\"'", NULL });
 
         test_strv_split();
         test_strv_split_newlines();



More information about the systemd-commits mailing list