[systemd-commits] 10 commits - man/systemd.service.xml man/systemd.socket.xml man/systemd.unit.xml src/conf-parser.c src/dbus.c src/device.c src/load-fragment.c src/main.c src/service.c src/strv.c src/util.c src/util.h units/fedora units/gentoo units/getty at .service.m4 units/graphical.target.m4 units/multi-user.target.m4 units/suse

Lennart Poettering lennart at kemper.freedesktop.org
Wed Jul 7 13:29:58 PDT 2010


 man/systemd.service.xml    |   49 +++++++++++------
 man/systemd.socket.xml     |   25 +++++----
 man/systemd.unit.xml       |    5 +
 src/conf-parser.c          |   48 +++++++++++++++--
 src/dbus.c                 |    8 +-
 src/device.c               |    2 
 src/load-fragment.c        |  125 ++++++++++++++++++++++++++-------------------
 src/main.c                 |    2 
 src/service.c              |    4 -
 src/strv.c                 |    2 
 src/util.c                 |   64 ++++++++++++++++-------
 src/util.h                 |   11 ++-
 units/fedora/halt.service  |    3 -
 units/gentoo/halt.service  |    3 -
 units/getty at .service.m4    |    7 --
 units/graphical.target.m4  |    5 -
 units/multi-user.target.m4 |    7 --
 units/suse/halt.service    |    3 -
 18 files changed, 234 insertions(+), 139 deletions(-)

New commits:
commit 07405e90968c39f04bc00e1af5b1671940482b19
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 22:29:41 2010 +0200

    units: in order to make the default services parseable by GKeyFile, merge repeated lines

diff --git a/units/fedora/halt.service b/units/fedora/halt.service
index 815c8fb..106ac6b 100644
--- a/units/fedora/halt.service
+++ b/units/fedora/halt.service
@@ -15,6 +15,5 @@ Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.a
 [Service]
 Type=finish
 ValidNoProcess=yes
-Environment=INIT_HALT=HALT
-Environment=RUNLEVEL=0
+Environment=INIT_HALT=HALT RUNLEVEL=0
 ExecStart=/etc/init.d/halt start
diff --git a/units/gentoo/halt.service b/units/gentoo/halt.service
index ecf4cff..56ac493 100644
--- a/units/gentoo/halt.service
+++ b/units/gentoo/halt.service
@@ -15,6 +15,5 @@ Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.a
 [Service]
 Type=finish
 ValidNoProcess=yes
-Environment=INIT_HALT=HALT
-Environment=RC_DOWN_HARDDISK=yes
+Environment=INIT_HALT=HALT RC_DOWN_HARDDISK=yes
 ExecStart=/etc/init.d/shutdown.sh
diff --git a/units/getty at .service.m4 b/units/getty at .service.m4
index f1f7f32..b82f5aa 100644
--- a/units/getty at .service.m4
+++ b/units/getty at .service.m4
@@ -29,9 +29,4 @@ RestartSec=0
 KillMode=process-group
 
 [Install]
-Alias=getty.target.wants/getty at tty1.service
-Alias=getty.target.wants/getty at tty2.service
-Alias=getty.target.wants/getty at tty3.service
-Alias=getty.target.wants/getty at tty4.service
-Alias=getty.target.wants/getty at tty5.service
-Alias=getty.target.wants/getty at tty6.service
+Alias=getty.target.wants/getty at tty1.service getty.target.wants/getty at tty2.service getty.target.wants/getty at tty3.service getty.target.wants/getty at tty4.service getty.target.wants/getty at tty5.service getty.target.wants/getty at tty6.service
diff --git a/units/graphical.target.m4 b/units/graphical.target.m4
index 6228026..468770a 100644
--- a/units/graphical.target.m4
+++ b/units/graphical.target.m4
@@ -22,7 +22,4 @@ Names=runlevel5.target
 )m4_dnl
 
 [Install]
-Alias=default.target
-m4_ifdef(`TARGET_FEDORA',
-Alias=runlevel5.target
-)m4_dnl
+Alias=default.target m4_ifdef(`TARGET_FEDORA', runlevel5.target)
diff --git a/units/multi-user.target.m4 b/units/multi-user.target.m4
index eb46b2b..010e7d8 100644
--- a/units/multi-user.target.m4
+++ b/units/multi-user.target.m4
@@ -22,9 +22,4 @@ Names=runlevel3.target
 )m4_dnl
 
 [Install]
