chiark / gitweb /
Simplify the meaning of %s
[elogind.git] / src / shared / util.c
index 490399c910876d5cfb0188ca22717ee90f06d5e8..0444cf44561360d20f0589e17283c5517fc77ee2 100644 (file)
@@ -70,6 +70,8 @@
 #include "path-util.h"
 #include "exit-status.h"
 #include "hashmap.h"
+#include "env-util.h"
+#include "fileio.h"
 
 int saved_argc = 0;
 char **saved_argv = NULL;
@@ -182,18 +184,25 @@ bool first_word(const char *s, const char *word) {
 }
 
 int close_nointr(int fd) {
-        assert(fd >= 0);
-
-        for (;;) {
-                int r;
+        int r;
 
-                r = close(fd);
-                if (r >= 0)
-                        return r;
+        assert(fd >= 0);
+        r = close(fd);
 
-                if (errno != EINTR)
-                        return -errno;
-        }
+        /* Just ignore EINTR; a retry loop is the wrong
+         * thing to do on Linux.
+         *
+         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+         */
+        if (_unlikely_(r < 0 && errno == EINTR))
+                return 0;
+        else if (r >= 0)
+                return r;
+        else
+                return -errno;
 }
 
 void close_nointr_nofail(int fd) {
@@ -210,6 +219,8 @@ void close_nointr_nofail(int fd) {
 void close_many(const int fds[], unsigned n_fd) {
         unsigned i;
 
+        assert(fds || n_fd <= 0);
+
         for (i = 0; i < n_fd; i++)
                 close_nointr_nofail(fds[i]);
 }
@@ -217,9 +228,9 @@ void close_many(const int fds[], unsigned n_fd) {
 int parse_boolean(const char *v) {
         assert(v);
 
-        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
+        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
                 return 1;
-        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
+        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
                 return 0;
 
         return -EINVAL;
@@ -281,7 +292,7 @@ int safe_atou(const char *s, unsigned *ret_u) {
         l = strtoul(s, &x, 0);
 
         if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+                return errno > 0 ? -errno : -EINVAL;
 
         if ((unsigned long) (unsigned) l != l)
                 return -ERANGE;
@@ -301,7 +312,7 @@ int safe_atoi(const char *s, int *ret_i) {
         l = strtol(s, &x, 0);
 
         if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+                return errno > 0 ? -errno : -EINVAL;
 
         if ((long) (int) l != l)
                 return -ERANGE;
@@ -344,6 +355,23 @@ int safe_atolli(const char *s, long long int *ret_lli) {
         return 0;
 }
 
+int safe_atod(const char *s, double *ret_d) {
+        char *x = NULL;
+        double d;
+
+        assert(s);
+        assert(ret_d);
+
+        errno = 0;
+        d = strtod(s, &x);
+
+        if (!x || x == s || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_d = (double) d;
+        return 0;
+}
+
 /* Split a string into words. */
 char *split(const char *c, size_t *l, const char *separator, char **state) {
         char *current;
@@ -520,31 +548,6 @@ int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
         return 0;
 }
 
-int write_one_line_file(const char *fn, const char *line) {
-        _cleanup_fclose_ FILE *f = NULL;
-
-        assert(fn);
-        assert(line);
-
-        f = fopen(fn, "we");
-        if (!f)
-                return -errno;
-
-        errno = 0;
-        if (fputs(line, f) < 0)
-                return errno ? -errno : -EIO;
-
-        if (!endswith(line, "\n"))
-                fputc('\n', f);
-
-        fflush(f);
-
-        if (ferror(f))
-                return errno ? -errno : -EIO;
-
-        return 0;
-}
-
 int fchmod_umask(int fd, mode_t m) {
         mode_t u;
         int r;
@@ -556,334 +559,6 @@ int fchmod_umask(int fd, mode_t m) {
         return r;
 }
 
-int write_one_line_file_atomic(const char *fn, const char *line) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(fn);
-        assert(line);
-
-        r = fopen_temporary(fn, &f, &p);
-        if (r < 0)
-                return r;
-
-        fchmod_umask(fileno(f), 0644);
-
-        errno = 0;
-        if (fputs(line, f) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (!endswith(line, "\n"))
-                fputc('\n', f);
-
-        fflush(f);
-
-        if (ferror(f))
-                r = errno ? -errno : -EIO;
-        else {
-                if (rename(p, fn) < 0)
-                        r = -errno;
-                else
-                        r = 0;
-        }
-
-finish:
-        if (r < 0)
-                unlink(p);
-
-        return r;
-}
-
-int read_one_line_file(const char *fn, char **line) {
-        _cleanup_fclose_ FILE *f = NULL;
-        char t[LINE_MAX], *c;
-
-        assert(fn);
-        assert(line);
-
-        f = fopen(fn, "re");
-        if (!f)
-                return -errno;
-
-        if (!fgets(t, sizeof(t), f)) {
-
-                if (ferror(f))
-                        return errno ? -errno : -EIO;
-
-                t[0] = 0;
-        }
-
-        c = strdup(t);
-        if (!c)
-                return -ENOMEM;
-        truncate_nl(c);
-
-        *line = c;
-        return 0;
-}
-
-int read_full_file(const char *fn, char **contents, size_t *size) {
-        _cleanup_fclose_ FILE *f = NULL;
-        size_t n, l;
-        _cleanup_free_ char *buf = NULL;
-        struct stat st;
-
-        assert(fn);
-        assert(contents);
-
-        f = fopen(fn, "re");
-        if (!f)
-                return -errno;
-
-        if (fstat(fileno(f), &st) < 0)
-                return -errno;
-
-        /* Safety check */
-        if (st.st_size > 4*1024*1024)
-                return -E2BIG;
-
-        n = st.st_size > 0 ? st.st_size : LINE_MAX;
-        l = 0;
-
-        for (;;) {
-                char *t;
-                size_t k;
-
-                t = realloc(buf, n+1);
-                if (!t)
-                        return -ENOMEM;
-
-                buf = t;
-                k = fread(buf + l, 1, n - l, f);
-
-                if (k <= 0) {
-                        if (ferror(f))
-                                return -errno;
-
-                        break;
-                }
-
-                l += k;
-                n *= 2;
-
-                /* Safety check */
-                if (n > 4*1024*1024)
-                        return -E2BIG;
-        }
-
-        buf[l] = 0;
-        *contents = buf;
-        buf = NULL;
-
-        if (size)
-                *size = l;
-
-        return 0;
-}
-
-int parse_env_file(
-                const char *fname,
-                const char *separator, ...) {
-
-        int r = 0;
-        char *contents = NULL, *p;
-
-        assert(fname);
-        assert(separator);
-
-        if ((r = read_full_file(fname, &contents, NULL)) < 0)
-                return r;
-
-        p = contents;
-        for (;;) {
-                const char *key = NULL;
-
-                p += strspn(p, separator);
-                p += strspn(p, WHITESPACE);
-
-                if (!*p)
-                        break;
-
-                if (!strchr(COMMENTS, *p)) {
-                        va_list ap;
-                        char **value;
-
-                        va_start(ap, separator);
-                        while ((key = va_arg(ap, char *))) {
-                                size_t n;
-                                char *v;
-
-                                value = va_arg(ap, char **);
-
-                                n = strlen(key);
-                                if (strncmp(p, key, n) != 0 ||
-                                    p[n] != '=')
-                                        continue;
-
-                                p += n + 1;
-                                n = strcspn(p, separator);
-
-                                if (n >= 2 &&
-                                    strchr(QUOTES, p[0]) &&
-                                    p[n-1] == p[0])
-                                        v = strndup(p+1, n-2);
-                                else
-                                        v = strndup(p, n);
-
-                                if (!v) {
-                                        r = -ENOMEM;
-                                        va_end(ap);
-                                        goto fail;
-                                }
-
-                                if (v[0] == '\0') {
-                                        /* return empty value strings as NULL */
-                                        free(v);
-                                        v = NULL;
-                                }
-
-                                free(*value);
-                                *value = v;
-
-                                p += n;
-
-                                r ++;
-                                break;
-                        }
-                        va_end(ap);
-                }
-
-                if (!key)
-                        p += strcspn(p, separator);
-        }
-
-fail:
-        free(contents);
-        return r;
-}
-
-int load_env_file(const char *fname,
-                  char ***rl) {
-
-        FILE _cleanup_fclose_ *f;
-        char *b;
-        char _cleanup_free_ *c = NULL;
-        char _cleanup_strv_free_ **m = NULL;
-
-        assert(fname);
-        assert(rl);
-
-        f = fopen(fname, "re");
-        if (!f)
-                return -errno;
-
-        while (!feof(f)) {
-                char l[LINE_MAX], *p, *u, *cs;
-                char **t;
-
-                if (!fgets(l, sizeof(l), f)) {
-                        if (!feof(f))
-                                return -errno;
-                        else if (!c)
-                                break;
-                }
-
-                cs = endswith(l, "\\\n");
-                if (cs) {
-                        *cs = '\0';
-                        b = strappend(c, l);
-                        if (!b)
-                                return log_oom();
-
-                        free(c);
-                        c = b;
-                        *l = '\0';
-                        continue;
-                }
-
-                if (c) {
-                        b = strappend(c, l);
-                        if (!b)
-                                return log_oom();
-
-                        free(c);
-                        c = b;
-                }
-
-                p = strstrip(c ? c : l);
-
-                if (!*p)
-                        continue;
-
-                if (strchr(COMMENTS, *p))
-                        continue;
-
-                u = normalize_env_assignment(p);
-                if (!u)
-                        return log_oom();
-
-                free(c);
-                c = NULL;
-
-                t = strv_append(m, u);
-                free(u);
-
-                if (!t)
-                        return log_oom();
-
-                strv_free(m);
-                m = t;
-        }
-
-        *rl = m;
-        m = NULL;
-
-        return 0;
-}
-
-int write_env_file(const char *fname, char **l) {
-        char **i, *p;
-        FILE *f;
-        int r;
-
-        r = fopen_temporary(fname, &f, &p);
-        if (r < 0)
-                return r;
-
-        fchmod_umask(fileno(f), 0644);
-
-        errno = 0;
-        STRV_FOREACH(i, l) {
-                fputs(*i, f);
-                fputc('\n', f);
-        }
-
-        fflush(f);
-
-        if (ferror(f)) {
-                if (errno != 0)
-                        r = -errno;
-                else
-                        r = -EIO;
-        } else {
-                if (rename(p, fname) < 0)
-                        r = -errno;
-                else
-                        r = 0;
-        }
-
-        if (r < 0)
-                unlink(p);
-
-        fclose(f);
-        free(p);
-
-        return r;
-}
-
 char *truncate_nl(char *s) {
         assert(s);
 
@@ -1062,10 +737,11 @@ int get_process_exe(pid_t pid, char **name) {
 }
 
 static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
-        char *p;
-        FILE *f;
-        int r;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        char line[LINE_MAX];
 
+        assert(field);
         assert(uid);
 
         if (pid == 0)
@@ -1075,21 +751,11 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
                 return -ENOMEM;
 
         f = fopen(p, "re");
-        free(p);
-
         if (!f)
                 return -errno;
 
-        while (!feof(f)) {
-                char line[LINE_MAX], *l;
-
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                break;
-
-                        r = -errno;
-                        goto finish;
-                }
+        FOREACH_LINE(line, f, return -errno) {
+                char *l;
 
                 l = strstrip(line);
 
@@ -1099,17 +765,11 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
 
                         l[strcspn(l, WHITESPACE)] = 0;
 
-                        r = parse_uid(l, uid);
-                        goto finish;
+                        return parse_uid(l, uid);
                 }
         }
 
-        r = -EIO;
-
-finish:
-        fclose(f);
-
-        return r;
+        return -EIO;
 }
 
 int get_process_uid(pid_t pid, uid_t *uid) {
@@ -1371,7 +1031,6 @@ int rmdir_parents(const char *path, const char *stop) {
         return 0;
 }
 
-
 char hexchar(int x) {
         static const char table[16] = "0123456789abcdef";
 
@@ -1392,6 +1051,23 @@ int unhexchar(char c) {
         return -1;
 }
 
+char *hexmem(const void *p, size_t l) {
+        char *r, *z;
+        const uint8_t *x;
+
+        z = r = malloc(l * 2 + 1);
+        if (!r)
+                return NULL;
+
+        for (x = p; x < (const uint8_t*) p + l; x++) {
+                *(z++) = hexchar(*x >> 4);
+                *(z++) = hexchar(*x & 15);
+        }
+
+        *z = 0;
+        return r;
+}
+
 char octchar(int x) {
         return '0' + (x & 7);
 }
@@ -1667,16 +1343,24 @@ char *bus_path_escape(const char *s) {
         assert(s);
 
         /* Escapes all chars that D-Bus' object path cannot deal
-         * with. Can be reverse with bus_path_unescape() */
+         * with. Can be reverse with bus_path_unescape(). We special
+         * case the empty string. */
 
-        if (!(r = new(char, strlen(s)*3+1)))
+        if (*s == 0)
+                return strdup("_");
+
+        r = new(char, strlen(s)*3 + 1);
+        if (!r)
                 return NULL;
 
         for (f = s, t = r; *f; f++) {
 
+                /* Escape everything that is not a-zA-Z0-9. We also
+                 * escape 0-9 if it's the first character */
+
                 if (!(*f >= 'A' && *f <= 'Z') &&
                     !(*f >= 'a' && *f <= 'z') &&
-                    !(*f >= '0' && *f <= '9')) {
+                    !(f > s && *f >= '0' && *f <= '9')) {
                         *(t++) = '_';
                         *(t++) = hexchar(*f >> 4);
                         *(t++) = hexchar(*f);
@@ -1694,7 +1378,12 @@ char *bus_path_unescape(const char *f) {
 
         assert(f);
 
-        if (!(r = strdup(f)))
+        /* Special case for the empty string */
+        if (streq(f, "_"))
+                return strdup("");
+
+        r = new(char, strlen(f) + 1);
+        if (!r)
                 return NULL;
 
         for (t = r; *f; f++) {
@@ -3201,12 +2890,13 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         }
 }
 
-int status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
         static const char status_indent[] = "         "; /* "[" STATUS "] " */
         _cleanup_free_ char *s = NULL;
         _cleanup_close_ int fd = -1;
-        struct iovec iovec[5];
+        struct iovec iovec[6];
         int n = 0;
+        static bool prev_ephemeral;
 
         assert(format);
 
@@ -3244,6 +2934,10 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
 
         zero(iovec);
 
+        if (prev_ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+        prev_ephemeral = ephemeral;
+
         if (status) {
                 if (!isempty(status)) {
                         IOVEC_SET_STRING(iovec[n++], "[");
@@ -3254,7 +2948,8 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
         }
 
         IOVEC_SET_STRING(iovec[n++], s);
-        IOVEC_SET_STRING(iovec[n++], "\n");
+        if (!ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\n");
 
         if (writev(fd, iovec, n) < 0)
                 return -errno;
@@ -3262,14 +2957,14 @@ int status_vprintf(const char *status, bool ellipse, const char *format, va_list
         return 0;
 }
 
-int status_printf(const char *status, bool ellipse, const char *format, ...) {
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
         va_list ap;
         int r;
 
         assert(format);
 
         va_start(ap, format);
-        r = status_vprintf(status, ellipse, format, ap);
+        r = status_vprintf(status, ellipse, ephemeral, format, ap);
         va_end(ap);
 
         return r;
@@ -3286,7 +2981,7 @@ int status_welcome(void) {
         if (r < 0 && r != -ENOENT)
                 log_warning("Failed to read /etc/os-release: %s", strerror(-r));
 
-        return status_printf(NULL, false,
+        return status_printf(NULL, false, false,
                              "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
                              isempty(ansi_color) ? "1" : ansi_color,
                              isempty(pretty_name) ? "Linux" : pretty_name);
@@ -3341,10 +3036,10 @@ char *replace_env(const char *format, char **env) {
                         if (*e == '}') {
                                 const char *t;
 
-                                if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
-                                        t = "";
+                                t = strempty(strv_env_get_n(env, word+2, e-word-2));
 
-                                if (!(k = strappend(r, t)))
+                                k = strappend(r, t);
+                                if (!k)
                                         goto fail;
 
                                 free(r);
@@ -3385,7 +3080,8 @@ char **replace_env_argv(char **argv, char **env) {
                         char **w, **m;
                         unsigned q;
 
-                        if ((e = strv_env_get(env, *i+1))) {
+                        e = strv_env_get(env, *i+1);
+                        if (e) {
 
                                 if (!(m = strv_split_quoted(e))) {
                                         r[k] = NULL;
@@ -3844,6 +3540,29 @@ int vtnr_from_tty(const char *tty) {
         return i;
 }
 
+char *resolve_dev_console(char **active) {
+        char *tty;
+
+        /* Resolve where /dev/console is pointing to, if /sys is actually ours
+         * (i.e. not read-only-mounted which is a sign for container setups) */
+
+        if (path_is_read_only_fs("/sys") > 0)
+                return NULL;
+
+        if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
+                return NULL;
+
+        /* If multiple log outputs are configured the last one is what
+         * /dev/console points to */
+        tty = strrchr(*active, ' ');
+        if (tty)
+                tty++;
+        else
+                tty = *active;
+
+        return tty;
+}
+
 bool tty_is_vc_resolve(const char *tty) {
         char *active = NULL;
         bool b;
@@ -3853,19 +3572,11 @@ bool tty_is_vc_resolve(const char *tty) {
         if (startswith(tty, "/dev/"))
                 tty += 5;
 
-        /* Resolve where /dev/console is pointing to, if /sys is
-         * actually ours (i.e. not read-only-mounted which is a sign
-         * for container setups) */
-        if (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0)
-                if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
-                        /* If multiple log outputs are configured the
-                         * last one is what /dev/console points to */
-                        tty = strrchr(active, ' ');
-                        if (tty)
-                                tty++;
-                        else
-                                tty = active;
-                }
+        if (streq(tty, "console")) {
+                tty = resolve_dev_console(&active);
+                if (!tty)
+                        return false;
+        }
 
         b = tty_is_vc(tty);
         free(active);
@@ -3914,8 +3625,8 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
 
         assert(directory);
 
-        /* Executes all binaries in a directory in parallel and waits
-         * until all they all finished. */
+        /* Executes all binaries in a directory in parallel and
+         * waits for them to finish. */
 
         if (!d) {
                 if (!(_d = opendir(directory))) {
@@ -4064,13 +3775,27 @@ static bool hostname_valid_char(char c) {
 
 bool hostname_is_valid(const char *s) {
         const char *p;
+        bool dot;
 
         if (isempty(s))
                 return false;
 
-        for (p = s; *p; p++)
-                if (!hostname_valid_char(*p))
-                        return false;
+        for (p = s, dot = true; *p; p++) {
+                if (*p == '.') {
+                        if (dot)
+                                return false;
+
+                        dot = true;
+                } else {
+                        if (!hostname_valid_char(*p))
+                                return false;
+
+                        dot = false;
+                }
+        }
+
+        if (dot)
+                return false;
 
         if (p-s > HOST_NAME_MAX)
                 return false;
@@ -4481,6 +4206,23 @@ char* uid_to_name(uid_t uid) {
         return r;
 }
 
+char* gid_to_name(gid_t gid) {
+        struct group *p;
+        char *r;
+
+        if (gid == 0)
+                return strdup("root");
+
+        p = getgrgid(gid);
+        if (p)
+                return strdup(p->gr_name);
+
+        if (asprintf(&r, "%lu", (unsigned long) gid) < 0)
+                return NULL;
+
+        return r;
+}
+
 int get_group_creds(const char **groupname, gid_t *gid) {
         struct group *g;
         gid_t id;
@@ -4519,14 +4261,10 @@ int get_group_creds(const char **groupname, gid_t *gid) {
         return 0;
 }
 
-int in_group(const char *name) {
-        gid_t gid, *gids;
+int in_gid(gid_t gid) {
+        gid_t *gids;
         int ngroups_max, r, i;
 
-        r = get_group_creds(&name, &gid);
-        if (r < 0)
-                return r;
-
         if (getgid() == gid)
                 return 1;
 
@@ -4549,6 +4287,17 @@ int in_group(const char *name) {
         return 0;
 }
 
+int in_group(const char *name) {
+        int r;
+        gid_t gid;
+
+        r = get_group_creds(&name, &gid);
+        if (r < 0)
+                return r;
+
+        return in_gid(gid);
+}
+
 int glob_exists(const char *path) {
         glob_t g;
         int r, k;
@@ -5497,62 +5246,16 @@ int get_home_dir(char **_h) {
         return 0;
 }
 
-int get_shell(char **_sh) {
-        char *sh;
-        const char *e;
-        uid_t u;
-        struct passwd *p;
-
-        assert(_sh);
-
-        /* Take the user specified one */
-        e = getenv("SHELL");
-        if (e) {
-                sh = strdup(e);
-                if (!sh)
-                        return -ENOMEM;
-
-                *_sh = sh;
-                return 0;
-        }
-
-        /* Hardcode home directory for root to avoid NSS */
-        u = getuid();
-        if (u == 0) {
-                sh = strdup("/bin/sh");
-                if (!sh)
-                        return -ENOMEM;
-
-                *_sh = sh;
-                return 0;
-        }
-
-        /* Check the database... */
-        errno = 0;
-        p = getpwuid(u);
-        if (!p)
-                return errno ? -errno : -ESRCH;
-
-        if (!path_is_absolute(p->pw_shell))
-                return -EINVAL;
-
-        sh = strdup(p->pw_shell);
-        if (!sh)
-                return -ENOMEM;
-
-        *_sh = sh;
-        return 0;
-}
-
-void freep(void *p) {
-        free(*(void**) p);
-}
-
 void fclosep(FILE **f) {
         if (*f)
                 fclose(*f);
 }
 
+void pclosep(FILE **f) {
+        if (*f)
+                pclose(*f);
+}
+
 void closep(int *fd) {
         if (*fd >= 0)
                 close_nointr_nofail(*fd);
@@ -5563,10 +5266,6 @@ void closedirp(DIR **d) {
                 closedir(*d);
 }
 
-void umaskp(mode_t *u) {
-        umask(*u);
-}
-
 bool filename_is_safe(const char *p) {
 
         if (isempty(p))
@@ -5603,6 +5302,18 @@ bool string_is_safe(const char *p) {
         return true;
 }
 
+bool string_has_cc(const char *p) {
+        const char *t;
+
+        assert(p);
+
+        for (t = p; *t; t++)
+                if (*t > 0 && *t < ' ')
+                        return true;
+
+        return false;
+}
+
 bool path_is_safe(const char *p) {
 
         if (isempty(p))
@@ -5835,7 +5546,6 @@ int on_ac_power(void) {
         for (;;) {
                 struct dirent *de;
                 union dirent_storage buf;
-                _cleanup_free_ char *p = NULL;
                 _cleanup_close_ int fd = -1, device = -1;
                 char contents[6];
                 ssize_t n;
@@ -5901,3 +5611,200 @@ int on_ac_power(void) {
 
         return found_online || !found_offline;
 }
+
+static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
+        char **i;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (!path_strv_canonicalize_uniq(search))
+                return -ENOMEM;
+
+        STRV_FOREACH(i, search) {
+                _cleanup_free_ char *p = NULL;
+                FILE *f;
+
+                p = strjoin(*i, "/", path, NULL);
+                if (!p)
+                        return -ENOMEM;
+
+                f = fopen(p, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                if (errno != ENOENT)
+                        return -errno;
+        }
+
+        return -ENOENT;
+}
+
+int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        copy = strv_copy((char**) search);
+        if (!copy)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, copy, _f);
+}
+
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        s = strv_split_nulstr(search);
+        if (!s)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, s, _f);
+}
+
+int create_tmp_dir(char template[], char** dir_name) {
+        int r = 0;
+        char *d, *dt;
+        mode_t _cleanup_umask_ u;
+
+        assert(dir_name);
+
+        u = umask(0077);
+        d = mkdtemp(template);
+        if (!d) {
+                log_error("Can't create directory %s: %m", template);
+                return -errno;
+        }
+
+        dt = strjoin(d, "/tmp", NULL);
+        if (!dt) {
+                r = log_oom();
+                goto fail2;
+        }
+
+        umask(0000);
+        r = mkdir(dt, 0777);
+        if (r) {
+                log_error("Can't create directory %s: %m", dt);
+                r = -errno;
+                goto fail1;
+        }
+        log_debug("Created temporary directory %s", dt);
+
+        r = chmod(dt, 0777 | S_ISVTX);
+        if (r < 0) {
+                log_error("Failed to chmod %s: %m", dt);
+                r = -errno;
+                goto fail1;
+        }
+        log_debug("Set sticky bit on %s", dt);
+
+        *dir_name = dt;
+
+        return 0;
+fail1:
+        rmdir(dt);
+fail2:
+        rmdir(template);
+        return r;
+}
+
+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;
+}