[systemd-commits] 9 commits - CODING_STYLE Makefile.am src/activate src/analyze src/ask-password src/binfmt src/boot src/bootchart src/bus-proxyd src/cgls src/cgtop src/core src/delta src/detect-virt src/escape src/firstboot src/hostname src/journal src/journal-remote src/libsystemd src/locale src/login src/machine src/machine-id-setup src/modules-load src/network src/notify src/nspawn src/path src/readahead src/resolve src/resolve-host src/run src/shared src/sleep src/socket-proxy src/sysctl src/systemctl src/sysusers src/test src/timedate src/tmpfiles src/tty-ask-password-agent src/udev TODO

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Sun Aug 3 19:02:44 PDT 2014


 CODING_STYLE                                        |    5 
 Makefile.am                                         |   63 +++--
 TODO                                                |    3 
 src/activate/activate.c                             |   12 
 src/analyze/analyze.c                               |   11 
 src/ask-password/ask-password.c                     |   22 -
 src/binfmt/binfmt.c                                 |   15 -
 src/boot/bootctl.c                                  |   33 +-
 src/bootchart/bootchart.c                           |   32 +-
 src/bus-proxyd/bus-proxyd.c                         |    3 
 src/cgls/cgls.c                                     |   15 -
 src/cgtop/cgtop.c                                   |   15 -
 src/core/main.c                                     |   10 
 src/core/manager.c                                  |    5 
 src/core/shutdown.c                                 |    9 
 src/delta/delta.c                                   |   12 
 src/detect-virt/detect-virt.c                       |   18 -
 src/escape/escape.c                                 |   15 -
 src/firstboot/firstboot.c                           |   15 -
 src/hostname/hostnamectl.c                          |   15 -
 src/journal-remote/journal-gatewayd.c               |    8 
 src/journal-remote/journal-remote.c                 |    3 
 src/journal/cat.c                                   |   15 -
 src/journal/coredumpctl.c                           |   46 +--
 src/journal/journalctl.c                            |   10 
 src/libsystemd/sd-bus/busctl.c                      |    8 
 src/locale/localectl.c                              |   15 -
 src/login/inhibit.c                                 |   15 -
 src/login/loginctl.c                                |   15 -
 src/machine-id-setup/machine-id-setup-main.c        |   11 
 src/machine/machinectl.c                            |   11 
 src/modules-load/modules-load.c                     |   11 
 src/network/networkd-wait-online.c                  |   15 -
 src/notify/notify.c                                 |   11 
 src/nspawn/nspawn.c                                 |   11 
 src/path/path.c                                     |   27 --
 src/readahead/readahead.c                           |   30 +-
 src/resolve-host/resolve-host.c                     |   11 
 src/resolve/.gitignore                              |    4 
 src/resolve/dns-type.c                              |   45 +++
 src/resolve/dns-type.h                              |  120 +++++++++
 src/resolve/resolved-dns-packet.c                   |  222 +++++++++++++++--
 src/resolve/resolved-dns-packet.h                   |   30 ++
 src/resolve/resolved-dns-rr.c                       |  194 ++++++++-------
 src/resolve/resolved-dns-rr.h                       |   56 +---
 src/run/run.c                                       |   11 
 src/shared/def.h                                    |    5 
 src/sleep/sleep.c                                   |   13 -
 src/socket-proxy/socket-proxyd.c                    |   16 -
 src/sysctl/sysctl.c                                 |   15 -
 src/systemctl/systemctl.c                           |   57 +---
 src/sysusers/sysusers.c                             |   15 -
 src/test/test-libudev.c                             |   22 +
 src/timedate/timedatectl.c                          |   11 
 src/tmpfiles/tmpfiles.c                             |   11 
 src/tty-ask-password-agent/tty-ask-password-agent.c |  249 +++++++-------------
 src/udev/udevadm.c                                  |   23 -
 57 files changed, 960 insertions(+), 760 deletions(-)

New commits:
commit 151226ab4bf276d60d51864330a99f886b923697
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Aug 3 18:17:22 2014 -0400

    resolved: RRSIG records

diff --git a/TODO b/TODO
index 3f13b91..a0f71f5 100644
--- a/TODO
+++ b/TODO
@@ -32,6 +32,7 @@ Features:
   - DNSSEC
         - use base64 for key presentation?
         - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)?
+        - add nice formatting of DNS timestamps
   - LLMNR:
         - do not fail daemon startup if socket is already busy (container)
         - process incoming notification of conflict
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 626b904..b97fd17 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -377,7 +377,8 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start
         return 0;
 }
 
-int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
+int dns_packet_append_name(DnsPacket *p, const char *name,
+                           bool allow_compression, size_t *start) {
         size_t saved_size;
         int r;
 
@@ -389,10 +390,11 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
         while (*name) {
                 _cleanup_free_ char *s = NULL;
                 char label[DNS_LABEL_MAX];
-                size_t n;
+                size_t n = 0;
                 int k;
 
-                n = PTR_TO_SIZE(hashmap_get(p->names, name));
+                if (allow_compression)
+                        n = PTR_TO_SIZE(hashmap_get(p->names, name));
                 if (n > 0) {
                         assert(n < p->size);
 
@@ -430,15 +432,19 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
                 if (r < 0)
                         goto fail;
 
-                r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
-                if (r < 0)
-                        goto fail;
+                if (allow_compression) {
+                        r = hashmap_ensure_allocated(&p->names,
+                                                     dns_name_hash_func,
+                                                     dns_name_compare_func);
+                        if (r < 0)
+                                goto fail;
 
-                r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
-                if (r < 0)
-                        goto fail;
+                        r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
+                        if (r < 0)
+                                goto fail;
 
-                s = NULL;
+                        s = NULL;
+                }
         }
 
         r = dns_packet_append_uint8(p, 0, NULL);
@@ -465,7 +471,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start)
 
         saved_size = p->size;
 
-        r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
+        r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL);
         if (r < 0)
                 goto fail;
 
@@ -524,14 +530,14 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->srv.name, NULL);
+                r = dns_packet_append_name(p, rr->srv.name, true, NULL);
                 break;
 
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
         case DNS_TYPE_CNAME:
         case DNS_TYPE_DNAME:
-                r = dns_packet_append_name(p, rr->ptr.name, NULL);
+                r = dns_packet_append_name(p, rr->ptr.name, true, NULL);
                 break;
 
         case DNS_TYPE_HINFO:
@@ -565,11 +571,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 break;
 
         case DNS_TYPE_SOA:
-                r = dns_packet_append_name(p, rr->soa.mname, NULL);
+                r = dns_packet_append_name(p, rr->soa.mname, true, NULL);
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->soa.rname, NULL);
+                r = dns_packet_append_name(p, rr->soa.rname, true, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -597,7 +603,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->mx.exchange, NULL);
+                r = dns_packet_append_name(p, rr->mx.exchange, true, NULL);
                 break;
 
         case DNS_TYPE_LOC:
@@ -656,6 +662,42 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
                 break;
 
+        case DNS_TYPE_RRSIG:
+                r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
+                break;
+
         case _DNS_TYPE_INVALID: /* unparseable */
         default:
 
@@ -824,7 +866,8 @@ fail:
         return r;
 }
 
-int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
+int dns_packet_read_name(DnsPacket *p, char **_ret,
+                         bool allow_compression, size_t *start) {
         size_t saved_rindex, after_rindex = 0;
         _cleanup_free_ char *ret = NULL;
         size_t n = 0, allocated = 0;
@@ -872,7 +915,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
                         memcpy(ret + n, t, r);
                         n += r;
                         continue;
-                } else if ((c & 0xc0) == 0xc0) {
+                } else if (allow_compression && (c & 0xc0) == 0xc0) {
                         uint16_t ptr;
 
                         /* Pointer */
@@ -929,7 +972,7 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
 
         saved_rindex = p->rindex;
 
-        r = dns_packet_read_name(p, &name, NULL);
+        r = dns_packet_read_name(p, &name, true, NULL);
         if (r < 0)
                 goto fail;
 
@@ -1050,14 +1093,14 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
                 if (r < 0)
                         goto fail;
-                r = dns_packet_read_name(p, &rr->srv.name, NULL);
+                r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
                 break;
 
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
         case DNS_TYPE_CNAME:
         case DNS_TYPE_DNAME:
-                r = dns_packet_read_name(p, &rr->ptr.name, NULL);
+                r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
                 break;
 
         case DNS_TYPE_HINFO:
@@ -1095,11 +1138,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 break;
 
         case DNS_TYPE_SOA:
-                r = dns_packet_read_name(p, &rr->soa.mname, NULL);
+                r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_read_name(p, &rr->soa.rname, NULL);
+                r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -1127,7 +1170,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
+                r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
                 break;
 
         case DNS_TYPE_LOC: {
@@ -1234,6 +1277,44 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 break;
         }
 
+        case DNS_TYPE_RRSIG:
+                r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_public_key(p, offset + rdlength - p->rindex,
+                                               &rr->rrsig.signature, &rr->rrsig.signature_size,
+                                               NULL);
+                break;
+
         default:
         unparseable:
                 r = dns_packet_read(p, rdlength, &d, NULL);
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index f3b0f0c..26a2e76 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -142,7 +142,8 @@ int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start);
 int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start);
 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start);
 int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start);
-int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start);
+int dns_packet_append_name(DnsPacket *p, const char *name,
+                           bool allow_compression, size_t *start);
 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start);
 int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start);
 
@@ -152,7 +153,8 @@ int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start);
 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start);
 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start);
 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start);
-int dns_packet_read_name(DnsPacket *p, char **ret, size_t *start);
+int dns_packet_read_name(DnsPacket *p, char **ret,
+                         bool allow_compression, size_t *start);
 int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start);
 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start);
 
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index bc0cbef..c792ded 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -274,6 +274,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                         free(rr->dnskey.key);
                         break;
 
+                case DNS_TYPE_RRSIG:
+                        free(rr->rrsig.signer);
+                        free(rr->rrsig.signature);
+                        break;
+
                 case DNS_TYPE_LOC:
                 case DNS_TYPE_A:
                 case DNS_TYPE_AAAA:
@@ -418,6 +423,21 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                        a->dnskey.key_size == b->dnskey.key_size &&
                        memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
 
+        case DNS_TYPE_RRSIG:
+                /* do the fast comparisons first */
+                if (a->rrsig.type_covered != a->rrsig.type_covered ||
+                    a->rrsig.algorithm != a->rrsig.algorithm ||
+                    a->rrsig.labels != a->rrsig.labels ||
+                    a->rrsig.original_ttl != a->rrsig.original_ttl ||
+                    a->rrsig.expiration != a->rrsig.expiration ||
+                    a->rrsig.inception != a->rrsig.inception ||
+                    a->rrsig.key_tag != a->rrsig.key_tag ||
+                    a->rrsig.signature_size != b->rrsig.signature_size ||
+                    memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
+                        return false;
+
+                return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
+
         default:
                 return a->generic.size == b->generic.size &&
                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@@ -604,6 +624,37 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 break;
         }
 
+        case DNS_TYPE_RRSIG: {
+                const char *type, *alg;
+
+                type = dns_type_to_string(rr->rrsig.type_covered);
+                alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
+
+                t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size);
+                if (!t)
+                        return -ENOMEM;
+
+                /* TYPE?? follows
+                 * http://tools.ietf.org/html/rfc3597#section-5 */
+
+                r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
+                             k,
+                             type ?: "TYPE",
+                             type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
+                             alg ? -1 : 0, alg,
+                             alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
+                             rr->rrsig.labels,
+                             rr->rrsig.original_ttl,
+                             rr->rrsig.expiration,
+                             rr->rrsig.inception,
+                             rr->rrsig.key_tag,
+                             rr->rrsig.signer,
+                             t);
+                if (r < 0)
+                        return -ENOMEM;
+                break;
+        }
+
         default:
                 t = hexmem(rr->generic.data, rr->generic.size);
                 if (!t)
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index e227264..3222f1f 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -125,6 +125,20 @@ struct DnsResourceRecord {
                         void* key;
                         size_t key_size;
                 } dnskey;
