]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/util.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / basic / util.c
index 40a4b8fbec3158b3a3a3ad3ee4e4ca4469cb2ae8..233a6c2e351da066a6eb5ba179f6d0a2cbf7cb17 100644 (file)
@@ -29,6 +29,7 @@
 #include <libintl.h>
 #include <limits.h>
 #include <linux/magic.h>
+#include <linux/oom.h>
 #include <linux/sched.h>
 #include <locale.h>
 #include <netinet/ip.h>
  * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
 #include <linux/fs.h>
 
+#include "build.h"
 #include "def.h"
 #include "device-nodes.h"
 #include "env-util.h"
+#include "escape.h"
 #include "exit-status.h"
 #include "fileio.h"
 #include "formats-util.h"
 #include "random-util.h"
 #include "signal-util.h"
 #include "sparse-endian.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "utf8.h"
-#include "util.h"
 #include "virt.h"
+#include "util.h"
 
 /* Put this test here for a lack of better place */
 assert_cc(EAGAIN == EWOULDBLOCK);
@@ -117,164 +121,6 @@ size_t page_size(void) {
         return pgsz;
 }
 
-int strcmp_ptr(const char *a, const char *b) {
-
-        /* Like strcmp(), but tries to make sense of NULL pointers */
-        if (a && b)
-                return strcmp(a, b);
-
-        if (!a && b)
-                return -1;
-
-        if (a && !b)
-                return 1;
-
-        return 0;
-}
-
-bool streq_ptr(const char *a, const char *b) {
-        return strcmp_ptr(a, b) == 0;
-}
-
-char* endswith(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
-
-        sl = strlen(s);
-        pl = strlen(postfix);
-
-        if (pl == 0)
-                return (char*) s + sl;
-
-        if (sl < pl)
-                return NULL;
-
-        if (memcmp(s + sl - pl, postfix, pl) != 0)
-                return NULL;
-
-        return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
-
-        sl = strlen(s);
-        pl = strlen(postfix);
-
-        if (pl == 0)
-                return (char*) s + sl;
-
-        if (sl < pl)
-                return NULL;
-
-        if (strcasecmp(s + sl - pl, postfix) != 0)
-                return NULL;
-
-        return (char*) s + sl - pl;
-}
-
-char* first_word(const char *s, const char *word) {
-        size_t sl, wl;
-        const char *p;
-
-        assert(s);
-        assert(word);
-
-        /* Checks if the string starts with the specified word, either
-         * followed by NUL or by whitespace. Returns a pointer to the
-         * NUL or the first character after the whitespace. */
-
-        sl = strlen(s);
-        wl = strlen(word);
-
-        if (sl < wl)
-                return NULL;
-
-        if (wl == 0)
-                return (char*) s;
-
-        if (memcmp(s, word, wl) != 0)
-                return NULL;
-
-        p = s + wl;
-        if (*p == 0)
-                return (char*) p;
-
-        if (!strchr(WHITESPACE, *p))
-                return NULL;
-
-        p += strspn(p, WHITESPACE);
-        return (char*) p;
-}
-
-size_t cescape_char(char c, char *buf) {
-        char * buf_old = buf;
-
-        switch (c) {
-
-                case '\a':
-                        *(buf++) = '\\';
-                        *(buf++) = 'a';
-                        break;
-                case '\b':
-                        *(buf++) = '\\';
-                        *(buf++) = 'b';
-                        break;
-                case '\f':
-                        *(buf++) = '\\';
-                        *(buf++) = 'f';
-                        break;
-                case '\n':
-                        *(buf++) = '\\';
-                        *(buf++) = 'n';
-                        break;
-                case '\r':
-                        *(buf++) = '\\';
-                        *(buf++) = 'r';
-                        break;
-                case '\t':
-                        *(buf++) = '\\';
-                        *(buf++) = 't';
-                        break;
-                case '\v':
-                        *(buf++) = '\\';
-                        *(buf++) = 'v';
-                        break;
-                case '\\':
-                        *(buf++) = '\\';
-                        *(buf++) = '\\';
-                        break;
-                case '"':
-                        *(buf++) = '\\';
-                        *(buf++) = '"';
-                        break;
-                case '\'':
-                        *(buf++) = '\\';
-                        *(buf++) = '\'';
-                        break;
-
-                default:
-                        /* For special chars we prefer octal over
-                         * hexadecimal encoding, simply because glib's
-                         * g_strescape() does the same */
-                        if ((c < ' ') || (c >= 127)) {
-                                *(buf++) = '\\';
-                                *(buf++) = octchar((unsigned char) c >> 6);
-                                *(buf++) = octchar((unsigned char) c >> 3);
-                                *(buf++) = octchar((unsigned char) c);
-                        } else
-                                *(buf++) = c;
-                        break;
-        }
-
-        return buf - buf_old;
-}
-
 int close_nointr(int fd) {
         assert(fd >= 0);
 
@@ -613,66 +459,6 @@ int safe_atod(const char *s, double *ret_d) {
         return 0;
 }
 
-static size_t strcspn_escaped(const char *s, const char *reject) {
-        bool escaped = false;
-        int n;
-
-        for (n=0; s[n]; n++) {
-                if (escaped)
-                        escaped = false;
-                else if (s[n] == '\\')
-                        escaped = true;
-                else if (strchr(reject, s[n]))
-                        break;
-        }
-
-        /* if s ends in \, return index of previous char */
-        return n - escaped;
-}
-
-/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
-        const char *current;
-
-        current = *state;
-
-        if (!*current) {
-                assert(**state == '\0');
-                return NULL;
-        }
-
-        current += strspn(current, separator);
-        if (!*current) {
-                *state = current;
-                return NULL;
-        }
-
-        if (quoted && strchr("\'\"", *current)) {
-                char quotechars[2] = {*current, '\0'};
-
-                *l = strcspn_escaped(current + 1, quotechars);
-                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
-                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
-                        /* right quote missing or garbage at the end */
-                        *state = current;
-                        return NULL;
-                }
-                *state = current++ + *l + 2;
-        } else if (quoted) {
-                *l = strcspn_escaped(current, separator);
-                if (current[*l] && !strchr(separator, current[*l])) {
-                        /* unfinished escape */
-                        *state = current;
-                        return NULL;
-                }
-                *state = current + *l;
-        } else {
-                *l = strcspn(current, separator);
-                *state = current + *l;
-        }
-
-        return current;
-}
 
 int fchmod_umask(int fd, mode_t m) {
         mode_t u;
@@ -685,48 +471,6 @@ int fchmod_umask(int fd, mode_t m) {
         return r;
 }
 
-char *truncate_nl(char *s) {
-        assert(s);
-
-        s[strcspn(s, NEWLINE)] = 0;
-        return s;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
-        size_t a;
-        char *r;
-
-        if (!s && !suffix)
-                return strdup("");
-
-        if (!s)
-                return strndup(suffix, b);
-
-        if (!suffix)
-                return strdup(s);
-
-        assert(s);
-        assert(suffix);
-
-        a = strlen(s);
-        if (b > ((size_t) -1) - a)
-                return NULL;
-
-        r = new(char, a+b+1);
-        if (!r)
-                return NULL;
-
-        memcpy(r, s, a);
-        memcpy(r+a, suffix, b);
-        r[a+b] = 0;
-
-        return r;
-}
-
-char *strappend(const char *s, const char *suffix) {
-        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
-}
-
 int readlinkat_malloc(int fd, const char *p, char **ret) {
         size_t l = 100;
         int r;
@@ -829,40 +573,6 @@ int readlink_and_canonicalize(const char *p, char **r) {
         return 0;
 }
 
-char *strstrip(char *s) {
-        char *e;
-
-        /* Drops trailing whitespace. Modifies the string in
-         * place. Returns pointer to first non-space character */
-
-        s += strspn(s, WHITESPACE);
-
-        for (e = strchr(s, 0); e > s; e --)
-                if (!strchr(WHITESPACE, e[-1]))
-                        break;
-
-        *e = 0;
-
-        return s;
-}
-
-char *delete_chars(char *s, const char *bad) {
-        char *f, *t;
-
-        /* Drops all whitespace, regardless where in the string */
-
-        for (f = s, t = s; *f; f++) {
-                if (strchr(bad, *f))
-                        continue;
-
-                *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return s;
-}
-
 char *file_in_same_dir(const char *path, const char *filename) {
         char *e, *ret;
         size_t k;
@@ -1564,350 +1274,6 @@ int undecchar(char c) {
         return -EINVAL;
 }
 
-char *cescape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert(s);
-
-        /* Does C style string escaping. May be reversed with
-         * cunescape(). */
-
-        r = new(char, strlen(s)*4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; *f; f++)
-                t += cescape_char(*f, t);
-
-        *t = 0;
-
-        return r;
-}
-
-static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
-        int r = 1;
-
-        assert(p);
-        assert(*p);
-        assert(ret);
-
-        /* Unescapes C style. Returns the unescaped character in ret,
-         * unless we encountered a \u sequence in which case the full
-         * unicode character is returned in ret_unicode, instead. */
-
-        if (length != (size_t) -1 && length < 1)
-                return -EINVAL;
-
-        switch (p[0]) {
-
-        case 'a':
-                *ret = '\a';
-                break;
-        case 'b':
-                *ret = '\b';
-                break;
-        case 'f':
-                *ret = '\f';
-                break;
-        case 'n':
-                *ret = '\n';
-                break;
-        case 'r':
-                *ret = '\r';
-                break;
-        case 't':
-                *ret = '\t';
-                break;
-        case 'v':
-                *ret = '\v';
-                break;
-        case '\\':
-                *ret = '\\';
-                break;
-        case '"':
-                *ret = '"';
-                break;
-        case '\'':
-                *ret = '\'';
-                break;
-
-        case 's':
-                /* This is an extension of the XDG syntax files */
-                *ret = ' ';
-                break;
-
-        case 'x': {
-                /* hexadecimal encoding */
-                int a, b;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unhexchar(p[1]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unhexchar(p[2]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* Don't allow NUL bytes */
-                if (a == 0 && b == 0)
-                        return -EINVAL;
-
-                *ret = (char) ((a << 4U) | b);
-                r = 3;
-                break;
-        }
-
-        case 'u': {
-                /* C++11 style 16bit unicode */
-
-                int a[4];
-                unsigned i;
-                uint32_t c;
-
-                if (length != (size_t) -1 && length < 5)
-                        return -EINVAL;
-
-                for (i = 0; i < 4; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
-
-                /* Don't allow 0 chars */
-                if (c == 0)
-                        return -EINVAL;
-
-                if (c < 128)
-                        *ret = c;
-                else {
-                        if (!ret_unicode)
-                                return -EINVAL;
-
-                        *ret = 0;
-                        *ret_unicode = c;
-                }
-
-                r = 5;
-                break;
-        }
-
-        case 'U': {
-                /* C++11 style 32bit unicode */
-
-                int a[8];
-                unsigned i;
-                uint32_t c;
-
-                if (length != (size_t) -1 && length < 9)
-                        return -EINVAL;
-
-                for (i = 0; i < 8; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
-                    ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] <<  8U) | ((uint32_t) a[6] <<  4U) |  (uint32_t) a[7];
-
-                /* Don't allow 0 chars */
-                if (c == 0)
-                        return -EINVAL;
-
-                /* Don't allow invalid code points */
-                if (!unichar_is_valid(c))
-                        return -EINVAL;
-
-                if (c < 128)
-                        *ret = c;
-                else {
-                        if (!ret_unicode)
-                                return -EINVAL;
-
-                        *ret = 0;
-                        *ret_unicode = c;
-                }
-
-                r = 9;
-                break;
-        }
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7': {
-                /* octal encoding */
-                int a, b, c;
-                uint32_t m;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unoctchar(p[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unoctchar(p[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unoctchar(p[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                /* don't allow NUL bytes */
-                if (a == 0 && b == 0 && c == 0)
-                        return -EINVAL;
-
-                /* Don't allow bytes above 255 */
-                m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
-                if (m > 255)
-                        return -EINVAL;
-
-                *ret = m;
-                r = 3;
-                break;
-        }
-
-        default:
-                return -EINVAL;
-        }
-
-        return r;
-}
-
-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. */
-
-        pl = prefix ? strlen(prefix) : 0;
-
-        r = new(char, pl+length+1);
-        if (!r)
-                return -ENOMEM;
-
-        if (prefix)
-                memcpy(r, prefix, pl);
-
-        for (f = s, t = r + pl; f < s + length; f++) {
-                size_t remaining;
-                uint32_t u;
-                char c;
-                int k;
-
-                remaining = s + length - f;
-                assert(remaining > 0);
-
-                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;
-                        }
-
-                        free(r);
-                        return -EINVAL;
-                }
-
-                k = cunescape_one(f + 1, remaining - 1, &c, &u);
-                if (k < 0) {
-                        if (flags & UNESCAPE_RELAX) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                continue;
-                        }
-
-                        free(r);
-                        return k;
-                }
-
-                if (c != 0)
-                        /* Non-Unicode? Let's encode this directly */
-                        *(t++) = c;
-                else
-                        /* Unicode? Then let's encode this in UTF-8 */
-                        t += utf8_encode_unichar(t, u);
-
-                f += k;
-        }
-
-        *t = 0;
-
-        *ret = r;
-        return t - r;
-}
-
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
-        return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-
-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) {
-        char *r, *t;
-        const char *f;
-
-        /* Escapes all chars in bad, in addition to \ and all special
-         * chars, in \xFF style escaping. May be reversed with
-         * cunescape(). */
-
-        r = new(char, strlen(s) * 4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; *f; f++) {
-
-                if ((*f < ' ') || (*f >= 127) ||
-                    (*f == '\\') || strchr(bad, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-char *ascii_strlower(char *t) {
-        char *p;
-
-        assert(t);
-
-        for (p = t; *p; p++)
-                if (*p >= 'A' && *p <= 'Z')
-                        *p = *p - 'A' + 'a';
-
-        return t;
-}
-
 _pure_ static bool hidden_file_allow_backup(const char *filename) {
         assert(filename);
 
@@ -2055,17 +1421,6 @@ int close_all_fds(const int except[], unsigned n_except) {
         return r;
 }
 
-bool chars_intersect(const char *a, const char *b) {
-        const char *p;
-
-        /* Returns true if any of the chars in a are in b. */
-        for (p = a; *p; p++)
-                if (strchr(b, *p))
-                        return true;
-
-        return false;
-}
-
 bool fstype_is_network(const char *fstype) {
         static const char table[] =
                 "afs\0"
@@ -2379,25 +1734,16 @@ bool is_device_path(const char *path) {
 
 int dir_is_empty(const char *path) {
         _cleanup_closedir_ DIR *d;
+        struct dirent *de;
 
         d = opendir(path);
         if (!d)
                 return -errno;
 
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-
-                if (!de)
-                        return 1;
+        FOREACH_DIRENT(de, d, return -errno)
+                return 0;
 
-                if (!hidden_file(de->d_name))
-                        return 0;
-        }
+        return 1;
 }
 
 char* dirname_malloc(const char *path) {
@@ -2488,21 +1834,45 @@ char* getlogname_malloc(void) {
         return lookup_uid(uid);
 }
 
-char *getusername_malloc(void) {
-        const char *e;
+char *getusername_malloc(void) {
+        const char *e;
+
+        e = getenv("USER");
+        if (e)
+                return strdup(e);
+
+        return lookup_uid(getuid());
+}
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
+        assert(s);
+        assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
+
+        return F_TYPE_EQUAL(s->f_type, magic_value);
+}
+
+int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+        struct statfs s;
+
+        if (fstatfs(fd, &s) < 0)
+                return -errno;
+
+        return is_fs_type(&s, magic_value);
+}
+
+int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+        _cleanup_close_ int fd = -1;
 
-        e = getenv("USER");
-        if (e)
-                return strdup(e);
+        fd = open(path, O_RDONLY);
+        if (fd < 0)
+                return -errno;
 
-        return lookup_uid(getuid());
+        return fd_check_fstype(fd, magic_value);
 }
 
 bool is_temporary_fs(const struct statfs *s) {
-        assert(s);
-
-        return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
-               F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
+    return is_fs_type(s, TMPFS_MAGIC) ||
+           is_fs_type(s, RAMFS_MAGIC);
 }
 
 int fd_is_temporary_fs(int fd) {
@@ -2550,34 +1920,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
         return 0;
 }
 
-cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
-        cpu_set_t *r;
-        unsigned n = 1024;
-
-        /* Allocates the cpuset in the right size */
-
-        for (;;) {
-                if (!(r = CPU_ALLOC(n)))
-                        return NULL;
-
-                if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
-                        CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
-
-                        if (ncpus)
-                                *ncpus = n;
-
-                        return r;
-                }
-
-                CPU_FREE(r);
-
-                if (errno != EINVAL)
-                        return NULL;
-
-                n *= 2;
-        }
-}
-
 int files_same(const char *filea, const char *fileb) {
         struct stat a, b;
 
@@ -2601,115 +1943,6 @@ int running_in_chroot(void) {
         return ret == 0;
 }
 
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x;
-        char *r;
-
-        assert(s);
-        assert(percent <= 100);
-        assert(new_length >= 3);
-
-        if (old_length <= 3 || old_length <= new_length)
-                return strndup(s, old_length);
-
-        r = new0(char, new_length+1);
-        if (!r)
-                return NULL;
-
-        x = (new_length * percent) / 100;
-
-        if (x > new_length - 3)
-                x = new_length - 3;
-
-        memcpy(r, s, x);
-        r[x] = '.';
-        r[x+1] = '.';
-        r[x+2] = '.';
-        memcpy(r + x + 3,
-               s + old_length - (new_length - x - 3),
-               new_length - x - 3);
-
-        return r;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x;
-        char *e;
-        const char *i, *j;
-        unsigned k, len, len2;
-
-        assert(s);
-        assert(percent <= 100);
-        assert(new_length >= 3);
-
-        /* if no multibyte characters use ascii_ellipsize_mem for speed */
-        if (ascii_is_valid(s))
-                return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
-        if (old_length <= 3 || old_length <= new_length)
-                return strndup(s, old_length);
-
-        x = (new_length * percent) / 100;
-
-        if (x > new_length - 3)
-                x = new_length - 3;
-
-        k = 0;
-        for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
-                int c;
-
-                c = utf8_encoded_to_unichar(i);
-                if (c < 0)
-                        return NULL;
-                k += unichar_iswide(c) ? 2 : 1;
-        }
-
-        if (k > x) /* last character was wide and went over quota */
-                x ++;
-
-        for (j = s + old_length; k < new_length && j > i; ) {
-                int c;
-
-                j = utf8_prev_char(j);
-                c = utf8_encoded_to_unichar(j);
-                if (c < 0)
-                        return NULL;
-                k += unichar_iswide(c) ? 2 : 1;
-        }
-        assert(i <= j);
-
-        /* we don't actually need to ellipsize */
-        if (i == j)
-                return memdup(s, old_length + 1);
-
-        /* make space for ellipsis */
-        j = utf8_next_char(j);
-
-        len = i - s;
-        len2 = s + old_length - j;
-        e = new(char, len + 3 + len2 + 1);
-        if (!e)
-                return NULL;
-
-        /*
-        printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
-               old_length, new_length, x, len, len2, k);
-        */
-
-        memcpy(e, s, len);
-        e[len]   = 0xe2; /* tri-dot ellipsis: â€¦ */
-        e[len + 1] = 0x80;
-        e[len + 2] = 0xa6;
-
-        memcpy(e + len + 3, j, len2 + 1);
-
-        return e;
-}
-
-char *ellipsize(const char *s, size_t length, unsigned percent) {
-        return ellipsize_mem(s, strlen(s), length, percent);
-}
-
 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
         _cleanup_close_ int fd;
         int r;
@@ -3042,32 +2275,10 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
         wait_for_terminate_and_warn(name, executor_pid, true);
 }
 
-bool nulstr_contains(const char*nulstr, const char *needle) {
-        const char *i;
-
-        if (!nulstr)
-                return false;
-
-        NULSTR_FOREACH(i, nulstr)
-                if (streq(i, needle))
-                        return true;
-
-        return false;
-}
-
 bool plymouth_running(void) {
         return access("/run/plymouth/pid", F_OK) >= 0;
 }
 
-char* strshorten(char *s, size_t l) {
-        assert(s);
-
-        if (l < strlen(s))
-                s[l] = 0;
-
-        return s;
-}
-
 int pipe_eof(int fd) {
         struct pollfd pollfd = {
                 .fd = fd,
@@ -3555,63 +2766,6 @@ int get_files_in_directory(const char *path, char ***list) {
         return n;
 }
 
-char *strjoin(const char *x, ...) {
-        va_list ap;
-        size_t l;
-        char *r, *p;
-
-        va_start(ap, x);
-
-        if (x) {
-                l = strlen(x);
-
-                for (;;) {
-                        const char *t;
-                        size_t n;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        n = strlen(t);
-                        if (n > ((size_t) -1) - l) {
-                                va_end(ap);
-                                return NULL;
-                        }
-
-                        l += n;
-                }
-        } else
-                l = 0;
-
-        va_end(ap);
-
-        r = new(char, l+1);
-        if (!r)
-                return NULL;
-
-        if (x) {
-                p = stpcpy(r, x);
-
-                va_start(ap, x);
-
-                for (;;) {
-                        const char *t;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        p = stpcpy(p, t);
-                }
-
-                va_end(ap);
-        } else
-                r[0] = 0;
-
-        return r;
-}
-
 bool is_main_thread(void) {
         static thread_local int cached = 0;
 
@@ -3726,6 +2880,10 @@ static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
 
+bool log_facility_unshifted_is_valid(int facility) {
+        return facility >= 0 && facility <= LOG_FAC(~0);
+}
+
 static const char *const log_level_table[] = {
         [LOG_EMERG] = "emerg",
         [LOG_ALERT] = "alert",
@@ -3739,6 +2897,10 @@ static const char *const log_level_table[] = {
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
 
+bool log_level_is_valid(int level) {
+        return level >= 0 && level <= LOG_DEBUG;
+}
+
 static const char* const sched_policy_table[] = {
         [SCHED_OTHER] = "other",
         [SCHED_BATCH] = "batch",
@@ -4229,29 +3391,6 @@ bool string_is_safe(const char *p) {
         return true;
 }
 
-/**
- * Check if a string contains control characters. If 'ok' is non-NULL
- * it may be a string containing additional CCs to be considered OK.
- */
-bool string_has_cc(const char *p, const char *ok) {
-        const char *t;
-
-        assert(p);
-
-        for (t = p; *t; t++) {
-                if (ok && strchr(ok, *t))
-                        continue;
-
-                if (*t > 0 && *t < ' ')
-                        return true;
-
-                if (*t == 127)
-                        return true;
-        }
-
-        return false;
-}
-
 bool path_is_safe(const char *p) {
 
         if (isempty(p))
@@ -4373,139 +3512,6 @@ const char *draw_special_char(DrawSpecialChar ch) {
         return draw_table[!is_locale_utf8()][ch];
 }
 
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
-        const char *f;
-        char *t, *r;
-        size_t l, old_len, new_len;
-
-        assert(text);
-        assert(old_string);
-        assert(new_string);
-
-        old_len = strlen(old_string);
-        new_len = strlen(new_string);
-
-        l = strlen(text);
-        r = new(char, l+1);
-        if (!r)
-                return NULL;
-
-        f = text;
-        t = r;
-        while (*f) {
-                char *a;
-                size_t d, nl;
-
-                if (!startswith(f, old_string)) {
-                        *(t++) = *(f++);
-                        continue;
-                }
-
-                d = t - r;
-                nl = l - old_len + new_len;
-                a = realloc(r, nl + 1);
-                if (!a)
-                        goto oom;
-
-                l = nl;
-                r = a;
-                t = r + d;
-
-                t = stpcpy(t, new_string);
-                f += old_len;
-        }
-
-        *t = 0;
-        return r;
-
-oom:
-        free(r);
-        return NULL;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
-        const char *i, *begin = NULL;
-        enum {
-                STATE_OTHER,
-                STATE_ESCAPE,
-                STATE_BRACKET
-        } state = STATE_OTHER;
-        char *obuf = NULL;
-        size_t osz = 0, isz;
-        FILE *f;
-
-        assert(ibuf);
-        assert(*ibuf);
-
-        /* Strips ANSI color and replaces TABs by 8 spaces */
-
-        isz = _isz ? *_isz : strlen(*ibuf);
-
-        f = open_memstream(&obuf, &osz);
-        if (!f)
-                return NULL;
-
-        for (i = *ibuf; i < *ibuf + isz + 1; i++) {
-
-                switch (state) {
-
-                case STATE_OTHER:
-                        if (i >= *ibuf + isz) /* EOT */
-                                break;
-                        else if (*i == '\x1B')
-                                state = STATE_ESCAPE;
-                        else if (*i == '\t')
-                                fputs("        ", f);
-                        else
-                                fputc(*i, f);
-                        break;
-
-                case STATE_ESCAPE:
-                        if (i >= *ibuf + isz) { /* EOT */
-                                fputc('\x1B', f);
-                                break;
-                        } else if (*i == '[') {
-                                state = STATE_BRACKET;
-                                begin = i + 1;
-                        } else {
-                                fputc('\x1B', f);
-                                fputc(*i, f);
-                                state = STATE_OTHER;
-                        }
-
-                        break;
-
-                case STATE_BRACKET:
-
-                        if (i >= *ibuf + isz || /* EOT */
-                            (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
-                                fputc('\x1B', f);
-                                fputc('[', f);
-                                state = STATE_OTHER;
-                                i = begin-1;
-                        } else if (*i == 'm')
-                                state = STATE_OTHER;
-                        break;
-                }
-        }
-
-        if (ferror(f)) {
-                fclose(f);
-                free(obuf);
-                return NULL;
-        }
-
-        fclose(f);
-
-        free(*ibuf);
-        *ibuf = obuf;
-
-        if (_isz)
-                *_isz = osz;
-
-        return obuf;
-}
-
 int on_ac_power(void) {
         bool found_offline = false, found_online = false;
         _cleanup_closedir_ DIR *d = NULL;
@@ -4664,77 +3670,6 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
         return search_and_fopen_internal(path, mode, root, s, _f);
 }
 
-char *strextend(char **x, ...) {
-        va_list ap;
-        size_t f, l;
-        char *r, *p;
-
-        assert(x);
-
-        l = f = *x ? strlen(*x) : 0;
-
-        va_start(ap, x);
-        for (;;) {
-                const char *t;
-                size_t n;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                n = strlen(t);
-                if (n > ((size_t) -1) - l) {
-                        va_end(ap);
-                        return NULL;
-                }
-
-                l += n;
-        }
-        va_end(ap);
-
-        r = realloc(*x, l+1);
-        if (!r)
-                return NULL;
-
-        p = r + f;
-
-        va_start(ap, x);
-        for (;;) {
-                const char *t;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                p = stpcpy(p, t);
-        }
-        va_end(ap);
-
-        *p = 0;
-        *x = r;
-
-        return r + l;
-}
-
-char *strrep(const char *s, unsigned n) {
-        size_t l;
-        char *r, *p;
-        unsigned i;
-
-        assert(s);
-
-        l = strlen(s);
-        p = r = malloc(l * n + 1);
-        if (!r)
-                return NULL;
-
-        for (i = 0; i < n; i++)
-                p = stpcpy(p, s);
-
-        *p = 0;
-        return r;
-}
-
 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
         size_t a, newalloc;
         void *q;
@@ -4804,52 +3739,21 @@ bool id128_is_valid(const char *s) {
                 for (i = 0; i < l; i++) {
                         char c = s[i];
 
-                        if ((i == 8 || i == 13 || i == 18 || i == 23)) {
-                                if (c != '-')
-                                        return false;
-                        } else {
-                                if (!(c >= '0' && c <= '9') &&
-                                    !(c >= 'a' && c <= 'z') &&
-                                    !(c >= 'A' && c <= 'Z'))
-                                        return false;
-                        }
-                }
-
-        } else
-                return false;
-
-        return true;
-}
-
-int split_pair(const char *s, const char *sep, char **l, char **r) {
-        char *x, *a, *b;
-
-        assert(s);
-        assert(sep);
-        assert(l);
-        assert(r);
-
-        if (isempty(sep))
-                return -EINVAL;
-
-        x = strstr(s, sep);
-        if (!x)
-                return -EINVAL;
-
-        a = strndup(s, x - s);
-        if (!a)
-                return -ENOMEM;
-
-        b = strdup(x + strlen(sep));
-        if (!b) {
-                free(a);
-                return -ENOMEM;
-        }
-
-        *l = a;
-        *r = b;
+                        if ((i == 8 || i == 13 || i == 18 || i == 23)) {
+                                if (c != '-')
+                                        return false;
+                        } else {
+                                if (!(c >= '0' && c <= '9') &&
+                                    !(c >= 'a' && c <= 'z') &&
+                                    !(c >= 'A' && c <= 'Z'))
+                                        return false;
+                        }
+                }
 
-        return 0;
+        } else
+                return false;
+
+        return true;
 }
 
 int shall_restore_state(void) {
@@ -5371,15 +4275,13 @@ int update_reboot_param_file(const char *param) {
         int r = 0;
 
         if (param) {
-
                 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
                 if (r < 0)
-                        log_error("Failed to write reboot param to "
-                                  REBOOT_PARAM_FILE": %s", strerror(-r));
+                        return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
         } else
-                unlink(REBOOT_PARAM_FILE);
+                (void) unlink(REBOOT_PARAM_FILE);
 
-        return r;
+        return 0;
 }
 
 int umount_recursive(const char *prefix, int flags) {
@@ -5806,442 +4708,20 @@ 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;
-
-        enum {
-                START,
-                VALUE,
-                VALUE_ESCAPE,
-                SINGLE_QUOTE,
-                SINGLE_QUOTE_ESCAPE,
-                DOUBLE_QUOTE,
-                DOUBLE_QUOTE_ESCAPE,
-                SEPARATOR,
-        } state = START;
-
-        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;
-
-                switch (state) {
-
-                case 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)) {
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                        (*p) ++;
-                                        goto finish_force_next;
-                                }
-                                break;
-                        }
-
-                        /* 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;
-
-                        state = VALUE;
-                        /* fallthrough */
-
-                case VALUE:
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        else if (c == '\'' && (flags & EXTRACT_QUOTES))
-                                state = SINGLE_QUOTE;
-                        else if (c == '\\')
-                                state = VALUE_ESCAPE;
-                        else if (c == '\"' && (flags & EXTRACT_QUOTES))
-                                state = DOUBLE_QUOTE;
-                        else if (strchr(separators, c)) {
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                        (*p) ++;
-                                        goto finish_force_next;
-                                }
-                                state = SEPARATOR;
-                        } else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case SINGLE_QUOTE:
-                        if (c == 0) {
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        } else if (c == '\'')
-                                state = VALUE;
-                        else if (c == '\\')
-                                state = SINGLE_QUOTE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case DOUBLE_QUOTE:
-                        if (c == 0)
-                                return -EINVAL;
-                        else if (c == '\"')
-                                state = VALUE;
-                        else if (c == '\\')
-                                state = DOUBLE_QUOTE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case SINGLE_QUOTE_ESCAPE:
-                case DOUBLE_QUOTE_ESCAPE:
-                case VALUE_ESCAPE:
-                        if (!GREEDY_REALLOC(s, allocated, sz+7))
-                                return -ENOMEM;
-
-                        if (c == 0) {
-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
-                                    (state == VALUE_ESCAPE || 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:
-                        state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
-                                (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
-                                VALUE;
-                        break;
-
-                case SEPARATOR:
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        if (!strchr(separators, c))
-                                goto finish;
-                        break;
-                }
-
-                (*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, EINVAL,
-                                   "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
-                else
-                        log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
-                                   "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;
-
-        assert(p);
-
-        /* Replaces a string pointer with an strdup()ed new string,
-         * possibly freeing the old one. */
-
-        if (streq_ptr(*p, s))
-                return 0;
-
-        if (s) {
-                t = strdup(s);
-                if (!t)
-                        return -ENOMEM;
-        } else
-                t = NULL;
-
-        free(*p);
-        *p = t;
-
-        return 1;
-}
-
-int ptsname_malloc(int fd, char **ret) {
-        size_t l = 100;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        for (;;) {
-                char *c;
-
-                c = new(char, l);
-                if (!c)
-                        return -ENOMEM;
-
-                if (ptsname_r(fd, c, l) == 0) {
-                        *ret = c;
-                        return 0;
-                }
-                if (errno != ERANGE) {
-                        free(c);
-                        return -errno;
-                }
-
-                free(c);
-                l *= 2;
-        }
-}
-
-int openpt_in_namespace(pid_t pid, int flags) {
-        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
-        _cleanup_close_pair_ int pair[2] = { -1, -1 };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
-        struct msghdr mh = {
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-        struct cmsghdr *cmsg;
-        siginfo_t si;
-        pid_t child;
-        int r;
-
-        assert(pid > 0);
-
-        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
-        if (r < 0)
-                return r;
-
-        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
-                return -errno;
-
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
-                int master;
-
-                pair[0] = safe_close(pair[0]);
-
-                r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
-                if (r < 0)
-                        _exit(EXIT_FAILURE);
-
-                master = posix_openpt(flags);
-                if (master < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (unlockpt(master) < 0)
-                        _exit(EXIT_FAILURE);
-
-                cmsg = CMSG_FIRSTHDR(&mh);
-                cmsg->cmsg_level = SOL_SOCKET;
-                cmsg->cmsg_type = SCM_RIGHTS;
-                cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-                memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
-
-                mh.msg_controllen = cmsg->cmsg_len;
-
-                if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
-                        _exit(EXIT_FAILURE);
-
-                _exit(EXIT_SUCCESS);
-        }
-
-        pair[1] = safe_close(pair[1]);
-
-        r = wait_for_terminate(child, &si);
-        if (r < 0)
-                return r;
-        if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
-                return -EIO;
-
-        if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
-                return -errno;
-
-        CMSG_FOREACH(cmsg, &mh)
-                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
-                        int *fds;
-                        unsigned n_fds;
-
-                        fds = (int*) CMSG_DATA(cmsg);
-                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
-                        if (n_fds != 1) {
-                                close_many(fds, n_fds);
-                                return -EIO;
-                        }
-
-                        return fds[0];
-                }
-
-        return -EIO;
-}
-
 ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+        char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
         _cleanup_close_ int fd = -1;
         ssize_t l;
 
         /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
 
-        fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+        fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
         if (fd < 0)
                 return -errno;
 
-        l = fgetxattr(fd, attribute, value, size);
+        xsprintf(fn, "/proc/self/fd/%i", fd);
+
+        l = getxattr(fn, attribute, value, size);
         if (l < 0)
                 return -errno;
 
@@ -6645,66 +5125,6 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
         return 0;
 }
 
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
-        assert(bad);
-
-        for (; *s; s++) {
-                if (*s == '\\' || strchr(bad, *s))
-                        *(t++) = '\\';
-
-                *(t++) = *s;
-        }
-
-        return t;
-}
-
-char *shell_escape(const char *s, const char *bad) {
-        char *r, *t;
-
-        r = new(char, strlen(s)*2+1);
-        if (!r)
-                return NULL;
-
-        t = strcpy_backslash_escaped(r, s, bad);
-        *t = 0;
-
-        return r;
-}
-
-char *shell_maybe_quote(const char *s) {
-        const char *p;
-        char *r, *t;
-
-        assert(s);
-
-        /* Encloses a string in double quotes if necessary to make it
-         * OK as shell string. */
-
-        for (p = s; *p; p++)
-                if (*p <= ' ' ||
-                    *p >= 127 ||
-                    strchr(SHELL_NEED_QUOTES, *p))
-                        break;
-
-        if (!*p)
-                return strdup(s);
-
-        r = new(char, 1+strlen(s)*2+1+1);
-        if (!r)
-                return NULL;
-
-        t = r;
-        *(t++) = '"';
-        t = mempcpy(t, s, p - s);
-
-        t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
-
-        *(t++)= '"';
-        *t = 0;
-
-        return r;
-}
-
 int parse_mode(const char *s, mode_t *ret) {
         char *x;
         long l;
@@ -6828,7 +5248,7 @@ int fgetxattr_malloc(int fd, const char *name, char **value) {
         }
 }
 
-int send_one_fd(int transport_fd, int fd) {
+int send_one_fd(int transport_fd, int fd, int flags) {
         union {
                 struct cmsghdr cmsghdr;
                 uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -6838,7 +5258,6 @@ int send_one_fd(int transport_fd, int fd) {
                 .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
-        ssize_t k;
 
         assert(transport_fd >= 0);
         assert(fd >= 0);
@@ -6850,14 +5269,13 @@ int send_one_fd(int transport_fd, int fd) {
         memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
 
         mh.msg_controllen = CMSG_SPACE(sizeof(int));
-        k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL);
-        if (k < 0)
+        if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
                 return -errno;
 
         return 0;
 }
 
-int receive_one_fd(int transport_fd) {
+int receive_one_fd(int transport_fd, int flags) {
         union {
                 struct cmsghdr cmsghdr;
                 uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -6866,33 +5284,76 @@ int receive_one_fd(int transport_fd) {
                 .msg_control = &control,
                 .msg_controllen = sizeof(control),
         };
-        struct cmsghdr *cmsg;
-        ssize_t k;
+        struct cmsghdr *cmsg, *found = NULL;
 
         assert(transport_fd >= 0);
 
         /*
-         * Receive a single FD via @transport_fd. We don't care for the
-         * transport-type, but the caller must assure that no other CMSG types
-         * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so
-         * for packet-based transports, the caller must ensure to send only a
-         * single FD per packet.
-         * This is best used in combination with send_one_fd().
+         * Receive a single FD via @transport_fd. We don't care for
+         * the transport-type. We retrieve a single FD at most, so for
+         * packet-based transports, the caller must ensure to send
+         * only a single FD per packet.  This is best used in
+         * combination with send_one_fd().
          */
 
-        k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC);
-        if (k < 0)
+        if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
                 return -errno;
 
-        cmsg = CMSG_FIRSTHDR(&mh);
-        if (!cmsg || CMSG_NXTHDR(&mh, cmsg) ||
-            cmsg->cmsg_level != SOL_SOCKET ||
-            cmsg->cmsg_type != SCM_RIGHTS ||
-            cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
-            *(const int *)CMSG_DATA(cmsg) < 0) {
+        CMSG_FOREACH(cmsg, &mh) {
+                if (cmsg->cmsg_level == SOL_SOCKET &&
+                    cmsg->cmsg_type == SCM_RIGHTS &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+                        assert(!found);
+                        found = cmsg;
+                        break;
+                }
+        }
+
+        if (!found) {
                 cmsg_close_all(&mh);
                 return -EIO;
         }
 
-        return *(const int *)CMSG_DATA(cmsg);
+        return *(int*) CMSG_DATA(found);
+}
+
+void nop_signal_handler(int sig) {
+        /* nothing here */
+}
+
+int version(void) {
+        puts(PACKAGE_STRING "\n"
+             SYSTEMD_FEATURES);
+        return 0;
+}
+
+bool fdname_is_valid(const char *s) {
+        const char *p;
+
+        /* Validates a name for $LISTEN_FDNAMES. We basically allow
+         * everything ASCII that's not a control character. Also, as
+         * special exception the ":" character is not allowed, as we
+         * use that as field separator in $LISTEN_FDNAMES.
+         *
+         * Note that the empty string is explicitly allowed
+         * here. However, we limit the length of the names to 255
+         * characters. */
+
+        if (!s)
+                return false;
+
+        for (p = s; *p; p++) {
+                if (*p < ' ')
+                        return false;
+                if (*p >= 127)
+                        return false;
+                if (*p == ':')
+                        return false;
+        }
+
+        return p - s < 256;
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+        return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
 }