[systemd-commits] 18 commits - .gitignore Makefile.am man/udevadm.xml src/analyze src/backlight src/bootchart src/cgtop src/core src/cryptsetup src/fsck src/gpt-auto-generator src/hostname src/journal src/libsystemd-bus src/libudev src/locale src/login src/machine src/nspawn src/nss-myhostname src/readahead src/shared src/systemctl src/test src/tmpfiles src/udev TODO

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Sun Oct 13 16:44:56 PDT 2013


 .gitignore                                  |    1 
 Makefile.am                                 |   10 +
 TODO                                        |    4 
 man/udevadm.xml                             |   49 ++++++---
 src/analyze/systemd-analyze.c               |   14 +-
 src/backlight/backlight.c                   |   55 ++++------
 src/bootchart/bootchart.c                   |    2 
 src/bootchart/svg.c                         |   18 +--
 src/cgtop/cgtop.c                           |    2 
 src/core/device.c                           |   34 +++---
 src/core/load-fragment.c                    |    3 
 src/core/manager.c                          |   22 +---
 src/core/namespace.c                        |   38 +++----
 src/core/umount.c                           |  143 +++++++++-------------------
 src/core/unit.c                             |    3 
 src/cryptsetup/cryptsetup.c                 |   27 +----
 src/fsck/fsck.c                             |   13 --
 src/gpt-auto-generator/gpt-auto-generator.c |  143 +++++++++-------------------
 src/hostname/hostnamectl.c                  |    2 
 src/journal/catalog.c                       |    2 
 src/journal/coredump.c                      |   12 +-
 src/journal/journal-file.c                  |    2 
 src/journal/journal-internal.h              |    7 -
 src/journal/journal-vacuum.c                |    3 
 src/journal/journalctl.c                    |    2 
 src/journal/journald-server.c               |   39 ++-----
 src/libsystemd-bus/bus-match.c              |    2 
 src/libsystemd-bus/bus-message.c            |    3 
 src/libsystemd-bus/sd-event.c               |   17 ++-
 src/libsystemd-bus/test-bus-memfd.c         |    2 
 src/libudev/libudev-enumerate.c             |    2 
 src/locale/localed.c                        |   40 ++-----
 src/login/logind-dbus.c                     |    2 
 src/login/sysfs-show.c                      |   22 +---
 src/machine/machined-dbus.c                 |   18 +--
 src/nspawn/nspawn.c                         |    4 
 src/nss-myhostname/netlink.c                |    3 
 src/readahead/readahead-collect.c           |   49 +++++----
 src/readahead/readahead-common.c            |   66 ++++--------
 src/shared/cgroup-show.c                    |   17 +--
 src/shared/conf-files.c                     |    2 
 src/shared/dbus-common.c                    |   20 +--
 src/shared/efivars.c                        |   13 --
 src/shared/fdset.h                          |    4 
 src/shared/fileio.c                         |    1 
 src/shared/gunicode.c                       |  110 +++++++++++++++++++++
 src/shared/gunicode.h                       |   28 +++++
 src/shared/install.c                        |   10 -
 src/shared/set.h                            |   10 -
 src/shared/socket-util.c                    |   17 +--
 src/shared/strv.h                           |    7 -
 src/shared/udev-util.h                      |   37 +++++++
 src/shared/utf8.c                           |    2 
 src/shared/utf8.h                           |    1 
 src/shared/util.c                           |   82 +++++++++++++++-
 src/shared/util.h                           |   46 ++++-----
 src/systemctl/systemctl.c                   |   12 +-
 src/test/test-ellipsize.c                   |   45 ++++++++
 src/test/test-libudev.c                     |   12 +-
 src/test/test-udev.c                        |   21 +---
 src/tmpfiles/tmpfiles.c                     |    5 
 src/udev/udev-ctrl.c                        |   17 +--
 src/udev/udevadm-hwdb.c                     |    2 
 src/udev/udevd.c                            |    5 
 64 files changed, 766 insertions(+), 640 deletions(-)

New commits:
commit 124b48b00d0c59fbbc2a8c3e27dba2cd6877aaa8
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Oct 13 19:43:19 2013 -0400

    man: add more markup to udevadm(8)

diff --git a/man/udevadm.xml b/man/udevadm.xml
index b959216..a1ffe42 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -61,9 +61,10 @@
   </refsynopsisdiv>
 
   <refsect1><title>Description</title>
-    <para>udevadm expects a command and command specific options.  It
-    controls the runtime behavior of udev, requests kernel events,
-    manages the event queue, and provides simple debugging mechanisms.</para>
+    <para><command>udevadm</command> expects a command and command
+    specific options.  It controls the runtime behavior of
+    <command>systemd-udevd</command>, requests kernel events, manages
+    the event queue, and provides simple debugging mechanisms.</para>
   </refsect1>
 
   <refsect1><title>OPTIONS</title>
@@ -97,23 +98,37 @@
         <varlistentry>
           <term><option>--query=<replaceable>type</replaceable></option></term>
           <listitem>
-            <para>Query the database for specified type of device data. It needs the
-            <option>--path</option> or <option>--name</option> to identify the specified
-            device. Valid queries are:
-            <command>name</command>, <command>symlink</command>, <command>path</command>,
-            <command>property</command>, <command>all</command>.</para>
+            <para>Query the database for specified type of device
+            data. It needs the <option>--path</option> or
+            <option>--name</option> to identify the specified
+            device. Valid queries are: <constant>name</constant>,
+            <constant>symlink</constant>, <constant>path</constant>,
+            <constant>property</constant>,
+            <constant>all</constant>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>--path=<replaceable>devpath</replaceable></option></term>
           <listitem>
-            <para>The devpath of the device to query.</para>
+            <para>The <filename>/sys</filename> path of the device to
+            query, e.g.
+            <filename><optional>/sys</optional>/class/block/sda</filename>.
+            Note that this option usually isn't very useful, since
+            <command>udev</command> can guess the type of the
+            argument, so <command>udevadm
+            --devpath=/class/block/sda</command> is equivalent to
+            <command>udevadm /sys/class/block/sda</command>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>--name=<replaceable>file</replaceable></option></term>
           <listitem>
-            <para>The name of the device node or a symlink to query</para>
+            <para>The name of the device node or a symlink to query,
+            e.g. <filename><optional>/dev</optional>/sda</filename>.
+            Note that this option usually isn't very useful, since
+            <command>udev</command> can guess the type of the
+            argument, so <command>udevadm --name=sda</command> is
+            equivalent to <command>udevadm /dev/sda</command>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
@@ -462,13 +477,15 @@
           </listitem>
         </varlistentry>
         <varlistentry>
-          <term><option>--resolve-names=<replaceable>early|late|never</replaceable></option></term>
+          <term><option>--resolve-names=<constant>early</constant>|<constant>late</constant>|<constant>never</constant></option></term>
           <listitem>
-            <para>Specify when udevadm should resolve names of users and groups.
-              When set to early (the default) names will be resolved when the
-              rules are parsed. When set to late names will be resolved for
-              every event. When set to never names will never be resolved and
-              all devices will be owned by root.</para>
+            <para>Specify when udevadm should resolve names of users
+            and groups.  When set to <constant>early</constant> (the
+            default) names will be resolved when the rules are
+            parsed. When set to <constant>late</constant> names will
+            be resolved for every event. When set to
+            <constant>never</constant> names will never be resolved
+            and all devices will be owned by root.</para>
           </listitem>
         </varlistentry>
         <varlistentry>

commit 0eb2e0e3403f03d0dd47c5043057edae3bc2c9a3
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Oct 13 17:41:24 2013 -0400

    event: avoid derefencing null pointer

diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c
index 96ba2ad..b318fd0 100644
--- a/src/libsystemd-bus/sd-event.c
+++ b/src/libsystemd-bus/sd-event.c
@@ -493,6 +493,10 @@ static void source_free(sd_event_source *s) {
 
                         break;
 
+                case SOURCE_DEFER:
+                        /* nothing */
+                        break;
+
                 case SOURCE_QUIT:
                         prioq_remove(s->event->quit, s, &s->quit.prioq_index);
                         break;
@@ -1526,15 +1530,17 @@ static int process_child(sd_event *e) {
 }
 
 static int process_signal(sd_event *e, uint32_t events) {
-        struct signalfd_siginfo si;
         bool read_one = false;
-        ssize_t ss;
         int r;
 
         assert(e);
+        assert(e->signal_sources);
+
         assert_return(events == EPOLLIN, -EIO);
 
         for (;;) {
+                struct signalfd_siginfo si;
+                ssize_t ss;
                 sd_event_source *s;
 
                 ss = read(e->signal_fd, &si, sizeof(si));
@@ -1550,17 +1556,16 @@ static int process_signal(sd_event *e, uint32_t events) {
 
                 read_one = true;
 
+                s = e->signal_sources[si.ssi_signo];
                 if (si.ssi_signo == SIGCHLD) {
                         r = process_child(e);
                         if (r < 0)
                                 return r;
-                        if (r > 0 || !e->signal_sources[si.ssi_signo])
+                        if (r > 0 || !s)
                                 continue;
-                } else {
-                        s = e->signal_sources[si.ssi_signo];
+                } else
                         if (!s)
                                 return -EIO;
-                }
 
                 s->signal.siginfo = si;
                 r = source_set_pending(s, true);

commit 23c6f770cc214a9c9fe29dc964b64400987faa62
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Oct 13 17:40:34 2013 -0400

    bus: make sure we don't try to malloc 0 bytes

diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index bc67c32..3f68435 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -1284,7 +1284,7 @@ static int part_make_space(
 
                 part->munmap_this = true;
         } else {
-                n = realloc(part->data, sz);
+                n = realloc(part->data, MAX(sz, 1u));
                 if (!n) {
                         m->poisoned = true;
                         return -ENOMEM;

commit 1ca208fb4f93e5869704af1812cbff7130a2fc03
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Oct 12 20:28:21 2013 -0400

    Introduce udev object cleanup functions

diff --git a/Makefile.am b/Makefile.am
index 77a7bbe..7b6df1b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -647,6 +647,7 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/sparse-endian.h \
 	src/shared/util.c \
 	src/shared/util.h \
+	src/shared/udev-util.h \
 	src/shared/virt.c \
 	src/shared/virt.h \
 	src/shared/efivars.c \
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index f22deed..c45b2d0 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -19,15 +19,15 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <libudev.h>
-
 #include "util.h"
 #include "mkdir.h"
 #include "fileio.h"
+#include "libudev.h"
+#include "udev-util.h"
 
 int main(int argc, char *argv[]) {
-        struct udev *udev = NULL;
-        struct udev_device *device = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *device = NULL;
         _cleanup_free_ char *saved = NULL;
         int r;
 
@@ -45,13 +45,13 @@ int main(int argc, char *argv[]) {
         r = mkdir_p("/var/lib/systemd/backlight", 0755);
         if (r < 0) {
                 log_error("Failed to create backlight directory: %s", strerror(-r));
-                goto finish;
+                return EXIT_FAILURE;
         }
 
         udev = udev_new();
         if (!udev) {
-                r = log_oom();
-                goto finish;
+                log_oom();
+                return EXIT_FAILURE;
         }
 
         errno = 0;
@@ -59,26 +59,24 @@ int main(int argc, char *argv[]) {
         if (!device)
                 device = udev_device_new_from_subsystem_sysname(udev, "leds", argv[2]);
         if (!device) {
-                if (errno != 0) {
+                if (errno != 0)
                         log_error("Failed to get backlight device '%s': %m", argv[2]);
-                        r = -errno;
-                } else
+                else
                         r = log_oom();
 
-                goto finish;
+                return EXIT_FAILURE;
         }
 
         if (!streq_ptr(udev_device_get_subsystem(device), "backlight") &&
             !streq_ptr(udev_device_get_subsystem(device), "leds")) {
                 log_error("Not a backlight device: %s", argv[2]);
-                r = -ENODEV;
-                goto finish;
+                return EXIT_FAILURE;
         }
 
         saved = strappend("/var/lib/systemd/backlight/", udev_device_get_sysname(device));
         if (!saved) {
-                r = log_oom();
-                goto finish;
+                log_oom();
+                return EXIT_FAILURE;
         }
 
         if (streq(argv[1], "load")) {
@@ -87,19 +85,17 @@ int main(int argc, char *argv[]) {
                 r = read_one_line_file(saved, &value);
                 if (r < 0) {
 
-                        if (r == -ENOENT) {
-                                r = 0;
-                                goto finish;
-                        }
+                        if (r == -ENOENT)
+                                return EXIT_SUCCESS;
 
                         log_error("Failed to read %s: %s", saved, strerror(-r));
-                        goto finish;
+                        return EXIT_FAILURE;
                 }
 
                 r = udev_device_set_sysattr_value(device, "brightness", value);
                 if (r < 0) {
                         log_error("Failed to write system attribute: %s", strerror(-r));
-                        goto finish;
+                        return EXIT_FAILURE;
                 }
 
         } else if (streq(argv[1], "save")) {
@@ -108,28 +104,19 @@ int main(int argc, char *argv[]) {
                 value = udev_device_get_sysattr_value(device, "brightness");
                 if (!value) {
                         log_error("Failed to read system attribute: %s", strerror(-r));
-                        goto finish;
+                        return EXIT_FAILURE;
                 }
 
                 r = write_string_file(saved, value);
                 if (r < 0) {
                         log_error("Failed to write %s: %s", saved, strerror(-r));
-                        goto finish;
+                        return EXIT_FAILURE;
                 }
 
         } else {
                 log_error("Unknown verb %s.", argv[1]);
-                r = -EINVAL;
-                goto finish;
+                return EXIT_FAILURE;
         }
 
-finish:
-        if (device)
-                udev_device_unref(device);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-
+        return EXIT_SUCCESS;
 }
diff --git a/src/core/umount.c b/src/core/umount.c
index 1e95ad7..99dbe27 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -27,7 +27,6 @@
 #include <unistd.h>
 #include <linux/loop.h>
 #include <linux/dm-ioctl.h>
-#include <libudev.h>
 
 #include "list.h"
 #include "mount-setup.h"
@@ -35,6 +34,8 @@
 #include "path-util.h"
 #include "util.h"
 #include "virt.h"
+#include "libudev.h"
+#include "udev-util.h"
 
 typedef struct MountPoint {
         char *path;
@@ -201,145 +202,108 @@ finish:
 }
 
 static int loopback_list_get(MountPoint **head) {
-        int r;
-        struct udev *udev;
-        struct udev_enumerate *e = NULL;
+        _cleanup_udev_unref_ struct udev *udev;
+        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *item = NULL, *first = NULL;
 
         assert(head);
 
-        if (!(udev = udev_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        udev = udev_new();
+        if (!udev)
+                return -ENOMEM;
 
-        if (!(e = udev_enumerate_new(udev))) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        e = udev_enumerate_new(udev);
+        if (!e)
+                return -ENOMEM;
 
         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
             udev_enumerate_add_match_sysname(e, "loop*") < 0 ||
-            udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL) < 0) {
-                r = -EIO;
-                goto finish;
-        }
+            udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL) < 0)
+                return -EIO;
 
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
+        if (udev_enumerate_scan_devices(e) < 0)
+                return -EIO;
 
         first = udev_enumerate_get_list_entry(e);
         udev_list_entry_foreach(item, first) {
                 MountPoint *lb;
-                struct udev_device *d;
+                _cleanup_udev_device_unref_ struct udev_device *d;
                 char *loop;
                 const char *dn;
 
-                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+                if (!d)
+                        return -ENOMEM;
 
-                if (!(dn = udev_device_get_devnode(d))) {
-                        udev_device_unref(d);
+                dn = udev_device_get_devnode(d);
+                if (!dn)
                         continue;
-                }
 
                 loop = strdup(dn);
-                udev_device_unref(d);
-
-                if (!loop) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                if (!loop)
+                        return -ENOMEM;
 
-                if (!(lb = new0(MountPoint, 1))) {
+                lb = new0(MountPoint, 1);
+                if (!lb) {
                         free(loop);
-                        r = -ENOMEM;
-                        goto finish;
+                        return -ENOMEM;
                 }
 
                 lb->path = loop;
                 LIST_PREPEND(MountPoint, mount_point, *head, lb);
         }
 
-        r = 0;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r;
+        return 0;
 }
 
 static int dm_list_get(MountPoint **head) {
-        int r;
-        struct udev *udev;
-        struct udev_enumerate *e = NULL;
+        _cleanup_udev_unref_ struct udev *udev;
+        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *item = NULL, *first = NULL;
 
         assert(head);
 
-        if (!(udev = udev_new())) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        udev = udev_new();
+        if (!udev)
+                return -ENOMEM;
 
-        if (!(e = udev_enumerate_new(udev))) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        e = udev_enumerate_new(udev);
+        if (!e)
+                return -ENOMEM;
 
         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
-            udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
-                r = -EIO;
-                goto finish;
-        }
+            udev_enumerate_add_match_sysname(e, "dm-*") < 0)
+                return -EIO;
 
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto finish;
-        }
+        if (udev_enumerate_scan_devices(e) < 0)
+                return -EIO;
 
         first = udev_enumerate_get_list_entry(e);
 
         udev_list_entry_foreach(item, first) {
                 MountPoint *m;
-                struct udev_device *d;
+                _cleanup_udev_device_unref_ struct udev_device *d;
                 dev_t devnum;
                 char *node;
                 const char *dn;
 
-                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+                if (!d)
+                        return -ENOMEM;
 
                 devnum = udev_device_get_devnum(d);
                 dn = udev_device_get_devnode(d);
-
-                if (major(devnum) == 0 || !dn) {
-                        udev_device_unref(d);
+                if (major(devnum) == 0 || !dn)
                         continue;
-                }
 
                 node = strdup(dn);
-                udev_device_unref(d);
-
-                if (!node) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                if (!node)
+                        return -ENOMEM;
 
-                if (!(m = new(MountPoint, 1))) {
+                m = new(MountPoint, 1);
+                if (!m) {
                         free(node);
-                        r = -ENOMEM;
-                        goto finish;
+                        return -ENOMEM;
                 }
 
                 m->path = node;
@@ -347,16 +311,7 @@ static int dm_list_get(MountPoint **head) {
                 LIST_PREPEND(MountPoint, mount_point, *head, m);
         }
 
-        r = 0;
-
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
-        return r;
+        return 0;
 }
 
 static int delete_loopback(const char *device) {
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 4f2f52a..0a15b50 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -25,7 +25,6 @@
 #include <mntent.h>
 
 #include <libcryptsetup.h>
-#include <libudev.h>
 
 #include "fileio.h"
 #include "log.h"
@@ -34,6 +33,8 @@
 #include "strv.h"
 #include "ask-password-api.h"
 #include "def.h"
+#include "libudev.h"
+#include "udev-util.h"
 
 static const char *opt_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *opt_cipher = NULL;
@@ -184,7 +185,7 @@ static void log_glue(int level, const char *msg, void *usrptr) {
         log_debug("%s", msg);
 }
 
-static char *disk_description(const char *path) {
+static char* disk_description(const char *path) {
 
         static const char name_fields[] = {
                 "ID_PART_ENTRY_NAME\0"
@@ -193,10 +194,9 @@ static char *disk_description(const char *path) {
                 "ID_MODEL\0"
         };
 
-        struct udev *udev = NULL;
-        struct udev_device *device = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *device = NULL;
         struct stat st;
-        char *description = NULL;
         const char *i;
 
         assert(path);
@@ -213,26 +213,17 @@ static char *disk_description(const char *path) {
 
         device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
         if (!device)
-                goto finish;
+                return NULL;
 
         NULSTR_FOREACH(i, name_fields) {
                 const char *name;
 
                 name = udev_device_get_property_value(device, i);
-                if (!isempty(name)) {
-                        description = strdup(name);
-                        break;
-                }
+                if (!isempty(name))
+                        return strdup(name);
         }
 
-finish:
-        if (device)
-                udev_device_unref(device);
-
-        if (udev)
-                udev_unref(udev);
-
-        return description;
+        return NULL;
 }
 
 static char *disk_mount_point(const char *label) {
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index f298cf7..96a79dd 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -27,7 +27,6 @@
 #include <fcntl.h>
 #include <sys/file.h>
 
-#include <libudev.h>
 #include <dbus/dbus.h>
 
 #include "util.h"
@@ -36,6 +35,8 @@
 #include "bus-errors.h"
 #include "virt.h"
 #include "fileio.h"
+#include "libudev.h"
+#include "udev-util.h"
 
 static bool arg_skip = false;
 static bool arg_force = false;
@@ -251,8 +252,8 @@ int main(int argc, char *argv[]) {
         int i = 0, r = EXIT_FAILURE, q;
         pid_t pid;
         siginfo_t status;
-        struct udev *udev = NULL;
-        struct udev_device *udev_device = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
         const char *device;
         bool root_directory;
         int progress_pipe[2] = { -1, -1 };
@@ -400,12 +401,6 @@ int main(int argc, char *argv[]) {
                 touch("/run/systemd/quotacheck");
 
 finish:
-        if (udev_device)
-                udev_device_unref(udev_device);
-
-        if (udev)
-                udev_unref(udev);
-
         close_pipe(progress_pipe);
 
         return r;
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 55fd6d6..b6f6a74 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -36,6 +36,7 @@
 #include "missing.h"
 #include "sd-id128.h"
 #include "libudev.h"
+#include "udev-util.h"
 #include "special.h"
 #include "unit-name.h"
 #include "virt.h"
@@ -53,10 +54,7 @@
 
 static const char *arg_dest = "/tmp";
 
-static inline void blkid_free_probep(blkid_probe *b) {
-        if (*b)
-                blkid_free_probe(*b);
-}
+define_trivial_cleanup_func(blkid_probe, blkid_free_probe)
 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
 
 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
@@ -237,8 +235,9 @@ static int add_home(const char *path, const char *fstype) {
 }
 
 static int enumerate_partitions(struct udev *udev, dev_t dev) {
-        struct udev_enumerate *e = NULL;
-        struct udev_device *parent = NULL, *d = NULL;
+        struct udev_device *parent = NULL;
+        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *d = NULL;
         struct udev_list_entry *first, *item;
         unsigned home_nr = (unsigned) -1;
         _cleanup_free_ char *home = NULL, *home_fstype = NULL;
@@ -249,71 +248,58 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) {
                 return log_oom();
 
         d = udev_device_new_from_devnum(udev, 'b', dev);
-        if (!d) {
-                r = log_oom();
-                goto finish;
-        }
+        if (!d)
+                return log_oom();
 
         parent = udev_device_get_parent(d);
-        if (!parent) {
-                r = log_oom();
-                goto finish;
-        }
+        if (!parent)
+                return log_oom();
 
         r = udev_enumerate_add_match_parent(e, parent);
-        if (r < 0) {
-                r = log_oom();
-                goto finish;
-        }
+        if (r < 0)
+                return log_oom();
 
         r = udev_enumerate_add_match_subsystem(e, "block");
-        if (r < 0) {
-                r = log_oom();
-                goto finish;
-        }
+        if (r < 0)
+                return log_oom();
 
         r = udev_enumerate_scan_devices(e);
         if (r < 0) {
                 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
                           major(dev), minor(dev), strerror(-r));
-                goto finish;
+                return r;
         }
 
         first = udev_enumerate_get_list_entry(e);
         udev_list_entry_foreach(item, first) {
                 _cleanup_free_ char *fstype = NULL;
                 const char *node = NULL;
-                struct udev_device *q;
+                _cleanup_udev_device_unref_ struct udev_device *q;
                 sd_id128_t type_id;
                 unsigned nr;
 
                 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
-                if (!q) {
-                        r = log_oom();
-                        goto finish;
-                }
+                if (!q)
+                        return log_oom();
 
                 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
-                        goto skip;
+                        continue;
 
                 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
-                        goto skip;
+                        continue;
 
                 node = udev_device_get_devnode(q);
-                if (!node) {
-                        r = log_oom();
-                        goto finish;
-                }
+                if (!node)
+                        return log_oom();
 
                 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
                 if (r < 0) {
                         log_error("Failed to verify GPT partition %s: %s",
                                   node, strerror(-r));
-                        udev_device_unref(q);
-                        goto finish;
+                        return r;
                 }
                 if (r == 0)
-                        goto skip;
+                        continue;
 
                 if (sd_id128_equal(type_id, GPT_SWAP))
                         add_swap(node, fstype);
@@ -321,10 +307,8 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) {
                         if (!home || nr < home_nr) {
                                 free(home);
                                 home = strdup(node);
-                                if (!home) {
-                                        r = log_oom();
-                                        goto finish;
-                                }
+                                if (!home)
+                                        return log_oom();
 
                                 home_nr = nr;
 
@@ -333,22 +317,11 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) {
                                 fstype = NULL;
                         }
                 }
-
-        skip:
-                udev_device_unref(q);
         }
 
         if (home && home_fstype)
                 add_home(home, home_fstype);
 
-finish:
-        if (d)
-                udev_device_unref(d);
-
-        if (e)
-                udev_enumerate_unref(e);
-
-
         return r;
 }
 
@@ -425,41 +398,31 @@ static int get_block_device(const char *path, dev_t *dev) {
 }
 
 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
-        struct udev_device *d = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *d;
         const char *t;
         char *n;
-        int r;
 
         d = udev_device_new_from_devnum(udev, 'b', devno);
         if (!d)
                 return log_oom();
 
         t = udev_device_get_devnode(d);
-        if (!t) {
-                r = -ENODEV;
-                goto finish;
-        }
+        if (!t)
+                return -ENODEV;
 
         n = strdup(t);
-        if (!n) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        if (!n)
+                return -ENOMEM;
 
         *ret = n;
-        r = 0;
-
-finish:
-        udev_device_unref(d);
-
-        return r;
+        return 0;
 }
 
 int main(int argc, char *argv[]) {
         _cleanup_free_ char *node = NULL;
-        struct udev *udev = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
         dev_t devno;
-        int r;
+        int r = 0;
 
         if (argc > 1 && argc != 4) {
                 log_error("This program takes three or no arguments.");
@@ -478,13 +441,11 @@ int main(int argc, char *argv[]) {
 
         if (in_initrd()) {
                 log_debug("In initrd, exiting.");
-                r = 0;
                 goto finish;
         }
 
         if (detect_container(NULL) > 0) {
                 log_debug("In a container, exiting.");
-                r = 0;
                 goto finish;
         }
 
@@ -523,8 +484,5 @@ int main(int argc, char *argv[]) {
         r = enumerate_partitions(udev, devno);
 
 finish:
-        if (udev)
-                udev_unref(udev);
-
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index 5bc6535..1bc912c 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -135,11 +135,8 @@ struct sd_journal {
 char *journal_make_match_string(sd_journal *j);
 void journal_print_header(sd_journal *j);
 
-static inline void journal_closep(sd_journal **j) {
-        sd_journal_close(*j);
-}
-
-#define _cleanup_journal_close_ _cleanup_(journal_closep)
+define_trivial_cleanup_func(sd_journal*, sd_journal_close)
+#define _cleanup_journal_close_ _cleanup_(sd_journal_closep)
 
 #define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval)                     \
         for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; )
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index 3c03bd1..7c1adfa 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -26,6 +26,7 @@
 #include "util.h"
 #include "sysfs-show.h"
 #include "path-util.h"
+#include "udev-util.h"
 
 static int show_sysfs_one(
                 struct udev *udev,
@@ -143,9 +144,9 @@ static int show_sysfs_one(
 }
 
 int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
-        struct udev *udev;
+        _cleanup_udev_unref_ struct udev *udev;
+        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *first = NULL;
-        struct udev_enumerate *e;
         int r;
 
         if (n_columns <= 0)
@@ -162,10 +163,8 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
                 return -ENOMEM;
 
         e = udev_enumerate_new(udev);
-        if (!e) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        if (!e)
+                return ENOMEM;
 
         if (!streq(seat, "seat0"))
                 r = udev_enumerate_add_match_tag(e, seat);
@@ -173,22 +172,15 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
                 r = udev_enumerate_add_match_tag(e, "seat");
 
         if (r < 0)
-                goto finish;
+                return r;
 
         r = udev_enumerate_scan_devices(e);
         if (r < 0)
-                goto finish;
+                return r;
 
         first = udev_enumerate_get_list_entry(e);
         if (first)
                 show_sysfs_one(udev, seat, &first, "/", prefix, n_columns);
 
-finish:
-        if (e)
-                udev_enumerate_unref(e);
-
-        if (udev)
-                udev_unref(udev);
-
         return r;
 }
diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c
index a234a89..aea1fbe 100644
--- a/src/readahead/readahead-common.c
+++ b/src/readahead/readahead-common.c
@@ -27,13 +27,14 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <unistd.h>
-#include <libudev.h>
 
 #include "log.h"
 #include "readahead-common.h"
 #include "util.h"
 #include "missing.h"
 #include "fileio.h"
+#include "libudev.h"
+#include "udev-util.h"
 
 int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) {
         assert(fd >= 0);
@@ -60,9 +61,9 @@ int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) {
 
 int fs_on_ssd(const char *p) {
         struct stat st;
-        struct udev *udev = NULL;
-        struct udev_device *udev_device = NULL, *look_at = NULL;
-        bool b = false;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
+        struct udev_device *look_at = NULL;
         const char *devtype, *rotational, *model, *id;
         int r;
 
@@ -128,7 +129,7 @@ int fs_on_ssd(const char *p) {
 
         udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev);
         if (!udev_device)
-                goto finish;
+                return false;
 
         devtype = udev_device_get_property_value(udev_device, "DEVTYPE");
         if (devtype && streq(devtype, "partition"))
@@ -137,46 +138,34 @@ int fs_on_ssd(const char *p) {
                 look_at = udev_device;
 
         if (!look_at)
-                goto finish;
+                return false;
 
         /* First, try high-level property */
         id = udev_device_get_property_value(look_at, "ID_SSD");
-        if (id) {
-                b = streq(id, "1");
-                goto finish;
-        }
+        if (id)
+                return streq(id, "1");
 
         /* Second, try kernel attribute */
         rotational = udev_device_get_sysattr_value(look_at, "queue/rotational");
-        if (rotational) {
-                b = streq(rotational, "0");
-                goto finish;
-        }
+        if (rotational)
+                return streq(rotational, "0");
 
         /* Finally, fallback to heuristics */
         look_at = udev_device_get_parent(look_at);
         if (!look_at)
-                goto finish;
+                return false;
 
         model = udev_device_get_sysattr_value(look_at, "model");
         if (model)
-                b = !!strstr(model, "SSD");
-
-finish:
-        if (udev_device)
-                udev_device_unref(udev_device);
-
-        if (udev)
-                udev_unref(udev);
+                return !!strstr(model, "SSD");
 
-        return b;
+        return false;
 }
 
 int fs_on_read_only(const char *p) {
         struct stat st;
-        struct udev *udev = NULL;
-        struct udev_device *udev_device = NULL;
-        bool b = false;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
         const char *read_only;
 
         assert(p);
@@ -187,24 +176,19 @@ int fs_on_read_only(const char *p) {
         if (major(st.st_dev) == 0)
                 return false;
 
-        if (!(udev = udev_new()))
+        udev = udev_new();
+        if (!udev)
                 return -ENOMEM;
 
-        if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev)))
-                goto finish;
-
-        if ((read_only = udev_device_get_sysattr_value(udev_device, "ro")))
-                if ((b = streq(read_only, "1")))
-                        goto finish;
-
-finish:
-        if (udev_device)
-                udev_device_unref(udev_device);
+        udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev);
+        if (!udev_device)
+                return false;
 
-        if (udev)
-                udev_unref(udev);
+        read_only = udev_device_get_sysattr_value(udev_device, "ro");
+        if (read_only)
+                return streq(read_only, "1");
 
-        return b;
+        return false;
 }
 
 bool enough_ram(void) {
diff --git a/src/shared/fdset.h b/src/shared/fdset.h
index 1a26005..6277e46 100644
--- a/src/shared/fdset.h
+++ b/src/shared/fdset.h
@@ -49,8 +49,5 @@ int fdset_iterate(FDSet *s, Iterator *i);
 #define FDSET_FOREACH(fd, fds, i) \
         for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i)))
 
-static inline void fdset_freep(FDSet **fds) {
-        if (*fds)
-                fdset_free(*fds);
-}
+define_trivial_cleanup_func(FDSet*, fdset_free)
 #define _cleanup_fdset_free_ _cleanup_(fdset_freep)
diff --git a/src/shared/install.c b/src/shared/install.c
index 5a780fe..3bced1a 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -44,10 +44,8 @@ typedef struct {
         Hashmap *have_installed;
 } InstallContext;
 
-#define _cleanup_lookup_paths_free_ \
-        __attribute__((cleanup(lookup_paths_free)))
-#define _cleanup_install_context_done_ \
-        __attribute__((cleanup(install_context_done)))
+#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free)
+#define _cleanup_install_context_done_ _cleanup_(install_context_done)
 
 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
         assert(paths);
diff --git a/src/shared/set.h b/src/shared/set.h
index e5d46e9..a291470 100644
--- a/src/shared/set.h
+++ b/src/shared/set.h
@@ -28,19 +28,13 @@
  * for each set use. */
 
 #include "hashmap.h"
+#include "util.h"
 
 typedef struct Set Set;
 
 Set *set_new(hash_func_t hash_func, compare_func_t compare_func);
 void set_free(Set* s);
-static inline void set_freep(Set **s) {
-        set_free(*s);
-}
-
 void set_free_free(Set *s);
-static inline void set_free_freep(Set **s) {
-        set_free_free(*s);
-}
 
 Set* set_copy(Set *s);
 int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func);
@@ -79,5 +73,7 @@ char **set_get_strv(Set *s);
 #define SET_FOREACH_BACKWARDS(e, s, i) \
         for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i)))
 
+define_trivial_cleanup_func(Set*, set_free)
+define_trivial_cleanup_func(Set*, set_free_free)
 #define _cleanup_set_free_ _cleanup_(set_freep)
 #define _cleanup_set_free_free_ _cleanup_(set_free_freep)
diff --git a/src/shared/strv.h b/src/shared/strv.h
index d1f2a0e..4d117f8 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -24,16 +24,13 @@
 #include <stdarg.h>
 #include <stdbool.h>
 
-#include "macro.h"
+#include "util.h"
 
 char *strv_find(char **l, const char *name) _pure_;
 char *strv_find_prefix(char **l, const char *name) _pure_;
 
 void strv_free(char **l);
-static inline void strv_freep(char ***l) {
-        strv_free(*l);
-}
-
+define_trivial_cleanup_func(char**, strv_free)
 #define _cleanup_strv_free_ _cleanup_(strv_freep)
 
 char **strv_copy(char * const *l);
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
new file mode 100644
index 0000000..bff8f5f
--- /dev/null
+++ b/src/shared/udev-util.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 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 "udev.h"
+#include "util.h"
+
+define_trivial_cleanup_func(struct udev*, udev_unref)
+define_trivial_cleanup_func(struct udev_device*, udev_device_unref)
+define_trivial_cleanup_func(struct udev_enumerate*, udev_enumerate_unref)
+define_trivial_cleanup_func(struct udev_event*, udev_event_unref)
+define_trivial_cleanup_func(struct udev_rules*, udev_rules_unref)
+
+#define _cleanup_udev_unref_ _cleanup_(udev_unrefp)
+#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp)
+#define _cleanup_udev_enumerate_unref_ _cleanup_(udev_enumerate_unrefp)
+#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp)
+#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp)
diff --git a/src/shared/util.h b/src/shared/util.h
index 09e556d..99a138c 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -556,42 +556,33 @@ static inline void freep(void *p) {
         free(*(void**) p);
 }
 
-static inline void fclosep(FILE **f) {
-        if (*f)
-                fclose(*f);
-}
-
-static inline void pclosep(FILE **f) {
-        if (*f)
-                pclose(*f);
-}
+#define define_trivial_cleanup_func(type, func) \
+        static inline void func##p(type *p) {   \
+        if (*p)                                 \
+                func(*p);                       \
+        }                                       \
 
 static inline void closep(int *fd) {
         if (*fd >= 0)
                 close_nointr_nofail(*fd);
 }
 
-static inline void closedirp(DIR **d) {
-        if (*d)
-                closedir(*d);
-}
-
 static inline void umaskp(mode_t *u) {
         umask(*u);
 }
 
-static inline void endmntentp(FILE **f) {
-        if (*f)
-                endmntent(*f);
-}
+define_trivial_cleanup_func(FILE*, fclose)
+define_trivial_cleanup_func(FILE*, pclose)
+define_trivial_cleanup_func(DIR*, closedir)
+define_trivial_cleanup_func(FILE*, endmntent)
 
 #define _cleanup_free_ _cleanup_(freep)
-#define _cleanup_fclose_ _cleanup_(fclosep)
-#define _cleanup_pclose_ _cleanup_(pclosep)
 #define _cleanup_close_ _cleanup_(closep)
-#define _cleanup_closedir_ _cleanup_(closedirp)
 #define _cleanup_umask_ _cleanup_(umaskp)
 #define _cleanup_globfree_ _cleanup_(globfree)
+#define _cleanup_fclose_ _cleanup_(fclosep)
+#define _cleanup_pclose_ _cleanup_(pclosep)
+#define _cleanup_closedir_ _cleanup_(closedirp)
 #define _cleanup_endmntent_ _cleanup_(endmntentp)
 
 _malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index f79d20c..9c06bc1 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -29,6 +29,7 @@
 #include <sys/epoll.h>
 
 #include "libudev.h"
+#include "udev-util.h"
 #include "util.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -117,7 +118,7 @@ static void print_device(struct udev_device *device)
 
 static int test_device(struct udev *udev, const char *syspath)
 {
-        struct udev_device *device;
+        _cleanup_udev_device_unref_ struct udev_device *device;
 
         printf("looking at device: %s\n", syspath);
         device = udev_device_new_from_syspath(udev, syspath);
@@ -126,13 +127,13 @@ static int test_device(struct udev *udev, const char *syspath)
                 return -1;
         }
         print_device(device);
-        udev_device_unref(device);
+
         return 0;
 }
 
 static int test_device_parents(struct udev *udev, const char *syspath)
 {
-        struct udev_device *device;
+        _cleanup_udev_device_unref_ struct udev_device *device;
         struct udev_device *device_parent;
 
         printf("looking at device: %s\n", syspath);
@@ -153,7 +154,6 @@ static int test_device_parents(struct udev *udev, const char *syspath)
                 print_device(device_parent);
                 device_parent = udev_device_get_parent(device_parent);
         } while (device_parent != NULL);
-        udev_device_unref(device);
 
         return 0;
 }
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 52b61b4..17825f1 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -34,6 +34,7 @@
 
 #include "missing.h"
 #include "udev.h"
+#include "udev-util.h"
 
 void udev_main_log(struct udev *udev, int priority,
                    const char *file, int line, const char *fn,
@@ -82,10 +83,10 @@ out:
 
 int main(int argc, char *argv[])
 {
-        struct udev *udev;
-        struct udev_event *event = NULL;
-        struct udev_device *dev = NULL;
-        struct udev_rules *rules = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
+        _cleanup_udev_event_unref_ struct udev_event *event = NULL;
+        _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+        _cleanup_udev_rules_unref_ struct udev_rules *rules = NULL;
         char syspath[UTIL_PATH_SIZE];
         const char *devpath;
         const char *action;
@@ -98,7 +99,8 @@ int main(int argc, char *argv[])
 
         udev = udev_new();
         if (udev == NULL)
-                exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
+
         log_debug("version %s\n", VERSION);
         label_init("/dev");
 
@@ -160,12 +162,7 @@ int main(int argc, char *argv[])
 out:
         if (event != NULL && event->fd_signal >= 0)
                 close(event->fd_signal);
-        udev_event_unref(event);
-        udev_device_unref(dev);
-        udev_rules_unref(rules);
         label_finish();
-        udev_unref(udev);
-        if (err != 0)
-                return EXIT_FAILURE;
-        return EXIT_SUCCESS;
+
+        return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 8122d6a..42cc34d 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -995,10 +995,7 @@ static void item_free(Item *i) {
         free(i);
 }
 
-static inline void item_freep(Item **i) {
-        if (*i)
-                item_free(*i);
-}
+define_trivial_cleanup_func(Item*, item_free)
 #define _cleanup_item_free_ _cleanup_(item_freep)
 
 static bool item_equal(Item *a, Item *b) {

commit b506291ff195e03ce793ac925cc2d158f0b452b5
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Oct 12 19:50:54 2013 -0400

    gitignore: ignore clang --analyze output

diff --git a/.gitignore b/.gitignore
index 2a2ed99..40015de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@
 *.la
 *.lo
 *.o
+*.plist
 *.stamp
 *.pyc
 __pycache__/

commit f6d2d421470a566cca05ceede788d61a0773e276
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Oct 12 13:43:07 2013 -0400

    Make sure that we don't dereference NULL
    
    The code was actually safe, because b should
    never be null, because if rvalue is empty, a different
    branch is taken. But we *do* check for NULL in the
    loop above, so it's better to also check here for symmetry.

diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 44920d6..f01843d 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1860,7 +1860,8 @@ int config_parse_documentation(const char *unit,
                         free(*a);
                 }
         }
-        *b = NULL;
+        if (b)
+                *b = NULL;
 
         return r;
 }

commit 97fec53e5e91222f43fc89d0ad45fa197742a363
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:34:21 2013 -0400

    udev: use initialization instead of zeroing in one place

diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index e60da90..662bd33 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -340,13 +340,18 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
 {
         struct udev_ctrl_msg *uctrl_msg;
         ssize_t size;
-        struct msghdr smsg;
         struct cmsghdr *cmsg;
         struct iovec iov;
-        struct ucred *cred;
         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+        struct msghdr smsg = {
+                .msg_iov = &iov,
+                .msg_iovlen = 1,
+                .msg_control = cred_msg,
+                .msg_controllen = sizeof(cred_msg),
+        };
+        struct ucred *cred;
 
-        uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
+        uctrl_msg = new0(struct udev_ctrl_msg, 1);
         if (uctrl_msg == NULL)
                 return NULL;
         uctrl_msg->refcount = 1;
@@ -381,11 +386,7 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
 
         iov.iov_base = &uctrl_msg->ctrl_msg_wire;
         iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
-        memset(&smsg, 0x00, sizeof(struct msghdr));
-        smsg.msg_iov = &iov;
-        smsg.msg_iovlen = 1;
-        smsg.msg_control = cred_msg;
-        smsg.msg_controllen = sizeof(cred_msg);
+
         size = recvmsg(conn->sock, &smsg, 0);
         if (size <  0) {
                 log_error("unable to receive ctrl message: %m\n");
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 7c6c5d6..1c2d00f 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -779,10 +779,11 @@ static void handle_signal(struct udev *udev, int signo)
 
                                 if (WIFEXITED(status)) {
                                         if (WEXITSTATUS(status) != 0)
-                                                log_error("worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
+                                                log_error("worker [%u] exit with return code %i\n",
+                                                          pid, WEXITSTATUS(status));
                                 } else if (WIFSIGNALED(status)) {
                                         log_error("worker [%u] terminated by signal %i (%s)\n",
-                                            pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+                                                  pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
                                 } else if (WIFSTOPPED(status)) {
                                         log_error("worker [%u] stopped\n", pid);
                                 } else if (WIFCONTINUED(status)) {

commit 872c8faaf2009422a91d227ae0b5c6f04c9d2c69
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:34:17 2013 -0400

    Fix write-only use of a few variables
    
    Since the invention of read-only memory, write-only memory has been
    considered deprecated. Where appropriate, either make use of the
    value, or avoid writing it, to make it clear that it is not used.

diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c
index a4f15eb..26769d6 100644
--- a/src/analyze/systemd-analyze.c
+++ b/src/analyze/systemd-analyze.c
@@ -384,9 +384,9 @@ static int pretty_boot_time(DBusConnection *bus, char **_buf) {
 
         size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
         if (t->kernel_time > 0)
-                size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
+                strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
         else
-                size = strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
+                strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
 
         ptr = strdup(buf);
         if (!ptr)
@@ -818,18 +818,18 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, unsigned
                 if (strv_contains(*units, *c)) {
                         r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0),
                                                     true, NULL, boot);
+                        if (r < 0)
+                                return r;
                         continue;
                 }
 
                 r = list_dependencies_one(bus, *c, level + 1, units,
                                           (branches << 1) | (to_print ? 1 : 0));
-                if(r < 0)
+                if (r < 0)
                         return r;
 
-
-                if(!to_print)
+                if (!to_print)
                         break;
-
         }
         return 0;
 }
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 14ccd3e..edbd381 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -254,7 +254,7 @@ static void do_journal_append(char *file)
 
         p = malloc(9 + BOOTCHART_MAX);
         if (!p) {
-                r = log_oom();
+                log_oom();
                 return;
         }
 
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index 5eee2d1..7ac0138 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -420,13 +420,10 @@ static void svg_pss_graph(void) {
         i = 1;
         LIST_FOREACH_BEFORE(link, sampledata, head) {
                 int bottom;
-                int top;
+                int top = 0;
                 struct ps_sched_struct *prev_sample;
                 struct ps_sched_struct *cross_place;
 
-                bottom = 0;
-                top = 0;
-
                 /* put all the small pss blocks into the bottom */
                 ps = ps_first->next_ps;
                 while (ps->next_ps) {
@@ -533,8 +530,8 @@ static void svg_io_bi_bar(void) {
         int max_here = 0;
         int i;
         int k;
-        struct list_sample_data *start_sampledata = sampledata;
-        struct list_sample_data *stop_sampledata = sampledata;
+        struct list_sample_data *start_sampledata;
+        struct list_sample_data *stop_sampledata;
 
         svg("<!-- IO utilization graph - In -->\n");
 
@@ -599,10 +596,7 @@ static void svg_io_bi_bar(void) {
                 int stop;
                 int diff;
                 double tot;
-                double pbi;
-
-                tot = 0;
-                pbi = 0;
+                double pbi = 0;
 
                 start = MAX(i - ((range / 2) - 1), 0);
                 stop = MIN(i + (range / 2), samples);
@@ -647,8 +641,8 @@ static void svg_io_bo_bar(void) {
         int max_here = 0;
         int i;
         int k;
-        struct list_sample_data *start_sampledata = sampledata;
-        struct list_sample_data *stop_sampledata = sampledata;
+        struct list_sample_data *start_sampledata;
+        struct list_sample_data *stop_sampledata;
 
         svg("<!-- IO utilization graph - out -->\n");
 
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 66015c2..c6d72b5 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -110,6 +110,8 @@ static void print_status_info(StatusInfo *i) {
                            "PRETTY_NAME", &pretty_name,
                            "CPE_NAME", &cpe_name,
                            NULL);
+        if (r < 0)
+                log_warning("Failed to read /etc/os-release: %s", strerror(-r));
 
         if (!isempty(pretty_name))
                 printf("  Operating System: %s\n", pretty_name);
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 68c353f..733373b 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -240,7 +240,7 @@ int main(int argc, char* argv[]) {
         coredump_bufsize = COREDUMP_MIN_START;
         coredump_data = malloc(coredump_bufsize);
         if (!coredump_data) {
-                r = log_oom();
+                log_warning("Failed to allocate memory for core, core will not be stored.");
                 goto finalize;
         }
 
@@ -251,7 +251,7 @@ int main(int argc, char* argv[]) {
                 n = loop_read(STDIN_FILENO, coredump_data + coredump_size,
                               coredump_bufsize - coredump_size, false);
                 if (n < 0) {
-                        log_error("Failed to read core dump data: %s", strerror(-n));
+                        log_error("Failed to read core data: %s", strerror(-n));
                         r = (int) n;
                         goto finish;
                 } else if (n == 0)
@@ -259,13 +259,13 @@ int main(int argc, char* argv[]) {
 
                 coredump_size += n;
 
-                if(coredump_size > COREDUMP_MAX) {
-                        log_error("Coredump too large, ignoring");
+                if (coredump_size > COREDUMP_MAX) {
+                        log_error("Core too large, core will not be stored.");
                         goto finalize;
                 }
 
                 if (!GREEDY_REALLOC(coredump_data, coredump_bufsize, coredump_size + 1)) {
-                        r = log_oom();
+                        log_warning("Failed to allocate memory for core, core will not be stored.");
                         goto finalize;
                 }
         }
@@ -277,7 +277,7 @@ int main(int argc, char* argv[]) {
 finalize:
         r = sd_journal_sendv(iovec, j);
         if (r < 0)
-                log_error("Failed to send coredump: %s", strerror(-r));
+                log_error("Failed to log coredump: %s", strerror(-r));
 
 finish:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/libsystemd-bus/test-bus-memfd.c b/src/libsystemd-bus/test-bus-memfd.c
index 05ef555..b9d6a25 100644
--- a/src/libsystemd-bus/test-bus-memfd.c
+++ b/src/libsystemd-bus/test-bus-memfd.c
@@ -102,7 +102,7 @@ int main(int argc, char *argv[]) {
 
         /* we did truncate it to 6 */
         r = sd_memfd_get_size(m, &sz);
-        assert_se(sz == 6);
+        assert_se(r >= 0 && sz == 6);
 
         /* map it, check content */
         r = sd_memfd_map(m, 0, 12, (void **)&s);
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index bb85c7d..890c5c6 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -484,7 +484,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message) {
                         return -EINVAL;
         }
 
-        r = manager_get_session_by_pid(m, leader, &session);
+        manager_get_session_by_pid(m, leader, &session);
         if (session) {
                 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
                 _cleanup_free_ char *path = NULL;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 036828b..a8a86ed 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -748,7 +748,7 @@ static int list_sockets(DBusConnection *bus, char **args) {
         }
         free(socket_infos);
 
-        return 0;
+        return r;
 }
 
 static int compare_unit_file_list(const void *a, const void *b) {
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index 716767b..f79d20c 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -429,7 +429,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem)
         return 0;
 }
 
-static int test_hwdb(struct udev *udev, const char *modalias) {
+static void test_hwdb(struct udev *udev, const char *modalias) {
         struct udev_hwdb *hwdb;
         struct udev_list_entry *entry;
 
@@ -440,7 +440,7 @@ static int test_hwdb(struct udev *udev, const char *modalias) {
         printf("\n");
 
         hwdb = udev_hwdb_unref(hwdb);
-        return 0;
+        assert(hwdb == NULL);
 }
 
 int main(int argc, char *argv[])
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
index d9dc73b..d0cce84 100644
--- a/src/udev/udevadm-hwdb.c
+++ b/src/udev/udevadm-hwdb.c
@@ -648,7 +648,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
 
                         udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0))
                                 printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
-                        hwdb = udev_hwdb_unref(hwdb);
+                        udev_hwdb_unref(hwdb);
                 }
         }
 out:

commit 51d122af23533b0b8318911c4fc8b128ad8eafb7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:48 2013 -0400

    Introduce _cleanup_fdset_free_

diff --git a/src/core/manager.c b/src/core/manager.c
index 58dacdc..b45a2e1 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -236,7 +236,7 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
                 *p++ = '*';
                 if (pos < width-1)
                         p = mempset(p, ' ', width-1-pos);
-                p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
+                strcpy(p, ANSI_HIGHLIGHT_OFF);
         }
 }
 
@@ -257,6 +257,7 @@ static void manager_print_jobs_in_progress(Manager *m) {
         /* m->n_running_jobs must be consistent with the contents of m->jobs,
          * so the above loop must have succeeded in finding j. */
         assert(counter == print_nr + 1);
+        assert(j);
 
         cylon_pos = m->jobs_in_progress_iteration % 14;
         if (cylon_pos >= 8)
@@ -2317,8 +2318,8 @@ int manager_distribute_fds(Manager *m, FDSet *fds) {
 
 int manager_reload(Manager *m) {
         int r, q;
-        FILE *f;
-        FDSet *fds;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_fdset_free_ FDSet *fds = NULL;
 
         assert(m);
 
@@ -2332,20 +2333,18 @@ int manager_reload(Manager *m) {
         fds = fdset_new();
         if (!fds) {
                 m->n_reloading --;
-                r = -ENOMEM;
-                goto finish;
+                return -ENOMEM;
         }
 
         r = manager_serialize(m, f, fds, false);
         if (r < 0) {
                 m->n_reloading --;
-                goto finish;
+                return r;
         }
 
         if (fseeko(f, 0, SEEK_SET) < 0) {
                 m->n_reloading --;
-                r = -errno;
-                goto finish;
+                return -errno;
         }
 
         /* From here on there is no way back. */
@@ -2389,13 +2388,6 @@ int manager_reload(Manager *m) {
 
         m->send_reloading_done = true;
 
-finish:
-        if (f)
-                fclose(f);
-
-        if (fds)
-                fdset_free(fds);
-
         return r;
 }
 
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index fc4a8a3..15e4873 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1223,7 +1223,7 @@ int main(int argc, char *argv[]) {
         bool saved_attr_valid = false;
         struct winsize ws;
         int kmsg_socket_pair[2] = { -1, -1 };
-        FDSet *fds = NULL;
+        _cleanup_fdset_free_ FDSet *fds = NULL;
 
         log_parse_environment();
         log_open();
@@ -1725,7 +1725,5 @@ finish:
         free(arg_directory);
         free(arg_machine);
 
-        fdset_free(fds);
-
         return r;
 }
diff --git a/src/shared/fdset.h b/src/shared/fdset.h
index a7bd5e2..1a26005 100644
--- a/src/shared/fdset.h
+++ b/src/shared/fdset.h
@@ -22,6 +22,7 @@
 ***/
 
 #include "set.h"
+#include "util.h"
 
 typedef struct FDSet FDSet;
 
@@ -47,3 +48,9 @@ int fdset_iterate(FDSet *s, Iterator *i);
 
 #define FDSET_FOREACH(fd, fds, i) \
         for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i)))
+
+static inline void fdset_freep(FDSet **fds) {
+        if (*fds)
+                fdset_free(*fds);
+}
+#define _cleanup_fdset_free_ _cleanup_(fdset_freep)

commit a3e7f417d72ba3251fd6b3a228a2721a4b725a03
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:43 2013 -0400

    bus: fix access to unitialized variable in error path
    
    src/machine/machined-dbus.c:237:13: warning: Branch condition evaluates to a garbage value
            if (m)
                ^

diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index 18c2d1c..bc67c32 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -639,7 +639,6 @@ int sd_bus_message_new_method_errorf(
                 const char *format,
                 ...) {
 
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         sd_bus_message *t;
         va_list ap;
         int r;
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 22caadf..2b622d1 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -203,7 +203,7 @@ static int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
 
         r = manager_add_machine(manager, name, &m);
         if (r < 0)
-                goto fail;
+                return r;
 
         m->leader = leader;
         m->class = c;
@@ -234,8 +234,7 @@ static int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
         return 0;
 
 fail:
-        if (m)
-                machine_add_to_gc_queue(m);
+        machine_add_to_gc_queue(m);
 
         return r;
 }
@@ -1003,17 +1002,12 @@ int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
         assert(name);
 
         machine = hashmap_get(m->machines, name);
-        if (machine) {
-                if (_machine)
-                        *_machine = machine;
-
-                return 0;
+        if (!machine) {
+                machine = machine_new(m, name);
+                if (!machine)
+                        return -ENOMEM;
         }
 
-        machine = machine_new(m, name);
-        if (!machine)
-                return -ENOMEM;
-
         if (_machine)
                 *_machine = machine;
 

commit 6891529fe1176c046ece579807ff48e3191692f3
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:36 2013 -0400

    drop-ins: check return value
    
    If the function failed, nothing serious would happen
    because unlink would probably return EFAULT, but this
    would obscure the real error and is a bit sloppy.

diff --git a/src/core/unit.c b/src/core/unit.c
index 4b97710..1db7d06 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2908,6 +2908,9 @@ int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
                 return 0;
 
         r = drop_in_file(u, mode, name, &p, &q);
+        if (r < 0)
+                return r;
+
         if (unlink(q) < 0)
                 r = errno == ENOENT ? 0 : -errno;
         else

commit 7ca9dffae1988a885e2e79c4bdca68169f4ca5ff
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:30 2013 -0400

    journald: use greedy_realloc in one place

diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 29429f6..518e9ec 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1145,13 +1145,13 @@ int process_event(Server *s, struct epoll_event *ev) {
                 }
 
                 for (;;) {
-                        struct msghdr msghdr;
-                        struct iovec iovec;
                         struct ucred *ucred = NULL;
                         struct timeval *tv = NULL;
                         struct cmsghdr *cmsg;
                         char *label = NULL;
                         size_t label_len = 0;
+
+                        struct iovec iovec;
                         union {
                                 struct cmsghdr cmsghdr;
 
@@ -1168,7 +1168,14 @@ int process_event(Server *s, struct epoll_event *ev) {
                                             CMSG_SPACE(sizeof(struct timeval)) +
                                             CMSG_SPACE(sizeof(int)) + /* fd */
                                             CMSG_SPACE(NAME_MAX)]; /* selinux label */
-                        } control;
+                        } control = {};
+                        struct msghdr msghdr = {
+                                .msg_iov = &iovec,
+                                .msg_iovlen = 1,
+                                .msg_control = &control,
+                                .msg_controllen = sizeof(control),
+                        };
+
                         ssize_t n;
                         int v;
                         int *fds = NULL;
@@ -1179,36 +1186,14 @@ int process_event(Server *s, struct epoll_event *ev) {
                                 return -errno;
                         }
 
-                        if (s->buffer_size < (size_t) v) {
-                                void *b;
-                                size_t l;
-
-                                l = MAX(LINE_MAX + (size_t) v, s->buffer_size * 2);
-                                b = realloc(s->buffer, l+1);
+                        if (!GREEDY_REALLOC(s->buffer, s->buffer_size, LINE_MAX + (size_t) v))
+                                return log_oom();
 
-                                if (!b) {
-                                        log_error("Couldn't increase buffer.");
-                                        return -ENOMEM;
-                                }
-
-                                s->buffer_size = l;
-                                s->buffer = b;
-                        }
-
-                        zero(iovec);
                         iovec.iov_base = s->buffer;
                         iovec.iov_len = s->buffer_size;
 
-                        zero(control);
-                        zero(msghdr);
-                        msghdr.msg_iov = &iovec;
-                        msghdr.msg_iovlen = 1;
-                        msghdr.msg_control = &control;
-                        msghdr.msg_controllen = sizeof(control);
-
                         n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
                         if (n < 0) {
-
                                 if (errno == EINTR || errno == EAGAIN)
                                         return 1;
 

commit 74dcc2df7b2a340c3e1fe9e61e5c8deb324c83d7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:20 2013 -0400

    dbus-common: avoid leak in error path
    
    src/shared/dbus-common.c:968:33: warning: Potential leak of memory pointed to by 'l'
                            return -EINVAL;
                                    ^~~~~~

diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c
index c727cae..3ba2d87 100644
--- a/src/shared/dbus-common.c
+++ b/src/shared/dbus-common.c
@@ -934,7 +934,7 @@ int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
 int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
         DBusMessageIter sub, sub2;
         unsigned n = 0, i = 0;
-        char **l;
+        _cleanup_strv_free_ char **l = NULL;
 
         assert(iter);
         assert(_l);
@@ -953,6 +953,7 @@ int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
         l = new(char*, n*2+1);
         if (!l)
                 return -ENOMEM;
+        l[0] = NULL; /* make sure that l is properly terminated at all times */
 
         dbus_message_iter_recurse(iter, &sub);
 
@@ -968,26 +969,25 @@ int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
                         return -EINVAL;
 
                 l[i] = strdup(a);
-                if (!l[i]) {
-                        strv_free(l);
+                if (!l[i])
                         return -ENOMEM;
-                }
+                i++;
 
-                l[++i] = strdup(b);
-                if (!l[i]) {
-                        strv_free(l);
+                l[i] = strdup(b);
+                if (!l[i])
                         return -ENOMEM;
-                }
-
                 i++;
+
                 dbus_message_iter_next(&sub);
         }
 
         assert(i == n*2);
         l[i] = NULL;
 
-        if (_l)
+        if (_l) {
                 *_l = l;
+                l = NULL; /* avoid freeing */
+        }
 
         return 0;
 }

commit b47d419c25ecc735615a1088060c1ec8bef1e41f
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Oct 12 12:15:49 2013 -0400

    Modernization
    
    Fixes minor leak in error path in device.c.

diff --git a/src/core/device.c b/src/core/device.c
index 9fca82a..25af2cb 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -189,10 +189,12 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
 
         assert(m);
 
-        if (!(sysfs = udev_device_get_syspath(dev)))
+        sysfs = udev_device_get_syspath(dev);
+        if (!sysfs)
                 return -ENOMEM;
 
-        if ((r = device_find_escape_name(m, path, &u)) < 0)
+        r = device_find_escape_name(m, path, &u);
+        if (r < 0)
                 return r;
 
         if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
@@ -234,17 +236,21 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                 first = hashmap_get(m->devices_by_sysfs, sysfs);
                 LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
 
-                if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 0)
+                r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
+                if (r < 0)
                         goto fail;
         }
 
         if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
             (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
-                if ((r = unit_set_description(u, model)) < 0)
+                r = unit_set_description(u, model);
+                if (r < 0)
                         goto fail;
-        } else
-                if ((r = unit_set_description(u, path)) < 0)
+        } else {
+                r = unit_set_description(u, path);
+                if (r < 0)
                         goto fail;
+        }
 
         if (main) {
                 /* The additional systemd udev properties we only
@@ -257,7 +263,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                         size_t l;
 
                         FOREACH_WORD_QUOTED(w, l, alias, state) {
-                                char *e;
+                                _cleanup_free_ char *e;
 
                                 e = strndup(w, l);
                                 if (!e) {
@@ -265,13 +271,10 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                                         goto fail;
                                 }
 
-                                if (!is_path(e)) {
-                                        log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
-                                        free(e);
-                                } else {
+                                if (is_path(e))
                                         device_update_unit(m, dev, e, false);
-                                        free(e);
-                                }
+                                else
+                                        log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
                         }
                 }
 
@@ -281,22 +284,21 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                         size_t l;
 
                         FOREACH_WORD_QUOTED(w, l, wants, state) {
-                                char *e, *n;
+                                _cleanup_free_ char *e, *n = NULL;
 
                                 e = strndup(w, l);
                                 if (!e) {
                                         r = -ENOMEM;
                                         goto fail;
                                 }
+
                                 n = unit_name_mangle(e);
                                 if (!n) {
                                         r = -ENOMEM;
                                         goto fail;
                                 }
-                                free(e);
 
                                 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
-                                free(n);
                                 if (r < 0)
                                         goto fail;
                         }
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index d2b4213..55fd6d6 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -48,6 +48,9 @@
  *
  */
 
+#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
+#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
+
 static const char *arg_dest = "/tmp";
 
 static inline void blkid_free_probep(blkid_probe *b) {
@@ -113,13 +116,13 @@ static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr
 
 
         if (fstype) {
-                char *fst;
-
                 errno = 0;
                 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
                 if (r != 0)
                         *fstype = NULL;
                 else {
+                        char *fst;
+
                         fst = strdup(v);
                         if (!fst)
                                 return -ENOMEM;
@@ -242,10 +245,8 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) {
         int r;
 
         e = udev_enumerate_new(udev);
-        if (!e) {
-                r = log_oom();
-                goto finish;
-        }
+        if (!e)
+                return log_oom();
 
         d = udev_device_new_from_devnum(udev, 'b', dev);
         if (!d) {
@@ -314,10 +315,9 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) {
                 if (r == 0)
                         goto skip;
 
-                if (sd_id128_equal(type_id, SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)))
+                if (sd_id128_equal(type_id, GPT_SWAP))
                         add_swap(node, fstype);
-                else if (sd_id128_equal(type_id, SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15))) {
-
+                else if (sd_id128_equal(type_id, GPT_HOME)) {
                         if (!home || nr < home_nr) {
                                 free(home);
                                 home = strdup(node);
@@ -353,7 +353,7 @@ finish:
 }
 
 static int get_btrfs_block_device(const char *path, dev_t *dev) {
-        struct btrfs_ioctl_fs_info_args fsi;
+        struct btrfs_ioctl_fs_info_args fsi = {};
         _cleanup_close_ int fd = -1;
         uint64_t id;
 
@@ -364,7 +364,6 @@ static int get_btrfs_block_device(const char *path, dev_t *dev) {
         if (fd < 0)
                 return -errno;
 
-        zero(fsi);
         if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
                 return -errno;
 
@@ -373,12 +372,11 @@ static int get_btrfs_block_device(const char *path, dev_t *dev) {
                 return 0;
 
         for (id = 1; id <= fsi.max_id; id++) {
-                struct btrfs_ioctl_dev_info_args di;
+                struct btrfs_ioctl_dev_info_args di = {
+                        .devid = id,
+                };
                 struct stat st;
 
-                zero(di);
-                di.devid = id;
-
                 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
                         if (errno == ENODEV)
                                 continue;
@@ -433,10 +431,8 @@ static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
         int r;
 
         d = udev_device_new_from_devnum(udev, 'b', devno);
-        if (!d) {
-                r = log_oom();
-                goto finish;
-        }
+        if (!d)
+                return log_oom();
 
         t = udev_device_get_devnode(d);
         if (!t) {
@@ -454,8 +450,7 @@ static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
         r = 0;
 
 finish:
-        if (d)
-                udev_device_unref(d);
+        udev_device_unref(d);
 
         return r;
 }
diff --git a/src/locale/localed.c b/src/locale/localed.c
index e160c04..3cac634 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -805,7 +805,7 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
 
                 free_data_x11();
         } else {
-                FILE *f;
+                _cleanup_fclose_ FILE *f;
                 unsigned n = 0;
                 unsigned best_matching = 0;
                 char *new_keymap = NULL;
@@ -815,16 +815,13 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
                         return -errno;
 
                 for (;;) {
-                        char **a;
+                        _cleanup_strv_free_ char **a = NULL;
                         unsigned matching = 0;
                         int r;
 
                         r = read_next_mapping(f, &n, &a);
-                        if (r < 0) {
-                                fclose(f);
+                        if (r < 0)
                                 return r;
-                        }
-
                         if (r == 0)
                                 break;
 
@@ -879,19 +876,11 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
 
                                 free(new_keymap);
                                 new_keymap = strdup(a[0]);
-
-                                if (!new_keymap) {
-                                        strv_free(a);
-                                        fclose(f);
+                                if (!new_keymap)
                                         return -ENOMEM;
-                                }
                         }
-
-                        strv_free(a);
                 }
 
-                fclose(f);
-
                 if (!streq_ptr(state.vc_keymap, new_keymap)) {
                         free(state.vc_keymap);
                         state.vc_keymap = new_keymap;
@@ -906,7 +895,8 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
 
         if (modified) {
                 dbus_bool_t b;
-                DBusMessage *changed;
+
+                _cleanup_dbus_message_unref_ DBusMessage *changed = NULL;
                 int r;
 
                 r = write_data_vconsole();
@@ -918,13 +908,10 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
                                 "org.freedesktop.locale1",
                                 "VConsoleKeymap\0"
                                 "VConsoleKeymapToggle\0");
-
                 if (!changed)
                         return -ENOMEM;
 
                 b = dbus_connection_send(connection, changed, NULL);
-                dbus_message_unref(changed);
-
                 if (!b)
                         return -ENOMEM;
 
@@ -935,31 +922,26 @@ static int convert_x11_to_vconsole(DBusConnection *connection) {
 }
 
 static int append_locale(DBusMessageIter *i, const char *property, void *userdata) {
-        int r, c = 0, p;
-        char **l;
+        int c, p;
+        _cleanup_strv_free_ char **l = NULL;
 
         l = new0(char*, _PROP_MAX+1);
         if (!l)
                 return -ENOMEM;
 
-        for (p = 0; p < _PROP_MAX; p++) {
+        for (p = 0, c = 0; p < _PROP_MAX; p++) {
                 char *t;
 
                 if (isempty(data[p]))
                         continue;
 
-                if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) {
-                        strv_free(l);
+                if (asprintf(&t, "%s=%s", names[p], data[p]) < 0)
                         return -ENOMEM;
-                }
 
                 l[c++] = t;
         }
 
-        r = bus_property_append_strv(i, property, (void*) l);
-        strv_free(l);
-
-        return r;
+        return bus_property_append_strv(i, property, (void*) l);
 }
 
 static const BusProperty bus_locale_properties[] = {
diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
index 6b74866..58b77bd 100644
--- a/src/readahead/readahead-collect.c
+++ b/src/readahead/readahead-collect.c
@@ -415,7 +415,8 @@ static int collect(const char *root) {
                         }
                 }
 
-                if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) {
+                n = read(fanotify_fd, &data, sizeof(data));
+                if (n < 0) {
 
                         if (errno == EINTR || errno == EAGAIN)
                                 continue;
@@ -436,7 +437,7 @@ static int collect(const char *root) {
                 }
 
                 for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) {
-                        char fn[PATH_MAX];
+                        char fn[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
                         int k;
 
                         if (m->fd < 0)
@@ -450,9 +451,8 @@ static int collect(const char *root) {
                                 goto next_iteration;
 
                         snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd);
-                        char_array_0(fn);
-
-                        if ((k = readlink_malloc(fn, &p)) >= 0) {
+                        k = readlink_malloc(fn, &p);
+                        if (k >= 0) {
                                 if (startswith(p, "/tmp") ||
                                     endswith(p, " (deleted)") ||
                                     hashmap_get(files, p))
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index cc44ab4..979fa8f 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -67,7 +67,7 @@ static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsi
         /* And sort */
         qsort(pids, n_pids, sizeof(pid_t), compare);
 
-        if(flags & OUTPUT_FULL_WIDTH)
+        if (flags & OUTPUT_FULL_WIDTH)
                 n_columns = 0;
         else {
                 if (n_columns > pid_width+2)
@@ -76,7 +76,7 @@ static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsi
                         n_columns = 20;
         }
         for (i = 0; i < n_pids; i++) {
-                char *t = NULL;
+                _cleanup_free_ char *t = NULL;
 
                 get_process_cmdline(pids[i], n_columns, true, &t);
 
@@ -87,8 +87,6 @@ static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsi
                        pid_width,
                        (unsigned long) pids[i],
                        strna(t));
-
-                free(t);
         }
 }
 
@@ -98,7 +96,7 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
         _cleanup_fclose_ FILE *f = NULL;
         size_t n = 0, n_allocated = 0;
         _cleanup_free_ pid_t *pids = NULL;
-        char *p = NULL;
+        _cleanup_free_ char *p = NULL;
         pid_t pid;
         int r;
 
@@ -106,13 +104,8 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
         if (r < 0)
                 return r;
 
-        fn = strappend(p, "/cgroup.procs");
-        free(p);
-        if (!fn)
-                return -ENOMEM;
-
+        fn = strappenda(p, "/cgroup.procs");
         f = fopen(fn, "re");
-        free(fn);
         if (!f)
                 return -errno;
 
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index f3eb6a6..000dae9 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -37,7 +37,7 @@ bool is_efi_boot(void) {
 
 static int read_flag(const char *varname) {
         int r;
-        void *v;
+        _cleanup_free_ void *v = NULL;
         size_t s;
         uint8_t b;
 
@@ -45,15 +45,11 @@ static int read_flag(const char *varname) {
         if (r < 0)
                 return r;
 
-        if (s != 1) {
-                r = -EINVAL;
-                goto finish;
-        }
+        if (s != 1)
+                return -EINVAL;
 
         b = *(uint8_t *)v;
         r = b > 0;
-finish:
-        free(v);
         return r;
 }
 
diff --git a/src/shared/install.c b/src/shared/install.c
index 9722ed4..5a780fe 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -1874,6 +1874,7 @@ static void unitfilelist_free(UnitFileList **f) {
         free((*f)->path);
         free(*f);
 }
+#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
 
 int unit_file_get_list(
                 UnitFileScope scope,
@@ -1925,8 +1926,7 @@ int unit_file_get_list(
                 for (;;) {
                         struct dirent *de;
                         union dirent_storage buffer;
-                        UnitFileList __attribute__((cleanup(unitfilelist_free)))
-                                *f = NULL;
+                        _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
 
                         r = readdir_r(d, &buffer.de, &de);
                         if (r != 0)
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 9224208..954686f 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -300,7 +300,8 @@ int socket_address_print(const SocketAddress *a, char **p) {
         case AF_INET: {
                 char *ret;
 
-                if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
+                ret = new(char, INET_ADDRSTRLEN+1+5+1);
+                if (!ret)
                         return -ENOMEM;
 
                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
@@ -316,7 +317,8 @@ int socket_address_print(const SocketAddress *a, char **p) {
         case AF_INET6: {
                 char *ret;
 
-                if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
+                ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1);
+                if (!ret)
                         return -ENOMEM;
 
                 ret[0] = '[';
@@ -334,8 +336,8 @@ int socket_address_print(const SocketAddress *a, char **p) {
                 char *ret;
 
                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
-
-                        if (!(ret = strdup("<unnamed>")))
+                        ret = strdup("<unnamed>");
+                        if (!ret)
                                 return -ENOMEM;
 
                 } else if (a->sockaddr.un.sun_path[0] == 0) {
@@ -346,7 +348,8 @@ int socket_address_print(const SocketAddress *a, char **p) {
                          * more than one NUL byte. That is
                          * actually an invalid assumption */
 
-                        if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
+                        ret = new(char, sizeof(a->sockaddr.un.sun_path)+1);
+                        if (!ret)
                                 return -ENOMEM;
 
                         ret[0] = '@';
@@ -354,8 +357,8 @@ int socket_address_print(const SocketAddress *a, char **p) {
                         ret[sizeof(a->sockaddr.un.sun_path)] = 0;
 
                 } else {
-
-                        if (!(ret = strdup(a->sockaddr.un.sun_path)))
+                        ret = strdup(a->sockaddr.un.sun_path);
+                        if (!ret)
                                 return -ENOMEM;
                 }
 
diff --git a/src/shared/util.c b/src/shared/util.c
index e18421e..54dbace 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -643,7 +643,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
 
         /* Kernel threads have no argv[] */
         if (r == NULL || r[0] == 0) {
-                char *t;
+                _cleanup_free_ char *t = NULL;
                 int h;
 
                 free(r);
@@ -656,8 +656,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
                         return h;
 
                 r = strjoin("[", t, "]", NULL);
-                free(t);
-
                 if (!r)
                         return -ENOMEM;
         }

commit 7ff7394d9e4e9189c30fd018235e6b1728c6f2d0
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Oct 11 19:33:13 2013 -0400

    Never call qsort on potentially NULL arrays
    
    This extends 62678ded 'efi: never call qsort on potentially
    NULL arrays' to all other places where qsort is used and it
    is not obvious that the count is non-zero.

diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c
index 27d063c..a4f15eb 100644
--- a/src/analyze/systemd-analyze.c
+++ b/src/analyze/systemd-analyze.c
@@ -768,7 +768,7 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, unsigned
         if (r < 0)
                 return r;
 
-        qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
 
         r = acquire_boot_times(bus, &boot);
         if (r < 0)
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index cacf705..293a211 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -461,7 +461,7 @@ static int display(Hashmap *a) {
                 if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
                         array[n++] = g;
 
-        qsort(array, n, sizeof(Group*), group_compare);
+        qsort_safe(array, n, sizeof(Group*), group_compare);
 
         /* Find the longest names in one run */
         for (j = 0; j < n; j++) {
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 16b132b..936f368 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -222,7 +222,7 @@ int setup_namespace(char** read_write_dirs,
                      strv_length(read_only_dirs) +
                      strv_length(inaccessible_dirs) +
                      (private_tmp ? 2 : 0);
-        BindMount *m, *mounts;
+        BindMount *m, *mounts = NULL;
         int r = 0;
 
         if (!mount_flags)
@@ -231,27 +231,29 @@ int setup_namespace(char** read_write_dirs,
         if (unshare(CLONE_NEWNS) < 0)
                 return -errno;
 
-        m = mounts = (BindMount *) alloca(n * sizeof(BindMount));
-        if ((r = append_mounts(&m, read_write_dirs, READWRITE)) < 0 ||
-                (r = append_mounts(&m, read_only_dirs, READONLY)) < 0 ||
-                (r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE)) < 0)
-                return r;
+        if (n) {
+                m = mounts = (BindMount *) alloca(n * sizeof(BindMount));
+                if ((r = append_mounts(&m, read_write_dirs, READWRITE)) < 0 ||
+                    (r = append_mounts(&m, read_only_dirs, READONLY)) < 0 ||
+                    (r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE)) < 0)
+                        return r;
+
+                if (private_tmp) {
+                        m->path = "/tmp";
+                        m->mode = PRIVATE_TMP;
+                        m++;
+
+                        m->path = "/var/tmp";
+                        m->mode = PRIVATE_VAR_TMP;
+                        m++;
+                }
 
-        if (private_tmp) {
-                m->path = "/tmp";
-                m->mode = PRIVATE_TMP;
-                m++;
+                assert(mounts + n == m);
 
-                m->path = "/var/tmp";
-                m->mode = PRIVATE_VAR_TMP;
-                m++;
+                qsort(mounts, n, sizeof(BindMount), mount_path_compare);
+                drop_duplicates(mounts, &n);
         }
 
-        assert(mounts + n == m);
-
-        qsort(mounts, n, sizeof(BindMount), mount_path_compare);
-        drop_duplicates(mounts, &n);
-
         /* Remount / as SLAVE so that nothing now mounted in the namespace
            shows up in the parent */
         if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index 7738d24..90ca008 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -399,7 +399,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
         }
 
         assert(n == hashmap_size(h));
-        qsort(items, n, sizeof(CatalogItem), catalog_compare_func);
+        qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
 
         r = write_catalog(database, h, sb, items, n);
         if (r < 0)
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 78b937b..901e71b 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1344,7 +1344,7 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st
 
         /* Order by the position on disk, in order to improve seek
          * times for rotating media. */
-        qsort(items, n_iovec, sizeof(EntryItem), entry_item_cmp);
+        qsort_safe(items, n_iovec, sizeof(EntryItem), entry_item_cmp);
 
         r = journal_file_append_entry_internal(f, ts, xor_hash, items, n_iovec, seqnum, ret, offset);
 
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 8d5effb..d4a1c6c 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -299,8 +299,7 @@ int journal_directory_vacuum(
                 n_list ++;
         }
 
-        if (n_list > 0)
-                qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
+        qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
 
         for (i = 0; i < n_list; i++) {
                 struct statvfs ss;
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 2f8be1b..275458c 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -761,7 +761,7 @@ static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative
                 sd_journal_flush_matches(j);
         }
 
-        qsort(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
+        qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
 
         if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
                 if (relative > (int) count || relative <= -(int)count)
diff --git a/src/libsystemd-bus/bus-match.c b/src/libsystemd-bus/bus-match.c
index 1411167..916682a 100644
--- a/src/libsystemd-bus/bus-match.c
+++ b/src/libsystemd-bus/bus-match.c
@@ -768,7 +768,7 @@ int bus_match_parse(
         }
 
         /* Order the whole thing, so that we always generate the same tree */
-        qsort(components, n_components, sizeof(struct bus_match_component), match_component_compare);
+        qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
 
         /* Check for duplicates */
         for (i = 0; i+1 < n_components; i++)
diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c
index 8146f27..e71d766 100644
--- a/src/libudev/libudev-enumerate.c
+++ b/src/libudev/libudev-enumerate.c
@@ -276,7 +276,7 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
                 size_t move_later_prefix = 0;
 
                 udev_list_cleanup(&udev_enumerate->devices_list);
-                qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
+                qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
 
                 max = udev_enumerate->devices_cur;
                 for (i = 0; i < max; i++) {
diff --git a/src/nss-myhostname/netlink.c b/src/nss-myhostname/netlink.c
index b1ef912..47a41f5 100644
--- a/src/nss-myhostname/netlink.c
+++ b/src/nss-myhostname/netlink.c
@@ -197,7 +197,8 @@ finish:
                 return r;
         }
 
-        qsort(list, n_list, sizeof(struct address), address_compare);
+        if (n_list)
+                qsort(list, n_list, sizeof(struct address), address_compare);
 
         *_list = list;
         *_n_list = n_list;
diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
index 32888ad..6b74866 100644
--- a/src/readahead/readahead-collect.c
+++ b/src/readahead/readahead-collect.c
@@ -536,8 +536,7 @@ done:
                 HASHMAP_FOREACH_KEY(q, p, files, i)
                         pack_file(pack, p, on_btrfs);
         } else {
-                struct item *ordered, *j;
-                unsigned k, n;
+                unsigned n;
 
                 /* On rotating media, order things by the block
                  * numbers */
@@ -545,25 +544,31 @@ done:
                 log_debug("Ordering...");
 
                 n = hashmap_size(files);
-                if (!(ordered = new(struct item, n))) {
-                        r = log_oom();
-                        goto finish;
-                }
-
-                j = ordered;
-                HASHMAP_FOREACH_KEY(q, p, files, i) {
-                        memcpy(j, q, sizeof(struct item));
-                        j++;
-                }
+                if (n) {
+                        _cleanup_free_ struct item *ordered;
+                        struct item *j;
+                        unsigned k;
+
+                        ordered = new(struct item, n);
+                        if (!ordered) {
+                                r = log_oom();
+                                goto finish;
+                        }
 
-                assert(ordered + n == j);
+                        j = ordered;
+                        HASHMAP_FOREACH_KEY(q, p, files, i) {
+                                memcpy(j, q, sizeof(struct item));
+                                j++;
+                        }
 
-                qsort(ordered, n, sizeof(struct item), qsort_compare);
+                        assert(ordered + n == j);
 
-                for (k = 0; k < n; k++)
-                        pack_file(pack, ordered[k].path, on_btrfs);
+                        qsort(ordered, n, sizeof(struct item), qsort_compare);
 
-                free(ordered);
+                        for (k = 0; k < n; k++)
+                                pack_file(pack, ordered[k].path, on_btrfs);
+                } else
+                        log_warning("No pack files");
         }
 
         log_debug("Finalizing...");
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index e971f36..cc44ab4 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -44,6 +44,8 @@ static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsi
         unsigned i, m, pid_width;
         pid_t biggest = 0;
 
+        assert(n_pids > 0);
+
         /* Filter duplicates */
         m = 0;
         for (i = 0; i < n_pids; i++) {
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index 6d99739..ed4070c 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -127,7 +127,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
                 return -ENOMEM;
         }
 
-        qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
+        qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
         *strv = files;
 
         hashmap_free(fh);
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index c015b16..f3eb6a6 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -384,8 +384,7 @@ int efi_get_boot_options(uint16_t **options) {
                 list[count ++] = id;
         }
 
-        if (list)
-                qsort(list, count, sizeof(uint16_t), cmp_uint16);
+        qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
 
         *options = list;
         return count;
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index 603a1c7..733b320 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -662,6 +662,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
         int r;
 
         assert(filename);
+        assert(pattern);
         assert(field);
 
         r = read_full_file(filename, &status, NULL);
diff --git a/src/shared/util.h b/src/shared/util.h
index 26af5b3..09e556d 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -772,3 +772,15 @@ bool id128_is_valid(const char *s) _pure_;
 void parse_user_at_host(char *arg, char **user, char **host);
 
 int split_pair(const char *s, const char *sep, char **l, char **r);
+
+/**
+ * Normal qsort requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void qsort_safe(void *base, size_t nmemb, size_t size,
+                              int (*compar)(const void *, const void *)) {
+        if (nmemb) {
+                assert(base);
+                qsort(base, nmemb, size, compar);
+        }
+}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d75281f..036828b 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -471,7 +471,7 @@ static int list_units(DBusConnection *bus, char **args) {
         if (r < 0)
                 return r;
 
-        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+        qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
         output_units_list(unit_infos, c);
 
@@ -733,8 +733,8 @@ static int list_sockets(DBusConnection *bus, char **args) {
                 listen = triggered = NULL; /* avoid cleanup */
         }
 
-        qsort(socket_infos, cs, sizeof(struct socket_info),
-              (__compar_fn_t) socket_info_compare);
+        qsort_safe(socket_infos, cs, sizeof(struct socket_info),
+                   (__compar_fn_t) socket_info_compare);
 
         output_sockets_list(socket_infos, cs);
 
@@ -1108,7 +1108,7 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, int leve
         if (r < 0)
                 return r;
 
-        qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
 
         STRV_FOREACH(c, deps) {
                 if (strv_contains(u, *c)) {
@@ -3532,7 +3532,7 @@ static int show_all(const char* verb,
         if (r < 0)
                 return r;
 
-        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+        qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
         for (u = unit_infos; u < unit_infos + c; u++) {
                 _cleanup_free_ char *p = NULL;

commit fb1316462952d17d6ebf19c3f093b730c13016a7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Oct 5 21:44:31 2013 -0400

    unicode: treat cute symbol block as fullwidth
    
    UNICODE standards only talk about fullwidth characters for East
    Asian scripts. But it seems that all those symbols are fullwidth
    too.

diff --git a/src/shared/gunicode.c b/src/shared/gunicode.c
index f2d4608..d89a2f3 100644
--- a/src/shared/gunicode.c
+++ b/src/shared/gunicode.c
@@ -85,8 +85,10 @@ unichar_iswide (unichar c)
     {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C},
     {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
     {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6},
-    {0x1B000, 0x1B001}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23A}, {0x1F240,
-    0x1F248}, {0x1F250, 0x1F251}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}
+    {0x1B000, 0x1B001}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23A},
+    {0x1F240, 0x1F248}, {0x1F250, 0x1F251},
+    {0x1F300, 0x1F567}, /* Miscellaneous Symbols and Pictographs */
+    {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
   };
 
   if (bsearch ((void *)(uintptr_t)c, wide, (sizeof (wide) / sizeof ((wide)[0])), sizeof wide[0],

commit 35d811f521ac5da19786ff64cf1d8a2ee13f1374
Author: Shawn Landden <shawn at churchofgit.com>
Date:   Fri Sep 20 18:37:34 2013 -0700

    test: test for ellipsize

diff --git a/Makefile.am b/Makefile.am
index fcdb69f..77a7bbe 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1137,6 +1137,7 @@ tests += \
 	test-unit-name \
 	test-unit-file \
 	test-utf8 \
+	test-ellipsize \
 	test-util \
 	test-date \
 	test-sleep \
@@ -1327,6 +1328,12 @@ test_log_SOURCES = \
 test_log_LDADD = \
 	libsystemd-core.la
 
+test_ellipsize_SOURCES = \
+	src/test/test-ellipsize.c
+
+test_ellipsize_LDADD = \
+	libsystemd-core.la
+
 test_date_SOURCES = \
 	src/test/test-date.c
 
diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c
new file mode 100644
index 0000000..f97c78e
--- /dev/null
+++ b/src/test/test-ellipsize.c
@@ -0,0 +1,45 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Shawn Landden
+
+  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 <stdio.h>
+
+#include "util.h"
+#include "utf8.h"
+#include "def.h"
+
+static void test_one(const char *p) {
+        _cleanup_free_ char *t;
+        t = ellipsize(p, columns(), 70);
+        puts(t);
+}
+
+int main(int argc, char *argv[]) {
+        test_one(DIGITS LETTERS DIGITS LETTERS);
+        test_one("한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어");
+        test_one("-日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国");
+        test_one("中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国-中国中国中国中国中国中国中国中国中国中国中国中国中国");
+        test_one("sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd");
+        test_one("🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮");
+        test_one("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
+        test_one("shórt");
+
+        return 0;
+}

commit f405e86de361ec305dc2b8634efeaa23dc144053
Author: Shawn Landden <shawn at churchofgit.com>
Date:   Fri Sep 20 18:37:33 2013 -0700

    util, utf8: make ellipsize take multi-byte characters into account
    
    rename old versions to ascii_*
    
    Do not take into account zerowidth characters, but do consider double-wide characters.
    Import needed utf8 helper code from glib.
    
    v3: rebase ontop of utf8 restructuring work
    
    [zj: tweak the algorithm a bit, move new code to separate file]

diff --git a/Makefile.am b/Makefile.am
index e5cd7a5..fcdb69f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -683,6 +683,8 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/exit-status.h \
 	src/shared/utf8.c \
 	src/shared/utf8.h \
+	src/shared/gunicode.c \
+	src/shared/gunicode.h \
 	src/shared/pager.c \
 	src/shared/pager.h \
 	src/shared/ioprio.h \
diff --git a/TODO b/TODO
index 4a498b9..955241a 100644
--- a/TODO
+++ b/TODO
@@ -17,10 +17,6 @@ Bugfixes:
 
 * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point.
 
-* ellipsize_mem must take into account multi-byte unicode characters, and
-  - make the resulting line the requested number of *characters*, not *bytes*,
-  - avoid truncuating multi-byte sequences in the middle.
-
 * When we detect invalid UTF-8, we cant't use it in an error message:
   log...("Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
 
diff --git a/src/shared/gunicode.c b/src/shared/gunicode.c
new file mode 100644
index 0000000..f2d4608
--- /dev/null
+++ b/src/shared/gunicode.c
@@ -0,0 +1,108 @@
+/* gunicode.c - Unicode manipulation functions
+ *
+ *  Copyright (C) 1999, 2000 Tom Tromey
+ *  Copyright 2000, 2005 Red Hat, Inc.
+ */
+
+#include "gunicode.h"
+
+#define unichar uint32_t
+
+/**
+ * g_utf8_prev_char:
+ * @p: a pointer to a position within a UTF-8 encoded string
+ *
+ * Finds the previous UTF-8 character in the string before @p.
+ *
+ * @p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte. If @p might be the first
+ * character of the string, you must use g_utf8_find_prev_char() instead.
+ *
+ * Return value: a pointer to the found character.
+ **/
+char *
+utf8_prev_char (const char *p)
+{
+  while (1)
+    {
+      p--;
+      if ((*p & 0xc0) != 0x80)
+        return (char *)p;
+    }
+}
+
+struct Interval
+{
+  unichar start, end;
+};
+
+static int
+interval_compare (const void *key, const void *elt)
+{
+  unichar c = (unichar) (long) (key);
+  struct Interval *interval = (struct Interval *)elt;
+
+  if (c < interval->start)
+    return -1;
+  if (c > interval->end)
+    return +1;
+
+  return 0;
+}
+
+/*
+ * NOTE:
+ *
+ * The tables for g_unichar_iswide() and g_unichar_iswide_cjk() are
+ * generated from the Unicode Character Database's file
+ * extracted/DerivedEastAsianWidth.txt using the gen-iswide-table.py
+ * in this way:
+ *
+ *   ./gen-iswide-table.py < path/to/ucd/extracted/DerivedEastAsianWidth.txt | fmt
+ *
+ * Last update for Unicode 6.0.
+ */
+
+/**
+ * g_unichar_iswide:
+ * @c: a Unicode character
+ *
+ * Determines if a character is typically rendered in a double-width
+ * cell.
+ *
+ * Return value: %TRUE if the character is wide
+ **/
+bool
+unichar_iswide (unichar c)
+{
+  /* See NOTE earlier for how to update this table. */
+  static const struct Interval wide[] = {
+    {0x1100, 0x115F}, {0x2329, 0x232A}, {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3},
+    {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, {0x3000, 0x303E}, {0x3041, 0x3096},
+    {0x3099, 0x30FF}, {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA},
+    {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x32FE},
+    {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C},
+    {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
+    {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6},
+    {0x1B000, 0x1B001}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23A}, {0x1F240,
+    0x1F248}, {0x1F250, 0x1F251}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}
+  };
+
+  if (bsearch ((void *)(uintptr_t)c, wide, (sizeof (wide) / sizeof ((wide)[0])), sizeof wide[0],
+               interval_compare))
+    return true;
+
+  return false;
+}
+
+const char utf8_skip_data[256] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
diff --git a/src/shared/gunicode.h b/src/shared/gunicode.h
new file mode 100644
index 0000000..a4b2934
--- /dev/null
+++ b/src/shared/gunicode.h
@@ -0,0 +1,28 @@
+/* gunicode.h - Unicode manipulation functions
+ *
+ *  Copyright (C) 1999, 2000 Tom Tromey
+ *  Copyright 2000, 2005 Red Hat, Inc.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+char *utf8_prev_char (const char *p);
+
+extern const char utf8_skip_data[256];
+
+/**
+ * g_utf8_next_char:
+ * @p: Pointer to the start of a valid UTF-8 character
+ *
+ * Skips to the next character in a UTF-8 string. The string must be
+ * valid; this macro is as fast as possible, and has no error-checking.
+ * You would use this macro to iterate over a string character by
+ * character. The macro returns the start of the next UTF-8 character.
+ * Before using this macro, use g_utf8_validate() to validate strings
+ * that may contain invalid UTF-8.
+ */
+#define utf8_next_char(p) (char *)((p) + utf8_skip_data[*(const unsigned char *)(p)])
+
+bool unichar_iswide (uint32_t c);
diff --git a/src/shared/utf8.c b/src/shared/utf8.c
index 31120af..98b68ef 100644
--- a/src/shared/utf8.c
+++ b/src/shared/utf8.c
@@ -98,7 +98,7 @@ static int utf8_encoded_expected_len(const char *str) {
 }
 
 /* decode one unicode char */
-static int utf8_encoded_to_unichar(const char *str) {
+int utf8_encoded_to_unichar(const char *str) {
         int unichar;
         int len;
         int i;
diff --git a/src/shared/utf8.h b/src/shared/utf8.h
index 96a03ea..e3eef11 100644
--- a/src/shared/utf8.h
+++ b/src/shared/utf8.h
@@ -35,3 +35,4 @@ char *ascii_filter(const char *s);
 char *utf16_to_utf8(const void *s, size_t length);
 
 int utf8_encoded_valid_unichar(const char *str);
+int utf8_encoded_to_unichar(const char *str);
diff --git a/src/shared/util.c b/src/shared/util.c
index 31cea79..e18421e 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -74,6 +74,8 @@
 #include "env-util.h"
 #include "fileio.h"
 #include "device-nodes.h"
+#include "utf8.h"
+#include "gunicode.h"
 
 int saved_argc = 0;
 char **saved_argv = NULL;
@@ -3288,7 +3290,7 @@ int running_in_chroot(void) {
                 a.st_ino != b.st_ino;
 }
 
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
         size_t x;
         char *r;
 
@@ -3319,6 +3321,80 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
         return r;
 }
 
+char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+        size_t x;
+        char *e;
+        const char *i, *j;
+        unsigned k, len, len2;
+
+        assert(s);
+        assert(percent <= 100);
+        assert(new_length >= 3);
+
+        /* if no multibyte characters use ascii_ellipsize_mem for speed */
+        if (ascii_is_valid(s))
+                return ascii_ellipsize_mem(s, old_length, new_length, percent);
+
+        if (old_length <= 3 || old_length <= new_length)
+                return strndup(s, old_length);
+
+        x = (new_length * percent) / 100;
+
+        if (x > new_length - 3)
+                x = new_length - 3;
+
+        k = 0;
+        for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
+                int c;
+
+                c = utf8_encoded_to_unichar(i);
+                if (c < 0)
+                        return NULL;
+                k += unichar_iswide(c) ? 2 : 1;
+        }
+
+        if (k > x) /* last character was wide and went over quota */
+                x ++;
+
+        for (j = s + old_length; k < new_length && j > i; ) {
+                int c;
+
+                j = utf8_prev_char(j);
+                c = utf8_encoded_to_unichar(j);
+                if (c < 0)
+                        return NULL;
+                k += unichar_iswide(c) ? 2 : 1;
+        }
+        assert(i <= j);
+
+        /* we don't actually need to ellipsize */
+        if (i == j)
+                return memdup(s, old_length + 1);
+
+        /* make space for ellipsis */
+        j = utf8_next_char(j);
+
+        len = i - s;
+        len2 = s + old_length - j;
+        e = new(char, len + 3 + len2 + 1);
+        if (!e)
+                return NULL;
+
+        /*
+        printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
+               old_length, new_length, x, len, len2, k);
+        */
+
+        memcpy(e, s, len);
+        e[len]   = 0xe2; /* tri-dot ellipsis: … */
+        e[len + 1] = 0x80;
+        e[len + 2] = 0xa6;
+
+        memcpy(e + len + 3, j, len2 + 1);
+
+        return e;
+}
+
 char *ellipsize(const char *s, size_t length, unsigned percent) {
         return ellipsize_mem(s, strlen(s), length, percent);
 }
diff --git a/src/shared/util.h b/src/shared/util.h
index c9d0782..26af5b3 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -405,6 +405,7 @@ static inline const char *ansi_highlight_off(void) {
 int running_in_chroot(void);
 
 char *ellipsize(const char *s, size_t length, unsigned percent);
+                                   /* bytes                 columns */
 char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);
 
 int touch(const char *path);



More information about the systemd-commits mailing list