chiark / gitweb /
logind: properly clean up user cgroups when they run empty
[elogind.git] / src / shared / util.c
index ae0ce320ad40b5bb0ac4cab909096a27bc7d315f..67ec5ae747777d7121bb7a9626ea85fd471bf8d9 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/kd.h>
 #include <dlfcn.h>
 #include <sys/wait.h>
-#include <sys/capability.h>
 #include <sys/time.h>
 #include <glob.h>
 #include <grp.h>
@@ -2707,7 +2706,7 @@ int parse_usec(const char *t, usec_t *usec) {
                 { "m", USEC_PER_MINUTE },
                 { "usec", 1ULL },
                 { "us", 1ULL },
-                { "", USEC_PER_SEC },
+                { "", USEC_PER_SEC }, /* default is sec */
         };
 
         const char *p;
@@ -2753,6 +2752,71 @@ int parse_usec(const char *t, usec_t *usec) {
         return 0;
 }
 
+int parse_nsec(const char *t, nsec_t *nsec) {
+        static const struct {
+                const char *suffix;
+                nsec_t nsec;
+        } table[] = {
+                { "sec", NSEC_PER_SEC },
+                { "s", NSEC_PER_SEC },
+                { "min", NSEC_PER_MINUTE },
+                { "hr", NSEC_PER_HOUR },
+                { "h", NSEC_PER_HOUR },
+                { "d", NSEC_PER_DAY },
+                { "w", NSEC_PER_WEEK },
+                { "msec", NSEC_PER_MSEC },
+                { "ms", NSEC_PER_MSEC },
+                { "m", NSEC_PER_MINUTE },
+                { "usec", NSEC_PER_USEC },
+                { "us", NSEC_PER_USEC },
+                { "nsec", 1ULL },
+                { "ns", 1ULL },
+                { "", 1ULL }, /* default is nsec */
+        };
+
+        const char *p;
+        nsec_t r = 0;
+
+        assert(t);
+        assert(nsec);
+
+        p = t;
+        do {
+                long long l;
+                char *e;
+                unsigned i;
+
+                errno = 0;
+                l = strtoll(p, &e, 10);
+
+                if (errno != 0)
+                        return -errno;
+
+                if (l < 0)
+                        return -ERANGE;
+
+                if (e == p)
+                        return -EINVAL;
+
+                e += strspn(e, WHITESPACE);
+
+                for (i = 0; i < ELEMENTSOF(table); i++)
+                        if (startswith(e, table[i].suffix)) {
+                                r += (nsec_t) l * table[i].nsec;
+                                p = e + strlen(table[i].suffix);
+                                break;
+                        }
+
+                if (i >= ELEMENTSOF(table))
+                        return -EINVAL;
+
+        } while (*p != 0);
+
+        *nsec = r;
+
+        return 0;
+}
+
 int parse_bytes(const char *t, off_t *bytes) {
         static const struct {
                 const char *suffix;
@@ -2949,12 +3013,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;
@@ -3131,14 +3203,14 @@ 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. */
 
         d = fdopendir(fd);
         if (!d) {
@@ -3149,7 +3221,8 @@ 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;
 
                 r = readdir_r(d, &buf, &de);
@@ -3164,51 +3237,41 @@ 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|O_NOATIME);
+                        /* 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;
                         }
 
-                        r = rm_rf_children(subdir_fd, only_dirs, honour_sticky);
+                        r = rm_rf_children(subdir_fd, only_dirs, honour_sticky, root_dev);
                         if (r < 0 && ret == 0)
                                 ret = r;
 
@@ -3251,7 +3314,7 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
                 return 0;
         }
 
-        r = rm_rf_children(fd, only_dirs, honour_sticky);
+        r = rm_rf_children(fd, only_dirs, honour_sticky, NULL);
 
         if (delete_root) {
 
@@ -5631,3 +5694,34 @@ bool is_valid_documentation_url(const char *url) {
 
         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);
+}