chiark / gitweb /
logind: optionally handle power, sleep and lid switch events
[elogind.git] / src / shared / util.c
index 43948ccbd8970c5076d2f00659d26f2d449fa4ce..70b159f8c314ead6fb62964ece54117d7e4bd240 100644 (file)
 #include <sys/wait.h>
 #include <sys/capability.h>
 #include <sys/time.h>
-#include <linux/rtc.h>
 #include <glob.h>
 #include <grp.h>
 #include <sys/mman.h>
-#include <sys/statvfs.h>
 
 #include "macro.h"
 #include "util.h"
@@ -65,6 +63,7 @@
 #include "log.h"
 #include "strv.h"
 #include "label.h"
+#include "path-util.h"
 #include "exit-status.h"
 #include "hashmap.h"
 
@@ -487,21 +486,6 @@ char *split_quoted(const char *c, size_t *l, char **state) {
         return (char*) current;
 }
 
-char **split_path_and_make_absolute(const char *p) {
-        char **l;
-        assert(p);
-
-        if (!(l = strv_split(p, ":")))
-                return NULL;
-
-        if (!strv_path_make_absolute_cwd(l)) {
-                strv_free(l);
-                return NULL;
-        }
-
-        return l;
-}
-
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
         int r;
         FILE *f;
@@ -613,7 +597,8 @@ int write_one_line_file(const char *fn, const char *line) {
         assert(fn);
         assert(line);
 
-        if (!(f = fopen(fn, "we")))
+        f = fopen(fn, "we");
+        if (!f)
                 return -errno;
 
         errno = 0;
@@ -1314,187 +1299,6 @@ int readlink_and_canonicalize(const char *p, char **r) {
         return 0;
 }
 
-int parent_of_path(const char *path, char **_r) {
-        const char *e, *a = NULL, *b = NULL, *p;
-        char *r;
-        bool slash = false;
-
-        assert(path);
-        assert(_r);
-
-        if (!*path)
-                return -EINVAL;
-
-        for (e = path; *e; e++) {
-
-                if (!slash && *e == '/') {
-                        a = b;
-                        b = e;
-                        slash = true;
-                } else if (slash && *e != '/')
-                        slash = false;
-        }
-
-        if (*(e-1) == '/')
-                p = a;
-        else
-                p = b;
-
-        if (!p)
-                return -EINVAL;
-
-        if (p == path)
-                r = strdup("/");
-        else
-                r = strndup(path, p-path);
-
-        if (!r)
-                return -ENOMEM;
-
-        *_r = r;
-        return 0;
-}
-
-
-char *file_name_from_path(const char *p) {
-        char *r;
-
-        assert(p);
-
-        if ((r = strrchr(p, '/')))
-                return r + 1;
-
-        return (char*) p;
-}
-
-bool path_is_absolute(const char *p) {
-        assert(p);
-
-        return p[0] == '/';
-}
-
-bool is_path(const char *p) {
-
-        return !!strchr(p, '/');
-}
-
-char *path_make_absolute(const char *p, const char *prefix) {
-        assert(p);
-
-        /* Makes every item in the list an absolute path by prepending
-         * the prefix, if specified and necessary */
-
-        if (path_is_absolute(p) || !prefix)
-                return strdup(p);
-
-        return join(prefix, "/", p, NULL);
-}
-
-char *path_make_absolute_cwd(const char *p) {
-        char *cwd, *r;
-
-        assert(p);
-
-        /* Similar to path_make_absolute(), but prefixes with the
-         * current working directory. */
-
-        if (path_is_absolute(p))
-                return strdup(p);
-
-        if (!(cwd = get_current_dir_name()))
-                return NULL;
-
-        r = path_make_absolute(p, cwd);
-        free(cwd);
-
-        return r;
-}
-
-char **strv_path_make_absolute_cwd(char **l) {
-        char **s;
-
-        /* Goes through every item in the string list and makes it
-         * absolute. This works in place and won't rollback any
-         * changes on failure. */
-
-        STRV_FOREACH(s, l) {
-                char *t;
-
-                if (!(t = path_make_absolute_cwd(*s)))
-                        return NULL;
-
-                free(*s);
-                *s = t;
-        }
-
-        return l;
-}
-
-char **strv_path_canonicalize(char **l) {
-        char **s;
-        unsigned k = 0;
-        bool enomem = false;
-
-        if (strv_isempty(l))
-                return l;
-
-        /* Goes through every item in the string list and canonicalize
-         * the path. This works in place and won't rollback any
-         * changes on failure. */
-
-        STRV_FOREACH(s, l) {
-                char *t, *u;
-
-                t = path_make_absolute_cwd(*s);
-                free(*s);
-
-                if (!t) {
-                        enomem = true;
-                        continue;
-                }
-
-                errno = 0;
-                u = canonicalize_file_name(t);
-                free(t);
-
-                if (!u) {
-                        if (errno == ENOMEM || !errno)
-                                enomem = true;
-
-                        continue;
-                }
-
-                l[k++] = u;
-        }
-
-        l[k] = NULL;
-
-        if (enomem)
-                return NULL;
-
-        return l;
-}
-
-char **strv_path_remove_empty(char **l) {
-        char **f, **t;
-
-        if (!l)
-                return NULL;
-
-        for (f = t = l; *f; f++) {
-
-                if (dir_is_empty(*f) > 0) {
-                        free(*f);
-                        continue;
-                }
-
-                *(t++) = *f;
-        }
-
-        *t = NULL;
-        return l;
-}
-
 int reset_all_signal_handlers(void) {
         int sig;
 
@@ -1973,107 +1777,6 @@ char *bus_path_unescape(const char *f) {
         return r;
 }
 
-char *path_kill_slashes(char *path) {
-        char *f, *t;
-        bool slash = false;
-
-        /* Removes redundant inner and trailing slashes. Modifies the
-         * passed string in-place.
-         *
-         * ///foo///bar/ becomes /foo/bar
-         */
-
-        for (f = path, t = path; *f; f++) {
-
-                if (*f == '/') {
-                        slash = true;
-                        continue;
-                }
-
-                if (slash) {
-                        slash = false;
-                        *(t++) = '/';
-                }
-
-                *(t++) = *f;
-        }
-
-        /* Special rule, if we are talking of the root directory, a
-        trailing slash is good */
-
-        if (t == path && slash)
-                *(t++) = '/';
-
-        *t = 0;
-        return path;
-}
-
-bool path_startswith(const char *path, const char *prefix) {
-        assert(path);
-        assert(prefix);
-
-        if ((path[0] == '/') != (prefix[0] == '/'))
-                return false;
-
-        for (;;) {
-                size_t a, b;
-
-                path += strspn(path, "/");
-                prefix += strspn(prefix, "/");
-
-                if (*prefix == 0)
-                        return true;
-
-                if (*path == 0)
-                        return false;
-
-                a = strcspn(path, "/");
-                b = strcspn(prefix, "/");
-
-                if (a != b)
-                        return false;
-
-                if (memcmp(path, prefix, a) != 0)
-                        return false;
-
-                path += a;
-                prefix += b;
-        }
-}
-
-bool path_equal(const char *a, const char *b) {
-        assert(a);
-        assert(b);
-
-        if ((a[0] == '/') != (b[0] == '/'))
-                return false;
-
-        for (;;) {
-                size_t j, k;
-
-                a += strspn(a, "/");
-                b += strspn(b, "/");
-
-                if (*a == 0 && *b == 0)
-                        return true;
-
-                if (*a == 0 || *b == 0)
-                        return false;
-
-                j = strcspn(a, "/");
-                k = strcspn(b, "/");
-
-                if (j != k)
-                        return false;
-
-                if (memcmp(a, b, j) != 0)
-                        return false;
-
-                a += j;
-                b += k;
-        }
-}
-
 char *ascii_strlower(char *t) {
         char *p;
 
@@ -2987,36 +2690,6 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
         return n;
 }
 
-int path_is_mount_point(const char *t, bool allow_symlink) {
-        struct stat a, b;
-        char *parent;
-        int r;
-
-        if (allow_symlink)
-                r = stat(t, &a);
-        else
-                r = lstat(t, &a);
-
-        if (r < 0) {
-                if (errno == ENOENT)
-                        return 0;
-
-                return -errno;
-        }
-
-        r = parent_of_path(t, &parent);
-        if (r < 0)
-                return r;
-
-        r = lstat(parent, &b);
-        free(parent);
-
-        if (r < 0)
-                return -errno;
-
-        return a.st_dev != b.st_dev;
-}
-
 int parse_usec(const char *t, usec_t *usec) {
         static const struct {
                 const char *suffix;
@@ -3276,12 +2949,20 @@ char* gethostname_malloc(void) {
 
         assert_se(uname(&u) >= 0);
 
-        if (u.nodename[0])
+        if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
                 return strdup(u.nodename);
 
         return strdup(u.sysname);
 }
 
+bool hostname_is_set(void) {
+        struct utsname u;
+
+        assert_se(uname(&u) >= 0);
+
+        return !isempty(u.nodename) && !streq(u.nodename, "(none)");
+}
+
 char* getlogname_malloc(void) {
         uid_t uid;
         long bufsize;
@@ -3458,16 +3139,17 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
         return 0;
 }
 
-static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
+int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
         DIR *d;
         int ret = 0;
 
         assert(fd >= 0);
 
         /* This returns the first error we run into, but nevertheless
-         * tries to go on */
+         * tries to go on. This closes the passed fd. */
 
-        if (!(d = fdopendir(fd))) {
+        d = fdopendir(fd);
+        if (!d) {
                 close_nointr_nofail(fd);
 
                 return errno == ENOENT ? 0 : -errno;
@@ -3475,12 +3157,13 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
 
         for (;;) {
                 struct dirent buf, *de;
-                bool is_dir, keep_around = false;
+                bool is_dir, keep_around;
+                struct stat st;
                 int r;
 
-                if ((r = readdir_r(d, &buf, &de)) != 0) {
-                        if (ret == 0)
-                                ret = -r;
+                r = readdir_r(d, &buf, &de);
+                if (r != 0 && ret == 0) {
+                        ret = -r;
                         break;
                 }
 
@@ -3490,54 +3173,43 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
                         continue;
 
-                if (de->d_type == DT_UNKNOWN) {
-                        struct stat st;
-
+                if (de->d_type == DT_UNKNOWN ||
+                    honour_sticky ||
+                    (de->d_type == DT_DIR && root_dev)) {
                         if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
                                 if (ret == 0 && errno != ENOENT)
                                         ret = -errno;
                                 continue;
                         }
 
-                        if (honour_sticky)
-                                keep_around =
-                                        (st.st_uid == 0 || st.st_uid == getuid()) &&
-                                        (st.st_mode & S_ISVTX);
-
                         is_dir = S_ISDIR(st.st_mode);
-
+                        keep_around =
+                                honour_sticky &&
+                                (st.st_uid == 0 || st.st_uid == getuid()) &&
+                                (st.st_mode & S_ISVTX);
                 } else {
-                        if (honour_sticky) {
-                                struct stat st;
-
-                                if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
-                                        if (ret == 0 && errno != ENOENT)
-                                                ret = -errno;
-                                        continue;
-                                }
-
-                                keep_around =
-                                        (st.st_uid == 0 || st.st_uid == getuid()) &&
-                                        (st.st_mode & S_ISVTX);
-                        }
-
                         is_dir = de->d_type == DT_DIR;
+                        keep_around = false;
                 }
 
                 if (is_dir) {
                         int subdir_fd;
 
-                        subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+                        /* if root_dev is set, remove subdirectories only, if device is same as dir */
+                        if (root_dev && st.st_dev != root_dev->st_dev)
+                                continue;
+
+                        subdir_fd = openat(fd, de->d_name,
+                                           O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
                         if (subdir_fd < 0) {
                                 if (ret == 0 && errno != ENOENT)
                                         ret = -errno;
                                 continue;
                         }
 
-                        if ((r = rm_rf_children(subdir_fd, only_dirs, honour_sticky)) < 0) {
-                                if (ret == 0)
-                                        ret = r;
-                        }
+                        r = rm_rf_children(subdir_fd, only_dirs, honour_sticky, root_dev);
+                        if (r < 0 && ret == 0)
+                                ret = r;
 
                         if (!keep_around)
                                 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
@@ -3565,19 +3237,20 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
 
         assert(path);
 
-        if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+        fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+        if (fd < 0) {
 
                 if (errno != ENOTDIR)
                         return -errno;
 
                 if (delete_root && !only_dirs)
-                        if (unlink(path) < 0)
+                        if (unlink(path) < 0 && errno != ENOENT)
                                 return -errno;
 
                 return 0;
         }
 
-        r = rm_rf_children(fd, only_dirs, honour_sticky);
+        r = rm_rf_children(fd, only_dirs, honour_sticky, NULL);
 
         if (delete_root) {
 
@@ -3656,15 +3329,15 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
 }
 
 void status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
-        char *s = NULL, *spaces = NULL, *e;
-        int fd = -1, c;
-        size_t emax, sl, left;
+        char *s = NULL;
+        static const char status_indent[] = "         "; /* "[" STATUS "] " */
+        int fd = -1;
         struct iovec iovec[5];
         int n = 0;
 
         assert(format);
 
-        /* This independent of logging, as status messages are
+        /* This is independent of logging, as status messages are
          * optional and go exclusively to the console. */
 
         if (vasprintf(&s, format, ap) < 0)
@@ -3675,15 +3348,19 @@ void status_vprintf(const char *status, bool ellipse, const char *format, va_lis
                 goto finish;
 
         if (ellipse) {
+                char *e;
+                size_t emax, sl;
+                int c;
+
                 c = fd_columns(fd);
                 if (c <= 0)
                         c = 80;
 
-                if (status) {
-                        sl = 2 + 6 + 1; /* " [" status "]" */
-                        emax = (size_t) c > sl ? c - sl - 1 : 0;
-                } else
-                        emax = c - 1;
+                sl = status ? strlen(status_indent) : 0;
+
+                emax = c - sl - 1;
+                if (emax < 3)
+                        emax = 3;
 
                 e = ellipsize(s, emax, 75);
                 if (e) {
@@ -3693,34 +3370,23 @@ void status_vprintf(const char *status, bool ellipse, const char *format, va_lis
         }
 
         zero(iovec);
-        IOVEC_SET_STRING(iovec[n++], s);
 
-        if (ellipse) {
-                sl = strlen(s);
-                left = emax > sl ? emax - sl : 0;
-                if (left > 0) {
-                        spaces = malloc(left);
-                        if (spaces) {
-                                memset(spaces, ' ', left);
-                                iovec[n].iov_base = spaces;
-                                iovec[n].iov_len = left;
-                                n++;
-                        }
-                }
+        if (status) {
+                if (!isempty(status)) {
+                        IOVEC_SET_STRING(iovec[n++], "[");
+                        IOVEC_SET_STRING(iovec[n++], status);
+                        IOVEC_SET_STRING(iovec[n++], "] ");
+                } else
+                        IOVEC_SET_STRING(iovec[n++], status_indent);
         }
 
-        if (status) {
-                IOVEC_SET_STRING(iovec[n++], " [");
-                IOVEC_SET_STRING(iovec[n++], status);
-                IOVEC_SET_STRING(iovec[n++], "]\n");
-        } else
-                IOVEC_SET_STRING(iovec[n++], "\n");
+        IOVEC_SET_STRING(iovec[n++], s);
+        IOVEC_SET_STRING(iovec[n++], "\n");
 
         writev(fd, iovec, n);
 
 finish:
         free(s);
-        free(spaces);
 
         if (fd >= 0)
                 close_nointr_nofail(fd);
@@ -4287,6 +3953,15 @@ bool tty_is_vc(const char *tty) {
         return vtnr_from_tty(tty) >= 0;
 }
 
+bool tty_is_console(const char *tty) {
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        return streq(tty, "console");
+}
+
 int vtnr_from_tty(const char *tty) {
         int i, r;
 
@@ -4343,7 +4018,7 @@ bool tty_is_vc_resolve(const char *tty) {
 const char *default_term_for_tty(const char *tty) {
         assert(tty);
 
-        return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt100";
+        return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102";
 }
 
 bool dirent_is_file(const struct dirent *de) {
@@ -4425,8 +4100,7 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
                                 _argv[1] = NULL;
                                 argv = _argv;
                         } else
-                                if (!argv[0])
-                                        argv[0] = path;
+                                argv[0] = path;
 
                         execv(path, argv);
 
@@ -4738,7 +4412,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
         if (!t)
                 return -ENOMEM;
 
-        fn = file_name_from_path(path);
+        fn = path_get_file_name(path);
         k = fn-path;
         memcpy(t, path, k);
         t[k] = '.';
@@ -4854,306 +4528,6 @@ int vt_disallocate(const char *name) {
         return 0;
 }
 
-static int files_add(Hashmap *h, const char *path, const char *suffix) {
-        DIR *dir;
-        struct dirent buffer, *de;
-        int r = 0;
-
-        dir = opendir(path);
-        if (!dir) {
-                if (errno == ENOENT)
-                        return 0;
-                return -errno;
-        }
-
-        for (;;) {
-                int k;
-                char *p, *f;
-
-                k = readdir_r(dir, &buffer, &de);
-                if (k != 0) {
-                        r = -k;
-                        goto finish;
-                }
-
-                if (!de)
-                        break;
-
-                if (!dirent_is_file_with_suffix(de, suffix))
-                        continue;
-
-                if (asprintf(&p, "%s/%s", path, de->d_name) < 0) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                f = canonicalize_file_name(p);
-                if (!f) {
-                        log_error("Failed to canonicalize file name '%s': %m", p);
-                        free(p);
-                        continue;
-                }
-                free(p);
-
-                log_debug("found: %s\n", f);
-                if (hashmap_put(h, file_name_from_path(f), f) <= 0)
-                        free(f);
-        }
-
-finish:
-        closedir(dir);
-        return r;
-}
-
-static int base_cmp(const void *a, const void *b) {
-        const char *s1, *s2;
-
-        s1 = *(char * const *)a;
-        s2 = *(char * const *)b;
-        return strcmp(file_name_from_path(s1), file_name_from_path(s2));
-}
-
-int conf_files_list(char ***strv, const char *suffix, const char *dir, ...) {
-        Hashmap *fh = NULL;
-        char **dirs = NULL;
-        char **files = NULL;
-        char **p;
-        va_list ap;
-        int r = 0;
-
-        va_start(ap, dir);
-        dirs = strv_new_ap(dir, ap);
-        va_end(ap);
-        if (!dirs) {
-                r = -ENOMEM;
-                goto finish;
-        }
-        if (!strv_path_canonicalize(dirs)) {
-                r = -ENOMEM;
-                goto finish;
-        }
-        if (!strv_uniq(dirs)) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        fh = hashmap_new(string_hash_func, string_compare_func);
-        if (!fh) {
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        STRV_FOREACH(p, dirs) {
-                if (files_add(fh, *p, suffix) < 0) {
-                        log_error("Failed to search for files.");
-                        r = -EINVAL;
-                        goto finish;
-                }
-        }
-
-        files = hashmap_get_strv(fh);
-        if (files == NULL) {
-                log_error("Failed to compose list of files.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
-
-finish:
-        strv_free(dirs);
-        hashmap_free(fh);
-        *strv = files;
-        return r;
-}
-
-int hwclock_is_localtime(void) {
-        FILE *f;
-        bool local = false;
-
-        /*
-         * The third line of adjtime is "UTC" or "LOCAL" or nothing.
-         *   # /etc/adjtime
-         *   0.0 0 0
-         *   0
-         *   UTC
-         */
-        f = fopen("/etc/adjtime", "re");
-        if (f) {
-                char line[LINE_MAX];
-                bool b;
-
-                b = fgets(line, sizeof(line), f) &&
-                        fgets(line, sizeof(line), f) &&
-                        fgets(line, sizeof(line), f);
-
-                fclose(f);
-
-                if (!b)
-                        return -EIO;
-
-
-                truncate_nl(line);
-                local = streq(line, "LOCAL");
-
-        } else if (errno != -ENOENT)
-                return -errno;
-
-        return local;
-}
-
-int hwclock_apply_localtime_delta(int *min) {
-        const struct timeval *tv_null = NULL;
-        struct timespec ts;
-        struct tm *tm;
-        int minuteswest;
-        struct timezone tz;
-
-        assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
-        assert_se(tm = localtime(&ts.tv_sec));
-        minuteswest = tm->tm_gmtoff / 60;
-
-        tz.tz_minuteswest = -minuteswest;
-        tz.tz_dsttime = 0; /* DST_NONE*/
-
-        /*
-         * If the hardware clock does not run in UTC, but in local time:
-         * The very first time we set the kernel's timezone, it will warp
-         * the clock so that it runs in UTC instead of local time.
-         */
-        if (settimeofday(tv_null, &tz) < 0)
-                return -errno;
-        if (min)
-                *min = minuteswest;
-        return 0;
-}
-
-int hwclock_reset_localtime_delta(void) {
-        const struct timeval *tv_null = NULL;
-        struct timezone tz;
-
-        tz.tz_minuteswest = 0;
-        tz.tz_dsttime = 0; /* DST_NONE*/
-
-        if (settimeofday(tv_null, &tz) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int rtc_open(int flags) {
-        int fd;
-        DIR *d;
-
-        /* First, we try to make use of the /dev/rtc symlink. If that
-         * doesn't exist, we open the first RTC which has hctosys=1
-         * set. If we don't find any we just take the first RTC that
-         * exists at all. */
-
-        fd = open("/dev/rtc", flags);
-        if (fd >= 0)
-                return fd;
-
-        d = opendir("/sys/class/rtc");
-        if (!d)
-                goto fallback;
-
-        for (;;) {
-                char *p, *v;
-                struct dirent buf, *de;
-                int r;
-
-                r = readdir_r(d, &buf, &de);
-                if (r != 0)
-                        goto fallback;
-
-                if (!de)
-                        goto fallback;
-
-                if (ignore_file(de->d_name))
-                        continue;
-
-                p = join("/sys/class/rtc/", de->d_name, "/hctosys", NULL);
-                if (!p) {
-                        closedir(d);
-                        return -ENOMEM;
-                }
-
-                r = read_one_line_file(p, &v);
-                free(p);
-
-                if (r < 0)
-                        continue;
-
-                r = parse_boolean(v);
-                free(v);
-
-                if (r <= 0)
-                        continue;
-
-                p = strappend("/dev/", de->d_name);
-                fd = open(p, flags);
-                free(p);
-
-                if (fd >= 0) {
-                        closedir(d);
-                        return fd;
-                }
-        }
-
-fallback:
-        if (d)
-                closedir(d);
-
-        fd = open("/dev/rtc0", flags);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-int hwclock_get_time(struct tm *tm) {
-        int fd;
-        int err = 0;
-
-        assert(tm);
-
-        fd = rtc_open(O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        /* This leaves the timezone fields of struct tm
-         * uninitialized! */
-        if (ioctl(fd, RTC_RD_TIME, tm) < 0)
-                err = -errno;
-
-        /* We don't now daylight saving, so we reset this in order not
-         * to confused mktime(). */
-        tm->tm_isdst = -1;
-
-        close_nointr_nofail(fd);
-
-        return err;
-}
-
-int hwclock_set_time(const struct tm *tm) {
-        int fd;
-        int err = 0;
-
-        assert(tm);
-
-        fd = rtc_open(O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        if (ioctl(fd, RTC_SET_TIME, tm) < 0)
-                err = -errno;
-
-        close_nointr_nofail(fd);
-
-        return err;
-}
-
 int copy_file(const char *from, const char *to) {
         int r, fdf, fdt;
 
@@ -5220,8 +4594,8 @@ int symlink_or_copy(const char *from, const char *to) {
         assert(from);
         assert(to);
 
-        if (parent_of_path(from, &pf) < 0 ||
-            parent_of_path(to, &pt) < 0) {
+        if (path_get_parent(from, &pf) < 0 ||
+            path_get_parent(to, &pt) < 0) {
                 r = -ENOMEM;
                 goto finish;
         }
@@ -5268,7 +4642,7 @@ int symlink_or_copy_atomic(const char *from, const char *to) {
         if (!t)
                 return -ENOMEM;
 
-        fn = file_name_from_path(to);
+        fn = path_get_file_name(to);
         k = fn-to;
         memcpy(t, to, k);
         t[k] = '.';
@@ -5510,7 +4884,7 @@ int in_search_path(const char *path, char **search) {
         char **i, *parent;
         int r;
 
-        r = parent_of_path(path, &parent);
+        r = path_get_parent(path, &parent);
         if (r < 0)
                 return r;
 
@@ -6149,13 +5523,141 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
         return 0;
 }
 
-int path_is_read_only_fs(const char *path) {
-        struct statvfs st;
+int getenv_for_pid(pid_t pid, const char *field, char **_value) {
+        char path[sizeof("/proc/")-1+10+sizeof("/environ")], *value = NULL;
+        int r;
+        FILE *f;
+        bool done = false;
+        size_t l;
+
+        assert(field);
+        assert(_value);
 
-        assert(path);
+        if (pid == 0)
+                pid = getpid();
+
+        snprintf(path, sizeof(path), "/proc/%lu/environ", (unsigned long) pid);
+        char_array_0(path);
 
-        if (statvfs(path, &st) < 0)
+        f = fopen(path, "re");
+        if (!f)
                 return -errno;
 
-        return !!(st.f_flag & ST_RDONLY);
+        l = strlen(field);
+        r = 0;
+
+        do {
+                char line[LINE_MAX];
+                unsigned i;
+
+                for (i = 0; i < sizeof(line)-1; i++) {
+                        int c;
+
+                        c = getc(f);
+                        if (_unlikely_(c == EOF)) {
+                                done = true;
+                                break;
+                        } else if (c == 0)
+                                break;
+
+                        line[i] = c;
+                }
+                line[i] = 0;
+
+                if (memcmp(line, field, l) == 0 && line[l] == '=') {
+                        value = strdup(line + l + 1);
+                        if (!value) {
+                                r = -ENOMEM;
+                                break;
+                        }
+
+                        r = 1;
+                        break;
+                }
+
+        } while (!done);
+
+        fclose(f);
+
+        if (r >= 0)
+                *_value = value;
+
+        return r;
+}
+
+int can_sleep(const char *type) {
+        char *p, *w, *state;
+        size_t l, k;
+        bool found = false;
+        int r;
+
+        assert(type);
+
+        r = read_one_line_file("/sys/power/state", &p);
+        if (r < 0)
+                return r == -ENOENT ? 0 : r;
+
+        k = strlen(type);
+
+        FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
+                if (l == k && strncmp(w, type, l) == 0) {
+                        found = true;
+                        break;
+                }
+        }
+
+        free(p);
+        return found;
+}
+
+bool is_valid_documentation_url(const char *url) {
+        assert(url);
+
+        if (startswith(url, "http://") && url[7])
+                return true;
+
+        if (startswith(url, "https://") && url[8])
+                return true;
+
+        if (startswith(url, "file:") && url[5])
+                return true;
+
+        if (startswith(url, "info:") && url[5])
+                return true;
+
+        if (startswith(url, "man:") && url[4])
+                return true;
+
+        return false;
+}
+
+bool in_initrd(void) {
+        static int saved = -1;
+
+        if (saved < 0)
+                saved = access("/etc/initrd-release", F_OK) >= 0;
+
+        return saved;
+}
+
+void warn_melody(void) {
+        int fd;
+
+        fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+        if (fd < 0)
+                return;
+
+        /* Yeah, this is synchronous. Kinda sucks. Bute well... */
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/440));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, 0);
+        close_nointr_nofail(fd);
 }