[Buildd-tools-devel] [PATCH 19/22] Add filesystem union support to loopback chroots
Jan-Marek Glogowski
glogow at fbihome.de
Thu Mar 26 21:13: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.
---
bin/schroot/schroot.conf.5.in | 12 ++-
bin/schroot/setup/10mount | 46 ++++++++++-
sbuild/sbuild-chroot-loopback.cc | 49 ++++++++---
sbuild/sbuild-chroot-loopback.h | 7 +-
sbuild/sbuild-chroot.cc | 2 -
test/Makefile.am | 1 +
test/sbuild-chroot-loopback.cc | 173 ++++++++++++++++++++++++++++++++++++++
test/test-sbuild-chroot.h | 15 +++-
8 files changed, 279 insertions(+), 26 deletions(-)
create mode 100644 test/sbuild-chroot-loopback.cc
diff --git a/bin/schroot/schroot.conf.5.in b/bin/schroot/schroot.conf.5.in
index b197bce..674470b 100644
--- a/bin/schroot/schroot.conf.5.in
+++ b/bin/schroot/schroot.conf.5.in
@@ -184,12 +184,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/bin/schroot/setup/10mount b/bin/schroot/setup/10mount
index a678778..d952db8 100755
--- a/bin/schroot/setup/10mount
+++ b/bin/schroot/setup/10mount
@@ -182,9 +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"
- CHROOT_MOUNT_DEVICE="$CHROOT_FILE"
elif [ "$CHROOT_TYPE" = "lvm-snapshot" ]; then
CHROOT_MOUNT_DEVICE="$CHROOT_LVM_SNAPSHOT_DEVICE"
elif [ "$CHROOT_TYPE" = "block-device" ]; then
@@ -204,6 +201,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
@@ -256,6 +286,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/sbuild/sbuild-chroot-loopback.cc b/sbuild/sbuild-chroot-loopback.cc
index 35fc044..9d748da 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()
{
}
@@ -47,11 +47,24 @@ 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);
+}
+
void
chroot_loopback::set_container (std::string const& file)
{
if (!is_absname(file))
- throw error(file, FILE_ABS);
+ throw chroot::error(file, FILE_ABS);
chroot_mountable::set_container(file);
}
@@ -59,7 +72,7 @@ chroot_loopback::set_container (std::string const& file)
void
chroot_loopback::setup_env (environment& env)
{
- chroot::setup_env(env);
+ chroot_fs_union::setup_env(env);
chroot_mountable::setup_env(env);
}
@@ -76,33 +89,45 @@ chroot_loopback::setup_lock (chroot::setup_type type,
// NOTE: taken from chroot_config::check_security.
if (file_status.uid() != 0)
- throw error(file, FILE_OWNER);
+ throw chroot::error(file, FILE_OWNER);
if (file_status.check_mode(stat::PERM_OTHER_WRITE))
- throw error(file, FILE_PERMS);
+ throw chroot::error(file, FILE_PERMS);
if (!file_status.is_regular())
- throw error(file, FILE_NOTREG);
+ throw chroot::error(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);
}
void
chroot_loopback::get_keyfile (keyfile& keyfile) const
{
- chroot::get_keyfile(keyfile);
+ chroot_fs_union::get_keyfile(keyfile);
chroot_mountable::get_keyfile(keyfile);
}
@@ -110,7 +135,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);
}
diff --git a/sbuild/sbuild-chroot-loopback.h b/sbuild/sbuild-chroot-loopback.h
index 91ed269..b27e0ff 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;
/**
* Set the file containing the chroot.
diff --git a/sbuild/sbuild-chroot.cc b/sbuild/sbuild-chroot.cc
index 41a314c..83db142 100644
--- a/sbuild/sbuild-chroot.cc
+++ b/sbuild/sbuild-chroot.cc
@@ -551,8 +551,6 @@ sbuild::chroot::print_details (std::ostream& stream) const
void
sbuild::chroot::get_keyfile (keyfile& keyfile) const
{
- keyfile.remove_group(get_name());
-
std::string type, container_key;
get_chroot_strings(&type, &container_key, NULL);
diff --git a/test/Makefile.am b/test/Makefile.am
index 60414b1..729bf2d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -74,6 +74,7 @@ sbuild_chroot_SOURCES = \
sbuild-chroot-file.cc \
sbuild-chroot-block-device.cc \
sbuild-chroot-lvm-snapshot.cc \
+ sbuild-chroot-loopback.cc \
test-sbuild-chroot.h
sbuild_chroot_LDADD = libtest.la
diff --git a/test/sbuild-chroot-loopback.cc b/test/sbuild-chroot-loopback.cc
new file mode 100644
index 0000000..0852ea8
--- /dev/null
+++ b/test/sbuild-chroot-loopback.cc
@@ -0,0 +1,173 @@
+/* Copyright © 2008-2009 Jan-Marek Glogowski <glogow at fbihome.de>
+ *
+ * schroot 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * schroot is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *********************************************************************/
+
+#include "config.h"
+
+#include <algorithm>
+#include <set>
+
+#include <sbuild/sbuild-chroot-loopback.h>
+
+#include "test-helpers.h"
+#include "test-sbuild-chroot.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+using namespace CppUnit;
+
+class chroot_loopback : public sbuild::chroot_loopback
+{
+public:
+ chroot_loopback():
+ sbuild::chroot_loopback()
+ {}
+
+ virtual ~chroot_loopback()
+ {}
+};
+
+class test_chroot_loopback : public test_chroot_base<chroot_loopback>
+{
+ CPPUNIT_TEST_SUITE(test_chroot_loopback);
+ CPPUNIT_TEST(test_file);
+ CPPUNIT_TEST(test_mount_options);
+ CPPUNIT_TEST(test_chroot_strings);
+ CPPUNIT_TEST(test_setup_env);
+ CPPUNIT_TEST(test_setup_env2);
+ CPPUNIT_TEST(test_session_flags);
+ CPPUNIT_TEST(test_print_details);
+ CPPUNIT_TEST(test_print_config);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ std::string loopback_file;
+
+public:
+ test_chroot_loopback():
+ test_chroot_base<chroot_loopback>(),
+ loopback_file()
+ {
+ loopback_file = abs_testdata_dir;
+ loopback_file.append("/loopback-file");
+ }
+
+ void setUp()
+ {
+ test_chroot_base<chroot_loopback>::setUp();
+ sbuild::chroot_loopback *c = dynamic_cast<sbuild::chroot_loopback *>(chroot.get());
+ c->set_mount_options("-t jfs -o quota,rw");
+ }
+
+ void
+ test_file()
+ {
+ sbuild::chroot_loopback *c = dynamic_cast<sbuild::chroot_loopback *>(chroot.get());
+ CPPUNIT_ASSERT(c);
+ c->set_container("/dev/some/file");
+ CPPUNIT_ASSERT(c->get_container() == "/dev/some/file");
+ }
+
+ void
+ test_mount_options()
+ {
+ sbuild::chroot_loopback *c = dynamic_cast<sbuild::chroot_loopback *>(chroot.get());
+ CPPUNIT_ASSERT(c);
+ c->set_mount_options("-o opt1,opt2");
+ CPPUNIT_ASSERT(c->get_mount_options() == "-o opt1,opt2");
+ }
+
+ void test_chroot_strings()
+ {
+ std::string type, key_name, detail_name;
+ chroot->get_chroot_strings(&type, &key_name, &detail_name);
+
+ CPPUNIT_ASSERT(type == "loopback");
+ CPPUNIT_ASSERT(key_name == "file");
+ CPPUNIT_ASSERT(detail_name == "File");
+ }
+
+ void setup_env_common(sbuild::environment& expected)
+ {
+ expected.add("CHROOT_TYPE", "loopback");
+ expected.add("CHROOT_NAME", "test-name");
+ expected.add("CHROOT_DESCRIPTION", "test-description");
+ expected.add("CHROOT_MOUNT_LOCATION", "/mnt/mount-location");
+ expected.add("CHROOT_PATH", "/mnt/mount-location");
+ 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_PURGE", "false");
+ expected.add("CHROOT_FS_UNION_TYPE", "none");
+ }
+
+ void test_setup_env()
+ {
+ sbuild::environment expected;
+ setup_env_common(expected);
+
+ test_chroot_base<chroot_loopback>::test_setup_env(expected);
+ }
+
+ void test_setup_env2()
+ {
+ sbuild::chroot_loopback *c = dynamic_cast<sbuild::chroot_loopback *>(chroot.get());
+ CPPUNIT_ASSERT(c);
+ c->set_container(loopback_file);
+
+ sbuild::environment expected;
+ setup_env_common(expected);
+
+ expected.add("CHROOT_FILE", loopback_file);
+ expected.add("CHROOT_CONTAINER", loopback_file);
+ expected.add("CHROOT_MOUNT_UUID", FS_UUID);
+
+ test_chroot_base<chroot_loopback>::test_setup_env(expected);
+ }
+
+ void test_session_flags()
+ {
+ CPPUNIT_ASSERT(chroot->get_session_flags() ==
+ sbuild::chroot::SESSION_NOFLAGS);
+ }
+
+ void test_print_details()
+ {
+ std::ostringstream os;
+ os << chroot;
+ // TODO: Compare output.
+ CPPUNIT_ASSERT(!os.str().empty());
+ }
+
+ void test_print_config()
+ {
+ std::ostringstream os;
+ sbuild::keyfile config;
+ config << chroot;
+ os << config;
+ // TODO: Compare output.
+ CPPUNIT_ASSERT(!os.str().empty());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_chroot_loopback);
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.2.1
More information about the Buildd-tools-devel
mailing list