static int check_btrfs(void) { struct statfs sfs; if (statfs("/var/lib/machines", &sfs) < 0) { if (errno != ENOENT) return -errno; if (statfs("/var/lib", &sfs) < 0) return -errno; } return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); }
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(filename); /* We explicitly *do* follow symlinks here, since we want to * allow symlinking trees into /var/lib/machines/, and treat * them normally. */ 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)) { _cleanup_close_ int fd = -1; unsigned file_attr = 0; if (!ret) return 1; if (!pretty) pretty = filename; fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY); if (fd < 0) return -errno; /* btrfs subvolumes have inode 256 */ if (st.st_ino == 256) { struct statfs sfs; if (fstatfs(fd, &sfs) < 0) return -errno; if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { BtrfsSubvolInfo info; BtrfsQuotaInfo quota; /* It's a btrfs subvolume */ r = btrfs_subvol_get_info_fd(fd, &info); if (r < 0) return r; r = image_new(IMAGE_SUBVOLUME, pretty, path, filename, info.read_only || read_only, info.otime, 0, ret); if (r < 0) return r; r = btrfs_subvol_get_quota_fd(fd, "a); if (r >= 0) { (*ret)->usage = quota.referred; (*ret)->usage_exclusive = quota.exclusive; (*ret)->limit = quota.referred_max; (*ret)->limit_exclusive = quota.exclusive_max; } return 1; } } /* If the IMMUTABLE bit is set, we consider the * directory read-only. Since the ioctl is not * supported everywhere we ignore failures. */ (void) read_attr_fd(fd, &file_attr); /* It's just a normal directory. */ r = image_new(IMAGE_DIRECTORY, pretty, path, filename, read_only || (file_attr & FS_IMMUTABLE_FL), 0, 0, ret); if (r < 0) return r; return 1; } else if (S_ISREG(st.st_mode) && endswith(filename, ".raw")) { usec_t crtime = 0; /* It's a RAW disk image */ if (!ret) return 1; fd_getcrtime_at(dfd, filename, &crtime, 0); if (!pretty) pretty = strndupa(filename, strlen(filename) - 4); r = image_new(IMAGE_RAW, pretty, path, filename, !(st.st_mode & 0222) || read_only, crtime, timespec_load(&st.st_mtim), ret); if (r < 0) return r; (*ret)->usage = (*ret)->usage_exclusive = st.st_blocks * 512; (*ret)->limit = (*ret)->limit_exclusive = st.st_size; return 1; } return 0; }
static int switchroot(const char *newroot) { /* Don't try to unmount the old "/", there's no way to do it. */ const char *umounts[] = { "/dev", "/proc", "/sys", "/run", NULL }; int i; int cfd; pid_t pid; struct stat newroot_stat, sb; if (stat(newroot, &newroot_stat) != 0) { warn(_("stat failed %s"), newroot); return -1; } for (i = 0; umounts[i] != NULL; i++) { char newmount[PATH_MAX]; snprintf(newmount, sizeof(newmount), "%s%s", newroot, umounts[i]); if ((stat(newmount, &sb) != 0) || (sb.st_dev != newroot_stat.st_dev)) { /* mount point seems to be mounted already or stat failed */ umount2(umounts[i], MNT_DETACH); continue; } if (mount(umounts[i], newmount, NULL, MS_MOVE, NULL) < 0) { warn(_("failed to mount moving %s to %s"), umounts[i], newmount); warnx(_("forcing unmount of %s"), umounts[i]); umount2(umounts[i], MNT_FORCE); } } if (chdir(newroot)) { warn(_("failed to change directory to %s"), newroot); return -1; } cfd = open("/", O_RDONLY); if (cfd < 0) { warn(_("cannot open %s"), "/"); return -1; } if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) { close(cfd); warn(_("failed to mount moving %s to /"), newroot); return -1; } if (chroot(".")) { close(cfd); warn(_("failed to change root")); return -1; } if (cfd >= 0) { pid = fork(); if (pid <= 0) { struct statfs stfs; if (fstatfs(cfd, &stfs) == 0 && (F_TYPE_EQUAL(stfs.f_type, STATFS_RAMFS_MAGIC) || F_TYPE_EQUAL(stfs.f_type, STATFS_TMPFS_MAGIC))) recursiveRemove(cfd); else warn(_("old root filesystem is not an initramfs")); if (pid == 0) exit(EXIT_SUCCESS); } close(cfd); } return 0; }
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { assert(s); assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type)); return F_TYPE_EQUAL(s->f_type, magic_value); }