bug-parted
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] libparted: ignore zero-length devices


From: Colin Watson
Subject: [PATCH] libparted: ignore zero-length devices
Date: Wed, 17 Nov 2010 15:14:50 +0000
User-agent: Mutt/1.5.18 (2008-05-17)

* bootstrap.conf (gnulib_modules): Add xstrtoll.
* configure.ac: Create DYNAMIC_LOADING output variable.
* libparted/arch/linux.c (_device_get_length): Return the value of
PARTED_TEST_DEVICE_LENGTH if set in the environment, strictly for use by
the test suite.
(init_generic): If geometry probing fails because the device was
zero-length, return quietly rather than throwing an exception.  This has
been observed in the wild with cciss devices, and it's difficult for
partitioners to tell the difference between that and more serious
errors.
* libparted/tests/Makefile.am (TESTS): Add t2100-zerolen.sh.
(check_PROGRAMS): Add zerolen.
(zerolen_SOURCES): Add.
(TESTS_ENVIRONMENT): Add DYNAMIC_LOADING and ENABLE_DEVICE_MAPPER.
* libparted/tests/t2100-zerolen.sh: New file.
* libparted/tests/zerolen.c: New file.
* tests/test-lib.sh (wait_for_dev_to_appear_): New function, copied from
tests/t-local.sh.
* NEWS (Bug fixes): Mention it.
---
 NEWS                             |    3 ++
 bootstrap.conf                   |    1 +
 configure.ac                     |    3 ++
 libparted/arch/linux.c           |   14 +++++++
 libparted/tests/Makefile.am      |    9 +++--
 libparted/tests/t2100-zerolen.sh |   75 ++++++++++++++++++++++++++++++++++++++
 libparted/tests/zerolen.c        |   52 ++++++++++++++++++++++++++
 tests/test-lib.sh                |   16 ++++++++
 8 files changed, 170 insertions(+), 3 deletions(-)
 create mode 100755 libparted/tests/t2100-zerolen.sh
 create mode 100644 libparted/tests/zerolen.c

diff --git a/NEWS b/NEWS
index 4979b90..65e5a69 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,9 @@ GNU parted NEWS                                    -*- 
outline -*-
   an msdos partition table on a very small device (smaller than one cylinder)
   is now recognized.  [bug introduced in parted-2.2]
 
+  libparted: zero-length devices (other than files) are ignored rather than
+  throwing an exception.
+
 
 * Noteworthy changes in release 2.3 (2010-05-28) [stable]
 
diff --git a/bootstrap.conf b/bootstrap.conf
index 01f354b..773c6c5 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -68,6 +68,7 @@ gnulib_modules="
   version-etc-fsf
   warnings
   xstrtol
+  xstrtoll
 "
 
 # Additional xgettext options to use.  Use "\\\newline" to break lines.
diff --git a/configure.ac b/configure.ac
index 54d3ec1..25960a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -310,10 +310,13 @@ fi
 
 dnl Check for libdl, if we are doing dynamic loading
 DL_LIBS=""
+AC_SUBST([DYNAMIC_LOADING])
+DYNAMIC_LOADING=no
 if test "$enable_dynamic_loading" = yes; then
        AC_CHECK_LIB([dl], [dlopen],
                DL_LIBS="-ldl"
                PARTED_LIBS="$PARTED_LIBS -ldl"
+               DYNAMIC_LOADING=yes
                AC_DEFINE([DYNAMIC_LOADING], [1], [Lazy linking to fs libs]),
                AC_MSG_ERROR(
                        [-ldl not found!  Try using --disable-dynamic-loading]
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index b1f7dc9..a5ae10c 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -46,6 +46,7 @@
 
 #include "../architecture.h"
 #include "dirname.h"
+#include "xstrtol.h"
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -719,11 +720,18 @@ _device_get_length (PedDevice* dev)
         unsigned long           size;
         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
         uint64_t bytes=0;
+        const char*             test_str;
+        PedSector               test_size;
 
 
         PED_ASSERT (dev->open_count > 0, return 0);
         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
 
+        test_str = getenv ("PARTED_TEST_DEVICE_LENGTH");
+        if (test_str
+            && xstrtoll (test_str, NULL, 10, &test_size, NULL) == LONGINT_OK)
+                return test_size;
+
         if (_kernel_has_blkgetsize64()) {
                 if (ioctl(arch_specific->fd, BLKGETSIZE64, &bytes) == 0) {
                         return bytes / dev->sector_size;
@@ -1189,6 +1197,12 @@ init_generic (PedDevice* dev, const char* model_name)
         if (_device_probe_geometry (dev)) {
                 ped_exception_leave_all ();
         } else {
+               if (!_device_get_length (dev)) {
+                       ped_exception_catch ();
+                       ped_exception_leave_all ();
+                       goto error_close_dev;
+               }
+
                 /* hack to allow use of files, for testing */
                 ped_exception_catch ();
                 ped_exception_leave_all ();
diff --git a/libparted/tests/Makefile.am b/libparted/tests/Makefile.am
index 2a60023..937cab8 100644
--- a/libparted/tests/Makefile.am
+++ b/libparted/tests/Makefile.am
@@ -3,9 +3,9 @@
 #
 # This file may be modified and/or distributed without restriction.
 
-TESTS = t1000-label.sh t2000-disk.sh t3000-symlink.sh
+TESTS = t1000-label.sh t2000-disk.sh t2100-zerolen.sh t3000-symlink.sh
 EXTRA_DIST = $(TESTS)
-check_PROGRAMS = label disk symlink
+check_PROGRAMS = label disk zerolen symlink
 AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
 
 LDADD = \
@@ -19,6 +19,7 @@ AM_CPPFLAGS = \
 
 label_SOURCES = common.h common.c label.c
 disk_SOURCES  = common.h common.c disk.c
+zerolen_SOURCES = common.h common.c zerolen.c
 symlink_SOURCES = common.h common.c symlink.c
 
 MAINTAINERCLEANFILES = Makefile.in
@@ -34,4 +35,6 @@ old-init.sh: Makefile.in
        mv address@hidden $@
 
 TESTS_ENVIRONMENT = \
-  top_srcdir='$(top_srcdir)'
+  top_srcdir='$(top_srcdir)' \
+  DYNAMIC_LOADING=$(DYNAMIC_LOADING) \
+  ENABLE_DEVICE_MAPPER=$(ENABLE_DEVICE_MAPPER)
diff --git a/libparted/tests/t2100-zerolen.sh b/libparted/tests/t2100-zerolen.sh
new file mode 100755
index 0000000..77d51de
--- /dev/null
+++ b/libparted/tests/t2100-zerolen.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Copyright (C) 2007-2010 Free Software Foundation, Inc.
+
+# 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 3 of the License, or
+# (at your option) any later version.
+
+# This program 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/>.
+
+test_description='run the zerolen unit tests in a directory supporting 
O_DIRECT'
+
+# Need root privileges to create a device-mapper device.
+privileges_required_=1
+device_mapper_required_=1
+
+: ${top_srcdir=../..}
+. "$top_srcdir/tests/test-lib.sh"
+
+init_root_dir_
+
+# This test only makes sense on Linux.
+test "$(uname -s)" = Linux \
+  || skip_test_ "not on Linux"
+
+test "x$DYNAMIC_LOADING" = xyes \
+  || skip_test_ "no dynamic loading support"
+
+test "x$ENABLE_DEVICE_MAPPER" = xyes \
+  || skip_test_ "no device-mapper support"
+
+# Device map name - should be random to not conflict with existing ones on
+# the system
+linear_=plinear-$$
+
+cleanup_()
+{
+  # 'dmsetup remove' may fail because udev is still processing the device.
+  # Try it repeatedly for 2s.
+  i=0
+  incr=1
+  while :; do
+    dmsetup remove $linear_ > /dev/null 2>&1 && break
+    sleep .1 2>/dev/null || { sleep 1; incr=10; }
+    i=$(expr $i + $incr); test $i = 20 && break
+  done
+  if test $i = 20; then
+    dmsetup remove $linear_
+  fi
+
+  test -n "$d1" && losetup -d "$d1"
+  rm -f "$f1"
+}
+
+f1=$(pwd)/1
+d1=$(loop_setup_ "$f1") \
+  || skip_test_ "is this partition mounted with 'nodev'?"
+
+echo "0 1024 linear $d1 0" | dmsetup create "$linear_" \
+  || skip_test_ "unable to create dm device"
+
+wait_for_dev_to_appear_ "/dev/mapper/$linear_" \
+  || skip_test_ "dm device did not appear"
+
+test_expect_success \
+    'run the actual tests' "zerolen /dev/mapper/$linear_"
+
+test_done
diff --git a/libparted/tests/zerolen.c b/libparted/tests/zerolen.c
new file mode 100644
index 0000000..cf2bd1c
--- /dev/null
+++ b/libparted/tests/zerolen.c
@@ -0,0 +1,52 @@
+#include <config.h>
+#include <unistd.h>
+
+#include <check.h>
+
+#include <parted/parted.h>
+
+#include "common.h"
+#include "progname.h"
+
+static const char* temporary_disk;
+
+/* TEST: Probe a zero-length disk image without raising an exception */
+START_TEST (test_probe)
+{
+        PedDevice* dev = ped_device_get (temporary_disk);
+        if (dev)
+                ped_device_destroy (dev);
+}
+END_TEST
+
+int
+main (int argc, char **argv)
+{
+        set_program_name (argv[0]);
+        int number_failed;
+        Suite* suite = suite_create ("ZeroLen");
+        TCase* tcase_probe = tcase_create ("Probe");
+
+        if (argc < 2) {
+                fail ("Insufficient arguments");
+                return EXIT_FAILURE;
+        }
+        temporary_disk = argv[1];
+        setenv ("PARTED_TEST_DEVICE_LENGTH", "0", 1);
+
+        /* Fail when an exception is raised */
+        ped_exception_set_handler (_test_exception_handler);
+
+        tcase_add_test (tcase_probe, test_probe);
+        /* Disable timeout for this test */
+        tcase_set_timeout (tcase_probe, 0);
+        suite_add_tcase (suite, tcase_probe);
+
+        SRunner* srunner = srunner_create (suite);
+        srunner_run_all (srunner, CK_VERBOSE);
+
+        number_failed = srunner_ntests_failed (srunner);
+        srunner_free (srunner);
+
+        return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/test-lib.sh b/tests/test-lib.sh
index 8ed9b01..c9b6f37 100644
--- a/tests/test-lib.sh
+++ b/tests/test-lib.sh
@@ -390,4 +390,20 @@ require_xfs_()
     }
 }
 
+# Helper function: wait 2s (via .1s increments) for FILE to appear.
+# Usage: wait_for_dev_to_appear_ /dev/sdg
+# Return 0 upon success, 1 upon failure.
+wait_for_dev_to_appear_()
+{
+  local file=$1
+  local i=0
+  local incr=1
+  while :; do
+    ls "$file" > /dev/null 2>&1 && return 0
+    sleep .1 2>/dev/null || { sleep 1; incr=10; }
+    i=$(expr $i + $incr); test $i = 20 && break
+  done
+  return 1
+}
+
 sector_size_=${PARTED_SECTOR_SIZE:-512}
-- 
1.7.1



reply via email to

[Prev in Thread] Current Thread [Next in Thread]