chiark / gitweb /
machined: make image read-only check indepenednt on own privs
[elogind.git] / src / machine / image.c
index 8f577adb59c36044aedc29c945c6cf2d5b0e38b2..8a119e5db71abea5b315507b1523d8a5eab6ad71 100644 (file)
 #include "strv.h"
 #include "utf8.h"
 #include "btrfs-util.h"
+#include "path-util.h"
 #include "image.h"
-#include "bus-label.h"
 
 static const char image_search_path[] =
+        "/var/lib/machines\0"
         "/var/lib/container\0"
-        "/var/lib/machine\0";
+        "/usr/local/lib/machines\0"
+        "/usr/lib/machines\0";
 
 Image *image_unref(Image *i) {
         if (!i)
@@ -43,18 +45,20 @@ Image *image_unref(Image *i) {
 
 static int image_new(
                 ImageType t,
-                const char *name,
+                const char *pretty,
                 const char *path,
+                const char *filename,
                 bool read_only,
+                usec_t crtime,
                 usec_t mtime,
-                usec_t btime,
                 Image **ret) {
 
         _cleanup_(image_unrefp) Image *i = NULL;
 
         assert(t >= 0);
         assert(t < _IMAGE_TYPE_MAX);
-        assert(name);
+        assert(pretty);
+        assert(filename);
         assert(ret);
 
         i = new0(Image, 1);
@@ -63,18 +67,22 @@ static int image_new(
 
         i->type = t;
         i->read_only = read_only;
+        i->crtime = crtime;
         i->mtime = mtime;
-        i->btime = btime;
 
-        i->name = strdup(name);
+        i->name = strdup(pretty);
         if (!i->name)
                 return -ENOMEM;
 
-        if (path) {
-                i->path = strdup(path);
-                if (!i->path)
-                        return -ENOMEM;
-        }
+        if (path)
+                i->path = strjoin(path, "/", filename, NULL);
+        else
+                i->path = strdup(filename);
+
+        if (!i->path)
+                return -ENOMEM;
+
+        path_kill_slashes(i->path);
 
         *ret = i;
         i = NULL;
@@ -82,31 +90,44 @@ static int image_new(
         return 0;
 }
 
-static int image_make(int dfd, const char *name, const char *path, Image **ret) {
+static int image_make(
+                const char *pretty,
+                int dfd,
+                const char *path,
+                const char *filename,
+                Image **ret) {
+
         struct stat st;
+        bool read_only;
         int r;
 
-        assert(dfd >= 0);
-        assert(name);
+        assert(filename);
 
         /* We explicitly *do* follow symlinks here, since we want to
          * allow symlinking trees into /var/lib/container/, and treat
          * them normally. */
 
-        if (fstatat(dfd, name, &st, 0) < 0)
+        if (fstatat(dfd, filename, &st, 0) < 0)
                 return -errno;
 
+        read_only =
+                (path && path_startswith(path, "/usr")) ||
+                (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
+
         if (S_ISDIR(st.st_mode)) {
 
                 if (!ret)
                         return 1;
 
+                if (!pretty)
+                        pretty = filename;
+
                 /* btrfs subvolumes have inode 256 */
                 if (st.st_ino == 256) {
                         _cleanup_close_ int fd = -1;
                         struct statfs sfs;
 
-                        fd = openat(dfd, name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
+                        fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
                         if (fd < 0)
                                 return -errno;
 
@@ -114,25 +135,21 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
                                 return -errno;
 
                         if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
-                                usec_t btime = 0;
-                                int ro;
+                                BtrfsSubvolInfo info;
 
                                 /* It's a btrfs subvolume */
 
-                                ro = btrfs_subvol_is_read_only_fd(fd);
-                                if (ro < 0)
-                                        return ro;
-
-                                /* r = btrfs_subvol_get_btime(fd, &btime); */
-                                /* if (r < 0) */
-                                /*         return r; */
+                                r = btrfs_subvol_get_info_fd(fd, &info);
+                                if (r < 0)
+                                        return r;
 
                                 r = image_new(IMAGE_SUBVOLUME,
-                                              name,
+                                              pretty,
                                               path,
-                                              ro,
+                                              filename,
+                                              info.read_only || read_only,
+                                              info.otime,
                                               0,
-                                              btime,
                                               ret);
                                 if (r < 0)
                                         return r;
@@ -144,9 +161,10 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
                 /* It's just a normal directory. */
 
                 r = image_new(IMAGE_DIRECTORY,
-                              name,
+                              pretty,
                               path,
-                              false,
+                              filename,
+                              read_only,
                               0,
                               0,
                               ret);
@@ -155,19 +173,26 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
 
                 return 1;
 
-        } else if (S_ISREG(st.st_mode) && endswith(name, ".gpt")) {
+        } else if (S_ISREG(st.st_mode) && endswith(filename, ".gpt")) {
+                usec_t crtime = 0;
 
                 /* It's a GPT block device */
 
                 if (!ret)
                         return 1;
 
+                fd_getcrtime_at(dfd, filename, &crtime, 0);
+
+                if (!pretty)
+                        pretty = strndupa(filename, strlen(filename) - 4);
+
                 r = image_new(IMAGE_GPT,
-                              name,
+                              pretty,
                               path,
-                              !!(st.st_mode & 0111),
+                              filename,
+                              !(st.st_mode & 0222) || read_only,
+                              crtime,
                               timespec_load(&st.st_mtim),
-                              0,
                               ret);
                 if (r < 0)
                         return r;
@@ -199,15 +224,27 @@ int image_find(const char *name, Image **ret) {
                         return -errno;
                 }
 
-                r = image_make(dirfd(d), name, path, ret);
-                if (r == 0 || r == -ENOENT)
-                        continue;
+                r = image_make(NULL, dirfd(d), path, name, ret);
+                if (r == 0 || r == -ENOENT) {
+                        _cleanup_free_ char *gpt = NULL;
+
+                        gpt = strappend(name, ".gpt");
+                        if (!gpt)
+                                return -ENOMEM;
+
+                        r = image_make(NULL, dirfd(d), path, gpt, ret);
+                        if (r == 0 || r == -ENOENT)
+                                continue;
+                }
                 if (r < 0)
                         return r;
 
                 return 1;
         }
 
+        if (streq(name, ".host"))
+                return image_make(NULL, AT_FDCWD, NULL, "/", ret);
+
         return 0;
 };
 
@@ -224,7 +261,7 @@ int image_discover(Hashmap *h) {
                 d = opendir(path);
                 if (!d) {
                         if (errno == ENOENT)
-                                return 0;
+                                continue;
 
                         return -errno;
                 }
@@ -238,7 +275,7 @@ int image_discover(Hashmap *h) {
                         if (hashmap_contains(h, de->d_name))
                                 continue;
 
-                        r = image_make(dirfd(d), de->d_name, path, &image);
+                        r = image_make(NULL, dirfd(d), path, de->d_name, &image);
                         if (r == 0 || r == -ENOENT)
                                 continue;
                         if (r < 0)
@@ -252,6 +289,21 @@ int image_discover(Hashmap *h) {
                 }
         }
 
+        if (!hashmap_contains(h, ".host")) {
+                _cleanup_(image_unrefp) Image *image = NULL;
+
+                r = image_make(".host", AT_FDCWD, NULL, "/", &image);
+                if (r < 0)
+                        return r;
+
+                r = hashmap_put(h, image->name, image);
+                if (r < 0)
+                        return r;
+
+                image = NULL;
+
+        }
+
         return 0;
 }
 
@@ -264,18 +316,6 @@ void image_hashmap_free(Hashmap *map) {
         hashmap_free(map);
 }
 
-char *image_bus_path(const char *name) {
-        _cleanup_free_ char *e = NULL;
-
-        assert(name);
-
-        e = bus_label_escape(name);
-        if (!e)
-                return NULL;
-
-        return strappend("/org/freedesktop/machine1/image/", e);
-}
-
 static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
         [IMAGE_DIRECTORY] = "directory",
         [IMAGE_SUBVOLUME] = "subvolume",