[buildd-tools-devel] [PATCH 7/8] Add filesystem union support to loopback chroots

Jan-Marek Glogowski glogow at fbihome.de
Wed May 20 17:55:57 UTC 2009


As unioning filesystems just work with directories, the 10mount
script first mounts the loopback device to a directory named
after the contained filesystem UUID in the SCHROOT_MOUNT_DIR.
This directory is used as the read-only branch.

As this chroot now inherits from two chroot based classes, it has
to change the behaviour of the chroot::get_keyfile function, which
won't clean the group of the supplied keyfile anymore, otherwise
the keys from the first class (fs-union) will be lost.
---
 etc/setup.d/10mount              |   45 +++++++++++++++++++++++++++++++++-
 man/schroot.conf.5.in            |   12 +++++----
 sbuild/sbuild-chroot-loopback.cc |   49 ++++++++++++++++++++++++++++---------
 sbuild/sbuild-chroot-loopback.h  |    7 ++++-
 test/Makefile.am                 |    7 +++++
 test/sbuild-chroot-loopback.cc   |    5 ++-
 test/test-sbuild-chroot.h        |   15 ++++++++++-
 7 files changed, 115 insertions(+), 25 deletions(-)

diff --git a/etc/setup.d/10mount b/etc/setup.d/10mount
index 8dc7b48..c659bfa 100755
--- a/etc/setup.d/10mount
+++ b/etc/setup.d/10mount
@@ -182,8 +182,6 @@ if [ "$CHROOT_TYPE" = "plain" ] || [ "$CHROOT_TYPE" = "directory" ] || [ "$CHROO
 	UNPACK_LOCATION="${UNPACK_DIR}/${SESSION_ID}"
 	CHROOT_MOUNT_OPTIONS="--bind"
 	CHROOT_MOUNT_DEVICE="$UNPACK_LOCATION"
-    elif [ "$CHROOT_TYPE" = "loopback" ]; then
-	CHROOT_MOUNT_OPTIONS="$CHROOT_MOUNT_OPTIONS -o loop"
     fi
 
     if [ $1 = "setup-start" ] || [ $1 = "setup-recover" ]; then
@@ -199,6 +197,39 @@ if [ "$CHROOT_TYPE" = "plain" ] || [ "$CHROOT_TYPE" = "directory" ] || [ "$CHROO
 	    exit 1
 	fi
 
+	if [ "$CHROOT_TYPE" = "loopback" ]; then
+	    LOOP_DEVICE=$(losetup -j ${CHROOT_FILE} | sed -e 's/:.*$//')
+	    if [ "xyes" = "x${CREATE_FS_UNION}" ]; then
+		if [ "x" = "x${LOOP_DEVICE}" ]; then
+		    LOOP_DEVICE=$(losetup -f)
+		    losetup -r "${LOOP_DEVICE}" "${CHROOT_FILE}"
+
+		    if ! do_mount_block_device "${CHROOT_MOUNT_OPTIONS}" "${LOOP_DEVICE}"
+		    then
+			losetup -d ${LOOP_DEVICE}
+			exit 1
+		    fi
+		else
+		    if ! do_mount_block_device "${CHROOT_MOUNT_OPTIONS}" "${LOOP_DEVICE}"
+		    then
+			exit 1
+		    fi
+		fi
+		CHROOT_MOUNT_DEVICE="${LOOP_DEVICE}"
+		CHROOT_MOUNT_OPTIONS=""
+		CHROOT_FS_UNION_RO_BRANCH="${MOUNT_DIR}/${CHROOT_MOUNT_UUID}"
+	    else
+		if [ "x" != "x${LOOP_DEVICE}" ]; then
+		    echo "The file '${CHROOT_FILE}' is already associated" \
+			"with device '${LOOP_DEVICE}'."
+		    exit 1
+		else
+		    CHROOT_MOUNT_DEVICE="${CHROOT_FILE}"
+		    CHROOT_MOUNT_OPTIONS="${CHROOT_MOUNT_OPTIONS} -o loop"
+		fi
+	    fi
+	fi
+
         # If recovering, we want to remount all filesystems to ensure
         # a sane state.
 	if [ $1 = "setup-recover" ]; then
@@ -251,6 +282,16 @@ if [ "$CHROOT_TYPE" = "plain" ] || [ "$CHROOT_TYPE" = "directory" ] || [ "$CHROO
 		rmdir "${UUID_MOUNT}" 2>/dev/null
 	    fi
 	    set -e
+	
+	    if [ "$CHROOT_TYPE" = "loopback" ]; then
+		LOOP_DEVICE=$(losetup -j ${CHROOT_FILE} | sed -e 's/:.*$//')
+		if [ "x" != "x$LOOP_DEVICE" ]; then
+		    MOUNT_POINT=$(get_mount_point "${LOOP_DEVICE}")
+		    if [ "x" = "x$MOUNT_POINT" ]; then
+			losetup -d $LOOP_DEVICE
+		    fi
+		fi
+	    fi
 	fi
 
 	if [ "$CHROOT_TYPE" != "file" ]; then
diff --git a/man/schroot.conf.5.in b/man/schroot.conf.5.in
index fad5890..b41be81 100644
--- a/man/schroot.conf.5.in
+++ b/man/schroot.conf.5.in
@@ -189,12 +189,14 @@ Loopback chroots
 .PP
 Chroots of type \[oq]loopback\[cq] are a filesystem available as a file on
 disk, accessed via a loopback mount.  The file will be loopback mounted and
-unmounted on demand.  They implement the \fBmountable chroot\fP options (see
-\[lq]\fIMountable chroot options\fP\[rq], below), plus an additional option:
+unmounted on demand.  They implement the \fBmountable chroot\fP and 
+\fBfs-union chroot\fP options (see \[lq]\fIMountable chroot options\fP\[rq]
+and \[lq]\fIFilesystem Union chroot options\fP\[rq], below), plus an 
+additional option:
 .TP
-\f[CBI]file=\fP\f[CI]file\fP This is the filename of the file containing the
-filesystem, including the absolute path.  For example,
-\[lq]/srv/chroot/sid\[rq].
+\f[CBI]file=\fP\f[CI]filename\fP
+This is the filename of the file containing the filesystem, including the
+absolute path.  For example \[lq]/srv/chroot/sid\[rq].
 .SS
 Block device chroots
 .PP
diff --git a/sbuild/sbuild-chroot-loopback.cc b/sbuild/sbuild-chroot-loopback.cc
index e191d68..361910e 100644
--- a/sbuild/sbuild-chroot-loopback.cc
+++ b/sbuild/sbuild-chroot-loopback.cc
@@ -32,7 +32,7 @@ using boost::format;
 using namespace sbuild;
 
 chroot_loopback::chroot_loopback ():
-  chroot(),
+  chroot_fs_union(),
   chroot_mountable(),
   file()
 {
@@ -48,6 +48,19 @@ chroot_loopback::clone () const
   return ptr(new chroot_loopback(*this));
 }
 
+sbuild::chroot::ptr
+chroot_loopback::clone_source () const
+{
+  ptr clone;
+
+  if (get_fs_union_configured()) {
+    clone = ptr(new chroot_loopback(*this));
+    chroot_source::clone_source_setup(clone);
+  }
+
+  return ptr(clone);
+}
+
 std::string const&
 chroot_loopback::get_file () const
 {
@@ -58,7 +71,7 @@ void
 chroot_loopback::set_file (std::string const& file)
 {
   if (!is_absname(file))
-    throw error(file, FILE_ABS);
+    throw chroot::error(file, FILE_ABS);
 
   this->file = file;
   chroot_mountable::set_mount_device(file);
@@ -81,7 +94,7 @@ chroot_loopback::get_chroot_type () const
 void
 chroot_loopback::setup_env (environment& env)
 {
-  chroot::setup_env(env);
+  chroot_fs_union::setup_env(env);
   chroot_mountable::setup_env(env);
 
   env.add("CHROOT_FILE", get_file());
@@ -99,27 +112,39 @@ chroot_loopback::setup_lock (chroot::setup_type type,
 
       // NOTE: taken from chroot_config::check_security.
       if (file_status.uid() != 0)
-	throw error(this->file, FILE_OWNER);
+	throw chroot::error(this->file, FILE_OWNER);
       if (file_status.check_mode(stat::PERM_OTHER_WRITE))
-	throw error(this->file, FILE_PERMS);
+	throw chroot::error(this->file, FILE_PERMS);
       if (!file_status.is_regular())
-	throw error(this->file, FILE_NOTREG);
+	throw chroot::error(this->file, FILE_NOTREG);
     }
 
-  /* By default, loopback chroots do no locking. */
+  /**
+   * By default, loopback chroots do no locking, but can create sessions
+   * using filesystem unions.
+   */
+  if (get_fs_union_configured() &&
+      ((type == SETUP_START && lock == true) ||
+       (type == SETUP_STOP && lock == false && status == 0)))
+    {
+      bool start = (type == SETUP_START);
+      setup_session_info(start);
+    }
 }
 
 sbuild::chroot::session_flags
 chroot_loopback::get_session_flags () const
 {
-  return SESSION_NOFLAGS | chroot_mountable::get_session_flags();
+  return SESSION_NOFLAGS 
+    | chroot_mountable::get_session_flags()
+    | chroot_fs_union::get_session_flags();
 }
 
 void
 chroot_loopback::get_details (format_detail& detail) const
 {
-  this->chroot::get_details(detail);
-  this->chroot_mountable::get_details(detail);
+  chroot_fs_union::get_details(detail);
+  chroot_mountable::get_details(detail);
 
   if (!this->file.empty())
     detail.add(_("File"), get_file());
@@ -128,7 +153,7 @@ chroot_loopback::get_details (format_detail& detail) const
 void
 chroot_loopback::get_keyfile (keyfile& keyfile) const
 {
-  chroot::get_keyfile(keyfile);
+  chroot_fs_union::get_keyfile(keyfile);
   chroot_mountable::get_keyfile(keyfile);
 
   keyfile::set_object_value(*this, &chroot_loopback::get_file,
@@ -139,7 +164,7 @@ void
 chroot_loopback::set_keyfile (keyfile const& keyfile,
 			      string_list&   used_keys)
 {
-  chroot::set_keyfile(keyfile, used_keys);
+  chroot_fs_union::set_keyfile(keyfile, used_keys);
   chroot_mountable::set_keyfile(keyfile, used_keys);
 
   keyfile::get_object_value(*this, &chroot_loopback::set_file,
diff --git a/sbuild/sbuild-chroot-loopback.h b/sbuild/sbuild-chroot-loopback.h
index a19ad0c..818a26d 100644
--- a/sbuild/sbuild-chroot-loopback.h
+++ b/sbuild/sbuild-chroot-loopback.h
@@ -19,7 +19,7 @@
 #ifndef SBUILD_CHROOT_LOOPBACK_H
 #define SBUILD_CHROOT_LOOPBACK_H
 
-#include <sbuild/sbuild-chroot.h>
+#include <sbuild/sbuild-chroot-fs-union.h>
 #include <sbuild/sbuild-chroot-mountable.h>
 
 namespace sbuild
@@ -30,7 +30,7 @@ namespace sbuild
    *
    * The file will be mounted on demand.
    */
-  class chroot_loopback : virtual public chroot,
+  class chroot_loopback : public chroot_fs_union,
 			  public chroot_mountable
   {
   protected:
@@ -45,6 +45,9 @@ namespace sbuild
 
     virtual chroot::ptr
     clone () const;
+ 
+    virtual chroot::ptr
+    clone_source () const;
 
     /**
      * Get the file containing the chroot.
diff --git a/test/Makefile.am b/test/Makefile.am
index 4a4cd31..f729230 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -72,6 +72,11 @@ sbuild_chroot_blockdev_sources =	\
 	sbuild-chroot-block-device.cc
 endif
 
+if BUILD_LOOPBACK
+sbuild_chroot_loopback_sources =	\
+	sbuild-chroot-loopback.cc
+endif
+
 if BUILD_LVMSNAP
 sbuild_chroot_lvmsnap_sources =	\
 	sbuild-chroot-lvm-snapshot.cc
@@ -83,8 +88,10 @@ sbuild_chroot_SOURCES = 			\
 	sbuild-chroot-file.cc			\
 	sbuild-chroot-directory.cc		\
 	$(sbuild_chroot_blockdev_sources)	\
+	$(sbuild_chroot_loopback_sources)	\
 	$(sbuild_chroot_lvmsnap_sources)	\
 	test-sbuild-chroot.h
+
 sbuild_chroot_LDADD =  libtest.la
 
 sbuild_chroot_config_SOURCES = sbuild-chroot-config.cc
diff --git a/test/sbuild-chroot-loopback.cc b/test/sbuild-chroot-loopback.cc
index 395bc4c..64e453f 100644
--- a/test/sbuild-chroot-loopback.cc
+++ b/test/sbuild-chroot-loopback.cc
@@ -111,7 +111,7 @@ public:
     expected.add("CHROOT_MOUNT_OPTIONS",  "-t jfs -o quota,rw");
     expected.add("CHROOT_SCRIPT_CONFIG",  sbuild::normalname(std::string(PACKAGE_SYSCONF_DIR) + "/script-defaults"));
     expected.add("CHROOT_SESSION_CLONE",  "false");
-    expected.add("CHROOT_SESSION_CREATE", "false");
+    expected.add("CHROOT_SESSION_CREATE", "true");
     expected.add("CHROOT_SESSION_PURGE",  "false");
     expected.add("CHROOT_FS_UNION_TYPE",  "none");
   }
@@ -134,6 +134,7 @@ public:
     setup_env_common(expected);
 
     expected.add("CHROOT_FILE",           loopback_file);
+    expected.add("CHROOT_MOUNT_DEVICE",   loopback_file);
     expected.add("CHROOT_MOUNT_UUID",     FS_UUID);
 
     test_chroot_base<chroot_loopback>::test_setup_env(expected);
@@ -142,7 +143,7 @@ public:
   void test_session_flags()
   {
     CPPUNIT_ASSERT(chroot->get_session_flags() ==
-		   sbuild::chroot::SESSION_NOFLAGS);
+		   sbuild::chroot::SESSION_CREATE);
   }
 
   void test_print_details()
diff --git a/test/test-sbuild-chroot.h b/test/test-sbuild-chroot.h
index e7d0c88..60fc7d0 100644
--- a/test/test-sbuild-chroot.h
+++ b/test/test-sbuild-chroot.h
@@ -19,6 +19,8 @@
 #ifndef TEST_SBUILD_CHROOT_H
 #define TEST_SBUILD_CHROOT_H
 
+#include <unistd.h>
+
 #include <sbuild/sbuild-chroot.h>
 
 #include <algorithm>
@@ -34,12 +36,21 @@ class test_chroot_base : public TestFixture
 {
 protected:
   sbuild::chroot::ptr chroot;
+  std::string abs_testdata_dir;
 
 public:
   test_chroot_base():
     TestFixture(),
-    chroot()
-  {}
+    chroot(),
+    abs_testdata_dir()
+  {
+    char cwd[FILENAME_MAX];
+    if (NULL != getcwd(cwd, FILENAME_MAX))
+      {
+        abs_testdata_dir = std::string(cwd);
+        abs_testdata_dir.append("/" TESTDATADIR);
+      }
+  }
 
   virtual ~test_chroot_base()
   {}
-- 
1.6.3.1




More information about the Buildd-tools-devel mailing list