summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--configure.ac2
-rw-r--r--libparted/tests/Makefile.am16
-rwxr-xr-xlibparted/tests/t1000-label.sh29
-rw-r--r--m4/o-direct.m4235
-rw-r--r--tests/Makefile.am11
-rwxr-xr-xtests/mkdtemp107
-rw-r--r--tests/test-lib.sh28
8 files changed, 407 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index 28054a3..1bcbf96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ configure
doc/C/po/parted.8.pot
doc/pt_BR/parted.8.pt_BR.po
libparted.pc
+libparted/tests/init.sh
libparted/tests/label
libtool
m4
diff --git a/configure.ac b/configure.ac
index 18a30d9..b21be56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -171,6 +171,7 @@ AC_PROG_GCC_TRADITIONAL
AM_PROG_CC_C_O
gl_EARLY
+parted_FIND_USABLE_TEST_DIR
dnl This test must come as early as possible after the compiler configuration
dnl tests, because the choice of the file model can (in principle) affect
@@ -460,7 +461,6 @@ AC_C_INLINE
AC_C_CONST
AC_C_RESTRICT
-
dnl Checks for library functions.
AC_CHECK_FUNCS(sigaction)
AC_CHECK_FUNCS(getuid)
diff --git a/libparted/tests/Makefile.am b/libparted/tests/Makefile.am
index 8c1e07b..12ad29f 100644
--- a/libparted/tests/Makefile.am
+++ b/libparted/tests/Makefile.am
@@ -1,12 +1,24 @@
# This file is part of GNU Parted
-# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
#
# This file may be modified and/or distributed without restriction.
-TESTS = label
+TESTS = t1000-label.sh
+EXTRA_DIST = $(TESTS)
bin_PROGRAMS = label
label_CFLAGS = $(CHECK_CFLAGS) -I$(top_srcdir)/include
label_LDADD = $(CHECK_LIBS) $(top_builddir)/libparted/libparted.la
label_SOURCES = common.h common.c label.c
MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = init.sh
+all: init.sh
+init.sh: Makefile.in
+ rm -f $@-t $@
+ echo 'PARTED_USABLE_TEST_DIR=$(PARTED_USABLE_TEST_DIR)' > $@-t
+ echo 'abs_top_srcdir=$(abs_top_srcdir)' >> $@-t
+ echo '. $(abs_top_srcdir)/tests/test-lib.sh' >> $@-t
+ echo 'PATH=$(abs_builddir)$(PATH_SEPARATOR)$$PATH; export PATH' >> $@-t
+ chmod a-w $@-t
+ mv $@-t $@
diff --git a/libparted/tests/t1000-label.sh b/libparted/tests/t1000-label.sh
new file mode 100755
index 0000000..34010b1
--- /dev/null
+++ b/libparted/tests/t1000-label.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Copyright (C) 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+test_description='run the label unit tests in a directory supporting O_DIRECT'
+# This wrapper around the ./label binary is used to find a directory
+# in which one can open a file with the O_DIRECT flag.
+
+. ./init.sh
+
+test_expect_success \
+ 'run the actual tests' 'label'
+
+test_done
diff --git a/m4/o-direct.m4 b/m4/o-direct.m4
new file mode 100644
index 0000000..ec84ef4
--- /dev/null
+++ b/m4/o-direct.m4
@@ -0,0 +1,235 @@
+#serial 1
+# Find a directory in which a disk-simulating file is usable by parted.
+# The problem is that on systems supporting O_DIRECT, open with O_DIRECT
+# fails for some file system types (e.g., tmpfs on linux-2.6.21).
+
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# From Jim Meyering.
+
+# Set PARTED_USABLE_TEST_DIR to the name of the first usable directory
+# from the list below. If none is usable, set it to the empty string.
+# Consider $TMPDIR only if it specifies an absolute name, and that
+# name contains no shell meta-character. Likewise for $HOME.
+# The candidate directories:
+# . $HOME $TMPDIR /tmp /var/tmp /dev/shm
+AC_DEFUN([parted_FIND_USABLE_TEST_DIR],
+[
+ AC_CACHE_CHECK([for a usable (O_DIRECT-supporting) temporary dir],
+ [parted_cv_func_open_O_DIRECT_temp_dir],
+ [
+ # First of all, if there is no O_DIRECT definition, use ".",
+ # and skip the run-test.
+ AC_EGREP_CPP([frobnozzle], [
+#include <fcntl.h>
+#ifdef O_DIRECT
+frobnozzle
+#endif
+ ], pe_have_O_DIRECT=yes, pe_have_O_DIRECT=no)
+ if test $pe_have_O_DIRECT = no; then
+ # With no O_DIRECT definition, "." is fine.
+ pe_cand_dirs=.
+ else
+ pe_cand_dirs=.
+ for pe_dir in "$HOME" "$TMPDIR"; do
+ case $pe_dir in
+ /tmp) ;;
+ /var/tmp) ;;
+ /dev/shm) ;;
+ /*) case $pe_dir in
+ # Accept $HOME or $TMP only if the value is nice and boring.
+ *[^/a-zA-Z0-9_.-]*) ;;
+ *) pe_cand_dirs="$pe_cand_dirs $pe_dir";;
+ esac
+ esac
+ done
+
+ # This is the list of candidate directories.
+ pe_cand_dirs="$pe_cand_dirs /tmp /var/tmp /dev/shm"
+
+ PARTED_CANDIDATE_DIRS=$pe_cand_dirs
+ export PARTED_CANDIDATE_DIRS
+
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOGICAL_BLOCK_SIZE 4096
+static char g_buf[2 * LOGICAL_BLOCK_SIZE];
+
+static inline void *
+ptr_align (void const *ptr, size_t alignment)
+{
+ char const *p0 = ptr;
+ char const *p1 = p0 + alignment - 1;
+ return (void *) (p1 - (size_t) p1 % alignment);
+}
+
+static int
+create_input_file (char const *file, char const *buf, size_t n_bytes)
+{
+ int fd = open (file, O_CREAT | O_WRONLY, 0600);
+ if (fd < 0)
+ return 1;
+ if (write (fd, buf, n_bytes) != n_bytes)
+ {
+ close (fd);
+ return 1;
+ }
+ return !! close (fd);
+}
+
+static int
+try_o_direct (char const *file)
+{
+ char const *p = ptr_align (g_buf, LOGICAL_BLOCK_SIZE);
+ int fd;
+
+ if (!(p + LOGICAL_BLOCK_SIZE < g_buf + sizeof g_buf))
+ return 4;
+
+ fd = open (file, O_WRONLY | O_DIRECT);
+ if (fd < 0)
+ return 1;
+
+ if (write (fd, p, LOGICAL_BLOCK_SIZE) != LOGICAL_BLOCK_SIZE)
+ return 1;
+
+ return !! close (fd);
+}
+
+#undef stpcpy
+#define stpcpy(a, b) my_stpcpy (a, b)
+static char *
+my_stpcpy (char *dest, const char *src)
+{
+ char *d = dest;
+ const char *s = src;
+ do *d++ = *s; while (*s++ != '\0');
+ return d - 1;
+}
+
+/* The base name of the file we'll create in the mkdtemp-returned
+ temporary directory. */
+#define BASENAME "x"
+
+/* Return 0 upon failure, else the 1-based index of the first
+ useful directory name from PARTED_CANDIDATE_DIRS. */
+int
+main ()
+{
+ char const *env_dirs;
+ char *dirs;
+ char *dir;
+ unsigned int n;
+ int found = 0;
+ size_t dirs_len;
+
+ if ((env_dirs = getenv ("PARTED_CANDIDATE_DIRS")) == NULL)
+ return 0;
+
+ dirs_len = strlen (env_dirs);
+ if ((dirs = strndup (env_dirs, dirs_len)) == NULL)
+ return 0;
+ dir = dirs;
+
+ for (n = 1; ; n++)
+ {
+ size_t dirname_len;
+ char *space;
+
+ /* Skip any leading spaces. */
+ while (*dir == ' ')
+ ++dir;
+
+ space = strchr (dir, ' ');
+ if (space)
+ {
+ *space = '\0';
+ dirname_len = space - dir;
+ }
+ else
+ {
+ dirname_len = strlen (dir);
+ }
+
+ if (dirname_len != 0)
+ {
+ /* Create an mkdtemp template starting with dir. */
+ char *tmp;
+ char *endp;
+ char const *base = "partedOD.XXXXXX";
+ /* Allocate enough space not just for the dir name, but
+ also for the name of the file to create within it. */
+ char *template = malloc (dirname_len + 1 + strlen (base)
+ + 1 + strlen (BASENAME) + 1);
+ if (template != NULL
+ && (endp = stpcpy (stpcpy (stpcpy (template, dir), "/"), base))
+ && (tmp = mkdtemp (template)) != NULL)
+ {
+ /* Append "/BASENAME" to create the file name. */
+ stpcpy (stpcpy (endp, "/"), BASENAME);
+
+ if (create_input_file (tmp, g_buf, sizeof g_buf) == 0
+ && try_o_direct (tmp) == 0)
+ found = 1;
+
+ unlink (tmp); /* ignore failure */
+ *endp = '\0';
+ rmdir (tmp); /* ignore failure */
+ }
+ if (template)
+ free (template);
+ }
+
+ if (found)
+ break;
+
+ dir += dirname_len + 1;
+ if (dirs + dirs_len < dir)
+ {
+ n = 0;
+ break;
+ }
+ }
+ free (dirs);
+
+ return n;
+}
+ ]])],
+ # If the above program exits with status 0, then
+ # there it found no useful directory. Use ".".
+ [parted_cv_func_open_O_DIRECT_temp_dir=.],
+
+ # It found one. The exit status is an index into the list.
+ # We also run this code when the program fails to compile or
+ # to link, as will happen on systems without a mkdtemp function.
+ [pe_err=$?; set _ $pe_cand_dirs; shift
+ eval parted_cv_func_open_O_DIRECT_temp_dir='$'$pe_err],
+
+ # When cross-compiling, use ".".
+ [parted_cv_func_open_O_DIRECT_temp_dir=.]
+ )
+ fi
+ ])
+ PARTED_USABLE_TEST_DIR=$parted_cv_func_open_O_DIRECT_temp_dir
+ AC_SUBST([PARTED_USABLE_TEST_DIR])
+
+ # If the result is ".", don't cache it. The next user of
+ # the cache may well be running from a different file system.
+ dnl Here, I'm using "$as_unset", which is a non-published (i.e., internal)
+ dnl part of autoconf, but we don't expect its name to change any time soon.
+ dnl and by then, it'll probably be ok to use "unset" all by itself.
+ if test "$parted_cv_func_open_O_DIRECT_temp_dir" = .; then
+ $as_unset parted_cv_func_open_O_DIRECT_temp_dir
+ fi
+])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 93247a0..59d38e5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -5,16 +5,17 @@ TESTS = \
t1500-small-ext2.sh \
t2000-mkfs.sh
-TESTS_ENVIRONMENT = \
- PATH="`pwd`/../parted$(PATH_SEPARATOR)$$PATH"
-
EXTRA_DIST = \
- $(TESTS) test-lib.sh
+ $(TESTS) test-lib.sh mkdtemp
CLEANFILES = init.sh
all: init.sh
init.sh: Makefile.in
rm -f $@-t $@
- ( echo 'srcdir=$(srcdir)'; echo '. $$srcdir/test-lib.sh' ) > $@-t
+ echo 'PARTED_USABLE_TEST_DIR=$(PARTED_USABLE_TEST_DIR)' > $@-t
+ echo 'abs_top_srcdir=$(abs_top_srcdir)' >> $@-t
+ echo '. $(abs_top_srcdir)/tests/test-lib.sh' >> $@-t
+ echo 'PATH=$(abs_top_builddir)/parted$(PATH_SEPARATOR)$$PATH' >> $@-t
+ echo 'export PATH' >> $@-t
chmod a-w $@-t
mv $@-t $@
diff --git a/tests/mkdtemp b/tests/mkdtemp
new file mode 100755
index 0000000..48fe054
--- /dev/null
+++ b/tests/mkdtemp
@@ -0,0 +1,107 @@
+#!/bin/sh
+# Create a temporary directory, sort of like mktemp -d does.
+# Usage: mkdtemp /tmp phoey.XXXXXXXXXX
+
+# First, try to use the mktemp program.
+# Failing that, we'll roll our own mktemp-like function:
+# - try to get random bytes from /dev/urandom
+# - failing that, generate output from a combination of quickly-varying
+# sources and gzip. Ignore non-varying gzip header, and extract
+# "random" bits from there.
+# - given those bits, map to file-name bytes using tr, and try to create
+# the desired directory.
+# - make only $MAX_TRIES attempts
+
+ME=$(basename "$0")
+die() { echo >&2 "$ME: $@"; exit 1; }
+
+MAX_TRIES=4
+
+rand_bytes()
+{
+ n=$1
+
+ chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
+
+ dev_rand=/dev/urandom
+ if test -r "$dev_rand"; then
+ # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194.
+ head -c$n "$dev_rand" | tr -c $chars 01234567$chars$chars$chars
+ return
+ fi
+
+ cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n'
+ data=$( (eval "$cmds") 2>&1 | gzip )
+
+ n_plus_50=$(expr $n + 50)
+
+ # Ensure that $data has length at least 50+$n
+ while :; do
+ len=$(echo "$data"|wc -c)
+ test $n_plus_50 -le $len && break;
+ data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip )
+ done
+
+ echo "$data" \
+ | dd bs=1 skip=50 count=$n 2>/dev/null \
+ | tr -c $chars 01234567$chars$chars$chars
+}
+
+mkdtemp()
+{
+ case $# in
+ 2);;
+ *) die "Usage: $ME DIR TEMPLATE";;
+ esac
+
+ destdir=$1
+ template=$2
+
+ case $template in
+ *XXXX) ;;
+ *) die "invalid template: $template (must have a suffix of at least 4 X's)";;
+ esac
+
+ fail=0
+
+ # First, try to use mktemp.
+ d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) \
+ || fail=1
+
+ # The resulting name must be in the specified directory.
+ case $d in "$destdir"*);; *) fail=1;; esac
+
+ # It must have created the directory.
+ test -d "$d" || fail=1
+
+ # It must have 0700 permissions.
+ perms=$(ls -dgo "$d" 2>/dev/null) || fail=1
+ case $perms in drwx------*) ;; *) fail=1;; esac
+
+ test $fail = 0 && {
+ echo "$d"
+ return
+ }
+
+ # If we reach this point, we'll have to create a directory manually.
+
+ # Get a copy of the template without its suffix of X's.
+ base_template=$(echo "$template"|sed 's/XX*$//')
+
+ # Calculate how many X's we've just removed.
+ nx=$(expr length "$template" - length "$base_template")
+
+ err=
+ i=1
+ while :; do
+ X=$(rand_bytes $nx)
+ candidate_dir="$destdir/$base_template$X"
+ err=$(mkdir -m 0700 "$candidate_dir" 2>&1) \
+ && { echo "$candidate_dir"; return; }
+ test $MAX_TRIES -le $i && break;
+ i=$(expr $i + 1)
+ done
+ die "$err"
+}
+
+mkdtemp "$@"
diff --git a/tests/test-lib.sh b/tests/test-lib.sh
index 8370963..59f85a4 100644
--- a/tests/test-lib.sh
+++ b/tests/test-lib.sh
@@ -201,11 +201,12 @@ if test "$privileges_required_" != ''; then
fi
fi
+# Test the binaries we have just built.
pwd_=`pwd`
+parted_="$pwd_/../parted/parted"
-# Test the binaries we have just built.
-PATH=$pwd_/../parted:$PATH
-export PATH
+test_dir_=$PARTED_USABLE_TEST_DIR
+test $test_dir_ = . && test_dir_=$pwd_
fail=
# Some tests require an actual hardware device, e.g., a real disk with a
@@ -222,8 +223,8 @@ if test $skip_ = 0 && test "$erasable_device_required_" != ''; then
if test "$DEVICE_TO_ERASE" != '' && test "$DEVICE_TO_ERASE_SIZE" != ''; then
dev_=$DEVICE_TO_ERASE
sz=$DEVICE_TO_ERASE_SIZE
- parted_output=$(parted -s $dev_ print) || fail="no such device: $dev_"
- parted -s $dev_ print|grep "^Disk $dev_: $sz$" \
+ parted_output=$($parted -s $dev_ print) || fail="no such device: $dev_"
+ $parted -s $dev_ print|grep "^Disk $dev_: $sz$" \
> /dev/null || fail="actual device size is not $sz"
# Try to see if $dev_ or any of its partitions is mounted.
# This is not reliable. FIXME: find a better way.
@@ -232,7 +233,7 @@ if test $skip_ = 0 && test "$erasable_device_required_" != ''; then
# contains no "//" or "/./" components.
# Prefer df --local, if it works, so we don't waste time
- # enumerating with lots of automounted file systems.
+ # enumerating lots of automounted file systems.
( df --local / > /dev/null 2>&1 ) && df='df --local' || df=df
$df | grep "^$dev_" && fail="$dev_ is already mounted"
$df | grep "^$dev_[0-9]" && fail="a partition of $dev_ is already mounted"
@@ -274,17 +275,16 @@ do
esac
done
+t0=$($abs_top_srcdir/tests/mkdtemp $test_dir_ parted-$this_test.XXXXXXXXXX) \
+ || error "failed to create temporary directory in $test_dir_"
+
# Run each test from within a temporary sub-directory named after the
-# test itself, and arrange to remove it upon exception and upon normal exit.
-t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp_=$t0/$$
-trap 'st=$?; cleanup_; cd "$pwd_" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $st' 0
+# test itself, and arrange to remove it upon exception or normal exit.
+trap 'st=$?; cleanup_; d='"$t0"';
+ cd '"$test_dir_"' && chmod -R u+rwx "$d" && rm -rf "$d" && exit $st' 0
trap '(exit $?); exit $?' 1 2 13 15
-framework_failure=0
-mkdir -p $tmp_ || framework_failure=1
-cd $tmp_ || framework_failure=1
-test $framework_failure = 0 \
- || error 'failed to create temporary directory'
+cd $t0 || error "failed to cd to $t0"
if ( diff --version < /dev/null 2>&1 | grep GNU ) 2>&1 > /dev/null; then
compare='diff -u'