[ostree] switchroot: Further work on being dracut-only



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]