]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: split out extract_first_word() and related calls into extract-word.[ch]
authorLennart Poettering <lennart@poettering.net>
Thu, 22 Oct 2015 18:12:31 +0000 (20:12 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 24 Oct 2015 21:03:49 +0000 (23:03 +0200)
This is quite a lot of code these days, hence move it to its own source
file.

Makefile.am
src/basic/cgroup-util.c
src/basic/cpu-set-util.c
src/basic/extract-word.c [new file with mode: 0644]
src/basic/extract-word.h [new file with mode: 0644]
src/basic/strv.h
src/basic/util.c
src/basic/util.h
src/shared/condition.c

index 89eaf805753c5d410bdef346ef790e179da2bae4..06bd5d4d9b5fce057bffcc553a49d2b550b34699 100644 (file)
@@ -781,6 +781,8 @@ libbasic_la_SOURCES = \
        src/basic/refcnt.h \
        src/basic/util.c \
        src/basic/util.h \
+       src/basic/extract-word.c \
+       src/basic/extract-word.h \
        src/basic/cpu-set-util.c \
        src/basic/cpu-set-util.h \
        src/basic/lockfile-util.c \
index 95fc2b9e5d76ef9ae861aebaeca7c8e67dcc08f4..a3ea512165d4545db80c0bb335bb8645bc909894 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <dirent.h>
 #include <errno.h>
-#include <unistd.h>
+#include <ftw.h>
 #include <signal.h>
-#include <string.h>
 #include <stdlib.h>
-#include <dirent.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <ftw.h>
+#include <unistd.h>
 
-#include "set.h"
-#include "macro.h"
-#include "util.h"
+#include "extract-word.h"
+#include "fileio.h"
 #include "formats-util.h"
-#include "process-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "mkdir.h"
 #include "path-util.h"
-#include "unit-name.h"
-#include "fileio.h"
+#include "process-util.h"
+#include "set.h"
 #include "special.h"
-#include "mkdir.h"
-#include "login-util.h"
+#include "unit-name.h"
+#include "util.h"
 #include "cgroup-util.h"
 
 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
index 519583c167a0760b3a4f025473b069157925aa18..5e064d854fad5726fc438880e01e272ee3061610 100644 (file)
@@ -20,6 +20,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "extract-word.h"
 #include "util.h"
 #include "cpu-set-util.h"
 
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
new file mode 100644 (file)
index 0000000..474e6fd
--- /dev/null
@@ -0,0 +1,274 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  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 "utf8.h"
+#include "util.h"
+
+#include "extract-word.h"
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
+        _cleanup_free_ char *s = NULL;
+        size_t allocated = 0, sz = 0;
+        int r;
+
+        char quote = 0;                 /* 0 or ' or " */
+        bool backslash = false;         /* whether we've just seen a backslash */
+        bool separator = false;         /* whether we've just seen a separator */
+        bool start = true;              /* false means we're looking at a value */
+
+        assert(p);
+        assert(ret);
+
+        if (!separators)
+                separators = WHITESPACE;
+
+        /* Bail early if called after last value or with no input */
+        if (!*p)
+                goto finish_force_terminate;
+
+        /* Parses the first word of a string, and returns it in
+         * *ret. Removes all quotes in the process. When parsing fails
+         * (because of an uneven number of quotes or similar), leaves
+         * the pointer *p at the first invalid character. */
+
+        for (;;) {
+                char c = **p;
+
+                if (start) {
+                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+                                if (!GREEDY_REALLOC(s, allocated, sz+1))
+                                        return -ENOMEM;
+
+                        if (c == 0)
+                                goto finish_force_terminate;
+                        else if (strchr(separators, c)) {
+                                (*p) ++;
+                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+                                        goto finish_force_next;
+                                continue;
+                        }
+
+                        /* We found a non-blank character, so we will always
+                         * want to return a string (even if it is empty),
+                         * allocate it here. */
+                        if (!GREEDY_REALLOC(s, allocated, sz+1))
+                                return -ENOMEM;
+
+                        start = false;
+                }
+
+                if (backslash) {
+                        if (!GREEDY_REALLOC(s, allocated, sz+7))
+                                return -ENOMEM;
+
+                        if (c == 0) {
+                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+                                    (!quote || flags & EXTRACT_RELAX)) {
+                                        /* If we find an unquoted trailing backslash and we're in
+                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+                                         * output.
+                                         *
+                                         * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
+                                         */
+                                        s[sz++] = '\\';
+                                        goto finish_force_terminate;
+                                }
+                                if (flags & EXTRACT_RELAX)
+                                        goto finish_force_terminate;
+                                return -EINVAL;
+                        }
+
+                        if (flags & EXTRACT_CUNESCAPE) {
+                                uint32_t u;
+
+                                r = cunescape_one(*p, (size_t) -1, &c, &u);
+                                if (r < 0) {
+                                        if (flags & EXTRACT_CUNESCAPE_RELAX) {
+                                                s[sz++] = '\\';
+                                                s[sz++] = c;
+                                                goto end_escape;
+                                        }
+                                        return -EINVAL;
+                                }
+
+                                (*p) += r - 1;
+
+                                if (c != 0)
+                                        s[sz++] = c; /* normal explicit char */
+                                else
+                                        sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+                        } else
+                                s[sz++] = c;
+
+end_escape:
+                        backslash = false;
+
+                } else if (quote) {     /* inside either single or double quotes */
+                        if (c == 0) {
+                                if (flags & EXTRACT_RELAX)
+                                        goto finish_force_terminate;
+                                return -EINVAL;
+                        } else if (c == quote)          /* found the end quote */
+                                quote = 0;
+                        else if (c == '\\')
+                                backslash = true;
+                        else {
+                                if (!GREEDY_REALLOC(s, allocated, sz+2))
+                                        return -ENOMEM;
+
+                                s[sz++] = c;
+                        }
+
+                } else if (separator) {
+                        if (c == 0)
+                                goto finish_force_terminate;
+                        if (!strchr(separators, c))
+                                goto finish;
+
+                } else {
+                        if (c == 0)
+                                goto finish_force_terminate;
+                        else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES))
+                                quote = c;
+                        else if (c == '\\')
+                                backslash = true;
+                        else if (strchr(separators, c)) {
+                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+                                        (*p) ++;
+                                        goto finish_force_next;
+                                }
+                                separator = true;
+                        } else {
+                                if (!GREEDY_REALLOC(s, allocated, sz+2))
+                                        return -ENOMEM;
+
+                                s[sz++] = c;
+                        }
+                }
+
+                (*p) ++;
+        }
+
+finish_force_terminate:
+        *p = NULL;
+finish:
+        if (!s) {
+                *p = NULL;
+                *ret = NULL;
+                return 0;
+        }
+
+finish_force_next:
+        s[sz] = 0;
+        *ret = s;
+        s = NULL;
+
+        return 1;
+}
+
+int extract_first_word_and_warn(
+                const char **p,
+                char **ret,
+                const char *separators,
+                ExtractFlags flags,
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *rvalue) {
+
+        /* Try to unquote it, if it fails, warn about it and try again but this
+         * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
+         * in invalid escape sequences. */
+        const char *save;
+        int r;
+
+        save = *p;
+        r = extract_first_word(p, ret, separators, flags);
+        if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+
+                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
+                *p = save;
+                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
+                else
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
+        }
+
+        return r;
+}
+
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+        va_list ap;
+        char **l;
+        int n = 0, i, c, r;
+
+        /* Parses a number of words from a string, stripping any
+         * quotes if necessary. */
+
+        assert(p);
+
+        /* Count how many words are expected */
+        va_start(ap, flags);
+        for (;;) {
+                if (!va_arg(ap, char **))
+                        break;
+                n++;
+        }
+        va_end(ap);
+
+        if (n <= 0)
+                return 0;
+
+        /* Read all words into a temporary array */
+        l = newa0(char*, n);
+        for (c = 0; c < n; c++) {
+
+                r = extract_first_word(p, &l[c], separators, flags);
+                if (r < 0) {
+                        int j;
+
+                        for (j = 0; j < c; j++)
+                                free(l[j]);
+
+                        return r;
+                }
+
+                if (r == 0)
+                        break;
+        }
+
+        /* If we managed to parse all words, return them in the passed
+         * in parameters */
+        va_start(ap, flags);
+        for (i = 0; i < n; i++) {
+                char **v;
+
+                v = va_arg(ap, char **);
+                assert(v);
+
+                *v = l[i];
+        }
+        va_end(ap);
+
+        return c;
+}
diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
new file mode 100644 (file)
index 0000000..ddc1c4f
--- /dev/null
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  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 "macro.h"
+
+typedef enum ExtractFlags {
+        EXTRACT_RELAX           = 1,
+        EXTRACT_CUNESCAPE       = 2,
+        EXTRACT_CUNESCAPE_RELAX = 4,
+        EXTRACT_QUOTES          = 8,
+        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
+} ExtractFlags;
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
+int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
index a5dc696a87c9b784d3b1beff308a58aa83bbaa10..e66794fc34d9f59caebf38b2c8f72f97c1547979 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <fnmatch.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include <fnmatch.h>
 
