[Buildd-tools-devel] [PATCH 18/22] Add filesystem UUID detection support
Jan-Marek Glogowski
glogow at fbihome.de
Thu Mar 26 21:13:56 UTC 2009
This allows to detect or set a filesystems UUID. It currently
supports detecting the UUID using libvolume_id. This is used
to mount loopback chroots to a unique directory, so the
filesystem can be used for multiple filesystem union sessions.
---
bin/schroot/setup/10mount | 54 +++++++++++++++++++++++-
configure.ac | 12 +++++-
debian/control | 2 +-
sbuild/Makefile.am | 5 +-
sbuild/sbuild-chroot-mountable.cc | 71 ++++++++++++++++++++++++++-----
sbuild/sbuild-chroot-mountable.h | 48 ++++++++++++++++----
sbuild/sbuild-util.cc | 85 +++++++++++++++++++++++++++++++++++++
sbuild/sbuild-util.h | 16 +++++++
test/Makefile.am | 8 +++-
test/sbuild-util.cc | 15 +++++++
test/setup-test-data | 7 ---
test/setup-test-data.in | 27 ++++++++++++
12 files changed, 315 insertions(+), 35 deletions(-)
delete mode 100755 test/setup-test-data
create mode 100755 test/setup-test-data.in
diff --git a/bin/schroot/setup/10mount b/bin/schroot/setup/10mount
index 0a5dc65..a678778 100755
--- a/bin/schroot/setup/10mount
+++ b/bin/schroot/setup/10mount
@@ -52,6 +52,38 @@ do_mount()
return $RESULT
}
+# Find mount point for block device
+# $1: block device
+get_mount_point()
+{
+ df "${1}" 2>/dev/null | sed -n -e "s#^${1} ##p" | sed -n -e "s#[^/]\+##p"
+}
+
+# Mounts a block-device ro by UUID to ${MOUNT_DIR}/<UUID>
+# $1: options
+# $2: block device
+do_mount_block_device()
+{
+ if [ ! -b "${2}" ] || [ "x" = "x${CHROOT_MOUNT_UUID}" ]; then
+ return 255
+ fi
+
+ UUID_MOUNT="${MOUNT_DIR}/${CHROOT_MOUNT_UUID}"
+
+ MOUNT_POINT=$(get_mount_point "${2}")
+ if [ "x" = "x${MOUNT_POINT}" ]; then
+ do_mount "${1} -o ro" "${2}" "${UUID_MOUNT}"
+ return $?
+ else
+ if [ "x${MOUNT_POINT}" = "x${UUID_MOUNT}" ]; then
+ return 0
+ else
+ echo "The device '${2}' is already in use on '${MOUNT_POINT}'"
+ return 254
+ fi
+ fi
+}
+
# Unmount all filesystems under specified location
# $1: mount base location
do_umount_all()
@@ -117,7 +149,7 @@ do_mount_fs_union()
fi
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
- echo "Using '$TYPE' for filesystem union"
+ echo "Using '$CHROOT_FS_UNION_TYPE' for filesystem union"
fi
return 0
@@ -181,6 +213,14 @@ if [ "$CHROOT_TYPE" = "plain" ] || [ "$CHROOT_TYPE" = "directory" ] || [ "$CHROO
if [ "xyes" = "x${CREATE_FS_UNION}" ]; then
if ! do_mount_fs_union "$CHROOT_FS_UNION_RO_BRANCH"
then
+ if [ "x" != "x${UUID_MOUNT}" ]; then
+ set +e
+ if umount "${UUID_MOUNT}" 2>/dev/null
+ then
+ rmdir "${UUID_MOUNT}" 2>/dev/null
+ fi
+ set -e
+ fi
exit 1
fi
else
@@ -206,6 +246,18 @@ if [ "$CHROOT_TYPE" = "plain" ] || [ "$CHROOT_TYPE" = "directory" ] || [ "$CHROO
do_umount_all "$CHROOT_MOUNT_LOCATION"
+ if [ "xyes" = "x${CREATE_FS_UNION}" ] \
+ && [ "x" != "x${CHROOT_MOUNT_UUID}" ];
+ then
+ UUID_MOUNT="${MOUNT_DIR}/${CHROOT_MOUNT_UUID}"
+ set +e
+ if umount "${UUID_MOUNT}" 2>/dev/null
+ then
+ rmdir "${UUID_MOUNT}" 2>/dev/null
+ fi
+ set -e
+ fi
+
if [ "$CHROOT_TYPE" != "file" ]; then
if echo "$CHROOT_MOUNT_LOCATION" | grep -q "^$MOUNT_DIR/"; then
if [ -d "$CHROOT_MOUNT_LOCATION" ]; then
diff --git a/configure.ac b/configure.ac
index a85cd91..2612534 100644
--- a/configure.ac
+++ b/configure.ac
@@ -200,16 +200,25 @@ AM_CONDITIONAL([USE_DOXYGEN], [test -n "$DOXYGEN"])
# Checks for libraries.
AH_TEMPLATE(HAVE_UUID, [Is libuuid available])
PKG_CHECK_MODULES([UUID], [uuid],
- [AC_DEFINE(HAVE_UUID)
+ [AC_DEFINE(HAVE_UUID, 1, [Have libuuid])
HAVE_UUID=true],
[HAVE_UUID=false])
+AH_TEMPLATE(HAVE_VOLUME_ID, [Is libvolume_id available])
+PKG_CHECK_MODULES([VOLUME_ID], [libvolume_id],
+ [AC_DEFINE(HAVE_VOLUME_ID, 1, [Have libvolume_id])
+ HAVE_VOLUME_ID=true],
+ [HAVE_VOLUME_ID=false])
+
AM_PATH_CPPUNIT([1.10.0], [HAVE_CPPUNIT=true])
AM_CONDITIONAL([USE_UNIT_TESTS], [test -n "$HAVE_CPPUNIT"])
SCHROOT_CFLAGS="$UUID_CFLAGS"
AC_SUBST([SCHROOT_CFLAGS])
+FS_UUID="59a6643d-e2a7-4d54-bfa6-eec927ffa181"
+AC_SUBST([FS_UUID])
+
# Checks for header files.
AC_CHECK_HEADERS([tr1/memory])
@@ -502,6 +511,7 @@ AC_CONFIG_FILES([bin/csbuild/Makefile])
AC_CONFIG_FILES([bin/csbuild/csbuild.1])
AC_CONFIG_FILES([scripts/po-notify])
AC_CONFIG_FILES([test/Makefile])
+AC_CONFIG_FILES([test/setup-test-data])
AC_CONFIG_FILES([Makefile])
dnl Output the generated config.status script.
AC_OUTPUT
diff --git a/debian/control b/debian/control
index 8df5779..812311f 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: admin
Priority: optional
Maintainer: Debian buildd-tools Developers <buildd-tools-devel at lists.alioth.debian.org>
Uploaders: Michael Banck <mbanck at debian.org>, Luk Claes <luk at debian.org>, Roger Leigh <rleigh at debian.org>, Francesco Paolo Lovergine <frankie at debian.org>
-Build-Depends: debhelper (>= 7.0.0), autotools-dev, pkg-config (>= 0.20), libpam0g-dev (>= 0.79-3.1), uuid-dev, liblockdev1-dev (>= 1.0.2), libboost1.37-dev (>= 1.34.0), libboost-program-options1.37-dev (>= 1.34.0), libboost-regex1.37-dev (>= 1.34.0), libboost-filesystem1.37-dev (>= 1.34.0), gettext, libcppunit-dev, doxygen, graphviz
+Build-Depends: debhelper (>= 7.0.0), autotools-dev, pkg-config (>= 0.20), libpam0g-dev (>= 0.79-3.1), uuid-dev, liblockdev1-dev (>= 1.0.2), libboost1.37-dev (>= 1.34.0), libboost-program-options1.37-dev (>= 1.34.0), libboost-regex1.37-dev (>= 1.34.0), libboost-filesystem1.37-dev (>= 1.34.0), gettext, libcppunit-dev, doxygen, graphviz, libvolume-id-dev, e2fsprogs
Standards-Version: 3.8.1
Vcs-Browser: http://git.debian.org/?p=buildd-tools/schroot.git
Vcs-Git: git://git.debian.org/git/buildd-tools/schroot
diff --git a/sbuild/Makefile.am b/sbuild/Makefile.am
index 400fcc0..2427004 100644
--- a/sbuild/Makefile.am
+++ b/sbuild/Makefile.am
@@ -21,7 +21,7 @@
include $(top_srcdir)/scripts/global.mk
-LOCAL_CXXFLAGS = $(SCHROOT_CFLAGS)
+LOCAL_CXXFLAGS = $(SCHROOT_CFLAGS) $(VOLUME_ID_CFLAGS)
DEFS = -D_GNU_SOURCE
@@ -115,7 +115,8 @@ libsbuild_la_SOURCES = \
nodist_libsbuild_la_SOURCES = \
sbuild-config.h
-libsbuild_la_LIBADD = $(UUID_LIBS) $(PAM_LIBS) $(LOCKDEV_LIBS) $(BOOST_LIBS) $(LIBINTL)
+libsbuild_la_LIBADD = $(UUID_LIBS) $(PAM_LIBS) $(LOCKDEV_LIBS) $(BOOST_LIBS) \
+ $(LIBINTL) $(VOLUME_ID_LIBS)
pkgconfigdatadir = $(libdir)/pkgconfig
diff --git a/sbuild/sbuild-chroot-mountable.cc b/sbuild/sbuild-chroot-mountable.cc
index 548a709..06e63a6 100644
--- a/sbuild/sbuild-chroot-mountable.cc
+++ b/sbuild/sbuild-chroot-mountable.cc
@@ -33,12 +33,15 @@ using namespace sbuild;
chroot_mountable::chroot_mountable ():
chroot(),
- mount_options()
+ mount_options(),
+ mount_uuid(NULL)
{
}
chroot_mountable::~chroot_mountable ()
{
+ if (mount_uuid != NULL)
+ delete mount_uuid;
}
std::string const&
@@ -53,27 +56,65 @@ chroot_mountable::set_mount_options (std::string const& mount_options)
this->mount_options = mount_options;
}
-std::string const&
-chroot_mountable::get_location () const
+void
+chroot_mountable::setup_env (environment& env)
+{
+ chroot::setup_env(env);
+
+ env.add("CHROOT_MOUNT_OPTIONS", get_mount_options());
+ env.add("CHROOT_MOUNT_UUID", get_mount_uuid(false));
+}
+
+void
+chroot_mountable::set_container (std::string const& container)
{
- return chroot::get_location();
+ set_mount_uuid(NULL);
+ chroot::set_container(container);
}
void
chroot_mountable::set_location (std::string const& location)
{
- if (!location.empty() && !is_absname(location))
- throw error(location, LOCATION_ABS);
-
chroot::set_location(location);
}
void
-chroot_mountable::setup_env (environment& env)
+chroot_mountable::set_mount_uuid (std::string const* uuid)
{
- this->chroot::setup_env(env);
+ if (uuid == NULL)
+ {
+ if (mount_uuid != NULL)
+ {
+ delete mount_uuid;
+ mount_uuid = NULL;
+ }
+ }
+ else
+ {
+ if (mount_uuid != NULL)
+ *mount_uuid = *uuid;
+ else
+ mount_uuid = new std::string(*uuid);
+ }
+}
- env.add("CHROOT_MOUNT_OPTIONS", get_mount_options());
+std::string const&
+chroot_mountable::get_mount_uuid (bool abort_on_drop_privileges)
+{
+ if (has_mount_uuid())
+ return *mount_uuid;
+
+ std::string filesystem = get_container();
+ std::string str_uuid;
+ if (filesystem.empty() ||
+ !get_filesystem_uuid(filesystem, abort_on_drop_privileges, str_uuid))
+ {
+ mount_uuid = new std::string();
+ }
+ else
+ set_mount_uuid(&str_uuid);
+
+ return *mount_uuid;
}
sbuild::chroot::session_flags
@@ -99,7 +140,8 @@ chroot_mountable::get_keyfile (keyfile& keyfile) const
keyfile::set_object_value(*this, &chroot_mountable::get_mount_options,
keyfile, get_name(), "mount-options");
- keyfile::set_object_value(*this, &chroot_mountable::get_location,
+ keyfile::set_object_value(*(static_cast<const chroot *>(this)),
+ &chroot::get_location,
keyfile, get_name(), "location");
}
@@ -119,3 +161,10 @@ chroot_mountable::set_keyfile (keyfile const& keyfile,
keyfile::PRIORITY_OPTIONAL);
used_keys.push_back("location");
}
+
+bool
+chroot_mountable::has_mount_uuid () const
+{
+ return (mount_uuid != NULL);
+}
+
diff --git a/sbuild/sbuild-chroot-mountable.h b/sbuild/sbuild-chroot-mountable.h
index 206d6b0..8d7b701 100644
--- a/sbuild/sbuild-chroot-mountable.h
+++ b/sbuild/sbuild-chroot-mountable.h
@@ -58,22 +58,37 @@ namespace sbuild
set_mount_options (std::string const& mount_options);
/**
- * Get the location. This is a path to the chroot directory
- * inside the device (absolute path from the device root).
+ * Set the device relative location.
*
- * @returns the location.
+ * This is a path to the chroot directory inside the device
+ * (absolute path from the device root). Even through it has to
+ * be an absolute path.
+ *
+ * @param location the location.
*/
- virtual std::string const&
- get_location () const;
+ void
+ set_location (std::string const& location);
/**
- * Set the location. This is a path to the chroot directory
- * inside the device (absolute path from the device root).
+ * Sets the UUID for the mount_device.
*
- * @param location the location.
+ * @param uuid the uuid of the mount_device.
*/
virtual void
- set_location (std::string const& location);
+ set_mount_uuid (std::string const* uuid);
+
+ virtual void
+ set_container (std::string const& container);
+
+ /**
+ * Gets the UUID of the filesystem on the mount_device.
+ *
+ * @param abort_on_error if true throws an exception, if no uuid could
+ * be found or generated.
+ * @return the uuid or an empty string.
+ */
+ virtual std::string const&
+ get_mount_uuid (bool abort_on_error = false);
virtual void
setup_env (environment& env);
@@ -92,9 +107,22 @@ namespace sbuild
set_keyfile (keyfile const& keyfile,
string_list& used_keys);
+ /**
+ * Returns the status of the UUID detection.
+ *
+ * This basically just prevents direct access to mount_uuid and allows
+ * reimplementation of get_mount_uuid detect the mount_uuid status.
+ *
+ * @return true, if mount_uuid is set and UUID detection was run.
+ */
+ bool
+ has_mount_uuid () const;
+
private:
/// The options to mount the device with.
- std::string mount_options;
+ std::string mount_options;
+ /// The UUID cache for the mount device.
+ std::string *mount_uuid;
};
}
diff --git a/sbuild/sbuild-util.cc b/sbuild/sbuild-util.cc
index 1cfa680..132578f 100644
--- a/sbuild/sbuild-util.cc
+++ b/sbuild/sbuild-util.cc
@@ -29,6 +29,21 @@
#include <sys/stat.h>
#include <unistd.h>
+#ifdef HAVE_VOLUME_ID
+extern "C" {
+#undef __cplusplus
+#include <libvolume_id.h>
+#define __cplusplus
+}
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+
using namespace sbuild;
namespace
@@ -406,6 +421,76 @@ sbuild::exec (std::string const& file,
return status;
}
+bool
+sbuild::get_filesystem_uuid(std::string const& filesystem,
+ bool abort_on_drop_privileges,
+ std::string& uuid)
+{
+ bool detected_uuid = false;
+
+#ifdef HAVE_VOLUME_ID
+ // This code is inspired by udevs vol_id program
+ struct volume_id *vol_id;
+ int retval;
+ int fd;
+
+ if (filesystem.empty())
+ goto return_filesystem_uuid;
+
+ fd = open(filesystem.c_str(), O_RDONLY | O_EXCL);
+ if (fd == -1)
+ goto return_filesystem_uuid;
+
+ vol_id = volume_id_open_fd(fd);
+ if (vol_id == NULL)
+ goto bailout_filesystem_uuid;
+
+ uint64_t size;
+ if (ioctl(fd, BLKGETSIZE64, &size) != 0)
+ size = 0;
+
+ if (getuid() == 0)
+ {
+ struct passwd *pw;
+
+ pw = getpwnam("nobody");
+ if (pw != NULL && pw->pw_uid > 0 && pw->pw_gid > 0)
+ {
+ if (abort_on_drop_privileges &&
+ (setgroups(0, NULL) != 0 ||
+ setgid(pw->pw_gid) != 0 ||
+ setuid(pw->pw_uid) != 0))
+ goto bailout_filesystem_uuid;
+ }
+ }
+
+ retval = volume_id_probe_filesystem(vol_id, 0, size);
+ if (retval != 0)
+ goto bailout_filesystem_uuid;
+
+ const char *c_uuid;
+ retval = volume_id_get_uuid(vol_id, &c_uuid);
+ if (retval == 0)
+ goto bailout_filesystem_uuid;
+
+ detected_uuid = true;
+
+ char uuid_enc[256];
+ volume_id_encode_string(c_uuid, uuid_enc, sizeof(uuid_enc));
+
+ uuid = std::string(uuid_enc);
+
+bailout_filesystem_uuid:
+ if (vol_id != NULL)
+ volume_id_close(vol_id);
+
+ close(fd);
+#endif
+
+return_filesystem_uuid:
+ return detected_uuid;
+}
+
sbuild::stat::stat (std::string const& file):
file(file),
fd(0),
diff --git a/sbuild/sbuild-util.h b/sbuild/sbuild-util.h
index 24c16cb..b8212ad 100644
--- a/sbuild/sbuild-util.h
+++ b/sbuild/sbuild-util.h
@@ -196,6 +196,22 @@ namespace sbuild
environment const& env);
/**
+ * Get the UUID of a filesystem.
+ *
+ * This function gets the filesystem UUID from a block device or a
+ * filesystem contained in a file.
+ *
+ * @param filesystem the path to the filesystem device or file.
+ * @param abort_on_drop_privileges abort if privileges drop failed.
+ * @param uuid the uuid string.
+ * @returns true on success, false on error.
+ */
+ bool
+ get_filesystem_uuid(std::string const& filesystem,
+ bool abort_on_drop_privileges,
+ std::string& uuid);
+
+ /**
* Get file status. stat(2) wrapper.
*/
class stat
diff --git a/test/Makefile.am b/test/Makefile.am
index ae7dcc1..60414b1 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -22,7 +22,7 @@
include $(top_srcdir)/scripts/global.mk
LOCAL_CXXFLAGS = $(SCHROOT_CFLAGS) $(CPPUNIT_CFLAGS) -I$(top_srcdir)/bin \
- -DTESTDATADIR='"./testdata"'
+ -DTESTDATADIR='"./testdata"' -DFS_UUID='"$(FS_UUID)"'
if USE_UNIT_TESTS
noinst_LTLIBRARIES = libtest.la
@@ -133,8 +133,12 @@ EXTRA_DIST = \
run-parts.ex1/30test3 \
run-parts.ex2 \
run-parts.ex3/50invalid \
- setup-test-data \
+ setup-test-data.in \
cleanup-test-data
clean-local:
$(srcdir)/cleanup-test-data
+
+all-local:
+ chmod a+rx ./setup-test-data
+
diff --git a/test/sbuild-util.cc b/test/sbuild-util.cc
index 603cf54..94c1488 100644
--- a/test/sbuild-util.cc
+++ b/test/sbuild-util.cc
@@ -22,6 +22,8 @@
#include <cppunit/extensions/HelperMacros.h>
+#include "config.h"
+
using namespace CppUnit;
class test_util : public TestCase
@@ -32,6 +34,9 @@ class test_util : public TestCase
CPPUNIT_TEST(test_string_list_to_string);
CPPUNIT_TEST(test_split_string);
CPPUNIT_TEST(test_find_program_in_path);
+#ifdef HAVE_VOLUME_ID
+ CPPUNIT_TEST(test_read_uuid);
+#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -89,6 +94,16 @@ public:
CPPUNIT_ASSERT(sbuild::find_program_in_path("sed", path, "") == "/bin/sed");
}
+ void test_read_uuid()
+ {
+ std::string uuid;
+ CPPUNIT_ASSERT(sbuild::get_filesystem_uuid
+ (TESTDATADIR "/does-not-exist", false, uuid) == false);
+ CPPUNIT_ASSERT(sbuild::get_filesystem_uuid
+ (TESTDATADIR "/loopback-file", false, uuid) == true);
+ CPPUNIT_ASSERT(uuid == FS_UUID);
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(test_util);
diff --git a/test/setup-test-data b/test/setup-test-data
deleted file mode 100755
index 1785149..0000000
--- a/test/setup-test-data
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-# This script ensures that the test data is owned by root.
-
-rm -rf testdata
-mkdir testdata
-cp -r ${srcdir}/*.ex* testdata
-chown -R root:root testdata
diff --git a/test/setup-test-data.in b/test/setup-test-data.in
new file mode 100755
index 0000000..01fd86f
--- /dev/null
+++ b/test/setup-test-data.in
@@ -0,0 +1,27 @@
+#!/bin/sh
+# This script ensures that the test data is owned by root
+# and creates some additional data for tests.
+
+if [ -d testdata ]; then
+ rm -rf testdata
+fi
+
+if [ $(id -u) -ne 0 ]; then
+ exit 1
+fi
+
+echo "Generating test data..."
+
+mkdir testdata
+
+LOOPBACK=testdata/loopback-file
+UUID=@FS_UUID@
+
+dd if=/dev/zero of=$LOOPBACK bs=1M count=5
+/sbin/mke2fs -F $LOOPBACK 1>/dev/null
+/sbin/tune2fs -U $UUID $LOOPBACK
+
+# chown data
+cp -r ${srcdir}/*.ex* testdata
+chown -R root:root testdata
+
--
1.6.2.1
More information about the Buildd-tools-devel
mailing list