[Parted-commits] GNU Parted Official Repository: Changes to 'stable-1.8.x'

Otavio Salvador otavio at alioth.debian.org
Fri May 25 17:24:51 UTC 2007


 .gitignore                     |    1 
 configure.ac                   |    2 
 doc/parted.texi                |    4 
 libparted/fs/ext2/ext2_mkfs.c  |    4 
 libparted/tests/Makefile.am    |   16 ++
 libparted/tests/t1000-label.sh |   29 +++++
 m4/o-direct.m4                 |  235 +++++++++++++++++++++++++++++++++++++++++
 parted/strlist.c               |   22 ---
 tests/Makefile.am              |   14 +-
 tests/mkdtemp                  |  107 ++++++++++++++++++
 tests/t3000-constraints.sh     |   61 ++++++++++
 tests/test-lib.sh              |   28 ++--
 12 files changed, 477 insertions(+), 46 deletions(-)

New commits:
commit 9322f93b2045f0504666f3e6947e8ff63bfb0586
Author: Jim Meyering <jim at meyering.net>
Date:   Fri May 25 19:13:28 2007 +0200

    Fix off-by-one error in previous change.
    * parted/strlist.c (str_list_print_wrap): Don't output a space unconditionally.
    (cherry picked from commit 0a5faac764f0a23ebcd3abbd5b65395253a1a24a)

diff --git a/parted/strlist.c b/parted/strlist.c
index b5d2ba4..7739e9b 100644
--- a/parted/strlist.c
+++ b/parted/strlist.c
@@ -495,7 +495,7 @@ str_list_print_wrap (const StrList* list, int line_length, int offset,
 			line_left = line_length - indent;
 
 			if (walk->next || *str)
-				printf ("\n%*s", indent, " ");
+				printf ("\n%*s", indent, "");
 			else if (line_break)
 				putchar ('\n');
 		}

commit 121d1710dd36958eae780693b70ea7fc7823ad4a
Author: Jim Meyering <jim at meyering.net>
Date:   Fri May 25 18:45:39 2007 +0200

    Remove a silly (and dangerous) function.
    
    This change has no effect, except in a low-memory condition,
    where the old code would dereference NULL, the new code no
    longer performs that malloc.
    
    * parted/strlist.c (get_spaces): Remove this function.
    Not only is it useless, but it also has an unchecked malloc.
    (str_list_print_wrap): Don't allocate and initialize a string
    just to print a sequence of N spaces.
    (cherry picked from commit c6b1b351b432c227157d8da6e99388958b07115a)