+#include "extract-word.h"
 #include "util.h"
 
 char *strv_find(char **l, const char *name) _pure_;
index 63c8abcf828bd6e5c12410ba2c0218d455f91e94..641e0b4d89edcb9d1ed0cd1b17a0e777e8698d6c 100644 (file)
@@ -1587,7 +1587,7 @@ char *cescape(const char *s) {
         return r;
 }
 
-static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
         int r = 1;
 
         assert(p);
@@ -5801,255 +5801,6 @@ int is_device_node(const char *path) {
         return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
 }
 
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
-        _cleanup_free_ char *s = NULL;
-        size_t allocated = 0, sz = 0;
-        int r;
-
-        char quote = 0;                 /* 0 or ' or " */
-        bool backslash = false;         /* whether we've just seen a backslash */
-        bool separator = false;         /* whether we've just seen a separator */
-        bool start = true;              /* false means we're looking at a value */
-
-        assert(p);
-        assert(ret);
-
-        if (!separators)
-                separators = WHITESPACE;
-
-        /* Bail early if called after last value or with no input */
-        if (!*p)
-                goto finish_force_terminate;
-
-        /* Parses the first word of a string, and returns it in
-         * *ret. Removes all quotes in the process. When parsing fails
-         * (because of an uneven number of quotes or similar), leaves
-         * the pointer *p at the first invalid character. */
-
-        for (;;) {
-                char c = **p;
-
-                if (start) {
-                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
-                                if (!GREEDY_REALLOC(s, allocated, sz+1))
-                                        return -ENOMEM;
-
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        else if (strchr(separators, c)) {
-                                (*p) ++;
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
-                                        goto finish_force_next;
-                                continue;
-                        }
-
-                        /* We found a non-blank character, so we will always
-                         * want to return a string (even if it is empty),
-                         * allocate it here. */
-                        if (!GREEDY_REALLOC(s, allocated, sz+1))
-                                return -ENOMEM;
-
-                        start = false;
-                }
-
-                if (backslash) {
-                        if (!GREEDY_REALLOC(s, allocated, sz+7))
-                                return -ENOMEM;
-
-                        if (c == 0) {
-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
-                                    (!quote || flags & EXTRACT_RELAX)) {
-                                        /* If we find an unquoted trailing backslash and we're in
-                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
-                                         * output.
-                                         *
-                                         * Unbalanced quotes will only be allowed in EXTRACT_RELAX
-                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
-                                         */
-                                        s[sz++] = '\\';
-                                        goto finish_force_terminate;
-                                }
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        }
-
-                        if (flags & EXTRACT_CUNESCAPE) {
-                                uint32_t u;
-
-                                r = cunescape_one(*p, (size_t) -1, &c, &u);
-                                if (r < 0) {
-                                        if (flags & EXTRACT_CUNESCAPE_RELAX) {
-                                                s[sz++] = '\\';
-                                                s[sz++] = c;
-                                                goto end_escape;
-                                        }
-                                        return -EINVAL;
-                                }
-
-                                (*p) += r - 1;
-
-                                if (c != 0)
-                                        s[sz++] = c; /* normal explicit char */
-                                else
-                                        sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
-                        } else
-                                s[sz++] = c;
-
-end_escape:
-                        backslash = false;
-
-                } else if (quote) {     /* inside either single or double quotes */
-                        if (c == 0) {
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        } else if (c == quote)          /* found the end quote */
-                                quote = 0;
-                        else if (c == '\\')
-                                backslash = true;
-                        else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                } else if (separator) {
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        if (!strchr(separators, c))
-                                goto finish;
-
-                } else {
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES))
-                                quote = c;
-                        else if (c == '\\')
-                                backslash = true;
-                        else if (strchr(separators, c)) {
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                        (*p) ++;
-                                        goto finish_force_next;
-                                }
-                                separator = true;
-                        } else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-                }
-
-                (*p) ++;
-        }
-
-finish_force_terminate:
-        *p = NULL;
-finish:
-        if (!s) {
-                *p = NULL;
-                *ret = NULL;
-                return 0;
-        }
-
-finish_force_next:
-        s[sz] = 0;
-        *ret = s;
-        s = NULL;
-
-        return 1;
-}
-
-int extract_first_word_and_warn(
-                const char **p,
-                char **ret,
-                const char *separators,
-                ExtractFlags flags,
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *rvalue) {
-
-        /* Try to unquote it, if it fails, warn about it and try again but this
-         * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
-         * in invalid escape sequences. */
-        const char *save;
-        int r;
-
-        save = *p;
-        r = extract_first_word(p, ret, separators, flags);
-        if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
-
-                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
-                *p = save;
-                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
-                else
-                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
-        }
-
-        return r;
-}
-
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
-        va_list ap;
-        char **l;
-        int n = 0, i, c, r;
-
-        /* Parses a number of words from a string, stripping any
-         * quotes if necessary. */
-
-        assert(p);
-
-        /* Count how many words are expected */
-        va_start(ap, flags);
-        for (;;) {
-                if (!va_arg(ap, char **))
-                        break;
-                n++;
-        }
-        va_end(ap);
-
-        if (n <= 0)
-                return 0;
-
-        /* Read all words into a temporary array */
-        l = newa0(char*, n);
-        for (c = 0; c < n; c++) {
-
-                r = extract_first_word(p, &l[c], separators, flags);
-                if (r < 0) {
-                        int j;
-
-                        for (j = 0; j < c; j++)
-                                free(l[j]);
-
-                        return r;
-                }
-
-                if (r == 0)
-                        break;
-        }
-
-        /* If we managed to parse all words, return them in the passed
-         * in parameters */
-        va_start(ap, flags);
-        for (i = 0; i < n; i++) {
-                char **v;
-
-                v = va_arg(ap, char **);
-                assert(v);
-
-                *v = l[i];
-        }
-        va_end(ap);
-
-        return c;
-}
-
 int free_and_strdup(char **p, const char *s) {
         char *t;
 
index a3ebb987e41e352021a8692551ca9388730f12ee..132e6f862b1de96dc653b5c8fe4bba467868faee 100644 (file)
@@ -270,6 +270,7 @@ typedef enum 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);
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode);
 
 char *xescape(const char *s, const char *bad);
 
@@ -879,18 +880,6 @@ int is_symlink(const char *path);
 int is_dir(const char *path, bool follow);
 int is_device_node(const char *path);
 
-typedef enum ExtractFlags {
-        EXTRACT_RELAX           = 1,
-        EXTRACT_CUNESCAPE       = 2,
-        EXTRACT_CUNESCAPE_RELAX = 4,
-        EXTRACT_QUOTES          = 8,
-        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
-} ExtractFlags;
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
-int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
-
 int free_and_strdup(char **p, const char *s);
 
 #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
index 1d7dd49e042ce2148f8eec444efa7f84aa689e24..6987cf71207cac95e1301f2c54839edf06e6ae62 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <fnmatch.h>
 
 #include "sd-id128.h"
-#include "util.h"
-#include "virt.h"
-#include "path-util.h"
-#include "architecture.h"
-#include "smack-util.h"
+
 #include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
+#include "architecture.h"
 #include "audit.h"
 #include "cap-list.h"
+#include "extract-word.h"
 #include "hostname-util.h"
+#include "ima-util.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "util.h"
+#include "virt.h"
 #include "condition.h"
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {