Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove switchroot code #57

Merged
merged 1 commit into from
Jan 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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