+
+                /* http://tools.ietf.org/html/rfc4034#section-3.1 */
+                struct {
+                        uint16_t type_covered;
+                        uint8_t algorithm;
+                        uint8_t labels;
+                        uint32_t original_ttl;
+                        uint32_t expiration;
+                        uint32_t inception;
+                        uint16_t key_tag;
+                        char *signer;
+                        void *signature;
+                        size_t signature_size;
+                } rrsig;
         };
 };
 

commit ff3d6560bead6879a2fed1bf99bfe8273b3723f1
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Aug 3 16:44:49 2014 -0400

    resolved: add identifiers for dnssec algorithms

diff --git a/TODO b/TODO
index 1dbb9ff..3f13b91 100644
--- a/TODO
+++ b/TODO
@@ -30,6 +30,8 @@ Features:
 
 * resolved:
   - DNSSEC
+        - use base64 for key presentation?
+        - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)?
   - LLMNR:
         - do not fail daemon startup if socket is already busy (container)
         - process incoming notification of conflict
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 951c798..626b904 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -1361,3 +1361,15 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
         [DNS_PROTOCOL_LLMNR] = "llmnr",
 };
 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
+
+static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
+        [DNSSEC_ALGORITHM_RSAMD5]     = "RSAMD5",
+        [DNSSEC_ALGORITHM_DH]         = "DH",
+        [DNSSEC_ALGORITHM_DSA]        = "DSA",
+        [DNSSEC_ALGORITHM_ECC]        = "ECC",
+        [DNSSEC_ALGORITHM_RSASHA1]    = "RSASHA1",
+        [DNSSEC_ALGORITHM_INDIRECT]   = "INDIRECT",
+        [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
+        [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
+};
+DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 4e30019..f3b0f0c 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -200,3 +200,19 @@ static inline uint16_t dnskey_to_flags(const DnsResourceRecord *rr) {
         return (rr->dnskey.zone_key_flag * DNSKEY_FLAG_ZONE_KEY |
                 rr->dnskey.sep_flag * DNSKEY_FLAG_SEP);
 }
+
+/* http://tools.ietf.org/html/rfc4034#appendix-A.1 */
+enum {
+        DNSSEC_ALGORITHM_RSAMD5 = 1,
+        DNSSEC_ALGORITHM_DH,
+        DNSSEC_ALGORITHM_DSA,
+        DNSSEC_ALGORITHM_ECC,
+        DNSSEC_ALGORITHM_RSASHA1,
+        DNSSEC_ALGORITHM_INDIRECT = 252,
+        DNSSEC_ALGORITHM_PRIVATEDNS,
+        DNSSEC_ALGORITHM_PRIVATEOID,
+        _DNSSEC_ALGORITHM_MAX_DEFINED
+};
+
+const char* dnssec_algorithm_to_string(int i) _const_;
+int dnssec_algorithm_from_string(const char *s) _pure_;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index ada7333..bc0cbef 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -584,19 +584,25 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
-        case DNS_TYPE_DNSKEY:
+        case DNS_TYPE_DNSKEY: {
+                const char *alg;
+
+                alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
+
                 t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
                 if (!t)
                         return -ENOMEM;
 
-                r = asprintf(&s, "%s %u 3 %u %s",
+                r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
                              k,
                              dnskey_to_flags(rr),
-                             rr->dnskey.algorithm,
+                             alg ? -1 : 0, alg,
+                             alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
                              t);
                 if (r < 0)
                         return -ENOMEM;
                 break;
+        }
 
         default:
                 t = hexmem(rr->generic.data, rr->generic.size);

commit 8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Aug 3 16:05:41 2014 -0400

    resolved: DNSKEY records

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index ba056f1..951c798 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -632,6 +632,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
                 if (r < 0)
                         goto fail;
+
                 r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
                 if (r < 0)
                         goto fail;
@@ -639,6 +640,22 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
                 break;
 
+        case DNS_TYPE_DNSKEY:
+                r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, 3u, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
+                break;
+
         case _DNS_TYPE_INVALID: /* unparseable */
         default:
 
@@ -942,12 +959,41 @@ fail:
         return r;
 }
 
+static int dns_packet_read_public_key(DnsPacket *p, size_t length,
+                                      void **dp, size_t *lengthp,
+                                      size_t *start) {
+        int r;
+        const void *d;
+        void *d2;
+
+        r = dns_packet_read(p, length, &d, NULL);
+        if (r < 0)
+                return r;
+
+        d2 = memdup(d, length);
+        if (!d2)
+                return -ENOMEM;
+
+        *dp = d2;
+        *lengthp = length;
+        return 0;
+}
+
 static bool loc_size_ok(uint8_t size) {
         uint8_t m = size >> 4, e = size & 0xF;
 
         return m <= 9 && e <= 9 && (m > 0 || e == 0);
 }
 
+static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) {
+        if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY))
+                return -EBADMSG;
+
+        rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY;
+        rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP;
+        return 0;
+}
+
 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
@@ -1143,7 +1189,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
         }
 
         case DNS_TYPE_SSHFP:
-
                 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
                 if (r < 0)
                         goto fail;
@@ -1152,18 +1197,42 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_read(p, rdlength - 2, &d, NULL);
+                r = dns_packet_read_public_key(p, rdlength - 2,
+                                               &rr->sshfp.key, &rr->sshfp.key_size,
+                                               NULL);
+                break;
+
+        case DNS_TYPE_DNSKEY: {
+                uint16_t flags;
+                uint8_t proto;
+
+                r = dns_packet_read_uint16(p, &flags, NULL);
                 if (r < 0)
                         goto fail;
 
-                rr->sshfp.key = memdup(d, rdlength - 2);
-                if (!rr->sshfp.key) {
-                        r = -ENOMEM;
+                r = dnskey_parse_flags(rr, flags);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &proto, NULL);
+                if (r < 0)
+                        goto fail;
+
+                /* protocol is required to be always 3 */
+                if (proto != 3) {
+                        r = -EBADMSG;
                         goto fail;
                 }
 
-                rr->sshfp.key_size = rdlength - 2;
+                r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_public_key(p, rdlength - 4,
+                                               &rr->dnskey.key, &rr->dnskey.key_size,
+                                               NULL);
                 break;
+        }
 
         default:
         unparseable:
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index af51f16..4e30019 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -192,3 +192,11 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_;
 
 #define LLMNR_MULTICAST_IPV4_ADDRESS ((struct in_addr) { .s_addr = htobe32(224U << 24 | 252U) })
 #define LLMNR_MULTICAST_IPV6_ADDRESS ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03 } })
+
+#define DNSKEY_FLAG_ZONE_KEY (1u << 8)
+#define DNSKEY_FLAG_SEP      (1u << 0)
+
+static inline uint16_t dnskey_to_flags(const DnsResourceRecord *rr) {
+        return (rr->dnskey.zone_key_flag * DNSKEY_FLAG_ZONE_KEY |
+                rr->dnskey.sep_flag * DNSKEY_FLAG_SEP);
+}
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index af22a89..ada7333 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -25,6 +25,7 @@
 
 #include "resolved-dns-domain.h"
 #include "resolved-dns-rr.h"
+#include "resolved-dns-packet.h"
 #include "dns-type.h"
 
 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
@@ -269,6 +270,10 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                         free(rr->sshfp.key);
                         break;
 
+                case DNS_TYPE_DNSKEY:
+                        free(rr->dnskey.key);
+                        break;
+
                 case DNS_TYPE_LOC:
                 case DNS_TYPE_A:
                 case DNS_TYPE_AAAA:
@@ -406,6 +411,13 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                        a->sshfp.key_size == b->sshfp.key_size &&
                        memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
 
+        case DNS_TYPE_DNSKEY:
+                return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
+                       a->dnskey.sep_flag == b->dnskey.sep_flag &&
+                       a->dnskey.algorithm == b->dnskey.algorithm &&
+                       a->dnskey.key_size == b->dnskey.key_size &&
+                       memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
+
         default:
                 return a->generic.size == b->generic.size &&
                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@@ -444,7 +456,7 @@ static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t alt
 }
 
 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
-        _cleanup_free_ char *k = NULL;
+        _cleanup_free_ char *k = NULL, *t = NULL;
         char *s;
         int r;
 
@@ -484,9 +496,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 break;
 
         case DNS_TYPE_SPF: /* exactly the same as TXT */
-        case DNS_TYPE_TXT: {
-                _cleanup_free_ char *t;
-
+        case DNS_TYPE_TXT:
                 t = strv_join_quoted(rr->txt.strings);
                 if (!t)
                         return -ENOMEM;
@@ -496,7 +506,6 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
 
                 break;
-        }
 
         case DNS_TYPE_A: {
                 _cleanup_free_ char *x = NULL;
@@ -511,18 +520,15 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 break;
         }
 
-        case DNS_TYPE_AAAA: {
-                _cleanup_free_ char *x = NULL;
-
-                r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
+        case DNS_TYPE_AAAA:
+                r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
                 if (r < 0)
                         return r;
 
-                s = strjoin(k, " ", x, NULL);
+                s = strjoin(k, " ", t, NULL);
                 if (!s)
                         return -ENOMEM;
                 break;
-        }
 
         case DNS_TYPE_SOA:
                 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
@@ -547,55 +553,61 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
-        case DNS_TYPE_LOC: {
-                _cleanup_free_ char *loc;
+        case DNS_TYPE_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)
+                t = format_location(rr->loc.latitude,
+                                    rr->loc.longitude,
+                                    rr->loc.altitude,
+                                    rr->loc.size,
+                                    rr->loc.horiz_pre,
+                                    rr->loc.vert_pre);
+                if (!t)
                         return -ENOMEM;
 
-                s = strjoin(k, " ", loc, NULL);
+                s = strjoin(k, " ", t, NULL);
                 if (!s)
                         return -ENOMEM;
-
                 break;
-        }
 
-        case DNS_TYPE_SSHFP: {
-                _cleanup_free_ char *x = NULL;
-
-                x = hexmem(rr->sshfp.key, rr->sshfp.key_size);
-                if (!x)
+        case DNS_TYPE_SSHFP:
+                t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
+                if (!t)
                         return -ENOMEM;
 
                 r = asprintf(&s, "%s %u %u %s",
                              k,
                              rr->sshfp.algorithm,
                              rr->sshfp.fptype,
-                             x);
+                             t);
                 if (r < 0)
                         return -ENOMEM;
                 break;
-        }
 
-        default: {
-                _cleanup_free_ char *x = NULL;
+        case DNS_TYPE_DNSKEY:
+                t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
+                if (!t)
+                        return -ENOMEM;
 
-                x = hexmem(rr->generic.data, rr->generic.size);
-                if (!x)
+                r = asprintf(&s, "%s %u 3 %u %s",
+                             k,
+                             dnskey_to_flags(rr),
+                             rr->dnskey.algorithm,
+                             t);
+                if (r < 0)
                         return -ENOMEM;
+                break;
 
-                s = strjoin(k, " ", x, NULL);
+        default:
+                t = hexmem(rr->generic.data, rr->generic.size);
+                if (!t)
+                        return -ENOMEM;
+
+                s = strjoin(k, " ", t, NULL);
                 if (!s)
                         return -ENOMEM;
                 break;
-        }}
+        }
 
         *ret = s;
         return 0;
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 20a344b..e227264 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -116,6 +116,15 @@ struct DnsResourceRecord {
                         void *key;
                         size_t key_size;
                 } sshfp;
