diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libparted/tests/Makefile.am | 16 | ||||
-rwxr-xr-x | libparted/tests/t1000-label.sh | 29 | ||||
-rw-r--r-- | m4/o-direct.m4 | 235 | ||||
-rw-r--r-- | tests/Makefile.am | 11 | ||||
-rwxr-xr-x | tests/mkdtemp | 107 | ||||
-rw-r--r-- | tests/test-lib.sh | 28 |
8 files changed, 407 insertions, 22 deletions
@@ -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' |