[ostree] switchroot: Further work on being dracut-only
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] switchroot: Further work on being dracut-only
- Date: Wed, 8 Feb 2012 22:34:58 +0000 (UTC)
commit 0172ab5a3a7c8ea97e2abcc58eebbbcd71c01885
Author: Colin Walters <walters verbum org>
Date: Wed Feb 8 17:32:34 2012 -0500
switchroot: Further work on being dracut-only
src/switchroot/ostree-switch-root.c | 174 ++++++++++++++++++++++++++++++----
1 files changed, 153 insertions(+), 21 deletions(-)
---
diff --git a/src/switchroot/ostree-switch-root.c b/src/switchroot/ostree-switch-root.c
index 16be2b8..f02edd8 100644
--- a/src/switchroot/ostree-switch-root.c
+++ b/src/switchroot/ostree-switch-root.c
@@ -1,7 +1,14 @@
/* -*- c-file-style: "gnu" -*-
* Switch to new root directory and start init.
+ *
* Copyright 2011,2012 Colin Walters <walters verbum org>
*
+ * Based on code from util-linux/sys-utils/switch_root.c,
+ * Copyright 2002-2009 Red Hat, Inc. All rights reserved.
+ * Authors:
+ * Peter Jones <pjones redhat com>
+ * Jeremy Katz <katzj redhat com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -57,6 +64,89 @@ perrorv (const char *format, ...)
return 0;
}
+/* remove all files/directories below dirName -- don't cross mountpoints */
+static int
+recursive_remove (int fd)
+{
+ struct stat rb;
+ DIR *dir;
+ int rc = -1;
+ int dfd;
+
+ if (!(dir = fdopendir (fd)))
+ {
+ perrorv ("failed to open directory");
+ goto done;
+ }
+
+ /* fdopendir() precludes us from continuing to use the input fd */
+ dfd = dirfd (dir);
+
+ if (fstat(dfd, &rb))
+ {
+ perrorv("failed to stat directory");
+ goto done;
+ }
+
+ while (1)
+ {
+ struct dirent *d;
+
+ errno = 0;
+ if (!(d = readdir (dir)))
+ {
+ if (errno)
+ {
+ perrorv ("failed to read directory");
+ goto done;
+ }
+ break; /* end of directory */
+ }
+
+ if (!strcmp (d->d_name, ".") || !strcmp (d->d_name, ".."))
+ continue;
+
+ if (d->d_type == DT_DIR)
+ {
+ struct stat sb;
+
+ if (fstatat (dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW))
+ {
+ perrorv ("failed to stat %s", d->d_name);
+ continue;
+ }
+
+ /* remove subdirectories if device is same as dir */
+ if (sb.st_dev == rb.st_dev)
+ {
+ int cfd;
+
+ cfd = openat (dfd, d->d_name, O_RDONLY);
+ if (cfd >= 0)
+ {
+ recursive_remove (cfd);
+ close (cfd);
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ if (unlinkat (dfd, d->d_name,
+ d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
+ perrorv ("failed to unlink %s", d->d_name);
+ }
+
+ rc = 0; /* success */
+
+ done:
+ if (dir)
+ closedir (dir);
+ return rc;
+}
+
int
main(int argc, char *argv[])
{
@@ -65,14 +155,17 @@ main(int argc, char *argv[])
const char *ostree_bind_mounts[] = { "/var", NULL };
const char *readonly_bind_mounts[] = { "/bin", "/etc", "/lib", "/sbin", "/usr",
NULL };
- const char *ostree_root = NULL;
+ const char *root_mountpoint = NULL;
+ const char *ostree_target = NULL;
const char *ostree_subinit = NULL;
char srcpath[PATH_MAX];
char destpath[PATH_MAX];
struct stat stbuf;
char **init_argv = NULL;
+ int initramfs_fd;
int i;
int before_init_argc = 0;
+ pid_t cleanup_pid;
if (argc < 3)
{
@@ -81,47 +174,86 @@ main(int argc, char *argv[])
}
before_init_argc++;
- ostree_root = argv[1];
+ root_mountpoint = argv[1];
before_init_argc++;
- ostree_subinit = argv[2];
+ ostree_target = argv[2];
+ before_init_argc++;
+ ostree_subinit = argv[3];
before_init_argc++;
- snprintf (destpath, sizeof(destpath), "/ostree/%s", ostree_root);
+ snprintf (destpath, sizeof(destpath), "%s/ostree/%s",
+ root_mountpoint, ostree_target);
if (stat (destpath, &stbuf) < 0)
{
perrorv ("Invalid ostree root '%s'", destpath);
exit (1);
}
- snprintf (destpath, sizeof(destpath), "/ostree/%s/var", ostree_root);
- if (mount ("/ostree/var", destpath, NULL, MS_BIND, NULL) < 0)
+ for (i = 0; initramfs_move_mounts[i] != NULL; i++)
{
- perrorv ("Failed to bind mount / to '%s'", destpath);
+ const char *path = initramfs_move_mounts[i];
+ snprintf (srcpath, sizeof(srcpath), path);
+ snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target, path);
+ if (mount (srcpath, destpath, NULL, MS_MOVE, NULL) < 0)
+ {
+ perrorv ("failed to move mount of %s to %s", srcpath, destpath);
+ exit (1);
+ }
+ }
+
+ if (chdir (root_mountpoint) < 0)
+ {
+ perrorv ("failed to chdir to %s", root_mountpoint);
+ exit (1);
+ }
+
+ initramfs_fd = open ("/", O_RDONLY);
+
+ if (mount (root_mountpoint, "/", NULL, MS_MOVE, NULL) < 0)
+ {
+ perrorv ("failed move %s to /", root_mountpoint);
+ return -1;
+ }
+
+ if (chroot (".") < 0)
+ {
+ perrorv ("failed to chroot to .");
exit (1);
}
- snprintf (destpath, sizeof(destpath), "/ostree/%s/sysroot", ostree_root);
+ if (initramfs_fd >= 0)
+ {
+ cleanup_pid = fork ();
+ if (cleanup_pid == 0)
+ {
+ recursive_remove (initramfs_fd);
+ exit (0);
+ }
+ close (initramfs_fd);
+ }
+
+ /* From this point on we're chrooted into the real root filesystem,
+ * so we no longer refer to root_mountpoint.
+ */
+
+ snprintf (destpath, sizeof(destpath), "/ostree/%s/sysroot", ostree_target);
if (mount ("/", destpath, NULL, MS_BIND, NULL) < 0)
{
perrorv ("Failed to bind mount / to '%s'", destpath);
exit (1);
}
- for (i = 0; initramfs_move_mounts[i] != NULL; i++)
+ snprintf (srcpath, sizeof(srcpath), "%s", "/ostree/var");
+ snprintf (destpath, sizeof(destpath), "/ostree/%s/var", ostree_target);
+ if (mount (srcpath, destpath, NULL, MS_BIND, NULL) < 0)
{
- const char *path = initramfs_move_mounts[i];
- snprintf (srcpath, sizeof(srcpath), path);
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_root, path);
- if (mount (srcpath, destpath, NULL, MS_MOVE, NULL) < 0)
- {
- perrorv ("failed to move mount of %s to %s", srcpath, destpath);
- exit (1);
- }
+ perrorv ("Failed to bind mount '%s' to '%s'", srcpath, destpath);
+ exit (1);
}
for (i = 0; toproot_bind_mounts[i] != NULL; i++)
{
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_root, toproot_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target, toproot_bind_mounts[i]);
if (mount (toproot_bind_mounts[i], destpath, NULL, MS_BIND & ~MS_RDONLY, NULL) < 0)
{
perrorv ("failed to bind mount (class:toproot) %s to %s", toproot_bind_mounts[i], destpath);
@@ -132,7 +264,7 @@ main(int argc, char *argv[])
for (i = 0; ostree_bind_mounts[i] != NULL; i++)
{
snprintf (srcpath, sizeof(srcpath), "/ostree/%s", ostree_bind_mounts[i]);
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_root, ostree_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target, ostree_bind_mounts[i]);
if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount (class:bind) %s to %s", srcpath, destpath);
@@ -142,7 +274,7 @@ main(int argc, char *argv[])
for (i = 0; readonly_bind_mounts[i] != NULL; i++)
{
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_root, readonly_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target, readonly_bind_mounts[i]);
if (mount (destpath, destpath, NULL, MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount (class:readonly) %s", destpath);
@@ -155,7 +287,7 @@ main(int argc, char *argv[])
}
}
- snprintf (destpath, sizeof(destpath), "/ostree/%s", ostree_root);
+ snprintf (destpath, sizeof(destpath), "/ostree/%s", ostree_target);
if (chroot (destpath) < 0)
{
perrorv ("failed to change root to '%s'", destpath);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]