1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/statfs.h>
28 #include "btrfs-util.h"
29 #include "path-util.h"
31 #include "machine-image.h"
33 static const char image_search_path[] =
35 "/var/lib/container\0"
36 "/usr/local/lib/machines\0"
37 "/usr/lib/machines\0";
39 Image *image_unref(Image *i) {
59 _cleanup_(image_unrefp) Image *i = NULL;
62 assert(t < _IMAGE_TYPE_MAX);
72 i->read_only = read_only;
75 i->size = i->size_exclusive = (uint64_t) -1;
76 i->limit = i->limit_exclusive = (uint64_t) -1;
78 i->name = strdup(pretty);
83 i->path = strjoin(path, "/", filename, NULL);
85 i->path = strdup(filename);
90 path_kill_slashes(i->path);
98 static int image_make(
102 const char *filename,
111 /* We explicitly *do* follow symlinks here, since we want to
112 * allow symlinking trees into /var/lib/container/, and treat
115 if (fstatat(dfd, filename, &st, 0) < 0)
119 (path && path_startswith(path, "/usr")) ||
120 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
122 if (S_ISDIR(st.st_mode)) {
123 _cleanup_close_ int fd = -1;
124 unsigned file_attr = 0;
132 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
136 /* btrfs subvolumes have inode 256 */
137 if (st.st_ino == 256) {
140 if (fstatfs(fd, &sfs) < 0)
143 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
144 BtrfsSubvolInfo info;
145 BtrfsQuotaInfo quota;
147 /* It's a btrfs subvolume */
149 r = btrfs_subvol_get_info_fd(fd, &info);
153 r = image_new(IMAGE_SUBVOLUME,
157 info.read_only || read_only,
164 r = btrfs_subvol_get_quota_fd(fd, "a);
166 (*ret)->size = quota.referred;
167 (*ret)->size_exclusive = quota.exclusive;
169 (*ret)->limit = quota.referred_max;
170 (*ret)->limit_exclusive = quota.exclusive_max;
177 /* If the IMMUTABLE bit is set, we consider the
178 * directory read-only. Since the ioctl is not
179 * supported everywhere we ignore failures. */
180 (void) read_attr_fd(fd, &file_attr);
182 /* It's just a normal directory. */
183 r = image_new(IMAGE_DIRECTORY,
187 read_only || (file_attr & FS_IMMUTABLE_FL),
196 } else if (S_ISREG(st.st_mode) && endswith(filename, ".gpt")) {
199 /* It's a GPT block device */
204 fd_getcrtime_at(dfd, filename, &crtime, 0);
207 pretty = strndupa(filename, strlen(filename) - 4);
209 r = image_new(IMAGE_GPT,
213 !(st.st_mode & 0222) || read_only,
215 timespec_load(&st.st_mtim),
220 (*ret)->size = (*ret)->size_exclusive = st.st_blocks * 512;
221 (*ret)->limit = (*ret)->limit_exclusive = st.st_size;
229 int image_find(const char *name, Image **ret) {
235 /* There are no images with invalid names */
236 if (!image_name_is_valid(name))
239 NULSTR_FOREACH(path, image_search_path) {
240 _cleanup_closedir_ DIR *d = NULL;
250 r = image_make(NULL, dirfd(d), path, name, ret);
251 if (r == 0 || r == -ENOENT) {
252 _cleanup_free_ char *gpt = NULL;
254 gpt = strappend(name, ".gpt");
258 r = image_make(NULL, dirfd(d), path, gpt, ret);
259 if (r == 0 || r == -ENOENT)
268 if (streq(name, ".host"))
269 return image_make(".host", AT_FDCWD, NULL, "/", ret);
274 int image_discover(Hashmap *h) {
280 NULSTR_FOREACH(path, image_search_path) {
281 _cleanup_closedir_ DIR *d = NULL;
292 FOREACH_DIRENT_ALL(de, d, return -errno) {
293 _cleanup_(image_unrefp) Image *image = NULL;
295 if (!image_name_is_valid(de->d_name))
298 if (hashmap_contains(h, de->d_name))
301 r = image_make(NULL, dirfd(d), path, de->d_name, &image);
302 if (r == 0 || r == -ENOENT)
307 r = hashmap_put(h, image->name, image);
315 if (!hashmap_contains(h, ".host")) {
316 _cleanup_(image_unrefp) Image *image = NULL;
318 r = image_make(".host", AT_FDCWD, NULL, "/", &image);
322 r = hashmap_put(h, image->name, image);
333 void image_hashmap_free(Hashmap *map) {
336 while ((i = hashmap_steal_first(map)))
342 int image_remove(Image *i) {
345 if (path_equal(i->path, "/") ||
346 path_startswith(i->path, "/usr"))
351 case IMAGE_SUBVOLUME:
352 return btrfs_subvol_remove(i->path);
354 case IMAGE_DIRECTORY:
355 /* Allow deletion of read-only directories */
356 (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
361 return rm_rf_dangerous(i->path, false, true, false);
368 int image_rename(Image *i, const char *new_name) {
369 _cleanup_free_ char *new_path = NULL, *nn = NULL;
370 unsigned file_attr = 0;
375 if (!image_name_is_valid(new_name))
378 if (path_equal(i->path, "/") ||
379 path_startswith(i->path, "/usr"))
382 r = image_find(new_name, NULL);
390 case IMAGE_DIRECTORY:
391 /* Turn of the immutable bit while we rename the image, so that we can rename it */
392 (void) read_attr_path(i->path, &file_attr);
394 if (file_attr & FS_IMMUTABLE_FL)
395 (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
399 case IMAGE_SUBVOLUME:
400 new_path = file_in_same_dir(i->path, new_name);
406 fn = strappenda(new_name, ".gpt");
407 new_path = file_in_same_dir(i->path, fn);
418 nn = strdup(new_name);
422 if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0)
425 /* Restore the immutable bit, if it was set before */
426 if (file_attr & FS_IMMUTABLE_FL)
427 (void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
440 int image_clone(Image *i, const char *new_name, bool read_only) {
441 const char *new_path;
446 if (!image_name_is_valid(new_name))
449 r = image_find(new_name, NULL);
457 case IMAGE_SUBVOLUME:
458 case IMAGE_DIRECTORY:
459 new_path = strappenda("/var/lib/container/", new_name);
461 r = btrfs_subvol_snapshot(i->path, new_path, read_only, true);
465 new_path = strappenda("/var/lib/container/", new_name, ".gpt");
467 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false, FS_NOCOW_FL);
480 int image_read_only(Image *i, bool b) {
484 if (path_equal(i->path, "/") ||
485 path_startswith(i->path, "/usr"))
490 case IMAGE_SUBVOLUME:
491 r = btrfs_subvol_set_read_only(i->path, b);
497 case IMAGE_DIRECTORY:
498 /* For simple directory trees we cannot use the access
499 mode of the top-level directory, since it has an
500 effect on the container itself. However, we can
501 use the "immutable" flag, to at least make the
502 top-level directory read-only. It's not as good as
503 a read-only subvolume, but at least something, and
504 we can read the value back.*/
506 r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
515 if (stat(i->path, &st) < 0)
518 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
521 /* If the images is now read-only, it's a good time to
522 * defrag it, given that no write patterns will
523 * fragment it again. */
525 (void) btrfs_defrag(i->path);
536 static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
537 [IMAGE_DIRECTORY] = "directory",
538 [IMAGE_SUBVOLUME] = "subvolume",
542 DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);