+
+                /* http://tools.ietf.org/html/rfc4034#section-2.1 */
+                struct {
+                        bool zone_key_flag:1;
+                        bool sep_flag:1;
+                        uint8_t algorithm;
+                        void* key;
+                        size_t key_size;
+                } dnskey;
         };
 };
 

commit de292aa1dd1942e151ff034fcb88504a86742f97
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Aug 3 14:02:04 2014 -0400

    resolve-host: make arg_type an int
    
    We are using it also to store _DNS_TYPE_INVALID, so it should be signed.

diff --git a/Makefile.am b/Makefile.am
index 45d2e58..ce8f247 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1189,7 +1189,7 @@ src/resolve/dns_type-list.txt: src/resolve/dns-type.h
 	$(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
 
 src/resolve/dns_type-to-name.h: src/resolve/dns_type-list.txt
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(uint16_t type) {\n\tswitch(type) {" } {printf "        case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print "\ndefault: return NULL;\n\t}\n}\n" }' <$< >$@
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf "        case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print "\ndefault: return NULL;\n\t}\n}\n" }' <$< >$@
 
 src/resolve/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
 	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 987b43a..4b46cdf 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -37,7 +37,7 @@
 
 static int arg_family = AF_UNSPEC;
 static int arg_ifindex = 0;
-static uint16_t arg_type = 0;
+static int arg_type = 0;
 static uint16_t arg_class = 0;
 static bool arg_legend = true;
 
@@ -316,6 +316,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        assert((uint16_t) arg_type == arg_type);
         r = sd_bus_message_append(req, "sqq", name, arg_class, arg_type);
         if (r < 0)
                 return bus_log_create_error(r);
@@ -482,11 +483,12 @@ static int parse_argv(int argc, char *argv[]) {
                                 return 0;
                         }
 
-                        r = dns_type_from_string(optarg, &arg_type);
-                        if (r < 0) {
+                        arg_type = dns_type_from_string(optarg);
+                        if (arg_type < 0) {
                                 log_error("Failed to parse RR record type %s", optarg);
                                 return r;
                         }
+                        assert(arg_type > 0 && (uint16_t) arg_type == arg_type);
 
                         break;
 
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
index 271a7e1..a3e7408 100644
--- a/src/resolve/dns-type.c
+++ b/src/resolve/dns-type.c
@@ -32,16 +32,14 @@ lookup_dns_type (register const char *str, register unsigned int len);
 #include "dns_type-from-name.h"
 #include "dns_type-to-name.h"
 
-int dns_type_from_string(const char *s, uint16_t *type) {
+int dns_type_from_string(const char *s) {
         const struct dns_type_name *sc;
 
         assert(s);
-        assert(type);
 
         sc = lookup_dns_type(s, strlen(s));
         if (!sc)
-                return -EINVAL;
+                return _DNS_TYPE_INVALID;
 
-        *type = sc->id;
-        return 0;
+        return sc->id;
 }
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
index 6606315..86951d2 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -21,12 +21,10 @@
 
 #pragma once
 
-#include <inttypes.h>
-
 #include "macro.h"
 
-const char *dns_type_to_string(uint16_t type);
-int dns_type_from_string(const char *s, uint16_t *type);
+const char *dns_type_to_string(int type);
+int dns_type_from_string(const char *s);
 
 /* DNS record types, taken from
  * http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml.

commit 7263f72499e962b3fd54cdb7c79d49ca72121ede
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Aug 1 19:37:16 2014 -0400

    resolve: add more record types and convert to gperf table
    
    We are unlikely to evert support most of them, but we can at least
    display the types properly.
    
    The list is taken from the IANA list.
    
    The table of number->name mappings is converted to a switch
    statement. gcc does a nice job of optimizing lookup (when optimization
    is enabled).
    
    systemd-resolve-host -t is now case insensitive.

diff --git a/Makefile.am b/Makefile.am
index 73aa420..45d2e58 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -201,6 +201,7 @@ AM_CPPFLAGS = \
 	-I $(top_srcdir)/src/timedate \
 	-I $(top_srcdir)/src/timesync \
 	-I $(top_srcdir)/src/resolve \
+	-I $(top_builddir)/src/resolve \
 	-I $(top_srcdir)/src/systemd \
 	-I $(top_builddir)/src/core \
 	-I $(top_srcdir)/src/core \
@@ -1148,19 +1149,23 @@ CLEANFILES += \
 	src/shared/errno-list.txt \
 	src/shared/errno-from-name.gperf \
 	src/shared/af-list.txt \
-	src/shared/af-from-name.gperf
+	src/shared/af-from-name.gperf \
+	src/shared/dns_type-list.txt \
+	src/shared/dns_type-from-name.gperf
 
 BUILT_SOURCES += \
 	src/shared/errno-from-name.h \
 	src/shared/errno-to-name.h \
 	src/shared/af-from-name.h \
-	src/shared/af-to-name.h
+	src/shared/af-to-name.h \
+	src/resolve/dns_type-from-name.h \
+	src/resolve/dns_type-to-name.h
 
-src/shared/%-from-name.gperf: src/shared/%-list.txt
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct $*_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
+%-from-name.gperf: %-list.txt
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct $(notdir $*)_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
 
-src/shared/%-from-name.h: src/shared/%-from-name.gperf
-	$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_$* -H hash_$*_name -p -C <$< >$@
+%-from-name.h: %-from-name.gperf
+	$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_$(notdir $*) -H hash_$(notdir $*)_name -p -C <$< >$@
 
 
 src/shared/errno-list.txt:
@@ -1178,6 +1183,17 @@ src/shared/af-list.txt:
 src/shared/af-to-name.h: src/shared/af-list.txt
 	$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
 
+
+src/resolve/dns_type-list.txt: src/resolve/dns-type.h
+	$(AM_V_at)$(MKDIR_P) $(dir $@)
+	$(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
+
+src/resolve/dns_type-to-name.h: src/resolve/dns_type-list.txt
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(uint16_t type) {\n\tswitch(type) {" } {printf "        case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print "\ndefault: return NULL;\n\t}\n}\n" }' <$< >$@
+
+src/resolve/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
+
 # ------------------------------------------------------------------------------
 systemd_SOURCES = \
 	src/core/main.c
@@ -4754,13 +4770,18 @@ systemd_resolved_SOURCES = \
 	src/resolve/resolved-dns-zone.h \
 	src/resolve/resolved-dns-zone.c \
 	src/resolve/resolved-dns-stream.h \
-	src/resolve/resolved-dns-stream.c
+	src/resolve/resolved-dns-stream.c \
+	src/resolve/dns-type.c \
+	src/resolve/dns-type.h \
+	src/resolve/dns_type-from-name.h \
+	src/resolve/dns_type-to-name.h
 
 nodist_systemd_resolved_SOURCES = \
 	src/resolve/resolved-gperf.c
 
 EXTRA_DIST += \
-	src/resolve/resolved-gperf.gperf
+	src/resolve/resolved-gperf.gperf \
+	src/resolve/dns_type-from-name.gperf
 
 CLEANFILES += \
 	src/resolve/resolved-gperf.c
@@ -4857,7 +4878,11 @@ systemd_resolve_host_SOURCES = \
 	src/resolve/resolved-dns-question.c \
 	src/resolve/resolved-dns-question.h \
 	src/resolve/resolved-dns-domain.c \
-	src/resolve/resolved-dns-domain.h
+	src/resolve/resolved-dns-domain.h \
+	src/resolve/dns-type.c \
+	src/resolve/dns-type.h \
+	src/resolve/dns_type-from-name.h \
+	src/resolve/dns_type-to-name.h
 
 systemd_resolve_host_LDADD = \
 	libsystemd-internal.la \
diff --git a/src/resolve/.gitignore b/src/resolve/.gitignore
index ca3016e..f083592 100644
--- a/src/resolve/.gitignore
+++ b/src/resolve/.gitignore
@@ -1,2 +1,6 @@
 /resolved-gperf.c
 /resolved.conf
+/dns_type-from-name.gperf
+/dns_type-from-name.h
+/dns_type-list.txt
+/dns_type-to-name.h
diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c
new file mode 100644
index 0000000..271a7e1
--- /dev/null
+++ b/src/resolve/dns-type.c
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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/>.
+***/
+
+#include "dns-type.h"
+
+typedef const struct {
+        uint16_t type;
+        const char *name;
+} dns_type;
+
+static const struct dns_type_name *
+lookup_dns_type (register const char *str, register unsigned int len);
+
+#include "dns_type-from-name.h"
+#include "dns_type-to-name.h"
+
+int dns_type_from_string(const char *s, uint16_t *type) {
+        const struct dns_type_name *sc;
+
+        assert(s);
+        assert(type);
+
+        sc = lookup_dns_type(s, strlen(s));
+        if (!sc)
+                return -EINVAL;
+
+        *type = sc->id;
+        return 0;
+}
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
new file mode 100644
index 0000000..6606315
--- /dev/null
+++ b/src/resolve/dns-type.h
@@ -0,0 +1,122 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  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/>.
+***/
+
+#pragma once
+
+#include <inttypes.h>
+
+#include "macro.h"
+
+const char *dns_type_to_string(uint16_t type);
+int dns_type_from_string(const char *s, uint16_t *type);
+
+/* DNS record types, taken from
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml.
+ */
+enum {
+        /* Normal records */
+        DNS_TYPE_A          = 0x01,
+        DNS_TYPE_NS,
+        DNS_TYPE_MD,
+        DNS_TYPE_MF,
+        DNS_TYPE_CNAME,
+        DNS_TYPE_SOA,
+        DNS_TYPE_MB,
+        DNS_TYPE_MG,
+        DNS_TYPE_MR,
+        DNS_TYPE_NULL,
+        DNS_TYPE_WKS,
+        DNS_TYPE_PTR,
+        DNS_TYPE_HINFO,
+        DNS_TYPE_MINFO,
+        DNS_TYPE_MX,
+        DNS_TYPE_TXT,
+        DNS_TYPE_RP,
+        DNS_TYPE_AFSDB,
+        DNS_TYPE_X25,
+        DNS_TYPE_ISDN,
+        DNS_TYPE_RT,
+        DNS_TYPE_NSAP,
+        DNS_TYPE_NSAP_PTR,
+        DNS_TYPE_SIG,
+        DNS_TYPE_KEY,
+        DNS_TYPE_PX,
+        DNS_TYPE_GPOS,
+        DNS_TYPE_AAAA,
+        DNS_TYPE_LOC,
+        DNS_TYPE_NXT,
+        DNS_TYPE_EID,
+        DNS_TYPE_NIMLOC,
+        DNS_TYPE_SRV,
+        DNS_TYPE_ATMA,
+        DNS_TYPE_NAPTR,
+        DNS_TYPE_KX,
+        DNS_TYPE_CERT,
+        DNS_TYPE_A6,
+        DNS_TYPE_DNAME,
+        DNS_TYPE_SINK,
+        DNS_TYPE_OPT,          /* EDNS0 option */
+        DNS_TYPE_APL,
+        DNS_TYPE_DS,
+        DNS_TYPE_SSHFP,
+        DNS_TYPE_IPSECKEY,
+        DNS_TYPE_RRSIG,
+        DNS_TYPE_NSEC,
+        DNS_TYPE_DNSKEY,
+        DNS_TYPE_DHCID,
+        DNS_TYPE_NSEC3,
+        DNS_TYPE_NSEC3PARAM,
+        DNS_TYPE_TLSA,
+
+        DNS_TYPE_HIP        = 0x37,
+        DNS_TYPE_NINFO,
+        DNS_TYPE_RKEY,
+        DNS_TYPE_TALINK,
+        DNS_TYPE_CDS,
+        DNS_TYPE_CDNSKEY,
+
+        DNS_TYPE_SPF        = 0x63,
+        DNS_TYPE_NID,
+        DNS_TYPE_L32,
+        DNS_TYPE_L64,
+        DNS_TYPE_LP,
+        DNS_TYPE_EUI48,
+        DNS_TYPE_EUI64,
+
+        DNS_TYPE_TKEY       = 0xF9,
+        DNS_TYPE_TSIG,
+        DNS_TYPE_IXFR,
+        DNS_TYPE_AXFR,
+        DNS_TYPE_MAILB,
+        DNS_TYPE_MAILA,
+        DNS_TYPE_ANY,
+        DNS_TYPE_URI,
+        DNS_TYPE_CAA,
+        DNS_TYPE_TA         = 0x8000,
+        DNS_TYPE_DLV,
+
+        _DNS_TYPE_MAX,
+        _DNS_TYPE_INVALID = -1
+};
+
+assert_cc(DNS_TYPE_SSHFP == 44);
+assert_cc(DNS_TYPE_TLSA == 52);
+assert_cc(DNS_TYPE_ANY == 255);
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 7d1cfe4..af22a89 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -25,6 +25,7 @@
 
 #include "resolved-dns-domain.h"
 #include "resolved-dns-rr.h"
+#include "dns-type.h"
 
 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
         DnsResourceKey *k;
@@ -627,54 +628,3 @@ int dns_class_from_string(const char *s, uint16_t *class) {
 
         return 0;
 }
-
-static const struct {
-        uint16_t type;
-        const char *name;
-} dns_types[] = {
-        { DNS_TYPE_A,     "A"     },
-        { DNS_TYPE_NS,    "NS"    },
-        { DNS_TYPE_CNAME, "CNAME" },
-        { DNS_TYPE_SOA,   "SOA"   },
-        { DNS_TYPE_PTR,   "PTR"   },
-        { DNS_TYPE_HINFO, "HINFO" },
-        { 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"   },
-        { DNS_TYPE_DNAME, "DNAME" },
-        { DNS_TYPE_ANY,   "ANY"   },
-        { DNS_TYPE_OPT,   "OPT"   },
-        { DNS_TYPE_TKEY,  "TKEY"  },
-        { DNS_TYPE_TSIG,  "TSIG"  },
-        { DNS_TYPE_IXFR,  "IXFR"  },
-        { DNS_TYPE_AXFR,  "AXFR"  },
-};
-
-const char *dns_type_to_string(uint16_t type) {
-        unsigned i;
-
-        for (i = 0; i < ELEMENTSOF(dns_types); i++)
-                if (dns_types[i].type == type)
-                        return dns_types[i].name;
-
-        return NULL;
-}
-
-int dns_type_from_string(const char *s, uint16_t *type) {
-        unsigned i;
-
-        assert(s);
-        assert(type);
-
-        for (i = 0; i < ELEMENTSOF(dns_types); i++)
-                if (strcaseeq(dns_types[i].name, s)) {
-                        *type = dns_types[i].type;
-                        return 0;
-                }
-
-        return -EINVAL;
-}
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 61c00d5..20a344b 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -27,6 +27,7 @@
 #include "util.h"
 #include "hashmap.h"
 #include "in-addr-util.h"
+#include "dns-type.h"
 
 typedef struct DnsResourceKey DnsResourceKey;
 typedef struct DnsResourceRecord DnsResourceRecord;
@@ -39,35 +40,6 @@ enum {
         _DNS_CLASS_INVALID = -1
 };
 
-/* DNS record types, see RFC 1035 */
-enum {
-        /* Normal records */
-        DNS_TYPE_A     = 0x01,
-        DNS_TYPE_NS    = 0x02,
-        DNS_TYPE_CNAME = 0x05,
-        DNS_TYPE_SOA   = 0x06,
-        DNS_TYPE_PTR   = 0x0C,
-        DNS_TYPE_HINFO = 0x0D,
-        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,
-        DNS_TYPE_SPF   = 0x63,
-
-        /* Special records */
-        DNS_TYPE_ANY   = 0xFF,
-        DNS_TYPE_OPT   = 0x29,      /* EDNS0 option */
-        DNS_TYPE_TKEY  = 0xF9,
-        DNS_TYPE_TSIG  = 0xFA,
-        DNS_TYPE_IXFR  = 0xFB,
-        DNS_TYPE_AXFR  = 0xFC,
-        _DNS_TYPE_MAX,
-        _DNS_TYPE_INVALID = -1
-};
-
 struct DnsResourceKey {
         unsigned n_ref;
         uint16_t class, type;
@@ -178,8 +150,5 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret);
 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref);
 
-const char *dns_type_to_string(uint16_t type);
-int dns_type_from_string(const char *name, uint16_t *type);
-
 const char *dns_class_to_string(uint16_t type);
 int dns_class_from_string(const char *name, uint16_t *class);

commit fd00a088216f6d6a6c502faf6b46c1e2ae7cbc54
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Aug 1 19:36:48 2014 -0400

    build-sys: use a common rule for some gperf commands

diff --git a/Makefile.am b/Makefile.am
index 30b2589..73aa420 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1156,37 +1156,27 @@ BUILT_SOURCES += \
 	src/shared/af-from-name.h \
 	src/shared/af-to-name.h
 
-src/shared/errno-list.txt:
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - < /dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+/ { print $$2; }'  > $@
+src/shared/%-from-name.gperf: src/shared/%-list.txt
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct $*_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
 
-src/shared/errno-from-name.gperf: src/shared/errno-list.txt
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct errno_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' < $< > $@
+src/shared/%-from-name.h: src/shared/%-from-name.gperf
+	$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_$* -H hash_$*_name -p -C <$< >$@
 
-src/shared/errno-from-name.h: src/shared/errno-from-name.gperf
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_errno -H hash_errno_name -p -C < $< > $@
 
-src/shared/errno-to-name.h: src/shared/errno-list.txt
+src/shared/errno-list.txt:
 	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} !/EDEADLOCK/ && !/EWOULDBLOCK/ && !/ENOTSUP/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@
+	$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - </dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+/ { print $$2; }'  >$@
 
-src/shared/af-list.txt:
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/socket.h - < /dev/null | grep -v AF_UNSPEC | grep -v AF_MAX | $(AWK) '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $$2; }'  > $@
+src/shared/errno-to-name.h: src/shared/errno-list.txt
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} !/EDEADLOCK/ && !/EWOULDBLOCK/ && !/ENOTSUP/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
 
