Skip to content

Commit

Permalink
Merge pull request #57 from containers/rm_switchroot
Browse files Browse the repository at this point in the history
Remove switchroot code
  • Loading branch information
ericcurtin authored Jan 19, 2024
2 parents 9170124 + 10f3029 commit 2aec723
Showing 1 changed file with 0 additions and 236 deletions.
236 changes: 0 additions & 236 deletions storage-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@
exit(errno); \
} while (0)

static inline void execl_single_arg(const char* exe) {
printd("execl_single_arg(\"%s\")\n", exe);
execl(exe, exe, (char*)NULL);
}

static inline long loop_ctl_get_free(void) {
autoclose const int loopctlfd = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
if (loopctlfd < 0) {
Expand Down Expand Up @@ -181,230 +176,6 @@ static inline int losetup(char** loopdev, const char* file) {
return 0;
}

static inline int recursive_rm(const int fd);

static inline int if_directory(const int dfd,
const struct dirent* d,
const struct stat* rb,
int* isdir) {
struct stat sb;
if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
print("stat of %s failed\n", d->d_name);
return 1;
}

/* skip if device is not the same */
if (sb.st_dev != rb->st_dev)
return 1;

/* remove subdirectories */
if (S_ISDIR(sb.st_mode)) {
autoclose const int cfd = openat(dfd, d->d_name, O_RDONLY);
if (cfd >= 0)
recursive_rm(cfd); /* it closes cfd too */

*isdir = 1;
}

return 0;
}

static inline int for_each_directory(DIR* dir,
const int dfd,
const struct stat* rb) {
errno = 0;
struct dirent* d = readdir(dir);
if (!d) {
if (errno) {
print("failed to read directory\n");
return -1;
}

return 0; /* end of directory */
}

if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..") ||
!strcmp(d->d_name, "initoverlayfs"))
return 1;

int isdir = 0;
if (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN)
if (if_directory(dfd, d, rb, &isdir))
return 1;

if (unlinkat(dfd, d->d_name, isdir ? AT_REMOVEDIR : 0))
print("failed to unlink %s\n", d->d_name);

return 1;
}

/* remove all files/directories below dirName -- don't cross mountpoints */
static inline int recursive_rm(const int fd) {
autoclosedir DIR* dir = fdopendir(fd);
if (!dir) {
print("failed to open directory\n");
return -1;
}

struct stat rb;
const int dfd = dirfd(dir);
if (fstat(dfd, &rb)) {
print("stat failed\n");
return -1;
}

while (1) {
const int ret = for_each_directory(dir, dfd, &rb);
if (ret <= 0)
return ret;
}

return 0;
}

static inline int move_chroot_chdir(const char* newroot) {
printd("move_chroot_chdir(\"%s\")\n", newroot);
if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) {
print("failed to mount moving %s to /\n", newroot);
return -1;
}

if (chroot(".")) {
print("failed to change root\n");
return -1;
}

if (chdir("/")) {
print("cannot change directory to %s\n", "/");
return -1;
}

return 0;
}

static inline int switchroot_move(const char* newroot) {
if (chdir(newroot)) {
print("failed to change directory to %s", newroot);
return -1;
}

autoclose const int cfd = open("/", O_RDONLY | O_CLOEXEC);
if (cfd < 0) {
print("cannot open %s", "/");
return -1;
}

if (move_chroot_chdir(newroot))
return -1;

switch (fork()) {
case 0: /* child */
{
struct statfs stfs;
if (fstatfs(cfd, &stfs) == 0 &&
(stfs.f_type == RAMFS_MAGIC || stfs.f_type == TMPFS_MAGIC)) {
recursive_rm(cfd);
} else
print("old root filesystem is not an initramfs");

exit(EXIT_SUCCESS);
}
case -1: /* error */
break;

default: /* parent */
return 0;
}

return -1;
}

static inline int stat_oldroot_newroot(const char* newroot,
struct stat* newroot_stat,
struct stat* oldroot_stat) {
if (stat("/", oldroot_stat) != 0) {
print("stat of %s failed\n", "/");
return -1;
}

if (stat(newroot, newroot_stat) != 0) {
print("stat of %s failed\n", newroot);
return -1;
}

return 0;
}

static inline 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};
struct stat newroot_stat, oldroot_stat, sb;
if (stat_oldroot_newroot(newroot, &newroot_stat, &oldroot_stat))
return -1;

for (int i = 0; umounts[i] != NULL; ++i) {
autofree char* newmount;
if (asprintf(&newmount, "%s%s", newroot, umounts[i]) < 0) {
print(
"asprintf(%p, \"%%s%%s\", \"%s\", \"%s\") MS_NODEV, NULL) %d (%s)\n",
(void*)newmount, newroot, umounts[i], errno, strerror(errno));
return -1;
}

if ((stat(umounts[i], &sb) == 0) && sb.st_dev == oldroot_stat.st_dev) {
/* mount point to move seems to be a normal directory or stat failed */
continue;
}

printd("(stat(\"%s\", %p) == 0) && %lx != %lx)\n", newmount, (void*)&sb,
sb.st_dev, newroot_stat.st_dev);
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;
}

printd("mount(\"%s\", \"%s\", NULL, MS_MOVE, NULL)\n", umounts[i],
newmount);
if (mount(umounts[i], newmount, NULL, MS_MOVE, NULL) < 0) {
print("failed to mount moving %s to %s, forcing unmount\n", umounts[i],
newmount);
umount2(umounts[i], MNT_FORCE);
}
}

return switchroot_move(newroot);
}

static inline int mount_proc_sys_dev(void) {
if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) {
print(
"mount(\"proc\", \"/proc\", \"proc\", MS_NOSUID | MS_NOEXEC | "
"MS_NODEV, NULL) %d (%s)\n",
errno, strerror(errno));
return errno;
}

if (mount("sysfs", "/sys", "sysfs", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) {
print(
"mount(\"sysfs\", \"/sys\", \"sysfs\", MS_NOSUID | MS_NOEXEC | "
"MS_NODEV, NULL) %d (%s)\n",
errno, strerror(errno));
return errno;
}

if (mount("devtmpfs", "/dev", "devtmpfs", MS_NOSUID | MS_STRICTATIME,
"mode=0755,size=4m")) {
print(
"mount(\"devtmpfs\", \"/dev\", \"devtmpfs\", MS_NOSUID | "
"MS_STRICTATIME, \"mode=0755,size=4m\") %d (%s)\n",
errno, strerror(errno));
return errno;
}

return 0;
}

static inline bool convert_bootfs(conf* c) {
if (!c->bootfs.val->c_str) {
print("c->bootfs.val.c_str pointer is null\n");
Expand Down Expand Up @@ -562,13 +333,6 @@ void wait_mount_bootfs(const conf* c) {
c->bootfs.val->c_str, c->bootfstype.val->c_str, errno, strerror(errno));
}

void exec_init(void) {
execl_single_arg("/sbin/init");
execl_single_arg("/etc/init");
execl_single_arg("/bin/init");
execl_single_arg("/bin/sh");
}

int main(void) {
pid_t loop_pid;
fork_execl_no_wait(loop_pid, "/usr/sbin/modprobe", "loop");
Expand Down

0 comments on commit 2aec723

Please sign in to comment.