X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fmachine-image.c;h=36b64e1fab8fec9cf0f6db88157f78c1509cd52a;hp=51f89d5921bcaba3893048092b5a3928fbc0f1b1;hb=b6b1849830f5e4a6065c3b0c993668e500c954d3;hpb=003dffde2c1b93afbc9aff24b277276f65424406 diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 51f89d592..36b64e1fa 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -20,11 +20,13 @@ ***/ #include +#include #include "strv.h" #include "utf8.h" #include "btrfs-util.h" #include "path-util.h" +#include "copy.h" #include "machine-image.h" static const char image_search_path[] = @@ -69,6 +71,8 @@ static int image_new( i->read_only = read_only; i->crtime = crtime; i->mtime = mtime; + i->size = i->size_exclusive = (uint64_t) -1; + i->limit = i->limit_exclusive = (uint64_t) -1; i->name = strdup(pretty); if (!i->name) @@ -136,6 +140,7 @@ static int image_make( if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { BtrfsSubvolInfo info; + BtrfsQuotaInfo quota; /* It's a btrfs subvolume */ @@ -154,6 +159,15 @@ static int image_make( if (r < 0) return r; + r = btrfs_subvol_get_quota_fd(fd, "a); + if (r >= 0) { + (*ret)->size = quota.referred; + (*ret)->size_exclusive = quota.exclusive; + + (*ret)->limit = quota.referred_max; + (*ret)->limit_exclusive = quota.exclusive_max; + } + return 1; } } @@ -197,6 +211,9 @@ static int image_make( if (r < 0) return r; + (*ret)->size = (*ret)->size_exclusive = st.st_blocks * 512; + (*ret)->limit = (*ret)->limit_exclusive = st.st_size; + return 1; } @@ -316,6 +333,161 @@ void image_hashmap_free(Hashmap *map) { hashmap_free(map); } +int image_remove(Image *i) { + assert(i); + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + return btrfs_subvol_remove(i->path); + + case IMAGE_DIRECTORY: + case IMAGE_GPT: + return rm_rf_dangerous(i->path, false, true, false); + + default: + return -ENOTSUP; + } +} + +int image_rename(Image *i, const char *new_name) { + _cleanup_free_ char *new_path = NULL, *nn = NULL; + int r; + + assert(i); + + if (!image_name_is_valid(new_name)) + return -EINVAL; + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + r = image_find(new_name, NULL); + if (r < 0) + return r; + if (r > 0) + return -EEXIST; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + case IMAGE_DIRECTORY: + new_path = file_in_same_dir(i->path, new_name); + break; + + case IMAGE_GPT: { + const char *fn; + + fn = strappenda(new_name, ".gpt"); + new_path = file_in_same_dir(i->path, fn); + break; + } + + default: + return -ENOTSUP; + } + + if (!new_path) + return -ENOMEM; + + nn = strdup(new_name); + if (!nn) + return -ENOMEM; + + if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0) + return -errno; + + free(i->path); + i->path = new_path; + new_path = NULL; + + free(i->name); + i->name = nn; + nn = NULL; + + return 0; +} + +int image_clone(Image *i, const char *new_name, bool read_only) { + const char *new_path; + int r; + + assert(i); + + if (!image_name_is_valid(new_name)) + return -EINVAL; + + r = image_find(new_name, NULL); + if (r < 0) + return r; + if (r > 0) + return -EEXIST; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + case IMAGE_DIRECTORY: + new_path = strappenda("/var/lib/container/", new_name); + + r = btrfs_subvol_snapshot(i->path, new_path, read_only, true); + break; + + case IMAGE_GPT: + new_path = strappenda("/var/lib/container/", new_name, ".gpt"); + + r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false); + break; + + default: + return -ENOTSUP; + } + + if (r < 0) + return r; + + return 0; +} + +int image_read_only(Image *i, bool b) { + int r; + assert(i); + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + r = btrfs_subvol_set_read_only(i->path, b); + if (r < 0) + return r; + break; + + case IMAGE_GPT: { + struct stat st; + + if (stat(i->path, &st) < 0) + return -errno; + + if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0) + return -errno; + break; + } + + case IMAGE_DIRECTORY: + default: + return -ENOTSUP; + } + + return 0; +} + static const char* const image_type_table[_IMAGE_TYPE_MAX] = { [IMAGE_DIRECTORY] = "directory", [IMAGE_SUBVOLUME] = "subvolume",