[systemd-commits] 4 commits - TODO man/systemd-system.conf.xml src/core src/import src/journal src/libsystemd src/login src/shared src/test src/tmpfiles

Lennart Poettering lennart at kemper.freedesktop.org
Tue Apr 7 06:43:37 PDT 2015


 TODO                               |    8 -----
 man/systemd-system.conf.xml        |   11 ++++++-
 src/core/load-fragment.c           |   51 ++++++++++++++++------------------
 src/core/manager.c                 |    6 +---
 src/core/mount.c                   |    8 ++---
 src/core/swap.c                    |    3 --
 src/core/umount.c                  |   38 +++++++++++++------------
 src/import/pull-common.c           |    6 ++--
 src/journal/journald-kmsg.c        |    6 +---
 src/libsystemd/sd-bus/bus-util.c   |   15 +++-------
 src/libsystemd/sd-bus/bus-util.h   |    2 -
 src/libsystemd/sd-login/sd-login.c |    6 ++--
 src/login/logind-acl.c             |    3 --
 src/login/logind-dbus.c            |    6 ++--
 src/login/logind-inhibit.c         |   12 ++++----
 src/shared/util.c                  |   55 +++++++++++++++++++++++--------------
 src/shared/util.h                  |   13 ++++++--
 src/test/test-util.c               |   31 ++++++++++++++++----
 src/tmpfiles/tmpfiles.c            |    8 ++---
 19 files changed, 156 insertions(+), 132 deletions(-)

New commits:
commit 2c0223282d804ec796c3dc7e0d9087717314ec6a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 6 20:28:37 2015 +0200

    update TODO

diff --git a/TODO b/TODO
index 6ac9879..c69f1f7 100644
--- a/TODO
+++ b/TODO
@@ -12,10 +12,6 @@ Bugfixes:
           Environment=ONE='one' "TWO='two two' too" THREE=
           ExecStart=/bin/python3 -c 'import sys;print(sys.argv)' $ONE $TWO $THREE
 
-* MEMORY return code is overloaded for syntax errors in the command line.
-  str_split_quoted() should return a real return code, so spawn_child can
-  report the failure properly.
-
 * When systemctl --host is used, underlying ssh connection can remain open.
   bus_close does not kill children?
 
@@ -42,8 +38,6 @@ Before 220:
 
 * bus-proxy: GetConnectionSELinuxSecurityContext() is completely broken
 
-* logind: make sure the syncrhonous polkit checks are not interactive, i.e. supporess client side interactive bus message header flag for them
-
 * timer units triggering services with failing conditions run busy:
   http://lists.freedesktop.org/archives/systemd-devel/2015-April/030095.html
 
@@ -55,8 +49,6 @@ Features:
 * fstab-generator should generate systemd-fsck-root.service when
   running in the initrd, and operate on the right device.
 
-* the default stop timeout for units is not documented anywhere.
-
 * .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC
 
 * systemd-run should support a mode where we wait for the unit to be started up

commit f5a05fb578cddcf6e46be68e4a38fdbc4b853f16
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 6 20:34:11 2015 +0200

    man: document default timeouts and start limit parameters

diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 1b74ed3..c06accd 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -260,7 +260,11 @@
         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for details on the per-unit settings). For non-service units,
         <varname>DefaultTimeoutStartSec=</varname> sets the default
-        <varname>TimeoutSec=</varname> value. </para></listitem>
+        <varname>TimeoutSec=</varname>
+        value. <varname>DefaultTimeoutStartSec=</varname> and
+        <varname>DefaultTimeoutStopSec=</varname> default to
+        90s. <varname>DefaultRestartSec=</varname> defaults to
+        100ms.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -272,7 +276,10 @@
         <varname>StartLimitInterval=</varname> and
         <varname>StartLimitBurst=</varname>. See
         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        for details on the per-service settings.</para></listitem>