diff --git a/parted/strlist.c b/parted/strlist.c
index da1b09f..b5d2ba4 100644
--- a/parted/strlist.c
+++ b/parted/strlist.c
@@ -1,6 +1,6 @@
 /*
     parted - a frontend to libparted
-    Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+    Copyright (C) 1999, 2000, 2001, 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
@@ -390,20 +390,6 @@ str_list_print (const StrList* list)
 	}
 }
 
-static char*
-get_spaces (int space_count)
-{
-	char*	str;
-	int	i;
-
-	str = malloc (space_count + 1);
-	for (i = 0; i < space_count; i++)
-		str [i] = ' ';
-	str [i] = 0;
-
-	return str;
-}
-
 static int
 str_search (const wchar_t* str, int n, wchar_t c)
 {
@@ -459,13 +445,11 @@ str_list_print_wrap (const StrList* list, int line_length, int offset,
 	int		cut_right;
 	int		cut_left;
 	int		line_left;
-	char*		spaces;
 	int		search_result;
 	int		line_break;
 
 	PED_ASSERT (line_length - indent > 10, return);
 
-	spaces = get_spaces (indent);
 	line_left = line_length - offset;
 
 	for (walk=list; walk; walk=walk->next) {
@@ -511,7 +495,7 @@ str_list_print_wrap (const StrList* list, int line_length, int offset,
 			line_left = line_length - indent;
 
 			if (walk->next || *str)
-				printf ("\n%s", spaces);
+				printf ("\n%*s", indent, " ");
 			else if (line_break)
 				putchar ('\n');
 		}
@@ -519,8 +503,6 @@ str_list_print_wrap (const StrList* list, int line_length, int offset,
 		print_wchar (str, 0);
 		line_left -= wchar_strlen (str);
 	}
-
-	free (spaces);
 }
 
 static int

commit 70cd4f6cf6e010429fa008b7e474a1dbad7fcd2e
Author: Jim Meyering <jim at meyering.net>
Date:   Fri May 25 13:58:15 2007 +0200

    doc/parted.texi (Static binaries): Correct an invalid example.
    One cannot specify "primary" for a partition on a loop device.
    (cherry picked from commit 953716d1e2c4e5fb86924776711d848d7cc31b95)

diff --git a/doc/parted.texi b/doc/parted.texi
index 6a317cf..139ea77 100644
--- a/doc/parted.texi
+++ b/doc/parted.texi
@@ -14,7 +14,7 @@ resizing, checking and copy partitions and file systems on them.
 @ifnottex @c texi2pdf don't understand copying and insertcopying ???
 @c modifications must also be done in the titlepage
 @copying
-Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
 Free Software Foundation, Inc.
 
 Permission is granted to copy, distribute and/or modify this document
@@ -335,7 +335,7 @@ of the latest GNU Parted version is available, which you can use thus:
 @item Create a file system. Example:
 
 @example
-$ @kbd{parted /dev/fd0 mklabel loop mkpartfs primary ext2 0 1.4}
+$ @kbd{parted /dev/fd0 mklabel loop mkpartfs ext2 0 1.4}
 @end example
 
 @item Mount the floppy disk, e.g.,

commit c7d6aaf8fc01f42a58dacbccfeac1f2b474321a3
Author: Jim Meyering <jim at meyering.net>
Date:   Thu May 24 20:00:22 2007 +0200

    Diagnose "ext2 FS too small" rather than triggering an assertion.
    * libparted/fs/ext2/ext2_mkfs.c (ext2_mkfs): An overlapping ext2
    partition request could still lead to a bug: constraint-resolution
    code would produce a single-sector candidate "range", and that
    would cause the ext2 fs-creation code to misbehave.  Now, it
    properly detects and reports the FS as being too small.
    * tests/t3000-constraints.sh: New test for the above.
    * tests/Makefile.am (TESTS): Add t3000-constraints.sh.
    (cherry picked from commit 32c069f0b2404cbc75eff3f729207bf9193979d0)

diff --git a/libparted/fs/ext2/ext2_mkfs.c b/libparted/fs/ext2/ext2_mkfs.c
index 8f74a45..92261f6 100644
--- a/libparted/fs/ext2/ext2_mkfs.c
+++ b/libparted/fs/ext2/ext2_mkfs.c
@@ -542,7 +542,8 @@ struct ext2_fs *ext2_mkfs(struct ext2_dev_handle *handle,
 
 	if (numblocks == 0)
 		numblocks = handle->ops->get_size(handle->cookie);
-        PED_ASSERT(numblocks != 0, return NULL);
+        if (numblocks == 0)
+                goto diagnose_fs_too_small;
 
 	if (blocks_per_group == (unsigned int) 0)
 		blocks_per_group = 8 << log_block_size;
@@ -589,6 +590,7 @@ struct ext2_fs *ext2_mkfs(struct ext2_dev_handle *handle,
           fs_too_small = 1;
 
 	if (fs_too_small) {
+	diagnose_fs_too_small:
 		ped_exception_throw (
 			PED_EXCEPTION_ERROR,
 			PED_EXCEPTION_CANCEL,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 59d38e5..27689c9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,7 +3,8 @@ TESTS = \
   t1000-mkpartfs.sh \
   t1100-busy-label.sh \
   t1500-small-ext2.sh \
-  t2000-mkfs.sh
+  t2000-mkfs.sh \
+  t3000-constraints.sh
 
 EXTRA_DIST = \
   $(TESTS) test-lib.sh mkdtemp
diff --git a/tests/t3000-constraints.sh b/tests/t3000-constraints.sh
new file mode 100755
index 0000000..07fe1b3
--- /dev/null
+++ b/tests/t3000-constraints.sh
@@ -0,0 +1,61 @@
+#!/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="exercise Parted's constraint-management code"
+
+. ./init.sh
+
+# FIXME: move this to test-lib.sh, and use it in t0000*.sh
+emit_superuser_warning()
+{
+  uid=`id -u` || uid=1
+  test "$uid" != 0 &&
+    echo 'WARNING: You are not superuser.  Watch out for permissions.'
+}
+
+dev=loop-file
+N=2
+t=ext2
+
+test_expect_success \
+    "setup: label and create a small $t partition" \
+    'dd if=/dev/zero of=$dev bs=${N}M count=1 2>/dev/null &&
+     { echo y; echo c; } > in &&
+     { emit_superuser_warning
+       echo "Warning: You requested a partition from 1000kB to 2000kB."
+       echo "The closest location we can manage is 15.9kB to 15.9kB." \
+	    " Is this still acceptable to you?"
+       echo "Yes/No? y"
+       echo "Error: File system too small for ext2."; } > exp &&
+     parted -s $dev mklabel msdos &&
+     parted -s $dev mkpartfs primary $t 1 $N'
+
+# Before parted-1.9, this would fail with a buffer overrun
+# leading to a segfault.
+test_expect_failure \
+    'try to create another partition in the same place' \
+    'parted ---pretend-input-tty $dev mkpartfs primary $t 1 $N <in >out 2>&1'
+
+test_expect_success \
+    'normalize the actual output' \
+    'sed "s,
   *
,,;s, $,," out > o2 && mv -f o2 out'
+
+test_expect_success 'check for expected output' '$compare out exp'
+
+test_done

commit b8e7114e77721d7e3299cc1dbbb91524d16ce023
Author: Jim Meyering <jim at meyering.net>
Date:   Thu May 24 18:21:43 2007 +0200

    Fix typo in privs-required test setup.
    * tests/test-lib.sh: Fix typo: s/\$parted/$parted_/.
    (cherry picked from commit 9b20990eb4491dcc626261a22f4f240abd9b3f74)

diff --git a/tests/test-lib.sh b/tests/test-lib.sh
index 59f85a4..050b967 100644
--- a/tests/test-lib.sh
+++ b/tests/test-lib.sh
@@ -223,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.

commit 07a13495995bd0695f73e48be9d89c36df42d1fa
Author: Jim Meyering <jim at meyering.net>
Date:   Wed May 23 22:28:53 2007 +0200

    Don't fail all tests when "." lacks O_DIRECT support.
    
    I often build tools on a tmpfs file system (it's faster), and
    found that parted tests always failed there.  That's because it tries
    to open the "device" (a file) with O_DIRECT, and at least the linux tmpfs
    driver always fails with EINVAL in that case.
    
    So here's a patch that makes it work.
    Since the test may require writing in a directory like /tmp,
    to which others typically have write access, it is particularly
    careful about security (see the mkdtemp script below), in case
    "make check" is run by e.g., root.
    
    Don't fail all tests when "." lacks O_DIRECT support.
    Before, running "make check" on a file system that doesn't support
    O_DIRECT (e.g. tmpfs), would always fail.  Now, it works, as long as
    the test machinery can find a writable directory in which open with
    O_DIRECT *does* work.
    * m4/o-direct.m4: New file.  Find a directory/FS with O_DIRECT support.
    * configure.ac: Use the new macro.
    * libparted/tests/t1000-label.sh: New file.  Wrap the binary, so
    it can take advantage of the code that finds O_DIRECT supporting FS.
    * tests/mkdtemp: New file.  Required, since when running tests as
    root, we may have to create a temporary directory in a directory
    like /tmp that's writable by others.
    * tests/Makefile.am (EXTRA_DIST): Add mkdtemp.
    * tests/test-lib.sh: When creating test subdir, and setting up "trap",
    use the directory specified in $PARTED_USABLE_TEST_DIR.
    Don't set PATH here.  Now, that's done via the generated, and always-
    sourced, init.sh.  As a result, invoke parted via its full file name.
    (cherry picked from commit 873251291e04dec0f7ab0d5b7d65809981ed95b4)

diff --git a/.gitignore b/.gitignore
index 8485e8a..89fe0ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ doc/C/po/parted.8.pot
 doc/pt_BR/parted.8.pt_BR.po
 gnulib/
 libparted.pc
+libparted/tests/init.sh
 libparted/tests/label
 libtool
 m4
diff --git a/configure.ac b/configure.ac
index bc08cc5..e946fad 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'



More information about the Parted-commits mailing list