-src/shared/af-from-name.gperf: src/shared/af-list.txt
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct af_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' < $< > $@
 
-src/shared/af-from-name.h: src/shared/af-from-name.gperf
+src/shared/af-list.txt:
 	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_af -H hash_af_name -p -C < $< > $@
+	$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/socket.h - </dev/null | grep -v AF_UNSPEC | grep -v AF_MAX | $(AWK) '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $$2; }'  >$@
 
 src/shared/af-to-name.h: src/shared/af-list.txt
-	$(AM_V_at)$(MKDIR_P) $(dir $@)
-	$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@
+	$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
 
 # ------------------------------------------------------------------------------
 systemd_SOURCES = \

commit 23432a1c249b9c513e438bffe9778a7ce2ee74fe
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Aug 1 19:36:33 2014 -0400

    resolved: align last rr column

diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 6cb4ed9..7d1cfe4 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -180,8 +180,7 @@ int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
                 t = tbuf;
         }
 
-        s = strjoin(DNS_RESOURCE_KEY_NAME(key), " ", c, " ", t, NULL);
-        if (!s)
+        if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
                 return -ENOMEM;
 
         *ret = s;

commit 1d749d044bf0e95697b6649e046aab82b0f02aa0
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Aug 3 12:52:03 2014 -0400

    tty-ask-password-agent: modernization

diff --git a/src/core/manager.c b/src/core/manager.c
index af508ef..32c0565 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1977,10 +1977,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 }
 
 void manager_send_unit_plymouth(Manager *m, Unit *u) {
-        union sockaddr_union sa = {
-                .un.sun_family = AF_UNIX,
-                .un.sun_path = "\0/org/freedesktop/plymouthd",
-        };
+        union sockaddr_union sa = PLYMOUTH_SOCKET;
 
         int n = 0;
         _cleanup_free_ char *message = NULL;
diff --git a/src/shared/def.h b/src/shared/def.h
index a52853c..92394e8 100644
--- a/src/shared/def.h
+++ b/src/shared/def.h
@@ -73,6 +73,11 @@
 #define UNIX_USER_BUS_FMT "unix:path=%s/bus"
 #define KERNEL_USER_BUS_FMT "kernel:path=/dev/kdbus/"UID_FMT"-user/bus"
 
+#define PLYMOUTH_SOCKET {                                       \
+                .un.sun_family = AF_UNIX,                       \
+                .un.sun_path = "\0/org/freedesktop/plymouthd",  \
+        }
+
 #ifndef TTY_GID
 #define TTY_GID 5
 #endif
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 528b899..8a02fb0 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -41,6 +41,7 @@
 #include "ask-password-api.h"
 #include "strv.h"
 #include "build.h"