+        for details on the per-service settings.
+        <varname>DefaultStartLimitInterval=</varname> defaults to
+        10s. <varname>DefaultStartLimitBurst=</varname> defaults to
+        5.</para></listitem>
       </varlistentry>
 
       <varlistentry>

commit ceb242292630b4633aa707b565585a1e8bcbfeb8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 6 20:25:56 2015 +0200

    polkit: rename bus_verify_polkit() to bus_test_polkit() and make it strictly non-interactive
    
    Interactive authorization should only happen asynchronously, hence
    disallow it in synchronous bus_verify_polkit(), and rename it to
    bus_test_polkit(). This way even if the bus message header asks for
    interactive authorization, we'll ask for non-interactive authorization
    which is actually the desired behaviour if CanSuspend, CanHibernate and
    friends, which call this function.

diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index dcad701..6498769 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -211,11 +211,10 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) {
         return sender_uid == good_user;
 }
 
-int bus_verify_polkit(
+int bus_test_polkit(
                 sd_bus_message *call,
                 int capability,
                 const char *action,
-                bool interactive,
                 uid_t good_user,
                 bool *_challenge,
                 sd_bus_error *e) {
@@ -225,6 +224,8 @@ int bus_verify_polkit(
         assert(call);
         assert(action);
 
+        /* Tests non-interactively! */
+
         r = check_good_user(call, good_user);
         if (r != 0)
                 return r;
@@ -237,19 +238,13 @@ int bus_verify_polkit(
 #ifdef ENABLE_POLKIT
         else {
                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-                int authorized = false, challenge = false, c;
+                int authorized = false, challenge = false;
                 const char *sender;
 
                 sender = sd_bus_message_get_sender(call);
                 if (!sender)
                         return -EBADMSG;
 
-                c = sd_bus_message_get_allow_interactive_authorization(call);
-                if (c < 0)
-                        return c;
-                if (c > 0)
-                        interactive = true;
-
                 r = sd_bus_call_method(
                                 call->bus,
                                 "org.freedesktop.PolicyKit1",
@@ -262,7 +257,7 @@ int bus_verify_polkit(
                                 "system-bus-name", 1, "name", "s", sender,
                                 action,
                                 0,
-                                !!interactive,
+                                0,
                                 "");
 
                 if (r < 0) {
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 9f04871..cc16a9d 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -69,7 +69,7 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
 
 int bus_check_peercred(sd_bus *c);
 
-int bus_verify_polkit(sd_bus_message *call, int capability, const char *action, bool interactive, uid_t good_user, bool *_challenge, sd_bus_error *e);
+int bus_test_polkit(sd_bus_message *call, int capability, const char *action, uid_t good_user, bool *_challenge, sd_bus_error *e);
 
 int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
 void bus_verify_polkit_async_registry_free(Hashmap *registry);
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a3d49ef..1571dd0 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1741,7 +1741,7 @@ static int method_can_shutdown_or_sleep(
         blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
 
         if (multiple_sessions) {
-                r = bus_verify_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, false, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 
@@ -1754,7 +1754,7 @@ static int method_can_shutdown_or_sleep(
         }
 
         if (blocked) {
-                r = bus_verify_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, false, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 
@@ -1770,7 +1770,7 @@ static int method_can_shutdown_or_sleep(
                 /* If neither inhibit nor multiple sessions
                  * apply then just check the normal policy */
 
-                r = bus_verify_polkit(message, CAP_SYS_BOOT, action, false, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, action, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 

commit 527b7a421ff3927d4f3f170b1b143452e88ae1dc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 6 20:11:41 2015 +0200

    util: rework cunescape(), improve error handling
    
    Change cunescape() to return a normal error code, so that we can
    distuingish OOM errors from parse errors.
    
    This also adds a flags parameter to control whether "relaxed" or normal
    parsing shall be done. If set no parse failures are generated, and the
    only reason why cunescape() can fail is OOM.

diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 07384d3..e61418d 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -507,16 +507,17 @@ int config_parse_exec_oom_score_adjust(const char* unit,
         return 0;
 }
 
-int config_parse_exec(const char *unit,
-                      const char *filename,
-                      unsigned line,
-                      const char *section,
-                      unsigned section_line,
-                      const char *lvalue,
-                      int ltype,
-                      const char *rvalue,
-                      void *data,
-                      void *userdata) {
+int config_parse_exec(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
         ExecCommand **e = data, *nce;
         char *path, **n;
@@ -568,15 +569,13 @@ int config_parse_exec(const char *unit,
                                                 word ++;
                                         }
                                 }
-                        } else
-                                if (strneq(word, ";", MAX(l, 1U)))
+                        } else if (strneq(word, ";", MAX(l, 1U)))
                                         goto found;
 
                         k++;
                 }
                 if (!isempty(state)) {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                                   "Trailing garbage, ignoring.");
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
                         return 0;
                 }
 
@@ -605,9 +604,10 @@ int config_parse_exec(const char *unit,
                         else
                                 skip = strneq(word, "\\;", MAX(l, 1U));
 
-                        c = cunescape_length(word + skip, l - skip);
-                        if (!c) {
-                                r = log_oom();
+                        r = cunescape_length(word + skip, l - skip, 0, &c);
+                        if (r < 0) {
+                                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to unescape command line, ignoring: %s", rvalue);
+                                r = 0;
                                 goto fail;
                         }
 
@@ -637,8 +637,7 @@ int config_parse_exec(const char *unit,
                 else
                         goto ok;
 
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "%s, ignoring: %s", reason, rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "%s, ignoring: %s", reason, rvalue);
                 r = 0;
                 goto fail;
 
@@ -1976,8 +1975,7 @@ int config_parse_environ(const char *unit,
         if (u) {
                 r = unit_full_printf(u, rvalue, &k);
                 if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, -r,
-                                   "Failed to resolve specifiers, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
         }
 
         if (!k)
@@ -1989,13 +1987,14 @@ int config_parse_environ(const char *unit,
                 _cleanup_free_ char *n;
                 char **x;
 
-                n = cunescape_length(word, l);
-                if (!n)
-                        return log_oom();
+                r = cunescape_length(word, l, 0, &n);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
+                        continue;
+                }
 
                 if (!env_assignment_is_valid(n)) {
-                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                                   "Invalid environment assignment, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
                         continue;
                 }
 
diff --git a/src/core/manager.c b/src/core/manager.c
index 73417ab..1c912fc 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2426,11 +2426,9 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         _cleanup_free_ char *uce = NULL;
                         char **e;
 
-                        uce = cunescape(l+4);
-                        if (!uce) {
-                                r = -ENOMEM;
+                        r = cunescape(l + 4, UNESCAPE_RELAX, &uce);
+                        if (r < 0)
                                 goto finish;
-                        }
 
                         e = strv_env_set(m->environment, uce);
                         if (!e) {
diff --git a/src/core/mount.c b/src/core/mount.c
index 53594cd..c4aa810 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1579,7 +1579,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
         r = 0;
         for (;;) {
                 const char *device, *path, *options, *fstype;
-                _cleanup_free_ const char *d = NULL, *p = NULL;
+                _cleanup_free_ char *d = NULL, *p = NULL;
                 struct libmnt_fs *fs;
                 int k;
 
@@ -1594,12 +1594,10 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
                 options = mnt_fs_get_options(fs);
                 fstype = mnt_fs_get_fstype(fs);
 
-                d = cunescape(device);
-                if (!d)
+                if (cunescape(device, UNESCAPE_RELAX, &d) < 0)
                         return log_oom();
 
-                p = cunescape(path);
-                if (!p)
+                if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
                         return log_oom();
 
                 (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
diff --git a/src/core/swap.c b/src/core/swap.c
index 6b1bdb5..53f1274 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1099,8 +1099,7 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
                         continue;
                 }
 
-                d = cunescape(dev);
-                if (!d)
+                if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
                         return log_oom();
 
                 device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
diff --git a/src/core/umount.c b/src/core/umount.c
index ceee70f..bee267a 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -62,6 +62,7 @@ static void mount_points_list_free(MountPoint **head) {
 static int mount_points_list_get(MountPoint **head) {
         _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
         unsigned int i;
+        int r;
 
         assert(head);
 
@@ -97,9 +98,9 @@ static int mount_points_list_get(MountPoint **head) {
                         continue;
                 }
 
-                p = cunescape(path);
-                if (!p)
-                        return -ENOMEM;
+                r = cunescape(path, UNESCAPE_RELAX, &p);
+                if (r < 0)
+                        return r;
 
                 /* Ignore mount points we can't unmount because they
                  * are API or because we are keeping them open (like
@@ -133,10 +134,12 @@ static int mount_points_list_get(MountPoint **head) {
 static int swap_list_get(MountPoint **head) {
         _cleanup_fclose_ FILE *proc_swaps = NULL;
         unsigned int i;
+        int r;
 
         assert(head);
 
-        if (!(proc_swaps = fopen("/proc/swaps", "re")))
+        proc_swaps = fopen("/proc/swaps", "re");
+        if (!proc_swaps)
                 return (errno == ENOENT) ? 0 : -errno;
 
         (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
@@ -146,19 +149,19 @@ static int swap_list_get(MountPoint **head) {
                 char *dev = NULL, *d;
                 int k;
 
-                if ((k = fscanf(proc_swaps,
-                                "%ms " /* device/file */
-                                "%*s " /* type of swap */
-                                "%*s " /* swap size */
-                                "%*s " /* used */
-                                "%*s\n", /* priority */
-                                &dev)) != 1) {
+                k = fscanf(proc_swaps,
+                           "%ms " /* device/file */
+                           "%*s " /* type of swap */
+                           "%*s " /* swap size */
+                           "%*s " /* used */
+                           "%*s\n", /* priority */
+                           &dev);
 
+                if (k != 1) {
                         if (k == EOF)
                                 break;
 
                         log_warning("Failed to parse /proc/swaps:%u.", i);
-
                         free(dev);
                         continue;
                 }
@@ -168,14 +171,13 @@ static int swap_list_get(MountPoint **head) {
                         continue;
                 }
 
-                d = cunescape(dev);
+                r = cunescape(dev, UNESCAPE_RELAX, &d);
                 free(dev);
+                if (r < 0)
+                        return r;
 
-                if (!d) {
-                        return -ENOMEM;
-                }
-
-                if (!(swap = new0(MountPoint, 1))) {
+                swap = new0(MountPoint, 1);
+                if (!swap) {
                         free(d);
                         return -ENOMEM;
                 }
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index efd67a2..5732353 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -92,9 +92,9 @@ int pull_find_old_etags(const char *url, const char *image_root, int dt, const c
                 if (a >= b)
                         continue;
 
-                u = cunescape_length(a, b - a);
-                if (!u)
-                        return -ENOMEM;
+                r = cunescape_length(a, b - a, 0, &u);
+                if (r < 0)
+                        return r;
 
                 if (!http_etag_is_valid(u)) {
                         free(u);
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index c4216c4..80bd9cd 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -201,8 +201,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
 
                 *e = 0;
 
-                m = cunescape_length_with_prefix(k, e - k, "_KERNEL_");
-                if (!m)
+                if (cunescape_length_with_prefix(k, e - k, "_KERNEL_", UNESCAPE_RELAX, &m) < 0)
                         break;
 
                 if (startswith(m, "_KERNEL_DEVICE="))
@@ -299,8 +298,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
                 }
         }
 
-        message = cunescape_length_with_prefix(p, pl, "MESSAGE=");
-        if (message)
+        if (cunescape_length_with_prefix(p, pl, "MESSAGE=", UNESCAPE_RELAX, &message) >= 0)
                 IOVEC_SET_STRING(iovec[n++], message);
 
         server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index cc0677b..072191e 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -496,9 +496,9 @@ _public_ int sd_session_get_desktop(const char *session, char **desktop) {
         if (r < 0)
                 return r;
 
-        t = cunescape(escaped);
-        if (!t)
-                return -ENOMEM;
+        r = cunescape(escaped, 0, &t);
+        if (r < 0)
+                return r;
 
         *desktop = t;
         return 0;
diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c
index 941fd72..d2b3337 100644
--- a/src/login/logind-acl.c
+++ b/src/login/logind-acl.c
@@ -253,8 +253,7 @@ int devnode_acl_all(struct udev *udev,
                 FOREACH_DIRENT(dent, dir, return -errno) {
                         _cleanup_free_ char *unescaped_devname = NULL;
 
-                        unescaped_devname = cunescape(dent->d_name);
-                        if (!unescaped_devname)
+                        if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0)
                                 return -ENOMEM;
 
                         n = strappend("/dev/", unescaped_devname);
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 5d81693..5eb1a2e 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -231,18 +231,18 @@ int inhibitor_load(Inhibitor *i) {
         }
 
         if (who) {
-                cc = cunescape(who);
-                if (!cc)
-                        return -ENOMEM;
+                r = cunescape(who, 0, &cc);
+                if (r < 0)
+                        return r;
 
                 free(i->who);
                 i->who = cc;
         }
 
         if (why) {
-                cc = cunescape(why);
-                if (!cc)
-                        return -ENOMEM;
+                r = cunescape(why, 0, &cc);
+                if (r < 0)
+                        return r;
 
                 free(i->why);
                 i->why = cc;
diff --git a/src/shared/util.c b/src/shared/util.c
index 8b011cc..67f66ac 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1466,12 +1466,13 @@ static int cunescape_one(const char *p, size_t length, char *ret) {
         return r;
 }
 
-char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
         char *r, *t;
         const char *f;
         size_t pl;
 
         assert(s);
+        assert(ret);
 
         /* Undoes C style string escaping, and optionally prefixes it. */
 
@@ -1479,7 +1480,7 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
 
         r = new(char, pl+length+1);
         if (!r)
-                return NULL;
+                return -ENOMEM;
 
         if (prefix)
                 memcpy(r, prefix, pl);
@@ -1491,17 +1492,31 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
                 remaining = s + length - f;
                 assert(remaining > 0);
 
-                if (*f != '\\' || remaining == 1) {
-                        /* a literal literal, or a trailing backslash, copy verbatim */
+                if (*f != '\\') {
+                        /* A literal literal, copy verbatim */
                         *(t++) = *f;
                         continue;
                 }
 
+                if (remaining == 1) {
+                        if (flags & UNESCAPE_RELAX) {
+                                /* A trailing backslash, copy verbatim */
+                                *(t++) = *f;
+                                continue;
+                        }
+
+                        return -EINVAL;
+                }
+
                 k = cunescape_one(f + 1, remaining - 1, t);
                 if (k < 0) {
-                        /* Invalid escape code, let's take it literal then */
-                        *(t++) = '\\';
-                        continue;
+                        if (flags & UNESCAPE_RELAX) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                                continue;
+                        }
+
+                        return k;
                 }
 
                 f += k;
@@ -1509,17 +1524,17 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
         }
 
         *t = 0;
-        return r;
-}
 
-char *cunescape_length(const char *s, size_t length) {
-        return cunescape_length_with_prefix(s, length, NULL);
+        *ret = r;
+        return t - r;
 }
 
-char *cunescape(const char *s) {
-        assert(s);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+        return cunescape_length_with_prefix(s, length, NULL, flags, ret);
+}
 
-        return cunescape_length(s, strlen(s));
+int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+        return cunescape_length(s, strlen(s), flags, ret);
 }
 
 char *xescape(const char *s, const char *bad) {
@@ -6731,9 +6746,9 @@ int umount_recursive(const char *prefix, int flags) {
                                 continue;
                         }
 
-                        p = cunescape(path);
-                        if (!p)
-                                return -ENOMEM;
+                        r = cunescape(path, UNESCAPE_RELAX, &p);
+                        if (r < 0)
+                                return r;
 
                         if (!path_startswith(p, prefix))
                                 continue;
@@ -6833,9 +6848,9 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                                 continue;
                         }
 
-                        p = cunescape(path);
-                        if (!p)
-                                return -ENOMEM;
+                        r = cunescape(path, UNESCAPE_RELAX, &p);
+                        if (r < 0)
+                                return r;
 
                         /* Let's ignore autofs mounts.  If they aren't
                          * triggered yet, we want to avoid triggering
diff --git a/src/shared/util.h b/src/shared/util.h
index 8823556..e7a5d63 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -311,9 +311,14 @@ char decchar(int x) _const_;
 int undecchar(char c) _const_;
 
 char *cescape(const char *s);
-char *cunescape(const char *s);
-char *cunescape_length(const char *s, size_t length);
-char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix);
+
+typedef enum UnescapeFlags {
+        UNESCAPE_RELAX = 1,
+} UnescapeFlags;
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
 
 char *xescape(const char *s, const char *bad);
 
@@ -1014,7 +1019,7 @@ int take_password_lock(const char *root);
 int is_symlink(const char *path);
 int is_dir(const char *path, bool follow);
 
-typedef enum UnquoteFlags{
+typedef enum UnquoteFlags {
         UNQUOTE_RELAX     = 1,
         UNQUOTE_CUNESCAPE = 2,
 } UnquoteFlags;
diff --git a/src/test/test-util.c b/src/test/test-util.c
index e9d1522..aaf25f8 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -417,23 +417,40 @@ static void test_cescape(void) {
 static void test_cunescape(void) {
         _cleanup_free_ char *unescaped;
 
-        unescaped = cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00");
-        assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
+        assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
+        assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
+        const char *x = "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00";
+        assert_se(streq_ptr(unescaped, x));
+        free(unescaped);
+        unescaped = NULL;
 
         /* incomplete sequences */
-        unescaped = cunescape("\\x0");
+        assert_se(cunescape("\\x0", 0, &unescaped) < 0);
+        assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0);
         assert_se(streq_ptr(unescaped, "\\x0"));
+        free(unescaped);
+        unescaped = NULL;
 
-        unescaped = cunescape("\\x");
+        assert_se(cunescape("\\x", 0, &unescaped) < 0);
+        assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0);
         assert_se(streq_ptr(unescaped, "\\x"));
+        free(unescaped);
+        unescaped = NULL;
 
-        unescaped = cunescape("\\");
+        assert_se(cunescape("\\", 0, &unescaped) < 0);
+        assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0);
         assert_se(streq_ptr(unescaped, "\\"));
+        free(unescaped);
+        unescaped = NULL;
 
-        unescaped = cunescape("\\11");
+        assert_se(cunescape("\\11", 0, &unescaped) < 0);
+        assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0);
         assert_se(streq_ptr(unescaped, "\\11"));
+        free(unescaped);
+        unescaped = NULL;
 
-        unescaped = cunescape("\\1");
+        assert_se(cunescape("\\1", 0, &unescaped) < 0);
+        assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0);
         assert_se(streq_ptr(unescaped, "\\1"));
 }
 
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 20972f6..8c89fb3 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -913,13 +913,13 @@ static int write_one_file(Item *i, const char *path) {
         }
 
         if (i->argument) {
-                _cleanup_free_ char *unescaped;
+                _cleanup_free_ char *unescaped = NULL;
 
                 log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
 
-                unescaped = cunescape(i->argument);
-                if (!unescaped)
-                        return log_oom();
+                r = cunescape(i->argument, 0, &unescaped);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
 
                 r = loop_write(fd, unescaped, strlen(unescaped), false);
                 if (r < 0)



More information about the systemd-commits mailing list