-Alias=default.target
-m4_ifdef(`TARGET_FEDORA',
-Alias=runlevel2.target
-Alias=runlevel3.target
-Alias=runlevel4.target
-)m4_dnl
+Alias=default.target m4_ifdef(`TARGET_FEDORA', runlevel2.target runlevel3.target runlevel4.target)
diff --git a/units/suse/halt.service b/units/suse/halt.service
index fbcf154..40d58b3 100644
--- a/units/suse/halt.service
+++ b/units/suse/halt.service
@@ -15,6 +15,5 @@ Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.a
 [Service]
 Type=finish
 ValidNoProcess=yes
-Environment=INIT_HALT=HALT
-Environment=RUNLEVEL=0
+Environment=INIT_HALT=HALT RUNLEVEL=0
 ExecStart=/etc/init.d/halt start
commit e167fb86f6935c0fe989d6ccfbbc0acadba245a2
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 22:28:51 2010 +0200

    util: handle \s escape as defined in the XDG spec properly in cunescape()

diff --git a/src/util.c b/src/util.c
index 5103cc6..a01229e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1182,6 +1182,11 @@ char *cunescape_length(const char *s, size_t length) {
                         *(t++) = '\'';
                         break;
 
+                case 's':
+                        /* This is an extension of the XDG syntax files */
+                        *(t++) = ' ';
+                        break;
+
                 case 'x': {
                         /* hexadecimal encoding */
                         int a, b;
commit 923f8d76dc1e14be0d8c969b1661d0279ddd97ba
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 22:28:02 2010 +0200

    dbus: shut down bus connection cleanly and fully when a direct client disconnects

diff --git a/src/dbus.c b/src/dbus.c
index 8172197..0008cfd 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -71,6 +71,7 @@ static const char *error_to_dbus(int error);
 static void bus_done_api(Manager *m);
 static void bus_done_system(Manager *m);
 static void bus_done_private(Manager *m);
+static void shutdown_connection(Manager *m, DBusConnection *c);
 
 static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
         Manager *m = data;
@@ -477,11 +478,8 @@ static DBusHandlerResult private_bus_message_filter(DBusConnection *connection,
                   dbus_message_get_member(message),
                   dbus_message_get_path(message));
 
-        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-                set_remove(m->bus_connections, connection);
-                set_remove(m->bus_connections_for_dispatch, connection);
-                dbus_connection_unref(connection);
-        }
+        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
+                shutdown_connection(m, connection);
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
commit b3eaa6288107210a84d6d121036fb4b2f7283ee2
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 21:22:56 2010 +0200

    man: update man pages for recent syntax changes

diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index bceb5aa..7eaf9cb 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -270,10 +270,21 @@
                                 <listitem><para>Additional commands
                                 that are executed before (resp. after)
                                 the command in
-                                <varname>ExecStart=</varname>. If
-                                specified more than once, all commands
-                                are executed one after the other,
-                                serially. Use of these settings is
+                                <varname>ExecStart=</varname>. Multiple
+                                command lines may be concatenated in a
+                                single directive, by seperating them
+                                by semicolons (these semicolons must
+                                be passed as seperate words). In that
+                                case, the commands are executed one
+                                after the other,
+                                serially. Alternatively, these
+                                directives may be specified more than
+                                once whith the same effect. However,
+                                the latter syntax is not recommended
+                                for compatibility with parsers
+                                suitable for XDG
+                                <filename>.desktop</filename> files.
+                                Use of these settings is
                                 optional.</para></listitem>
                         </varlistentry>
 
@@ -281,20 +292,24 @@
                                 <term><varname>ExecReload=</varname></term>
                                 <listitem><para>Commands to execute to
                                 trigger a configuration reload in the
-                                service. If used more than once, all
-                                commands are executed one after the
-                                other, serially. Use of this setting is optional.
-                                </para></listitem>
+                                service. This argument takes multiple
+                                command lines, following the same
+                                scheme as pointed out for
+                                <varname>ExecStartPre=</varname>
+                                above. Use of this setting is
+                                optional.  </para></listitem>
                         </varlistentry>
 
                         <varlistentry>
                                 <term><varname>ExecStop=</varname></term>
                                 <listitem><para>Commands to execute to
                                 stop the service started via
-                                <varname>ExecStart=</varname>. If used
-                                more than once, all commands are
-                                executed one after the other,
-                                serially. Use of this setting is
+                                <varname>ExecStart=</varname>. This
+                                argument takes multiple command lines,
+                                following the same scheme as pointed
+                                out for
+                                <varname>ExecStartPre=</varname>
+                                above. Use of this setting is
                                 optional. All processes remaining for
                                 a service after the commands
                                 configured in this option are run are
@@ -312,10 +327,12 @@
                                 that are executed after the service
                                 was stopped using the commands
                                 configured in
-                                <varname>ExecStop=</varname>. If
-                                specified more than once, all commands
-                                are executed one after the other,
-                                serially. Use of these settings is
+                                <varname>ExecStop=</varname>. This
+                                argument takes multiple command lines,
+                                following the same scheme as pointed
+                                out for
+                                <varname>ExecStartPre</varname>. Use
+                                of these settings is
                                 optional.</para></listitem>
                         </varlistentry>
 
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 32102fa..20dc00e 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -440,16 +440,18 @@
                         <varlistentry>
                                 <term><varname>ExecStartPre=</varname></term>
                                 <term><varname>ExecStartPost=</varname></term>
-                                <listitem><para>Takes a command line,
-                                which is executed before (resp. after)
-                                the listening sockets/FIFOs are created and
+                                <listitem><para>Takes one or more
+                                command lines, which are executed
+                                before (resp. after) the listening
+                                sockets/FIFOs are created and
                                 bound. The first token of the command
                                 line must be an absolute file name,
                                 then followed by arguments for the
-                                process. If specified more than once,
-                                all commands are executed one after
-                                the other, fully serialized. The use of
-                                these settings is optional.</para></listitem>
+                                process. Multiple command lines may be
+                                specified following the same scheme as
+                                used for
+                                <varname>ExecStartPre=</varname> of
+                                service unit files.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
@@ -458,10 +460,11 @@
                                 <listitem><para>Additional commands
                                 that are executed before (resp. after)
                                 the listening sockets/FIFOs are closed
-                                and removed. If specified more than
-                                once, all commands are executed one
-                                after the other, fully serialized. The use of
-                                these settings is optional.</para></listitem>
+                                and removed. Multiple command lines
+                                may be specified following the same
+                                scheme as used for
+                                <varname>ExecStartPre=</varname> of
+                                service unit files.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 26272c4..a06eed5 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -114,7 +114,10 @@
                 are understood: s, min, h, d, w, ms, us.</para>
 
                 <para>Empty lines and lines starting with # or ; are
-                ignored. This may be used for commenting.</para>
+                ignored. This may be used for commenting. Lines ending
+                in a backslash are concatenated with the following
+                line while reading and the backslash is replaced by a
+                space character. This may be used to wrap long lines.</para>
 
                 <para>If a line starts with <option>.include</option>
                 followed by a file name the specified file will be
commit 61e5d8ed877b6389ea94c05e0e2f646f8b66d8bd
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 20:59:20 2010 +0200

    service: allow configuration of more than one Exec command in one line

diff --git a/src/load-fragment.c b/src/load-fragment.c
index 43b8093..c3909e9 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -364,73 +364,94 @@ static int config_parse_exec(
                 void *data,
                 void *userdata) {
 
-        ExecCommand **e = data, *nce = NULL;
-        char **n;
-        char *w;
+        ExecCommand **e = data, *nce;
+        char *path, **n;
         unsigned k;
-        size_t l;
-        char *state, *path = NULL;
-        bool honour_argv0, write_to_path;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
+        assert(e);
 
         /* We accept an absolute path as first argument, or
          * alternatively an absolute prefixed with @ to allow
          * overriding of argv[0]. */
 
-        honour_argv0 = rvalue[0] == '@';
+        for (;;) {
+                char *w;
+                size_t l;
+                char *state;
+                bool honour_argv0, write_to_path;
 
-        if (rvalue[honour_argv0 ? 1 : 0] != '/') {
-                log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
-                return -EINVAL;
-        }
+                path = NULL;
+                nce = NULL;
+                n = NULL;
 
-        k = 0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
+                rvalue += strspn(rvalue, WHITESPACE);
 
-        if (!(n = new(char*, k + (honour_argv0 ? 0 : 1))))
-                return -ENOMEM;
+                if (rvalue[0] == 0)
+                        break;
 
-        k = 0;
-        write_to_path = honour_argv0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                if (write_to_path) {
-                        if (!(path = strndup(w+1, l-1)))
-                                goto fail;
-                        write_to_path = false;
-                } else {
-                        if (!(n[k++] = strndup(w, l)))
-                                goto fail;
+                honour_argv0 = rvalue[0] == '@';
+
+                if (rvalue[honour_argv0 ? 1 : 0] != '/') {
+                        log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
+                        return -EINVAL;
                 }
-        }
 
-        n[k] = NULL;
+                k = 0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", l) == 0)
+                                break;
 
-        if (!n[0]) {
-                log_error("[%s:%u] Invalid command line: %s", filename, line, rvalue);
-                strv_free(n);
-                return -EINVAL;
-        }
+                        k++;
+                }
 
-        if (!path)
-                if (!(path = strdup(n[0])))
-                        goto fail;
+                if (!(n = new(char*, k + (honour_argv0 ? 0 : 1))))
+                        return -ENOMEM;
+
+                k = 0;
+                write_to_path = honour_argv0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", l) == 0)
+                                break;
+
+                        if (write_to_path) {
+                                if (!(path = cunescape_length(w+1, l-1)))
+                                        goto fail;
+                                write_to_path = false;
+                        } else {
+                                if (!(n[k++] = cunescape_length(w, l)))
+                                        goto fail;
+                        }
+                }
 
-        assert(path_is_absolute(path));
+                n[k] = NULL;
 
-        if (!(nce = new0(ExecCommand, 1)))
-                goto fail;
+                if (!n[0]) {
+                        log_error("[%s:%u] Invalid command line: %s", filename, line, rvalue);
+                        strv_free(n);
+                        return -EINVAL;
+                }
 
-        nce->argv = n;
-        nce->path = path;
+                if (!path)
+                        if (!(path = strdup(n[0])))
+                                goto fail;
 
-        path_kill_slashes(nce->path);
+                assert(path_is_absolute(path));
+
+                if (!(nce = new0(ExecCommand, 1)))
+                        goto fail;
 
-        exec_command_append_list(e, nce);
+                nce->argv = n;
+                nce->path = path;
+
+                path_kill_slashes(nce->path);
+
+                exec_command_append_list(e, nce);
+
+                rvalue = state;
+        }
 
         return 0;
 
commit f60f22dfbb8cfa0eb55d1896db0e4c3f7d3cfacb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 20:58:41 2010 +0200

    util: use quoted word parsing where applicable

diff --git a/src/conf-parser.c b/src/conf-parser.c
index df3584d..1cabc0d 100644
--- a/src/conf-parser.c
+++ b/src/conf-parser.c
@@ -423,7 +423,7 @@ int config_parse_strv(
                 k = 0;
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                if (!(n[k++] = strndup(w, l)))
+                if (!(n[k++] = cunescape_length(w, l)))
                         goto fail;
 
         n[k] = NULL;
@@ -475,7 +475,7 @@ int config_parse_path_strv(
                         n[k] = (*sv)[k];
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                if (!(n[k] = strndup(w, l))) {
+                if (!(n[k] = cunescape_length(w, l))) {
                         r = -ENOMEM;
                         goto fail;
                 }
diff --git a/src/device.c b/src/device.c
index a0349c4..2079f1c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -244,7 +244,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u
                         goto fail;
 
         if (wants) {
-                FOREACH_WORD(w, l, wants, state) {
+                FOREACH_WORD_QUOTED(w, l, wants, state) {
                         char *e;
 
                         if (!(e = strndup(w, l))) {
diff --git a/src/load-fragment.c b/src/load-fragment.c
index 1cc7c5c..43b8093 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -61,7 +61,7 @@ static int config_parse_deps(
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t, *k;
                 int r;
 
@@ -103,7 +103,7 @@ static int config_parse_names(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t, *k;
                 int r;
 
@@ -689,7 +689,7 @@ static int config_parse_cpu_affinity(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
                 unsigned cpu;
@@ -766,7 +766,7 @@ static int config_parse_secure_bits(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 if (first_word(w, "keep-caps"))
                         c->secure_bits |= SECURE_KEEP_CAPS;
                 else if (first_word(w, "keep-caps-locked"))
@@ -807,7 +807,7 @@ static int config_parse_bounding_set(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
                 cap_value_t cap;
@@ -902,11 +902,11 @@ static int config_parse_cgroup(
         size_t l;
         char *state;
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
 
-                if (!(t = strndup(w, l)))
+                if (!(t = cunescape_length(w, l)))
                         return -ENOMEM;
 
                 r = unit_add_cgroup_from_text(u, t);
@@ -967,7 +967,7 @@ static int config_parse_mount_flags(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 if (strncmp(w, "shared", l) == 0)
                         flags |= MS_SHARED;
                 else if (strncmp(w, "slave", l) == 0)
diff --git a/src/main.c b/src/main.c
index 592edbe..d5902b3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -426,7 +426,7 @@ static int config_parse_cpu_affinity(
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
                 unsigned cpu;
diff --git a/src/service.c b/src/service.c
index ccc8312..fed8227 100644
--- a/src/service.c
+++ b/src/service.c
@@ -526,7 +526,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
                                 state = LSB;
 
-                                FOREACH_WORD(w, z, t+9, i) {
+                                FOREACH_WORD_QUOTED(w, z, t+9, i) {
                                         char *n, *m;
 
                                         if (!(n = strndup(w, z))) {
@@ -563,7 +563,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
                                 state = LSB;
 
-                                FOREACH_WORD(w, z, strchr(t, ':')+1, i) {
+                                FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
                                         char *n, *m;
 
                                         if (!(n = strndup(w, z))) {
diff --git a/src/strv.c b/src/strv.c
index 01464e1..a663696 100644
--- a/src/strv.c
+++ b/src/strv.c
@@ -264,7 +264,7 @@ char **strv_split_quoted(const char *s) {
 
         i = 0;
         FOREACH_WORD_QUOTED(w, l, s, state)
-                if (!(r[i++] = strndup(w, l))) {
+                if (!(r[i++] = cunescape_length(w, l))) {
                         strv_free(r);
                         return NULL;
                 }
commit 6febfd0d4bdf7519e119149b8d8ec03c210aed1d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 20:58:02 2010 +0200

    util: introduce cunescape_length()

diff --git a/src/util.c b/src/util.c
index 58b96ae..5103cc6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1129,7 +1129,7 @@ char *cescape(const char *s) {
         return r;
 }
 
-char *cunescape(const char *s) {
+char *cunescape_length(const char *s, size_t length) {
         char *r, *t;
         const char *f;
 
@@ -1137,10 +1137,10 @@ char *cunescape(const char *s) {
 
         /* Undoes C style string escaping */
 
-        if (!(r = new(char, strlen(s)+1)))
+        if (!(r = new(char, length+1)))
                 return r;
 
-        for (f = s, t = r; *f; f++) {
+        for (f = s, t = r; f < s + length; f++) {
 
                 if (*f != '\\') {
                         *(t++) = *f;
@@ -1242,6 +1242,9 @@ finish:
         return r;
 }
 
+char *cunescape(const char *s) {
+        return cunescape_length(s, strlen(s));
+}
 
 char *xescape(const char *s, const char *bad) {
         char *r, *t;
diff --git a/src/util.h b/src/util.h
index fed0e67..ff79583 100644
--- a/src/util.h
+++ b/src/util.h
@@ -222,6 +222,12 @@ int undecchar(char c);
 
 char *cescape(const char *s);
 char *cunescape(const char *s);
+char *cunescape_length(const char *s, size_t length);
+
+char *xescape(const char *s, const char *bad);
+
+char *bus_path_escape(const char *s);
+char *bus_path_unescape(const char *s);
 
 char *path_kill_slashes(char *path);
 
@@ -230,11 +236,6 @@ bool path_equal(const char *a, const char *b);
 
 char *ascii_strlower(char *path);
 
-char *xescape(const char *s, const char *bad);
-
-char *bus_path_escape(const char *s);
-char *bus_path_unescape(const char *s);
-
 bool ignore_file(const char *filename);
 
 bool chars_intersect(const char *a, const char *b);
commit 0bab36f250cc79776954fd6066c1e2a33f64c016
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 20:57:47 2010 +0200

    util: properly handle escaped quotes in words in split_quoted()

diff --git a/src/util.c b/src/util.c
index 78eb728..58b96ae 100644
--- a/src/util.c
+++ b/src/util.c
@@ -360,7 +360,8 @@ char *split(const char *c, size_t *l, const char *separator, char **state) {
 /* Split a string into words, but consider strings enclosed in '' and
  * "" as words even if they include spaces. */
 char *split_quoted(const char *c, size_t *l, char **state) {
-        char *current;
+        char *current, *e;
+        bool escaped = false;
 
         current = *state ? *state : (char*) c;
 
@@ -371,26 +372,45 @@ char *split_quoted(const char *c, size_t *l, char **state) {
 
         if (*current == '\'') {
                 current ++;
-                *l = strcspn(current, "'");
-                *state = current+*l;
 
-                if (**state == '\'')
-                        (*state)++;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (*e == '\'')
+                                break;
+                }
+
+                *l = e-current;
+                *state = *e == 0 ? e : e+1;
         } else if (*current == '\"') {
                 current ++;
-                *l = strcspn(current, "\"");
-                *state = current+*l;
 
-                if (**state == '\"')
-                        (*state)++;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (*e == '\"')
+                                break;
+                }
+
+                *l = e-current;
+                *state = *e == 0 ? e : e+1;
         } else {
-                *l = strcspn(current, WHITESPACE);
-                *state = current+*l;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (strchr(WHITESPACE, *e))
+                                break;
+                }
+                *l = e-current;
+                *state = e;
         }
 
-        /* FIXME: Cannot deal with strings that have spaces AND ticks
-         * in them */
-
         return (char*) current;
 }
 
commit f3d4cc01488e4b7acf05da02b487f93ae9744337
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 20:57:10 2010 +0200

    util: fix handling of unknown escapes in cunescape()

diff --git a/src/util.c b/src/util.c
index 8360eb6..78eb728 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1212,7 +1212,7 @@ char *cunescape(const char *s) {
                 default:
                         /* Invalid escape code, let's take it literal then */
                         *(t++) = '\\';
-                        *(t++) = 'f';
+                        *(t++) = *f;
                         break;
                 }
         }
commit 3dab29438c431f8e068c079af13ed26a81e563d3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jul 7 18:20:42 2010 +0200

    conf-parser: support continuation lines with trailing backslashes in lines

diff --git a/src/conf-parser.c b/src/conf-parser.c
index a220453..df3584d 100644
--- a/src/conf-parser.c
+++ b/src/conf-parser.c
@@ -142,6 +142,7 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
         char *section = NULL;
         int r;
         bool ours = false;
+        char *continuation = NULL;
 
         assert(filename);
         assert(t);
@@ -157,7 +158,8 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
         }
 
         while (!feof(f)) {
-                char l[LINE_MAX];
+                char l[LINE_MAX], *p, *c = NULL, *e;
+                bool escaped = false;
 
                 if (!fgets(l, sizeof(l), f)) {
                         if (feof(f))
@@ -168,7 +170,44 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
                         goto finish;
                 }
 
-                if ((r = parse_line(filename, ++line, &section, sections, t, relaxed, l, userdata)) < 0)
+                truncate_nl(l);
+
+                if (continuation) {
+                        if (!(c = strappend(continuation, l))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        free(continuation);
+                        continuation = NULL;
+                        p = c;
+                } else
+                        p = l;
+
+                for (e = p; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                }
+
+                if (escaped) {
+                        *(e-1) = ' ';
+
+                        if (c)
+                                continuation = c;
+                        else if (!(continuation = strdup(l))) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        continue;
+                }
+
+                r = parse_line(filename, ++line, &section, sections, t, relaxed, p, userdata);
+                free(c);
+
+                if (r < 0)
                         goto finish;
         }
 
@@ -176,6 +215,7 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co
 
 finish:
         free(section);
+        free(continuation);
 
         if (f && ours)
                 fclose(f);


More information about the systemd-commits mailing list