[buildd-tools-devel] [PATCH 07/17] [chroot_loopback] Add filesystem union support
Jan-Marek Glogowski
glogow at fbihome.de
Tue Jun 30 18:05:45 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 +-
sbuild/sbuild-session.cc | 21 -----
sbuild/sbuild-util.cc | 14 +++
sbuild/sbuild-util.h | 9 ++
test/Makefile.am | 7 ++
test/sbuild-chroot-loopback.cc | 168 ++++++++++++++++++++++++++++++++++++++
test/test-sbuild-chroot.h | 10 ++-
10 files changed, 298 insertions(+), 44 deletions(-)
create mode 100644 test/sbuild-chroot-loopback.cc
diff --git a/etc/setup.d/10mount b/etc/setup.d/10mount
index 8083b87..7d0a632 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 800072c..92400fd 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/sbuild/sbuild-session.cc b/sbuild/sbuild-session.cc
index e0c7143..0cb96f5 100644
--- a/sbuild/sbuild-session.cc
+++ b/sbuild/sbuild-session.cc
@@ -128,27 +128,6 @@ namespace
};
/**
- * Get the current working directory. If it can't be found, fall
- * back to root.
- *
- * @returns the current working directory.
- */
- std::string
- getcwd ()
- {
- std::string cwd;
-
- char *raw_cwd = ::getcwd (0, 0);
- if (raw_cwd)
- cwd = raw_cwd;
- else
- cwd = "/";
- free(raw_cwd);
-
- return cwd;
- }
-
- /**
* Check group membership.
*
* @param group the group to check for.
diff --git a/sbuild/sbuild-util.cc b/sbuild/sbuild-util.cc
index 132578f..fd83ff2 100644
--- a/sbuild/sbuild-util.cc
+++ b/sbuild/sbuild-util.cc
@@ -202,6 +202,20 @@ sbuild::is_valid_filename (std::string const& name,
return match;
}
+std::string
+sbuild::getcwd ()
+{
+ std::string cwd;
+
+ char *raw_cwd = ::getcwd (0, 0);
+ if (raw_cwd)
+ cwd = raw_cwd;
+ else
+ cwd = "/";
+ free(raw_cwd);
+
+ return cwd;
+}
std::string
sbuild::string_list_to_string (sbuild::string_list const& list,
diff --git a/sbuild/sbuild-util.h b/sbuild/sbuild-util.h
index c4864db..2bf6784 100644
--- a/sbuild/sbuild-util.h
+++ b/sbuild/sbuild-util.h
@@ -93,6 +93,15 @@ namespace sbuild
bool lsb_mode = true);
/**
+ * Get the current working directory. If it can't be found, fall
+ * back to root.
+ *
+ * @returns the current working directory.
+ */
+ std::string
+ getcwd ();
+
+ /**
* Convert a string_list into a string. The strings are
* concatenated using separator as a delimiter.
*
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
new file mode 100644
index 0000000..64e453f
--- /dev/null
+++ b/test/sbuild-chroot-loopback.cc
@@ -0,0 +1,168 @@
+/* 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_type);
+ 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_file("/dev/some/file");
+ CPPUNIT_ASSERT(c->get_file() == "/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_type()
+ {
+ CPPUNIT_ASSERT(chroot->get_chroot_type() == "loopback");
+ }
+
+ 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", "true");
+ 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_file(loopback_file);
+
+ sbuild::environment expected;
+ 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);
+ }
+
+ void test_session_flags()
+ {
+ CPPUNIT_ASSERT(chroot->get_session_flags() ==
+ sbuild::chroot::SESSION_CREATE);
+ }
+
+ 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..462dfdf 100644
--- a/test/test-sbuild-chroot.h
+++ b/test/test-sbuild-chroot.h
@@ -20,6 +20,7 @@
#define TEST_SBUILD_CHROOT_H
#include <sbuild/sbuild-chroot.h>
+#include <sbuild/sbuild-util.h>
#include <algorithm>
#include <iostream>
@@ -34,12 +35,17 @@ 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()
+ {
+ abs_testdata_dir = sbuild::getcwd();
+ abs_testdata_dir.append("/" TESTDATADIR);
+ }
virtual ~test_chroot_base()
{}
--
1.6.3.2
More information about the Buildd-tools-devel
mailing list