+#include "def.h"
 
 static enum {
         ACTION_LIST,
@@ -59,9 +60,9 @@ static int ask_password_plymouth(
                 bool accept_cached,
                 char ***_passphrases) {
 
-        int fd = -1, notify = -1;
-        union sockaddr_union sa = {};
-        char *packet = NULL;
+        _cleanup_close_ int fd = -1, notify = -1;
+        union sockaddr_union sa = PLYMOUTH_SOCKET;
+        _cleanup_free_ char *packet = NULL;
         ssize_t k;
         int r, n;
         struct pollfd pollfd[2] = {};
@@ -75,28 +76,23 @@ static int ask_password_plymouth(
         assert(_passphrases);
 
         if (flag_file) {
-                if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
+                notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
+                if (notify < 0)
+                        return -errno;
 
-                if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
+                r = inotify_add_watch(notify, flag_file, IN_ATTRIB); /* for the link count */
+                if (r < 0)
+                        return -errno;
         }
 
-        if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
-                r = -errno;
-                goto finish;
-        }
+        fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (fd < 0)
+                return -errno;
 
-        sa.sa.sa_family = AF_UNIX;
-        strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
-        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+        r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+        if (r < 0) {
                 log_error("Failed to connect to Plymouth: %m");
-                r = -errno;
-                goto finish;
+                return -errno;
         }
 
         if (accept_cached) {
@@ -106,15 +102,12 @@ static int ask_password_plymouth(
                             message, &n) < 0)
                 packet = NULL;
 
-        if (!packet) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        if (!packet)
+                return log_oom();
 
-        if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
-                r = k < 0 ? (int) k : -EIO;
-                goto finish;
-        }
+        k = loop_write(fd, packet, n + 1, true);
+        if (k != n + 1)
+                return k < 0 ? (int) k : -EIO;
 
         pollfd[POLL_SOCKET].fd = fd;
         pollfd[POLL_SOCKET].events = POLLIN;
@@ -129,31 +122,23 @@ static int ask_password_plymouth(
 
                         y = now(CLOCK_MONOTONIC);
 
-                        if (y > until) {
-                                r = -ETIME;
-                                goto finish;
-                        }
+                        if (y > until)
+                                return -ETIME;
 
                         sleep_for = (int) ((until - y) / USEC_PER_MSEC);
                 }
 
-                if (flag_file)
-                        if (access(flag_file, F_OK) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                if ((j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) {
+                if (flag_file && access(flag_file, F_OK) < 0)
+                        return -errno;
 
+                j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+                if (j < 0) {
                         if (errno == EINTR)
                                 continue;
 
-                        r = -errno;
-                        goto finish;
-                } else if (j == 0) {
-                        r = -ETIME;
-                        goto finish;
-                }
+                        return -errno;
+                } else if (j == 0)
+                        return -ETIME;
 
                 if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
                         flush_fd(notify);
@@ -161,10 +146,9 @@ static int ask_password_plymouth(
                 if (pollfd[POLL_SOCKET].revents == 0)
                         continue;
 
-                if ((k = read(fd, buffer + p, sizeof(buffer) - p)) <= 0) {
-                        r = k < 0 ? -errno : -EIO;
-                        goto finish;
-                }
+                k = read(fd, buffer + p, sizeof(buffer) - p);
+                if (k <= 0)
+                        return r = k < 0 ? -errno : -EIO;
 
                 p += k;
 
@@ -180,15 +164,12 @@ static int ask_password_plymouth(
                                 free(packet);
                                 packet = NULL;
 
-                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
+                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
+                                        return -ENOMEM;
 
-                                if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
-                                        r = k < 0 ? (int) k : -EIO;
-                                        goto finish;
-                                }
+                                k = loop_write(fd, packet, n+1, true);
+                                if (k != n + 1)
+                                        return k < 0 ? (int) k : -EIO;
 
                                 accept_cached = false;
                                 p = 0;
@@ -196,8 +177,7 @@ static int ask_password_plymouth(
                         }
 
                         /* No password, because UI not shown */
-                        r = -ENOENT;
-                        goto finish;
+                        return -ENOENT;
 
                 } else if (buffer[0] == 2 || buffer[0] == 9) {
                         uint32_t size;
@@ -209,38 +189,25 @@ static int ask_password_plymouth(
 
                         memcpy(&size, buffer+1, sizeof(size));
                         size = le32toh(size);
-                        if (size+5 > sizeof(buffer)) {
-                                r = -EIO;
-                                goto finish;
-                        }
+                        if (size + 5 > sizeof(buffer))
+                                return -EIO;
 
                         if (p-5 < size)
                                 continue;
 
-                        if (!(l = strv_parse_nulstr(buffer + 5, size))) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
+                        l = strv_parse_nulstr(buffer + 5, size);
+                        if (!l)
+                                return -ENOMEM;
 
                         *_passphrases = l;
                         break;
 
-                } else {
+                } else
                         /* Unknown packet */
-                        r = -EIO;
-                        goto finish;
-                }
+                        return -EIO;
         }
 
-        r = 0;
-
-finish:
-        safe_close(notify);
-        safe_close(fd);
-
-        free(packet);
-
-        return r;
+        return 0;
 }
 
 static int parse_password(const char *filename, char **wall) {
@@ -255,7 +222,7 @@ static int parse_password(const char *filename, char **wall) {
                 { "Ask", "Message",      config_parse_string,   0, &message       },
                 { "Ask", "PID",          config_parse_unsigned, 0, &pid           },
                 { "Ask", "AcceptCached", config_parse_bool,     0, &accept_cached },
-                { NULL, NULL, NULL, 0, NULL }
+                {}
         };
 
         int r;
@@ -328,13 +295,12 @@ static int parse_password(const char *filename, char **wall) {
                                 if (!packet)
                                         r = -ENOMEM;
                                 else {
-                                        char *d;
-
-                                        packet[0] = '+';
-                                        d = packet+1;
+                                        char *d = packet + 1;
 
                                         STRV_FOREACH(p, passwords)
                                                 d = stpcpy(d, *p) + 1;
+
+                                        packet[0] = '+';
                                 }
                         }
 
@@ -367,7 +333,7 @@ static int parse_password(const char *filename, char **wall) {
                         }
                 }
 
-                if (r == -ETIME || r == -ENOENT)
+                if (IN_SET(r, -ETIME, -ENOENT))
                         /* If the query went away, that's OK */
                         return 0;
 
@@ -397,7 +363,7 @@ static int parse_password(const char *filename, char **wall) {
 }
 
 static int wall_tty_block(void) {
-        char *p;
+        _cleanup_free_ char *p = NULL;
         int fd, r;
         dev_t devnr;
 
@@ -412,8 +378,6 @@ static int wall_tty_block(void) {
         mkfifo(p, 0600);
 
         fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-        free(p);
-
         if (fd < 0)
                 return -errno;
 
@@ -421,21 +385,15 @@ static int wall_tty_block(void) {
 }
 
 static bool wall_tty_match(const char *path) {
-        int fd, k;
-        char *p;
+        int fd, r;
         struct stat st;
+        _cleanup_free_ char *p = NULL;
 
-        if (path_is_absolute(path))
-                k = lstat(path, &st);
-        else {
-                if (asprintf(&p, "/dev/%s", path) < 0)
-                        return true;
-
-                k = lstat(p, &st);
-                free(p);
-        }
+        if (!path_is_absolute(path))
+                path = strappenda("/dev/", path);
 
-        if (k < 0)
+        r = lstat(path, &st);
+        if (r < 0)
                 return true;
 
         if (!S_ISCHR(st.st_mode))
@@ -453,8 +411,6 @@ static bool wall_tty_match(const char *path) {
                 return true;
 
         fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-        free(p);
-
         if (fd < 0)
                 return true;
 
@@ -464,11 +420,12 @@ static bool wall_tty_match(const char *path) {
 }
 
 static int show_passwords(void) {
-        DIR *d;
+        _cleanup_closedir_ DIR *d;
         struct dirent *de;
         int r = 0;
 
-        if (!(d = opendir("/run/systemd/ask-password"))) {
+        d = opendir("/run/systemd/ask-password");
+        if (!d) {
                 if (errno == ENOENT)
                         return 0;
 
@@ -477,9 +434,8 @@ static int show_passwords(void) {
         }
 
         while ((de = readdir(d))) {
-                char *p;
+                _cleanup_free_ char *p = NULL, *wall = NULL;
                 int q;
-                char *wall;
 
                 /* We only support /dev on tmpfs, hence we can rely on
                  * d_type to be reliable */
@@ -493,27 +449,18 @@ static int show_passwords(void) {
                 if (!startswith(de->d_name, "ask."))
                         continue;
 
-                if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) {
-                        r = log_oom();
-                        goto finish;
-                }
+                p = strappend("/run/systemd/ask-password/", de->d_name);
+                if (!p)
+                        return log_oom();
 
-                wall = NULL;
-                if ((q = parse_password(p, &wall)) < 0)
+                q = parse_password(p, &wall);
+                if (q < 0 && r == 0)
                         r = q;
 
-                free(p);
-
-                if (wall) {
+                if (wall)
                         utmp_wall(wall, NULL, wall_tty_match);
-                        free(wall);
-                }
         }
 
-finish:
-        if (d)
-                closedir(d);
-
         return r;
 }
 
@@ -524,7 +471,7 @@ static int watch_passwords(void) {
                 _FD_MAX
         };
 
-        int notify = -1, signal_fd = -1, tty_block_fd = -1;
+        _cleanup_close_ int notify = -1, signal_fd = -1, tty_block_fd = -1;
         struct pollfd pollfd[_FD_MAX] = {};
         sigset_t mask;
         int r;
@@ -533,25 +480,20 @@ static int watch_passwords(void) {
 
         mkdir_p_label("/run/systemd/ask-password", 0755);
 
-        if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
-                r = -errno;
-                goto finish;
-        }
+        notify = inotify_init1(IN_CLOEXEC);
+        if (notify < 0)
+                return -errno;
 
-        if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
-                r = -errno;
-                goto finish;
-        }
+        if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0)
+                return -errno;
 
         assert_se(sigemptyset(&mask) == 0);
         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
-        if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
-                log_error("signalfd(): %m");
-                r = -errno;
-                goto finish;
-        }
+        signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+        if (signal_fd < 0)
+                return -errno;
 
         pollfd[FD_INOTIFY].fd = notify;
         pollfd[FD_INOTIFY].events = POLLIN;
@@ -559,16 +501,15 @@ static int watch_passwords(void) {
         pollfd[FD_SIGNAL].events = POLLIN;
 
         for (;;) {
-                if ((r = show_passwords()) < 0)
+                r = show_passwords();
+                if (r < 0)
                         log_error("Failed to show password: %s", strerror(-r));
 
                 if (poll(pollfd, _FD_MAX, -1) < 0) {
-
                         if (errno == EINTR)
                                 continue;
 
-                        r = -errno;
-                        goto finish;
+                        return -errno;
                 }
 
                 if (pollfd[FD_INOTIFY].revents != 0)
@@ -578,14 +519,7 @@ static int watch_passwords(void) {
                         break;
         }
 
-        r = 0;
-
-finish:
-        safe_close(notify);
-        safe_close(signal_fd);
-        safe_close(tty_block_fd);
-
-        return r;
+        return 0;
 }
 
 static void help(void) {
@@ -692,7 +626,8 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        if ((r = parse_argv(argc, argv)) <= 0)
+        r = parse_argv(argc, argv);
+        if (r <= 0)
                 goto finish;
 
         if (arg_console) {
@@ -700,8 +635,7 @@ int main(int argc, char *argv[]) {
                 release_terminal();
         }
 
-        if (arg_action == ACTION_WATCH ||
-            arg_action == ACTION_WALL)
+        if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
                 r = watch_passwords();
         else
                 r = show_passwords();

commit 601185b43da638b1c74153deae01dbd518680889
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Aug 2 11:12:21 2014 -0400

    Unify parse_argv style
    
    getopt is usually good at printing out a nice error message when
    commandline options are invalid. It distinguishes between an unknown
    option and a known option with a missing arg. It is better to let it
    do its job and not use opterr=0 unless we actually want to suppress
    messages. So remove opterr=0 in the few places where it wasn't really
    useful.
    
    When an error in options is encountered, we should not print a lengthy
    help() and overwhelm the user, when we know precisely what is wrong
    with the commandline. In addition, since help() prints to stdout, it
    should not be used except when requested with -h or --help.
    
    Also, simplify things here and there.

diff --git a/CODING_STYLE b/CODING_STYLE
index e22c1ed..ca3b518 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -167,3 +167,8 @@
   caching for any thread that is not the main thread. Use
   is_main_thread() to detect whether the calling thread is the main
   thread.
+
+- Option parsing:
+  - Do not print full help() on error, be specific about the error.
+  - Do not print messages to stdout on error.
+  - Do not POSIX_ME_HARDER unless necessary, i.e. avoid "+" in option string.
diff --git a/src/activate/activate.c b/src/activate/activate.c
index c3309a8..8942773 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -279,7 +279,7 @@ static int install_chld_handler(void) {
         return r;
 }
 
-static int help(void) {
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Listen on sockets and launch child on connection.\n\n"
                "Options:\n"
@@ -290,10 +290,7 @@ static int help(void) {
                "  --version                Print version string and exit\n"
                "\n"
                "Note: file descriptors from sd_listen_fds() will be passed through.\n"
-               , program_invocation_short_name
-               );
-
-        return 0;
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -319,7 +316,8 @@ static int parse_argv(int argc, char *argv[]) {
         while ((c = getopt_long(argc, argv, "+hl:aE:", options, NULL)) >= 0)
                 switch(c) {
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -354,7 +352,7 @@ static int parse_argv(int argc, char *argv[]) {
                 }
 
         if (optind == argc) {
-                log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
+                log_error("%s: command to execute is missing.",
                           program_invocation_short_name);
                 return -EINVAL;
         }
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 888f6b7..d0bf014 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -1255,10 +1255,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        opterr = 0;
-
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
-
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
                 switch (c) {
 
                 case 'h':
@@ -1323,17 +1320,11 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case '?':
-                        log_error("Unknown option %s.", argv[optind-1]);
-                        return -EINVAL;
-
-                case ':':
-                        log_error("Missing argument to %s.", argv[optind-1]);
                         return -EINVAL;
 
                 default:
                         assert_not_reached("Unhandled option code.");
                 }
-        }
 
         return 1; /* work to do */
 }
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index 4d5690c..5c37cff 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -50,8 +50,7 @@ static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
 static bool arg_accept_cached = false;
 static bool arg_multiple = false;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] MESSAGE\n\n"
                "Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
                "  -h --help          Show this help\n"
@@ -60,10 +59,8 @@ static int help(void) {
                "     --no-tty        Ask question via agent even on TTY\n"
                "     --accept-cached Accept cached passwords\n"
                "     --multiple      List multiple passwords if available\n"
-               "     --id=ID         Query identifier (e.g. cryptsetup:/dev/sda5)\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --id=ID         Query identifier (e.g. cryptsetup:/dev/sda5)\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -93,12 +90,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_ICON:
                         arg_icon = optarg;
@@ -133,10 +131,9 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
-        if (optind != argc-1) {
-                help();
+        if (optind != argc - 1) {
+                log_error("%s: required argument missing.", program_invocation_short_name);
                 return -EINVAL;
         }
 
@@ -151,7 +148,8 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        if ((r = parse_argv(argc, argv)) <= 0)
+        r = parse_argv(argc, argv);
+        if (r <= 0)
                 goto finish;
 
         if (arg_timeout > 0)
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 9fc5d4e..c1c1522 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -122,15 +122,12 @@ static int apply_file(const char *path, bool ignore_enoent) {
         return r;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Registers binary formats.\n\n"
                "  -h --help             Show this help\n"
-               "     --version          Show package version\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --version          Show package version\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -150,12 +147,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -168,7 +166,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 359e273..51b51c4 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -32,17 +32,14 @@
 #include "util.h"
 #include "utf8.h"
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] COMMAND ...\n\n"
                "Query or change firmware and boot manager settings.\n\n"
                "  -h --help              Show this help\n"
                "     --version           Show package version\n"
                "Commands:\n"
-               "  status                 Show current boot settings\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  status                 Show current boot settings\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -51,8 +48,8 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         static const struct option options[] = {
-                { "help",                no_argument,       NULL, 'h'                     },
-                { "version",             no_argument,       NULL, ARG_VERSION             },
+                { "help",        no_argument, NULL, 'h'          },
+                { "version",     no_argument, NULL, ARG_VERSION  },
                 {}
         };
 
@@ -61,12 +58,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -79,7 +77,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
@@ -268,21 +265,17 @@ static int bootctl_main(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        int r, retval = EXIT_FAILURE;
+        int r;
 
         log_parse_environment();
         log_open();
 
         r = parse_argv(argc, argv);
-        if (r < 0)
-                goto finish;
-        else if (r == 0) {
-                retval = EXIT_SUCCESS;
+        if (r <= 0)
                 goto finish;
-        }
 
         r = bootctl_main(argc, argv);
-        retval = r < 0 ? EXIT_FAILURE : r;
-finish:
-        return retval;
+
+ finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 5683025..c0e176d 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -163,7 +163,7 @@ static void help(void) {
                 DEFAULT_INIT);
 }
 
-static int parse_args(int argc, char *argv[]) {
+static int parse_argv(int argc, char *argv[]) {
         static const struct option options[] = {
                 {"rel",           no_argument,        NULL,  'r'},
                 {"freq",          required_argument,  NULL,  'f'},
@@ -180,12 +180,14 @@ static int parse_args(int argc, char *argv[]) {
                 {"entropy",       no_argument,        NULL,  'e'},
                 {}
         };
-        int c;
+        int c, r;
 
-        while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0) {
-                int r;
+        if (getpid() == 1)
+                opterr = 0;
 
+        while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0)
                 switch (c) {
+
                 case 'r':
                         arg_relative = true;
                         break;
@@ -238,18 +240,22 @@ static int parse_args(int argc, char *argv[]) {
                         break;
                 case 'h':
                         help();
-                        exit (EXIT_SUCCESS);
+                        return 0;
+                case '?':
+                        if (getpid() != 1)
+                                return -EINVAL;
+                        else
+                                return 0;
                 default:
-                        break;
+                        assert_not_reached("Unhandled option code.");
                 }
-        }
 
-        if (arg_hz <= 0.0) {
-                fprintf(stderr, "Error: Frequency needs to be > 0\n");
+        if (arg_hz <= 0) {
+                log_error("Frequency needs to be > 0");
                 return -EINVAL;
         }
 
-        return 0;
+        return 1;
 }
 
 static void do_journal_append(char *file) {
@@ -314,9 +320,9 @@ int main(int argc, char *argv[]) {
 
         parse_conf();
 
-        r = parse_args(argc, argv);
-        if (r < 0)
-                return EXIT_FAILURE;
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 
         /*
          * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index 1f17fe8..e5713d6 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -93,7 +93,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -156,7 +156,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         /* If the first command line argument is only "x" characters
          * we'll write who we are talking to into it, so that "ps" is
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 052ac8f..6e9bd23 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -46,8 +46,7 @@ static bool arg_all = false;
 static int arg_full = -1;
 static char* arg_machine = NULL;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CGROUP...]\n\n"
                "Recursively show control group contents.\n\n"
                "  -h --help           Show this help\n"
@@ -56,10 +55,8 @@ static int help(void) {
                "  -a --all            Show all groups, including empty\n"
                "  -l --full           Do not ellipsize output\n"
                "  -k                  Include kernel threads in output\n"
-               "  -M --machine        Show container\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  -M --machine        Show container\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -84,12 +81,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -122,7 +120,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index fd0023b..509fe4c 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -548,8 +548,7 @@ static int display(Hashmap *a) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Show top control groups by their resource usage.\n\n"
                "  -h --help           Show this help\n"
@@ -563,10 +562,8 @@ static int help(void) {
                "  -d --delay=DELAY    Delay between updates\n"
                "  -n --iterations=N   Run for N iterations before exiting\n"
                "  -b --batch          Run in batch mode, accepting no input\n"
-               "     --depth=DEPTH    Maximum traversal depth (default: %u)\n",
-               program_invocation_short_name, arg_depth);
-
-        return 0;
+               "     --depth=DEPTH    Maximum traversal depth (default: %u)\n"
+               , program_invocation_short_name, arg_depth);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -594,12 +591,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -674,7 +672,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind < argc) {
                 log_error("Too many arguments.");
diff --git a/src/core/main.c b/src/core/main.c
index e9909de..d2104cb 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -952,13 +952,13 @@ static int parse_argv(int argc, char *argv[]) {
                          * parse_proc_cmdline_word() or ignore. */
 
                 case '?':
-                default:
-                        if (getpid() != 1) {
-                                log_error("Unknown option code %c", c);
+                        if (getpid() != 1)
                                 return -EINVAL;
-                        }
+                        else
+                                return 0;
 
-                        break;
+                default:
+                        assert_not_reached("Unhandled option code.");
                 }
 
         if (optind < argc && getpid() != 1) {
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index fde3ce9..1abc140 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -74,9 +74,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        opterr = 0;
-
-        while ((c = getopt_long(argc, argv, ":", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_LOG_LEVEL:
@@ -115,11 +113,6 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case '?':
-                        log_error("Unknown option %s.", argv[optind-1]);
-                        return -EINVAL;
-
-                case ':':
-                        log_error("Missing argument to %s.", argv[optind-1]);
                         return -EINVAL;
 
                 default:
diff --git a/src/delta/delta.c b/src/delta/delta.c
index dd7523d..cd8bd35 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -473,18 +473,15 @@ static int process_suffix_chop(const char *arg) {
         return -EINVAL;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [SUFFIX...]\n\n"
                "Find overridden configuration files.\n\n"
                "  -h --help           Show this help\n"
                "     --version        Show package version\n"
                "     --no-pager       Do not pipe output into a pager\n"
                "     --diff[=1|0]     Show a diff when overridden files differ\n"
-               "  -t --type=LIST...   Only display a selected set of override types\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  -t --type=LIST...   Only display a selected set of override types\n"
+               , program_invocation_short_name);
 }
 
 static int parse_flags(const char *flag_str, int flags) {
@@ -534,7 +531,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -585,7 +582,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 8cf8dcf..ff5bee5 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -36,18 +36,15 @@ static enum {
         ONLY_CONTAINER
 } arg_mode = ANY_VIRTUALIZATION;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Detect execution in a virtualized environment.\n\n"
                "  -h --help             Show this help\n"
                "     --version          Show package version\n"
                "  -c --container        Only detect whether we are run in a container\n"
                "  -v --vm               Only detect whether we are run in a VM\n"
-               "  -q --quiet            Don't output anything, just set return value\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  -q --quiet            Don't output anything, just set return value\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -70,12 +67,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -100,10 +98,10 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind < argc) {
-                help();
+                log_error("%s takes no arguments.",
+                          program_invocation_short_name);
                 return -EINVAL;
         }
 
diff --git a/src/escape/escape.c b/src/escape/escape.c
index ba2fb47..f2a0721 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -37,8 +37,7 @@ static const char *arg_suffix = NULL;
 static const char *arg_template = NULL;
 static bool arg_path = false;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [NAME...]\n\n"
                "Show system and user paths.\n\n"
                "  -h --help               Show this help\n"
@@ -47,10 +46,8 @@ static int help(void) {
                "     --template=TEMPLATE  Insert strings as instance into template\n"
                "  -u --unescape           Unescape strings\n"
                "  -m --mangle             Mangle strings\n"
-               "  -p --path               When escaping/unescaping assume the string is a path\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  -p --path               When escaping/unescaping assume the string is a path\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -77,12 +74,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -127,7 +125,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind >= argc) {
                 log_error("Not enough arguments.");
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 2c08ad4..fd73adb 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -647,8 +647,7 @@ static int process_root_password(void) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Configures basic settings of the system.\n\n"
                "  -h --help                    Show this help\n"
@@ -670,10 +669,8 @@ static int help(void) {
                "     --copy-timezone           Copy timezone from host\n"
                "     --copy-root-password      Copy root password from host\n"
                "     --copy                    Copy locale, timezone, root password\n"
-               "     --setup-machine-id        Generate a new random machine ID\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --setup-machine-id        Generate a new random machine ID\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -729,12 +726,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -887,7 +885,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 7e6922b..69da54f 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -321,8 +321,7 @@ static int set_deployment(sd_bus *bus, char **args, unsigned n) {
         return set_simple_string(bus, "SetDeployment", args[1]);
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] COMMAND ...\n\n"
                "Query or change system hostname.\n\n"
                "  -h --help              Show this help\n"
@@ -338,10 +337,8 @@ static int help(void) {
                "  set-hostname NAME      Set system hostname\n"
                "  set-icon-name NAME     Set icon name for host\n"
                "  set-chassis NAME       Set chassis type for host\n"
-               "  set-deployment NAME    Set deployment environment for host\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  set-deployment NAME    Set deployment environment for host\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -371,12 +368,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -415,7 +413,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 6cfe229..db81fe3 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -857,8 +857,7 @@ static int request_handler(
         return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found.\n");
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] ...\n\n"
                "HTTP server for journal events.\n\n"
                "  -h --help           Show this help\n"
@@ -867,8 +866,6 @@ static int help(void) {
                "     --key=KEY.PEM    Server key in PEM format\n"
                "     --trust=CERT.PEM Certificat authority certificate in PEM format\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -898,7 +895,8 @@ static int parse_argv(int argc, char *argv[]) {
                 switch(c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 1df1786..c8e3c23 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -1370,8 +1370,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
+                        assert_not_reached("Unknown option code.");
                 }
 
         if (optind < argc)
diff --git a/src/journal/cat.c b/src/journal/cat.c
index a525bcf..627c062 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -36,18 +36,15 @@ static char *arg_identifier = NULL;
 static int arg_priority = LOG_INFO;
 static bool arg_level_prefix = true;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Execute process with stdout/stderr connected to the journal.\n\n"
                "  -h --help               Show this help\n"
                "     --version            Show package version\n"
                "  -t --identifier=STRING  Set syslog identifier\n"
                "  -p --priority=PRIORITY  Set priority value (0..7)\n"
-               "     --level-prefix=BOOL  Control whether level prefix shall be parsed\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --level-prefix=BOOL  Control whether level prefix shall be parsed\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -71,12 +68,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -120,7 +118,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index 2bc9021..f5cf85a 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -81,29 +81,6 @@ static Set *new_matches(void) {
         return set;
 }
 
-static int help(void) {
-
-        printf("%s [OPTIONS...]\n\n"
-               "List or retrieve coredumps from the journal.\n\n"
-               "Flags:\n"
-               "  -h --help          Show this help\n"
-               "     --version       Print version string\n"
-               "     --no-pager      Do not pipe output into a pager\n"
-               "     --no-legend     Do not print the column headers.\n"
-               "  -1                 Show information about most recent entry only\n"
-               "  -F --field=FIELD   List all values a certain field takes\n"
-               "  -o --output=FILE   Write output to FILE\n\n"
-
-               "Commands:\n"
-               "  list [MATCHES...]  List available coredumps (default)\n"
-               "  info [MATCHES...]  Show detailed information about one or more coredumps\n"
-               "  dump [MATCHES...]  Print first matching coredump to stdout\n"
-               "  gdb [MATCHES...]   Start gdb for the first matching coredump\n"
-               , program_invocation_short_name);
-
-        return 0;
-}
-
 static int add_match(Set *set, const char *match) {
         int r = -ENOMEM;
         unsigned pid;
@@ -144,6 +121,26 @@ fail:
         return r;
 }
 
+static void help(void) {
+        printf("%s [OPTIONS...]\n\n"
+               "List or retrieve coredumps from the journal.\n\n"
+               "Flags:\n"
+               "  -h --help          Show this help\n"
+               "     --version       Print version string\n"
+               "     --no-pager      Do not pipe output into a pager\n"
+               "     --no-legend     Do not print the column headers.\n"
+               "  -1                 Show information about most recent entry only\n"
+               "  -F --field=FIELD   List all values a certain field takes\n"
+               "  -o --output=FILE   Write output to FILE\n\n"
+
+               "Commands:\n"
+               "  list [MATCHES...]  List available coredumps (default)\n"
+               "  info [MATCHES...]  Show detailed information about one or more coredumps\n"
+               "  dump [MATCHES...]  Print first matching coredump to stdout\n"
+               "  gdb [MATCHES...]   Start gdb for the first matching coredump\n"
+               , program_invocation_short_name);
+}
+
 static int parse_argv(int argc, char *argv[], Set *matches) {
         enum {
                 ARG_VERSION = 0x100,
@@ -171,7 +168,8 @@ static int parse_argv(int argc, char *argv[], Set *matches) {
 
                 case 'h':
                         arg_action = ACTION_NONE;
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         arg_action = ACTION_NONE;
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 52fd8be..5c4a71d 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -160,7 +160,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
         return 0;
 }
 
-static int help(void) {
+static void help(void) {
 
         pager_open_if_enabled();
 
@@ -218,8 +218,6 @@ static int help(void) {
                "     --verify              Verify journal file consistency\n"
 #endif
                , program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -306,12 +304,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xrM:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xrM:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -633,7 +632,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_follow && !arg_no_tail && arg_lines < 0)
                 arg_lines = 10;
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 4545047..b6839c1 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -320,7 +320,6 @@ static int status(sd_bus *bus, char *argv[]) {
 }
 
 static int help(void) {
-
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Introspect the bus.\n\n"
                "  -h --help               Show this help\n"
@@ -341,8 +340,8 @@ static int help(void) {
                "  list                    List bus names\n"
                "  monitor [SERVICE...]    Show bus traffic\n"
                "  status NAME             Show name status\n"
-               "  help                    Show this help\n",
-               program_invocation_short_name);
+               "  help                    Show this help\n"
+               , program_invocation_short_name);
 
         return 0;
 }
@@ -386,7 +385,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -455,7 +454,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (!arg_unique && !arg_acquired && !arg_activatable)
                 arg_unique = arg_acquired = arg_activatable = true;
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 8acc212..69d5007 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -440,8 +440,7 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] COMMAND ...\n\n"
                "Query or change system locale and keyboard settings.\n\n"
                "  -h --help                Show this help\n"
@@ -463,10 +462,8 @@ static int help(void) {
                "  list-x11-keymap-layouts  Show known X11 keyboard mapping layouts\n"
                "  list-x11-keymap-variants [LAYOUT]\n"
                "                           Show known X11 keyboard mapping variants\n"
-               "  list-x11-keymap-options  Show known X11 keyboard mapping options\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  list-x11-keymap-options  Show known X11 keyboard mapping options\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -494,12 +491,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -534,7 +532,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index 24e8fb0..02b6b25 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -122,8 +122,7 @@ static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Execute a process while inhibiting shutdown/sleep/idle.\n\n"
                "  -h --help               Show this help\n"
@@ -135,10 +134,8 @@ static int help(void) {
                "     --who=STRING         A descriptive string who is inhibiting\n"
                "     --why=STRING         A descriptive string why is being inhibited\n"
                "     --mode=MODE          One of block or delay\n"
-               "     --list               List active inhibitors\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --list               List active inhibitors\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -168,12 +165,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -206,7 +204,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_action == ACTION_INHIBIT && argc == 1)
                 arg_action = ACTION_LIST;
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index ebe9c1f..1773276 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -1047,8 +1047,7 @@ static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the login manager.\n\n"
                "  -h --help              Show this help\n"
@@ -1086,10 +1085,8 @@ static int help(void) {
                "  show-seat NAME...        Show properties of one or more seats\n"
                "  attach NAME DEVICE...    Attach one or more devices to a seat\n"
                "  flush-devices            Flush all device associations\n"
-               "  terminate-seat NAME...   Terminate all sessions on one or more seats\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  terminate-seat NAME...   Terminate all sessions on one or more seats\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1123,12 +1120,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -1195,7 +1193,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 1c933ce..85bbfc4 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -31,16 +31,13 @@
 
 static const char *arg_root = "";
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Initialize /etc/machine-id from a random source.\n\n"
                "  -h --help             Show this help\n"
                "     --version          Show package version\n"
                "     --root=ROOT        Filesystem root\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -62,12 +59,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -84,7 +82,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind < argc) {
                 log_error("Extraneous arguments");
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 574c988..02d5d30 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -779,8 +779,7 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the virtual machine and container registration manager.\n\n"
                "  -h --help              Show this help\n"
@@ -804,8 +803,6 @@ static int help(void) {
                "  kill NAME...           Send signal to processes of a VM/container\n"
                "  terminate NAME...      Terminate one or more VMs/containers\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -837,12 +834,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -904,7 +902,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index ecb84da..c77b092 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -181,15 +181,12 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
         return r;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Loads statically configured kernel modules.\n\n"
                "  -h --help             Show this help\n"
                "     --version          Show package version\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -209,12 +206,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -227,7 +225,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index d588935..6c2fdd1 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -30,17 +30,14 @@
 static bool arg_quiet = false;
 static char **arg_interfaces = NULL;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Block until network is configured.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Print version string\n"
                "  -q --quiet                Do not show status information\n"
-               "  -i --interface=INTERFACE  Block until at least these interfaces have appeared\n",
-               program_invocation_short_name);
-
-        return 0;
+               "  -i --interface=INTERFACE  Block until at least these interfaces have appeared\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -62,12 +59,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case 'q':
                         arg_quiet = true;
@@ -90,7 +88,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/notify/notify.c b/src/notify/notify.c
index f463c4d..2148ae0 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -42,8 +42,7 @@ static const char *arg_status = NULL;
 static bool arg_booted = false;
 static const char *arg_readahead = NULL;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
                "Notify the init system about service status updates.\n\n"
                "  -h --help             Show this help\n"
@@ -54,8 +53,6 @@ static int help(void) {
                "     --booted           Returns 0 if the system was booted up with systemd, non-zero otherwise\n"
                "     --readahead=ACTION Controls read-ahead operations\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -85,12 +82,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -131,7 +129,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind >= argc &&
             !arg_ready &&
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b118c73..76e86b7 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -166,8 +166,7 @@ static unsigned long arg_personality = 0xffffffffLU;
 static const char *arg_image = NULL;
 static Volatile arg_volatile = VOLATILE_NO;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
                "Spawn a minimal namespace container for debugging, testing and building.\n\n"
                "  -h --help                 Show this help\n"
@@ -216,8 +215,6 @@ static int help(void) {
                "                            the service unit nspawn is running in\n"
                "     --volatile[=MODE]      Run the system in volatile mode\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -285,12 +282,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -593,7 +591,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_share_system)
                 arg_register = false;
diff --git a/src/path/path.c b/src/path/path.c
index c2936e0..347921a 100644
--- a/src/path/path.c
+++ b/src/path/path.c
@@ -77,18 +77,6 @@ static const char* const path_table[_SD_PATH_MAX] = {
         [SD_PATH_SEARCH_CONFIGURATION] = "search-configuration",
 };
 
-static int help(void) {
-
-        printf("%s [OPTIONS...] [NAME...]\n\n"
-               "Show system and user paths.\n\n"
-               "  -h --help             Show this help\n"
-               "     --version          Show package version\n"
-               "     --suffix=SUFFIX    Suffix to append to paths\n",
-               program_invocation_short_name);
-
-        return 0;
-}
-
 static int list_homes(void) {
         uint64_t i = 0;
         int r = 0;
@@ -135,6 +123,15 @@ static int print_home(const char *n) {
         return -ENOTSUP;
 }
 
+static void help(void) {
+        printf("%s [OPTIONS...] [NAME...]\n\n"
+               "Show system and user paths.\n\n"
+               "  -h --help             Show this help\n"
+               "     --version          Show package version\n"
+               "     --suffix=SUFFIX    Suffix to append to paths\n",
+               program_invocation_short_name);
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -154,12 +151,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -176,7 +174,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/readahead/readahead.c b/src/readahead/readahead.c
index 73cf538..35176e9 100644
--- a/src/readahead/readahead.c
+++ b/src/readahead/readahead.c
@@ -36,31 +36,26 @@ unsigned arg_files_max = 16*1024;
 off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
 usec_t arg_timeout = 2*USEC_PER_MINUTE;
 
-static int help(void) {
-
-        printf("%s [OPTIONS...] collect [DIRECTORY]\n\n"
+static void help(void) {
+        printf("%1$s [OPTIONS...] collect [DIRECTORY]\n\n"
                "Collect read-ahead data on early boot.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n"
                "     --files-max=INT        Maximum number of files to read ahead\n"
                "     --file-size-max=BYTES  Maximum size of files to read ahead\n"
-               "     --timeout=USEC         Maximum time to spend collecting data\n\n\n",
-               program_invocation_short_name);
-
-        printf("%s [OPTIONS...] replay [DIRECTORY]\n\n"
+               "     --timeout=USEC         Maximum time to spend collecting data\n"
+               "\n\n"
+               "%1$s [OPTIONS...] replay [DIRECTORY]\n\n"
                "Replay collected read-ahead data on early boot.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n"
-               "     --file-size-max=BYTES  Maximum size of files to read ahead\n\n\n",
-               program_invocation_short_name);
-
-        printf("%s [OPTIONS...] analyze [PACK FILE]\n\n"
+               "     --file-size-max=BYTES  Maximum size of files to read ahead\n"
+               "\n\n"
+               "%1$s [OPTIONS...] analyze [PACK-FILE]\n\n"
                "Analyze collected read-ahead data.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -86,12 +81,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -131,11 +127,11 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind != argc-1 &&
             optind != argc-2) {
-                help();
+                log_error("%s: wrong number of arguments.",
+                          program_invocation_short_name);
                 return -EINVAL;
         }
 
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 80ce9cb..987b43a 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -448,7 +448,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h46i:t:c:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h46i:t:c:", options, NULL)) >= 0)
                 switch(c) {
 
                 case 'h':
@@ -514,7 +514,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_type == 0 && arg_class != 0) {
                 log_error("--class= may only be used in conjunction with --type=");
diff --git a/src/run/run.c b/src/run/run.c
index b9be145..f8f0ea2 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -48,8 +48,7 @@ static bool arg_nice_set = false;
 static char **arg_environment = NULL;
 static char **arg_property = NULL;
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n"
                "Run the specified command in a transient scope or service unit.\n\n"
                "  -h --help                 Show this help\n"
@@ -70,8 +69,6 @@ static int help(void) {
                "     --nice=NICE            Nice level\n"
                "     --setenv=NAME=VALUE    Set environment\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -119,12 +116,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hrH:M:p:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hrH:M:p:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -215,7 +213,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind >= argc) {
                 log_error("Command line to execute required.");
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 5adbea5..ca00eea 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -134,8 +134,7 @@ static int execute(char **modes, char **states) {
         return r;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s COMMAND\n\n"
                "Suspend the system, hibernate the system, or both.\n\n"
                "Commands:\n"
@@ -144,10 +143,7 @@ static int help(void) {
                "  suspend              Suspend the system\n"
                "  hibernate            Hibernate the system\n"
                "  hybrid-sleep         Both hibernate and suspend the system\n"
-               , program_invocation_short_name
-               );
-
-        return 0;
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -166,10 +162,11 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
                 switch(c) {
                 case 'h':
-                        return help();
+                        help();
+                        return 0; /* done */
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index b791305..f6e6672 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -589,17 +589,13 @@ static int add_listen_socket(Context *context, int fd) {
         return 0;
 }
 
-static int help(void) {
-
-        printf("%s [HOST:PORT]\n"
-               "%s [SOCKET]\n\n"
+static void help(void) {
+        printf("%1$s [HOST:PORT]\n"
+               "%1$s [SOCKET]\n\n"
                "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
                "  -h --help              Show this help\n"
                "     --version           Show package version\n",
-               program_invocation_short_name,
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -620,12 +616,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -638,7 +635,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind >= argc) {
                 log_error("Not enough parameters.");
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 06defa5..8ce9870 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -214,16 +214,13 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
         return r;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Applies kernel sysctl settings.\n\n"
                "  -h --help             Show this help\n"
                "     --version          Show package version\n"
-               "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -245,12 +242,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -276,7 +274,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 8ec0db2..daf7e31 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -5432,7 +5432,7 @@ static int is_system_running(sd_bus *bus, char **args) {
         return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-static int systemctl_help(void) {
+static void systemctl_help(void) {
 
         pager_open_if_enabled();
 
@@ -5557,12 +5557,9 @@ static int systemctl_help(void) {
                "  hibernate                       Hibernate the system\n"
                "  hybrid-sleep                    Hibernate and suspend the system\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
-static int halt_help(void) {
-
+static void halt_help(void) {
         printf("%s [OPTIONS...]%s\n\n"
                "%s the system.\n\n"
                "     --help      Show this help\n"
@@ -5578,12 +5575,9 @@ static int halt_help(void) {
                arg_action == ACTION_REBOOT   ? "Reboot" :
                arg_action == ACTION_POWEROFF ? "Power off" :
                                                "Halt");
-
-        return 0;
 }
 
-static int shutdown_help(void) {
-
+static void shutdown_help(void) {
         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
                "Shut down the system.\n\n"
                "     --help      Show this help\n"
@@ -5595,12 +5589,9 @@ static int shutdown_help(void) {
                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
                "  -c             Cancel a pending shutdown\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
-static int telinit_help(void) {
-
+static void telinit_help(void) {
         printf("%s [OPTIONS...] {COMMAND}\n\n"
                "Send control commands to the init daemon.\n\n"
                "     --help      Show this help\n"
@@ -5613,18 +5604,13 @@ static int telinit_help(void) {
                "  q, Q           Reload init daemon configuration\n"
                "  u, U           Reexecute init daemon\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
-static int runlevel_help(void) {
-
+static void runlevel_help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Prints the previous and current runlevel of the init system.\n\n"
                "     --help      Show this help\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static void help_types(void) {
@@ -5719,12 +5705,13 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return systemctl_help();
+                        systemctl_help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -5992,7 +5979,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
                 log_error("Cannot access user instance remotely.");
@@ -6032,11 +6018,12 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 if (runlevel == '0' || runlevel == '6')
                         arg_force = 2;
 
-        while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
-                        return halt_help();
+                        halt_help();
+                        return 0;
 
                 case ARG_HALT:
                         arg_action = ACTION_HALT;
@@ -6079,7 +6066,6 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
                 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
@@ -6164,11 +6150,12 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
-                        return shutdown_help();
+                        shutdown_help();
+                        return 0;
 
                 case 'H':
                         arg_action = ACTION_HALT;
@@ -6217,7 +6204,6 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
                 r = parse_time_spec(argv[optind], &arg_when);
@@ -6278,11 +6264,12 @@ static int telinit_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
-                        return telinit_help();
+                        telinit_help();
+                        return 0;
 
                 case ARG_NO_WALL:
                         arg_no_wall = true;
@@ -6294,10 +6281,10 @@ static int telinit_parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind >= argc) {
-                telinit_help();
+                log_error("%s: required argument missing.",
+                          program_invocation_short_name);
                 return -EINVAL;
         }
 
@@ -6343,11 +6330,12 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
-                        return runlevel_help();
+                        runlevel_help();
+                        return 0;
 
                 case '?':
                         return -EINVAL;
@@ -6355,7 +6343,6 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind < argc) {
                 log_error("Too many arguments.");
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index b7c1609..19568ad 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1413,16 +1413,13 @@ static void free_database(Hashmap *by_name, Hashmap *by_id) {
         hashmap_free(by_id);
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Creates system user accounts.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n"
-               "     --root=PATH            Operate on an alternate filesystem root\n",
-               program_invocation_short_name);
-
-        return 0;
+               "     --root=PATH            Operate on an alternate filesystem root\n"
+               , program_invocation_short_name);
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1444,12 +1441,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -1471,7 +1469,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index f5c8bc7..912b613 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -1,3 +1,4 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 /***
   This file is part of systemd.
 
@@ -423,6 +424,7 @@ int main(int argc, char *argv[]) {
         const char *syspath = "/devices/virtual/mem/null";
         const char *subsystem = NULL;
         char path[1024];
+        int c;
 
         udev = udev_new();
         printf("context: %p\n", udev);
@@ -433,34 +435,38 @@ int main(int argc, char *argv[]) {
         udev_set_log_fn(udev, log_fn);
         printf("set log: %p\n", log_fn);
 
-        for (;;) {
-                int option;
 
-                option = getopt_long(argc, argv, "+p:s:dhV", options, NULL);
-                if (option == -1)
-                        break;
+        while ((c = getopt_long(argc, argv, "p:s:dhV", options, NULL)) >= 0)
+                switch (c) {
 
-                switch (option) {
                 case 'p':
                         syspath = optarg;
                         break;
+
                 case 's':
                         subsystem = optarg;
                         break;
+
                 case 'd':
                         if (udev_get_log_priority(udev) < LOG_INFO)
                                 udev_set_log_priority(udev, LOG_INFO);
                         break;
+
                 case 'h':
                         printf("--debug --syspath= --subsystem= --help\n");
                         goto out;
+
                 case 'V':
                         printf("%s\n", VERSION);
                         goto out;
-                default:
+
+                case '?':
                         goto out;
+
+                default:
+                        assert_not_reached("Unhandled option code.");
                 }
-        }
+
 
         /* add sys path if needed */
         if (!startswith(syspath, "/sys")) {
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 5312315..36c3f3c 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -374,8 +374,7 @@ static int list_timezones(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] COMMAND ...\n\n"
                "Query or change system time and date settings.\n\n"
                "  -h --help                Show this help message\n"
@@ -393,8 +392,6 @@ static int help(void) {
                "  set-local-rtc BOOL       Control whether RTC is in local time\n"
                "  set-ntp BOOL             Control whether NTP is enabled\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -422,12 +419,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -462,7 +460,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         return 1;
 }
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 68cfa55..79fd0b7 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1407,8 +1407,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         return 0;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
                "  -h --help                 Show this help\n"
@@ -1421,8 +1420,6 @@ static int help(void) {
                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
                "     --root=PATH            Operate on an alternate filesystem root\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1456,12 +1453,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -1509,7 +1507,6 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (!arg_clean && !arg_create && !arg_remove) {
                 log_error("You need to specify at least one of --clean, --create or --remove.");
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 94ae567..528b899 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -588,8 +588,7 @@ finish:
         return r;
 }
 
-static int help(void) {
-
+static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Process system password requests.\n\n"
                "  -h --help     Show this help\n"
@@ -601,8 +600,6 @@ static int help(void) {
                "     --plymouth Ask question with Plymouth instead of on TTY\n"
                "     --console  Ask question on /dev/console instead of current TTY\n",
                program_invocation_short_name);
-
-        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -634,12 +631,13 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
 
                 switch (c) {
 
                 case 'h':
-                        return help();
+                        help();
+                        return 0;
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -676,10 +674,9 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
-        }
 
         if (optind != argc) {
-                help();
+                log_error("%s takes no arguments.", program_invocation_short_name);
                 return -EINVAL;
         }
 
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index 1c06c1a..2c11550 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -1,3 +1,4 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 /*
  * Copyright (C) 2007-2012 Kay Sievers <kay at vrfy.org>
  *
@@ -89,7 +90,7 @@ int main(int argc, char *argv[]) {
         };
         const char *command;
         unsigned int i;
-        int rc = 1;
+        int rc = 1, c;
 
         udev = udev_new();
         if (udev == NULL)
@@ -100,32 +101,30 @@ int main(int argc, char *argv[]) {
         udev_set_log_fn(udev, udev_main_log);
         label_init("/dev");
 
-        for (;;) {
-                int option;
+        while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
+                switch (c) {
 
-                option = getopt_long(argc, argv, "+dhV", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
                 case 'd':
                         log_set_max_level(LOG_DEBUG);
                         udev_set_log_priority(udev, LOG_DEBUG);
                         break;
+
                 case 'h':
                         rc = adm_help(udev, argc, argv);
                         goto out;
+
                 case 'V':
                         rc = adm_version(udev, argc, argv);
                         goto out;
+
                 default:
                         goto out;
                 }
-        }
+
         command = argv[optind];
 
         if (command != NULL)
-                for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++) {
+                for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++)
                         if (streq(udevadm_cmds[i]->name, command)) {
                                 argc -= optind;
                                 argv += optind;
@@ -134,10 +133,8 @@ int main(int argc, char *argv[]) {
                                 rc = run_command(udev, udevadm_cmds[i], argc, argv);
                                 goto out;
                         }
-                }
 
-        fprintf(stderr, "missing or unknown command\n\n");
-        adm_help(udev, argc, argv);
+        fprintf(stderr, "%s: missing or unknown command", program_invocation_short_name);
         rc = 2;
 out:
         label_finish();



More information about the systemd-commits mailing list