chiark / gitweb /
shared: add readlink_value
[elogind.git] / src / shared / util.c
index cf9d487b829b67087691a43da7959d0637020a10..f0e0c0dd3d0c6f1ea9583a0ac49d361034aae0aa 100644 (file)
@@ -695,7 +695,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
         }
 
         /* Kernel threads have no argv[] */
-        if (r == NULL || r[0] == 0) {
+        if (isempty(r)) {
                 _cleanup_free_ char *t = NULL;
                 int h;
 
@@ -893,6 +893,28 @@ int readlink_malloc(const char *p, char **ret) {
         return readlinkat_malloc(AT_FDCWD, p, ret);
 }
 
+int readlink_value(const char *p, char **ret) {
+        _cleanup_free_ char *link = NULL;
+        char *value;
+        int r;
+
+        r = readlink_malloc(p, &link);
+        if (r < 0)
+                return r;
+
+        value = basename(link);
+        if (!value)
+                return -ENOENT;
+
+        value = strdup(value);
+        if (!value)
+                return -ENOMEM;
+
+        *ret = value;
+
+        return 0;
+}
+
 int readlink_and_make_absolute(const char *p, char **r) {
         _cleanup_free_ char *target = NULL;
         char *k;
@@ -1878,9 +1900,6 @@ int open_terminal(const char *name, int mode) {
                 c++;
         }
 
-        if (fd < 0)
-                return -errno;
-
         r = isatty(fd);
         if (r < 0) {
                 safe_close(fd);
@@ -2077,7 +2096,7 @@ int acquire_terminal(
                  * ended our handle will be dead. It's important that
                  * we do this after sleeping, so that we don't enter
                  * an endless loop. */
-                safe_close(fd);
+                fd = safe_close(fd);
         }
 
         safe_close(notify);
@@ -2469,14 +2488,53 @@ char* dirname_malloc(const char *path) {
 }
 
 int dev_urandom(void *p, size_t n) {
-        _cleanup_close_ int fd;
+        static int have_syscall = -1;
+        int r, fd;
         ssize_t k;
 
+        /* Gathers some randomness from the kernel. This call will
+         * never block, and will always return some data from the
+         * kernel, regardless if the random pool is fully initialized
+         * or not. It thus makes no guarantee for the quality of the
+         * returned entropy, but is good enough for or usual usecases
+         * of seeding the hash functions for hashtable */
+
+        /* Use the getrandom() syscall unless we know we don't have
+         * it, or when the requested size is too large for it. */
+        if (have_syscall != 0 || (size_t) (int) n != n) {
+                r = getrandom(p, n, GRND_NONBLOCK);
+                if (r == (int) n) {
+                        have_syscall = true;
+                        return 0;
+                }
+
+                if (r < 0) {
+                        if (errno == ENOSYS)
+                                /* we lack the syscall, continue with
+                                 * reading from /dev/urandom */
+                                have_syscall = false;
+                        else if (errno == EAGAIN)
+                                /* not enough entropy for now. Let's
+                                 * remember to use the syscall the
+                                 * next time, again, but also read
+                                 * from /dev/urandom for now, which
+                                 * doesn't care about the current
+                                 * amount of entropy.  */
+                                have_syscall = true;
+                        else
+                                return -errno;
+                } else
+                        /* too short read? */
+                        return -EIO;
+        }
+
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)
                 return errno == ENOENT ? -ENOSYS : -errno;
 
         k = loop_read(fd, p, n, true);
+        safe_close(fd);
+
         if (k < 0)
                 return (int) k;
         if ((size_t) k != n)
@@ -2485,8 +2543,36 @@ int dev_urandom(void *p, size_t n) {
         return 0;
 }
 
-void random_bytes(void *p, size_t n) {
+void initialize_srand(void) {
         static bool srand_called = false;
+        unsigned x;
+#ifdef HAVE_SYS_AUXV_H
+        void *auxv;
+#endif
+
+        if (srand_called)
+                return;
+
+        x = 0;
+
+#ifdef HAVE_SYS_AUXV_H
+        /* The kernel provides us with a bit of entropy in auxv, so
+         * let's try to make use of that to seed the pseudo-random
+         * generator. It's better than nothing... */
+
+        auxv = (void*) getauxval(AT_RANDOM);
+        if (auxv)
+                x ^= *(unsigned*) auxv;
+#endif
+
+        x ^= (unsigned) now(CLOCK_REALTIME);
+        x ^= (unsigned) gettid();
+
+        srand(x);
+        srand_called = true;
+}
+
+void random_bytes(void *p, size_t n) {
         uint8_t *q;
         int r;
 
@@ -2497,28 +2583,7 @@ void random_bytes(void *p, size_t n) {
         /* If some idiot made /dev/urandom unavailable to us, he'll
          * get a PRNG instead. */
 
-        if (!srand_called) {
-                unsigned x = 0;
-
-#ifdef HAVE_SYS_AUXV_H
-                /* The kernel provides us with a bit of entropy in
-                 * auxv, so let's try to make use of that to seed the
-                 * pseudo-random generator. It's better than
-                 * nothing... */
-
-                void *auxv;
-
-                auxv = (void*) getauxval(AT_RANDOM);
-                if (auxv)
-                        x ^= *(unsigned*) auxv;
-#endif
-
-                x ^= (unsigned) now(CLOCK_REALTIME);
-                x ^= (unsigned) gettid();
-
-                srand(x);
-                srand_called = true;
-        }
+        initialize_srand();
 
         for (q = p; q < (uint8_t*) p + n; q ++)
                 *q = rand();
@@ -2740,7 +2805,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
         if (k < 0)
                 return k;
 
-        snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
+        sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
 
         k = readlink_malloc(fn, &s);
         if (k < 0) {
@@ -2898,6 +2963,19 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root
         return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
 }
 
+static int file_is_priv_sticky(const char *p) {
+        struct stat st;
+
+        assert(p);
+
+        if (lstat(p, &st) < 0)
+                return -errno;
+
+        return
+                (st.st_uid == 0 || st.st_uid == getuid()) &&
+                (st.st_mode & S_ISVTX);
+}
+
 static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
         int fd, r;
         struct statfs s;
@@ -3136,7 +3214,8 @@ char *replace_env(const char *format, char **env) {
 
                 case CURLY:
                         if (*e == '{') {
-                                if (!(k = strnappend(r, word, e-word-1)))
+                                k = strnappend(r, word, e-word-1);
+                                if (!k)
                                         goto fail;
 
                                 free(r);
@@ -3146,7 +3225,8 @@ char *replace_env(const char *format, char **env) {
                                 state = VARIABLE;
 
                         } else if (*e == '$') {
-                                if (!(k = strnappend(r, word, e-word)))
+                                k = strnappend(r, word, e-word);
+                                if (!k)
                                         goto fail;
 
                                 free(r);
@@ -3178,7 +3258,8 @@ char *replace_env(const char *format, char **env) {
                 }
         }
 
-        if (!(k = strnappend(r, word, e-word)))
+        k = strnappend(r, word, e-word);
+        if (!k)
                 goto fail;
 
         free(r);
@@ -3276,7 +3357,7 @@ unsigned columns(void) {
         c = 0;
         e = getenv("COLUMNS");
         if (e)
-                safe_atoi(e, &c);
+                (void) safe_atoi(e, &c);
 
         if (c <= 0)
                 c = fd_columns(STDOUT_FILENO);
@@ -3310,7 +3391,7 @@ unsigned lines(void) {
         l = 0;
         e = getenv("LINES");
         if (e)
-                safe_atou(e, &l);
+                (void) safe_atou(e, &l);
 
         if (l <= 0)
                 l = fd_lines(STDOUT_FILENO);
@@ -3532,41 +3613,33 @@ char *unquote(const char *s, const char* quotes) {
 }
 
 char *normalize_env_assignment(const char *s) {
-        _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL;
-        char *eq, *r;
+        _cleanup_free_ char *value = NULL;
+        const char *eq;
+        char *p, *name;
 
         eq = strchr(s, '=');
         if (!eq) {
-                char *t;
+                char *r, *t;
 
                 r = strdup(s);
                 if (!r)
                         return NULL;
 
                 t = strstrip(r);
-                if (t == r)
-                        return r;
+                if (t != r)
+                        memmove(r, t, strlen(t) + 1);
 
-                memmove(r, t, strlen(t) + 1);
                 return r;
         }
 
-        name = strndup(s, eq - s);
-        if (!name)
-                return NULL;
-
-        p = strdup(eq + 1);
-        if (!p)
-                return NULL;
+        name = strndupa(s, eq - s);
+        p = strdupa(eq + 1);
 
         value = unquote(strstrip(p), QUOTES);
         if (!value)
                 return NULL;
 
-        if (asprintf(&r, "%s=%s", strstrip(name), value) < 0)
-                r = NULL;
-
-        return r;
+        return strjoin(strstrip(name), "=", value, NULL);
 }
 
 int wait_for_terminate(pid_t pid, siginfo_t *status) {
@@ -3911,7 +3984,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
                         }
                 }
 
-                pids = hashmap_new(NULL, NULL);
+                pids = hashmap_new(NULL);
                 if (!pids) {
                         log_oom();
                         _exit(EXIT_FAILURE);
@@ -4783,19 +4856,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
         return -ENOENT;
 }
 
-int file_is_priv_sticky(const char *p) {
-        struct stat st;
-
-        assert(p);
-
-        if (lstat(p, &st) < 0)
-                return -errno;
-
-        return
-                (st.st_uid == 0 || st.st_uid == getuid()) &&
-                (st.st_mode & S_ISVTX);
-}
-
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
@@ -4981,24 +5041,6 @@ bool kexec_loaded(void) {
        return loaded;
 }
 
-int strdup_or_null(const char *a, char **b) {
-        char *c;
-
-        assert(b);
-
-        if (!a) {
-                *b = NULL;
-                return 0;
-        }
-
-        c = strdup(a);
-        if (!c)
-                return -ENOMEM;
-
-        *b = c;
-        return 0;
-}
-
 int prot_from_flags(int flags) {
 
         switch (flags & O_ACCMODE) {
@@ -6118,27 +6160,28 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
 
 int shall_restore_state(void) {
         _cleanup_free_ char *line = NULL;
-        const char *word, *state;
-        size_t l;
+        const char *p;
         int r;
 
         r = proc_cmdline(&line);
         if (r < 0)
                 return r;
-        if (r == 0) /* Container ... */
-                return 1;
 
         r = 1;
+        p = line;
 
-        FOREACH_WORD_QUOTED(word, l, line, state) {
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
                 const char *e;
-                char n[l+1];
                 int k;
 
-                memcpy(n, word, l);
-                n[l] = 0;
+                k = unquote_first_word(&p, &word, true);
+                if (k < 0)
+                        return k;
+                if (k == 0)
+                        break;
 
-                e = startswith(n, "systemd.restore_state=");
+                e = startswith(word, "systemd.restore_state=");
                 if (!e)
                         continue;
 
@@ -6151,51 +6194,35 @@ int shall_restore_state(void) {
 }
 
 int proc_cmdline(char **ret) {
-        int r;
-
-        if (detect_container(NULL) > 0) {
-                char *buf = NULL, *p;
-                size_t sz = 0;
-
-                r = read_full_file("/proc/1/cmdline", &buf, &sz);
-                if (r < 0)
-                        return r;
-
-                for (p = buf; p + 1 < buf + sz; p++)
-                        if (*p == 0)
-                                *p = ' ';
-
-                *p = 0;
-                *ret = buf;
-                return 1;
-        }
-
-        r = read_one_line_file("/proc/cmdline", ret);
-        if (r < 0)
-                return r;
+        assert(ret);
 
-        return 1;
+        if (detect_container(NULL) > 0)
+                return get_process_cmdline(1, 0, false, ret);
+        else
+                return read_one_line_file("/proc/cmdline", ret);
 }
 
 int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
         _cleanup_free_ char *line = NULL;
-        const char *w, *state;
-        size_t l;
+        const char *p;
         int r;
 
         assert(parse_item);
 
         r = proc_cmdline(&line);
         if (r < 0)
-                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
-        if (r <= 0)
-                return 0;
+                return r;
 
-        FOREACH_WORD_QUOTED(w, l, line, state) {
-                char word[l+1], *value;
+        p = line;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                char *value = NULL;
 
-                memcpy(word, w, l);
-                word[l] = 0;
+                r = unquote_first_word(&p, &word, true);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
 
                 /* Filter out arguments that are intended only for the
                  * initrd */
@@ -6712,7 +6739,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
 
         path_kill_slashes(cleaned);
 
-        done = set_new(string_hash_func, string_compare_func);
+        done = set_new(&string_hash_ops);
         if (!done)
                 return -ENOMEM;
 
@@ -6722,7 +6749,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
                 bool top_autofs = false;
                 char *x;
 
-                todo = set_new(string_hash_func, string_compare_func);
+                todo = set_new(&string_hash_ops);
                 if (!todo)
                         return -ENOMEM;
 
@@ -6954,13 +6981,24 @@ int is_symlink(const char *path) {
         if (lstat(path, &info) < 0)
                 return -errno;
 
-        if (S_ISLNK(info.st_mode))
-                return 1;
+        return !!S_ISLNK(info.st_mode);
+}
 
-        return 0;
+int is_dir(const char* path, bool follow) {
+        struct stat st;
+        int r;
+
+        if (follow)
+                r = stat(path, &st);
+        else
+                r = lstat(path, &st);
+        if (r < 0)
+                return -errno;
+
+        return !!S_ISDIR(st.st_mode);
 }
 
-int unquote_first_word(const char **p, char **ret) {
+int unquote_first_word(const char **p, char **ret, bool relax) {
         _cleanup_free_ char *s = NULL;
         size_t allocated = 0, sz = 0;
 
@@ -7019,8 +7057,11 @@ int unquote_first_word(const char **p, char **ret) {
                         break;
 
                 case VALUE_ESCAPE:
-                        if (c == 0)
+                        if (c == 0) {
+                                if (relax)
+                                        goto finish;
                                 return -EINVAL;
+                        }
 
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
@@ -7031,9 +7072,11 @@ int unquote_first_word(const char **p, char **ret) {
                         break;
 
                 case SINGLE_QUOTE:
-                        if (c == 0)
+                        if (c == 0) {
+                                if (relax)
+                                        goto finish;
                                 return -EINVAL;
-                        else if (c == '\'')
+                        else if (c == '\'')
                                 state = VALUE;
                         else if (c == '\\')
                                 state = SINGLE_QUOTE_ESCAPE;
@@ -7047,8 +7090,11 @@ int unquote_first_word(const char **p, char **ret) {
                         break;
 
                 case SINGLE_QUOTE_ESCAPE:
-                        if (c == 0)
+                        if (c == 0) {
+                                if (relax)
+                                        goto finish;
                                 return -EINVAL;
+                        }
 
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
@@ -7074,8 +7120,11 @@ int unquote_first_word(const char **p, char **ret) {
                         break;
 
                 case DOUBLE_QUOTE_ESCAPE:
-                        if (c == 0)
+                        if (c == 0) {
+                                if (relax)
+                                        goto finish;
                                 return -EINVAL;
+                        }
 
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
@@ -7135,7 +7184,7 @@ int unquote_many_words(const char **p, ...) {
         l = newa0(char*, n);
         for (c = 0; c < n; c++) {
 
-                r = unquote_first_word(p, &l[c]);
+                r = unquote_first_word(p, &l[c], false);
                 if (r < 0) {
                         int j;
 
@@ -7185,3 +7234,23 @@ int free_and_strdup(char **p, const char *s) {
 
         return 0;
 }
+
+int sethostname_idempotent(const char *s) {
+        int r;
+        char buf[HOST_NAME_MAX + 1] = {};
+
+        assert(s);
+
+        r = gethostname(buf, sizeof(buf));
+        if (r < 0)
+                return -errno;
+
+        if (streq(buf, s))
+                return 0;
+
+        r = sethostname(s, strlen(s));
+        if (r < 0)
+                return -errno;
+
+        return 1;
+}