Add automated filesystem checking based on scripts I've used now for
authorVladimir Serbinenko <phcoder@gmail.com>
Tue, 19 Nov 2013 20:05:59 +0000 (21:05 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Tue, 19 Nov 2013 20:05:59 +0000 (21:05 +0100)
quite some time locally. Most of the test require root so they are
skipped when run without necessarry privelegies.

25 files changed:
ChangeLog
Makefile.am
Makefile.util.def
gentpl.py
tests/btrfs_test.in [new file with mode: 0644]
tests/cpio_test.in [new file with mode: 0644]
tests/exfat_test.in [new file with mode: 0644]
tests/ext234_test.in [new file with mode: 0644]
tests/fat_test.in [new file with mode: 0644]
tests/hfs_test.in [new file with mode: 0644]
tests/hfsplus_test.in [new file with mode: 0644]
tests/iso9660_test.in [new file with mode: 0644]
tests/jfs_test.in [new file with mode: 0644]
tests/minixfs_test.in [new file with mode: 0644]
tests/nilfs2_test.in [new file with mode: 0644]
tests/ntfs_test.in [new file with mode: 0644]
tests/reiserfs_test.in [new file with mode: 0644]
tests/romfs_test.in [new file with mode: 0644]
tests/squashfs_test.in [new file with mode: 0644]
tests/tar_test.in [new file with mode: 0644]
tests/udf_test.in [new file with mode: 0644]
tests/util/grub-fs-tester.in [new file with mode: 0644]
tests/xfs_test.in [new file with mode: 0644]
tests/zfs_test.in [new file with mode: 0644]
util/garbage-gen.c [new file with mode: 0644]

index d0e3f56..5e63bea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-11-19  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Add automated filesystem checking based on scripts I've used now for
+       quite some time locally. Most of the test require root so they are
+       skipped when run without necessarry privelegies.
+
 2013-11-19  Colin Watson  <cjwatson@ubuntu.com>
 
        * util/grub-install.c (main): Adjust info messages to match
index 5063256..1e3b25b 100644 (file)
@@ -70,6 +70,10 @@ build-grub-mkfont: util/grub-mkfont.c grub-core/unidata.c grub-core/kern/emu/mis
        $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) -DGRUB_MKFONT=1 -DGRUB_BUILD=1 -DGRUB_UTIL=1 -DGRUB_BUILD_PROGRAM_NAME=\"build-grub-mkfont\" $^ $(build_freetype_cflags) $(build_freetype_libs)
 CLEANFILES += build-grub-mkfont
 
+garbage-gen: util/garbage-gen.c
+       $(BUILD_CC) -o $@ $(BUILD_CFLAGS) $(BUILD_CPPFLAGS)  $^
+CLEANFILES += garbage-gen
+
 build-grub-gen-asciih: util/grub-gen-asciih.c
        $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) -DGRUB_MKFONT=1 -DGRUB_BUILD=1 -DGRUB_UTIL=1 $^ $(build_freetype_cflags) $(build_freetype_libs) -Wall -Werror
 CLEANFILES += build-grub-gen-asciih
index ede7468..040b846 100644 (file)
@@ -690,6 +690,127 @@ script = {
   installdir = noinst;
 };
 
+script = {
+  name = grub-fs-tester;
+  common = tests/util/grub-fs-tester.in;
+  installdir = noinst;
+  dependencies = garbage-gen;
+};
+
+script = {
+  testcase;
+  name = ext234_test;
+  common = tests/ext234_test.in;
+};
+
+script = {
+  testcase;
+  name = squashfs_test;
+  common = tests/squashfs_test.in;
+};
+
+script = {
+  testcase;
+  name = iso9660_test;
+  common = tests/iso9660_test.in;
+};
+
+script = {
+  testcase;
+  name = hfsplus_test;
+  common = tests/hfsplus_test.in;
+};
+
+script = {
+  testcase;
+  name = ntfs_test;
+  common = tests/ntfs_test.in;
+};
+
+script = {
+  testcase;
+  name = reiserfs_test;
+  common = tests/reiserfs_test.in;
+};
+
+script = {
+  testcase;
+  name = fat_test;
+  common = tests/fat_test.in;
+};
+
+script = {
+  testcase;
+  name = minixfs_test;
+  common = tests/minixfs_test.in;
+};
+
+script = {
+  testcase;
+  name = xfs_test;
+  common = tests/xfs_test.in;
+};
+
+script = {
+  testcase;
+  name = nilfs2_test;
+  common = tests/nilfs2_test.in;
+};
+
+script = {
+  testcase;
+  name = romfs_test;
+  common = tests/romfs_test.in;
+};
+
+script = {
+  testcase;
+  name = exfat_test;
+  common = tests/exfat_test.in;
+};
+
+script = {
+  testcase;
+  name = tar_test;
+  common = tests/tar_test.in;
+};
+
+script = {
+  testcase;
+  name = udf_test;
+  common = tests/udf_test.in;
+};
+
+script = {
+  testcase;
+  name = hfs_test;
+  common = tests/hfs_test.in;
+};
+
+script = {
+  testcase;
+  name = jfs_test;
+  common = tests/jfs_test.in;
+};
+
+script = {
+  testcase;
+  name = btrfs_test;
+  common = tests/btrfs_test.in;
+};
+
+script = {
+  testcase;
+  name = zfs_test;
+  common = tests/zfs_test.in;
+};
+
+script = {
+  testcase;
+  name = cpio_test;
+  common = tests/cpio_test.in;
+};
+
 script = {
   testcase;
   name = example_scripted_test;
index 3ec853e..c805480 100644 (file)
--- a/gentpl.py
+++ b/gentpl.py
@@ -541,8 +541,8 @@ def script(platform):
     r += "[+ IF mansection +]" + manpage("grub-mkconfig_lib") + "[+ ENDIF +]"
     r += "[+ ENDIF +]"
 
-    r += rule("[+ name +]", "$(top_builddir)/config.status " + platform_sources(platform), """
-(skip=1; for x in $^; do if [ $$skip = 1 ]; then skip=0; else cat "$$x"; fi; done) | $(top_builddir)/config.status --file=$@:-
+    r += rule("[+ name +]", "$(top_builddir)/config.status " + platform_sources(platform) + platform_dependencies(platform), """
+(for x in """ + platform_sources(platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
 chmod a+x [+ name +]
 """)
 
diff --git a/tests/btrfs_test.in b/tests/btrfs_test.in
new file mode 100644 (file)
index 0000000..c55d947
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.btrfs >/dev/null 2>&1; then
+   echo "mkfs.btrfs not installed; cannot test btrfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" btrfs
+"@builddir@/grub-fs-tester" btrfs_zlib
+"@builddir@/grub-fs-tester" btrfs_lzo
+"@builddir@/grub-fs-tester" btrfs_raid0
+"@builddir@/grub-fs-tester" btrfs_raid1
+"@builddir@/grub-fs-tester" btrfs_single
+"@builddir@/grub-fs-tester" btrfs_raid10
diff --git a/tests/cpio_test.in b/tests/cpio_test.in
new file mode 100644 (file)
index 0000000..0b09db5
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+if ! which cpio >/dev/null 2>&1; then
+   echo "cpio not installed; cannot test cpio."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" cpio_bin
+"@builddir@/grub-fs-tester" cpio_odc
+"@builddir@/grub-fs-tester" cpio_newc
+"@builddir@/grub-fs-tester" cpio_crc
+"@builddir@/grub-fs-tester" cpio_ustar
+"@builddir@/grub-fs-tester" cpio_hpbin
+"@builddir@/grub-fs-tester" cpio_hpodc
diff --git a/tests/exfat_test.in b/tests/exfat_test.in
new file mode 100644 (file)
index 0000000..fc1a0fe
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.exfat >/dev/null 2>&1; then
+   echo "mkfs.exfat not installed; cannot test exFAT."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" exfat
diff --git a/tests/ext234_test.in b/tests/ext234_test.in
new file mode 100644 (file)
index 0000000..8910b71
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.ext2 >/dev/null 2>&1; then
+   echo "mkfs.ext2 not installed; cannot test ext2."
+   exit 77
+fi
+
+if ! which mkfs.ext3 >/dev/null 2>&1; then
+   echo "mkfs.ext3 not installed; cannot test ext3."
+   exit 77
+fi
+
+if ! which mkfs.ext4 >/dev/null 2>&1; then
+   echo "mkfs.ext4 not installed; cannot test ext4."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" ext2_old
+"@builddir@/grub-fs-tester" ext2
+"@builddir@/grub-fs-tester" ext3
+"@builddir@/grub-fs-tester" ext4
diff --git a/tests/fat_test.in b/tests/fat_test.in
new file mode 100644 (file)
index 0000000..1d132b5
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.vfat >/dev/null 2>&1; then
+   echo "mkfs.vfat not installed; cannot test FAT."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" vfat16a
+"@builddir@/grub-fs-tester" vfat12a
+"@builddir@/grub-fs-tester" vfat12
+"@builddir@/grub-fs-tester" vfat16
+"@builddir@/grub-fs-tester" vfat32
diff --git a/tests/hfs_test.in b/tests/hfs_test.in
new file mode 100644 (file)
index 0000000..e3e88f1
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.hfs >/dev/null 2>&1; then
+   echo "mkfs.hfs not installed; cannot test HFS."
+   exit 77
+fi
+
+if ! modprobe mac-roman; then
+   echo "no mac-roman support; cannot test HFS."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" hfs
diff --git a/tests/hfsplus_test.in b/tests/hfsplus_test.in
new file mode 100644 (file)
index 0000000..f947c4a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.hfsplus >/dev/null 2>&1; then
+   echo "mkfs.hfsplus not installed; cannot test hfsplus."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" hfsplus
+"@builddir@/grub-fs-tester" hfsplus_casesens
+"@builddir@/grub-fs-tester" hfsplus_wrap
diff --git a/tests/iso9660_test.in b/tests/iso9660_test.in
new file mode 100644 (file)
index 0000000..fdcc9e1
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -e
+
+if ! which xorriso >/dev/null 2>&1; then
+   echo "xorriso not installed; cannot test iso9660."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" joliet
+"@builddir@/grub-fs-tester" rockridge
+"@builddir@/grub-fs-tester" rockridge_joliet
+"@builddir@/grub-fs-tester" joliet_1999
+"@builddir@/grub-fs-tester" rockridge_1999
+"@builddir@/grub-fs-tester" rockridge_joliet_1999
\ No newline at end of file
diff --git a/tests/jfs_test.in b/tests/jfs_test.in
new file mode 100644 (file)
index 0000000..c2e5ece
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.jfs >/dev/null 2>&1; then
+   echo "mkfs.jfs not installed; cannot test JFS."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" jfs
diff --git a/tests/minixfs_test.in b/tests/minixfs_test.in
new file mode 100644 (file)
index 0000000..8075ba8
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.minix >/dev/null 2>&1; then
+   echo "mkfs.minix not installed; cannot test minixfs."
+   exit 77
+fi
+
+if ! mkfs.minix -h | grep -- -v > /dev/null; then
+    echo "mkfs.minix doesn't support minix3fs; cannot test minix*fs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" minix
+"@builddir@/grub-fs-tester" minix2
+"@builddir@/grub-fs-tester" minix3
diff --git a/tests/nilfs2_test.in b/tests/nilfs2_test.in
new file mode 100644 (file)
index 0000000..780b60e
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.nilfs2 >/dev/null 2>&1; then
+   echo "mkfs.nilfs2 not installed; cannot test nilfs2."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" nilfs2
diff --git a/tests/ntfs_test.in b/tests/ntfs_test.in
new file mode 100644 (file)
index 0000000..6bf09e6
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.ntfs >/dev/null 2>&1; then
+   echo "mkfs.ntfs not installed; cannot test ntfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" ntfs
+"@builddir@/grub-fs-tester" ntfscomp
\ No newline at end of file
diff --git a/tests/reiserfs_test.in b/tests/reiserfs_test.in
new file mode 100644 (file)
index 0000000..678efe7
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.reiserfs >/dev/null 2>&1; then
+   echo "mkfs.reiserfs not installed; cannot test reiserfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" reiserfs
+"@builddir@/grub-fs-tester" reiserfs_old
+
diff --git a/tests/romfs_test.in b/tests/romfs_test.in
new file mode 100644 (file)
index 0000000..83e0931
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+if ! which genromfs >/dev/null 2>&1; then
+   echo "genromfs not installed; cannot test romfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" romfs
diff --git a/tests/squashfs_test.in b/tests/squashfs_test.in
new file mode 100644 (file)
index 0000000..ec34e01
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+if ! which mksquashfs >/dev/null 2>&1; then
+   echo "mksquashfs not installed; cannot test squashfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" squash4_gzip
+"@builddir@/grub-fs-tester" squash4_xz
+"@builddir@/grub-fs-tester" squash4_lzo
diff --git a/tests/tar_test.in b/tests/tar_test.in
new file mode 100644 (file)
index 0000000..46ba3bc
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+if ! which tar >/dev/null 2>&1; then
+   echo "tar not installed; cannot test tar."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" tarfs
diff --git a/tests/udf_test.in b/tests/udf_test.in
new file mode 100644 (file)
index 0000000..fe244e2
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkudffs >/dev/null 2>&1; then
+   echo "mkudffs not installed; cannot test UDF."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" udf
+
diff --git a/tests/util/grub-fs-tester.in b/tests/util/grub-fs-tester.in
new file mode 100644 (file)
index 0000000..9e8aa08
--- /dev/null
@@ -0,0 +1,1427 @@
+#!/bin/bash
+
+set -e
+
+fs="$1"
+
+GRUBFSTEST="@builddir@/grub-fstest"
+
+tempdir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
+
+# This wrapper is to ease insertion of valgrind or time statistics
+run_it () {
+    "$GRUBFSTEST" "$@"
+}
+
+run_grubfstest () {
+    run_it -c $NEED_IMAGES_N "${NEED_IMAGES[@]}"  "$@"
+}
+
+# OS LIMITATION: GNU/Linux has no AFS support, so we use a premade image and a reference tar file. I.a. no multiblocksize test
+
+MINLOGSECSIZE=9
+MAXLOGSECSIZE=9
+case x"$fs" in
+    xntfs*)
+       MINLOGSECSIZE=8
+       MAXLOGSECSIZE=12;;
+    xvfat*|xmsdos*)
+       MINLOGSECSIZE=9
+           #  OS LIMITATION: It could go up to 32768 but Linux rejects sector sizes > 4096
+       MAXLOGSECSIZE=12;;
+    xext*)
+       MINLOGSECSIZE=8
+       MAXLOGSECSIZE=12;;
+    xbtrfs*)
+       MINLOGSECSIZE=8
+           #  OS LIMITATION: It could go up to 32768 but Linux rejects sector sizes > 4096
+       MAXLOGSECSIZE=12;;
+    xxfs)
+       MINLOGSECSIZE=9
+           # OS LIMITATION: GNU/Linux doesn't accept > 4096
+       MAXLOGSECSIZE=12;;
+    xzfs*)
+           # OS LIMITATION: zfs-fuse hangs when creating zpool with sectors <=256B.
+       MINLOGSECSIZE=9
+           # OS LIMITATION: zfs-fuse fails with >= 32K sectors.
+       # OS limitation: zfs-fuse always uses ashift=9 with loop devices
+       MAXLOGSECSIZE=9;;
+esac
+for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE + 1)); do
+    SECSIZE="$((1 << LOGSECSIZE))"
+    MINBLKSIZE=512
+    MAXBLKSIZE=512
+    BLKSTEP=0
+    case x"$fs" in
+       xntfs*)
+           MINBLKSIZE=$SECSIZE
+           MAXBLKSIZE=65536
+           if [ x"$SECSIZE" = x256 ]; then
+               MINBLKSIZE=512
+               MAXBLKSIZE=32768
+           fi
+           ;;
+       xvfat* | xmsdos*)
+           MINBLKSIZE=$SECSIZE
+           MAXBLKSIZE=$((128*SECSIZE))
+           ;;
+       xexfat*)
+           MINBLKSIZE=$SECSIZE
+               # It could go further but it requires more and more space
+           MAXBLKSIZE=8286208
+           ;;
+       xhfs)
+           MINBLKSIZE=512
+           # OS LIMITATION: should be 1048576 but linux hangs on unmnount with
+           # >= 524288
+           MAXBLKSIZE=262144
+           ;;
+       xhfsplus | xhfsplus_casesens | xhfsplus_wrap)
+           MINBLKSIZE=512
+           MAXBLKSIZE=1048576
+           ;;
+       xnilfs2)
+           MINBLKSIZE=1024
+           MAXBLKSIZE=4096
+           ;;
+       xsfs*)
+           MINBLKSIZE=512
+           MAXBLKSIZE=4096
+           ;;
+       xaffs | xaffs_intl)
+           MINBLKSIZE=512
+           MAXBLKSIZE=4096
+           ;;
+       xreiserfs*)
+           MINBLKSIZE=512
+               # OS LIMITATION: 8192 isn't supported.
+           MAXBLKSIZE=4096
+           ;;
+       x"mdraid"*)
+           MINBLKSIZE=4096
+               # OS LIMITATION: Linux oopses with >=32768K
+           MAXBLKSIZE=$((16384*1024))
+           ;;
+       x"lvm_raid4" | x"lvm_raid5" | x"lvm_raid6")
+               # OS LIMITATION: Linux crashes with less than 16384
+           MINBLKSIZE=16384
+               # Could go further but what's the point?
+           MAXBLKSIZE=$((65536*1024))
+           ;;
+       x"lvm_mirrorall")
+           MINBLKSIZE=2048
+               # Could go further but what's the point?
+           MAXBLKSIZE=$((65536*1024))
+           ;;
+       x"lvm_mirror1")
+           MINBLKSIZE=4096
+               # Could go further but what's the point?
+           MAXBLKSIZE=$((65536*1024))
+           ;;
+       x"lvm_stripe")
+           MINBLKSIZE=4096
+               # Could go further but what's the point?
+           MAXBLKSIZE=$((65536*1024))
+           ;;
+       x"lvm"*)
+           MINBLKSIZE=1024
+               # Could go further but what's the point?
+           MAXBLKSIZE=$((65536*1024))
+           ;;
+       xext*)
+           MINBLKSIZE=1024
+           if [ $MINBLKSIZE -lt $SECSIZE ]; then
+               MINBLKSIZE=$SECSIZE
+           fi
+           MAXBLKSIZE=4096
+           ;;
+       xsquash*)
+           MINBLKSIZE=4096
+           MAXBLKSIZE=1048576;;
+       xxfs)
+           MINBLKSIZE=$SECSIZE
+               # OS Limitation: GNU/Linux doesn't accept > 4096
+           MAXBLKSIZE=4096;;
+       xudf)
+           MINBLKSIZE=1024
+           MAXBLKSIZE=4096;;
+       xbfs)
+           MINBLKSIZE=1024
+           MAXBLKSIZE=8192;;
+       xufs*)
+           MINBLKSIZE=4096
+               # OS Limitation: Linux rejects 65536 blocks.
+           MAXBLKSIZE=32768;;
+       xminix3)
+               # OS LIMITATION: Linux rejects non-power-of-two blocks.
+               # OS LIMITATION: Linux rejects > 4096.
+           MINBLKSIZE=1024
+           MAXBLKSIZE=4096;;
+    esac
+    for ((BLKSIZE=MINBLKSIZE;BLKSIZE<=MAXBLKSIZE;BLKSIZE=BLKSTEP?BLKSIZE+BLKSTEP:2*BLKSIZE)); do
+       MAXDEVICES=1
+       MINDEVICES=1
+       export fs
+       case x"$fs" in
+           x"zfs_raidz" | x"zfs_stripe" | x"zfs_mirror" | xbtrfs_raid0 \
+               | xbtrfs_raid1 | x"mdraid"*"_raid4" | x"mdraid"*"_raid5" \
+               | x"mdraid"*"_linear" \
+               | x"mdraid"*"_raid10" | xlvm_mirror1 | xlvm_mirrorall)
+               MINDEVICES=2
+               MAXDEVICES=7
+               ;;
+           xbtrfs_raid10)
+               MINDEVICES=4
+               MAXDEVICES=7
+               ;;
+           x"zfs_raidz2"| xlvm_raid5 | xlvm_raid4)
+               MINDEVICES=3
+               MAXDEVICES=7;;
+           x"zfs_raidz3" | x"mdraid"*"_raid6")
+               MINDEVICES=4
+               MAXDEVICES=7;;
+           xlvm_raid6)
+               MINDEVICES=5
+               MAXDEVICES=7;;
+           x"mdraid"*"_raid0" | x"mdraid"*"_raid1" | x"lvm" | xlvm_stripe)
+               MINDEVICES=1
+               MAXDEVICES=7;;
+       esac
+
+       for ((NDEVICES=MINDEVICES; NDEVICES <= MAXDEVICES; NDEVICES++)); do
+           export NDEVICES
+           unset FSIMAGES
+           for ((i=0; i < NDEVICES; i++)); do
+               FSIMAGES[i]="${tempdir}/${fs}_${SECSIZE}_${BLKSIZE}_${NDEVICES}_$i.img"
+           done
+           export FSIMAGES
+           unset NEED_IMAGES;
+
+           case x$fs in
+           # RAID 1 has to work with even one device of the set.
+               xzfs_mirror | x"mdraid"*"_raid1" | xlvm_mirrorall)
+                   NEED_IMAGES_N=1;;
+            # Degrade raidz by removing 3 devices
+               xzfs_raidz3)
+                   NEED_IMAGES_N=$((NDEVICES-3));;
+            # Degrade raidz by removing 2 devices
+               xzfs_raidz2 | x"mdraid"*"_raid6" | x"lvm_raid6")
+                   NEED_IMAGES_N=$((NDEVICES-2));;
+           # Degrade raidz and btrfs RAID1 by removing one device
+               xbtrfs_raid1 | xbtrfs_raid10 | xzfs_raidz | x"mdraid"*"_raid4" \
+                   | x"mdraid"*"_raid5" | x"mdraid"*"_raid10" | xlvm_mirror1 \
+                   | x"lvm_raid4" | x"lvm_raid5")
+                   NEED_IMAGES_N=$((NDEVICES-1));;
+               *)
+                   NEED_IMAGES_N=$NDEVICES;;
+           esac
+           for ((i=0;i < NEED_IMAGES_N; i++)); do
+               NEED_IMAGES[i]="${FSIMAGES[i]}";
+           done
+           export NEED_IMAGES_N
+           export NEED_IMAGES
+
+           MNTPOINTRO="${tempdir}/${fs}_ro"
+           MNTPOINTRW="${tempdir}/${fs}_rw"
+           MOUNTOPTS=""
+           MOUNTFS="$fs"
+           MASTER="${tempdir}/master"
+           FSLABEL="grub_;/testé莭莽茝😁киритi urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewrewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfew"
+           CFILESN=1
+           if test -f /usr/share/dict/american-english; then
+               CFILESSRC[0]="/usr/share/dict/american-english"
+           else
+               CFILESSRC[0]="/usr/share/dict/linux.words"
+           fi
+           case x"$fs" in
+                   # FS LIMITATION: 8.3 names
+               xmsdos*)
+                   CFILES[0]="american.eng";;
+               xiso9660)
+                   CFILES[0]="american_english";;
+               *)
+                   CFILES[0]="american-english";;
+           esac
+        # OS LIMITATION: Limited by NAME_MAX (usually 255) in GNU/Linux
+           LONGNAME="qwertzuiopasdfghjklyxcvbnm1234567890qwertzuiopasdfghjklyxcvbnm1234567890oiewqfiewioqoiqoiurqruewqoiuwoieoiiuewqroreqiufieiuwrnureweriuvceoiroiewqoiricdsalkcndsakfirefoiwqeoircorejwoijfreoijojoiewjfwnfcoirenfoirefnreoifenoiwfnoirewoifoiwqwoieqfrqwioerijewr"
+           rm -rf "$MASTER"
+
+           case x"$fs" in
+               # FS LIMITATION: HFS+ label is at most 255 UTF-16 chars
+               # OS LIMITATION: Linux HFS+ tools check UTF-8 length and don't
+               # handle out-of-BMP characters
+               x"hfsplus" | x"hfsplus_casesens" | x"hfsplus_wrap")
+                   FSLABEL="grub_;/testé䏌䐓䏕киритi urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoiq"
+                   ;;
+           # FS LIMITATION: btrfs label is at most 255 UTF-8 chars
+               x"btrfs"*)
+                   FSLABEL="grub_;/testé莭莽😁киритi urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoif";;
+
+           # FS LIMITATION: exfat is at most 15 UTF-16 chars
+               x"exfat")
+                   FSLABEL="géт ;/莭莽😁кир";;
+           # FS LIMITATION: ntfs label is at most ?? UTF-16 chars
+               x"ntfs"*)
+                   FSLABEL="grub_;/testéтi u莭😁茝кириrewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvniwnivrewiuvcrewvnuewvrrrewniureifiuewifjiww";;
+           # FS LIMITATION: nilfs2 label is at most 80 UTF-8 characters
+               x"nilfs2")
+                   FSLABEL="grub_;/testéтi u😁莽茝кириrewfceniuewruevrewnuuireurevueurnievrewfne";;
+                   # FS LIMITATION: afs and iso9660 label is at most 32 UTF-8 characters
+               x"afs" | xiso9660 | xrockridge | xrockridge_joliet\
+                     | xiso9660_1999 | xrockridge_1999 | xrockridge_joliet_1999)
+                    FSLABEL="gr_;/é莭莽😁кирит u";;
+                   # FS LIMITATION: bfs label is at most 32 UTF-8 characters
+                   # OS LIMITATION: bfs label can't contain ; or /
+               x"bfs")
+                   FSLABEL="grub_é莭莽😁кирит u";;
+               # FS LIMITATION: Joliet label is at most 16 UTF-16 characters
+               # OS LIMITATION: xorriso doesn't handle out-of-BMP characters
+               xjoliet | xjoliet_1999)
+                   FSLABEL="g;/_é䏌䐓䏕䎛䎾䏴кит u"
+                   #FSLABEL="g;/_é莭莽😁кит u"
+                   ;;
+           # FS LIMITATION: reiserfs, extN and jfs label is at most 16 UTF-8 characters
+               x"reiserfs_old" | x"reiserfs" | x"ext2" | xext2_old | x"ext3" | x"ext4" | x"lvm"* | x"mdraid"* | x"jfs" | x"jfs_caseins")
+                   FSLABEL="g;/éт 莭😁";;
+            # FS LIMITATION: No underscore, space, semicolon, slash or international characters in UFS* in label. Limited to 32 UTF-8 characters
+               x"ufs1" | x"ufs1_sun" | x"ufs2")
+                   FSLABEL="grubtest""ieurrucnenreeiurueurewf";;
+           # FS LIMITATION: XFS label is at most 12 UTF-8 characters
+               x"xfs")
+                   FSLABEL="géт 😁к";;
+            # FS LIMITATION: FAT labels limited to 11 characters, no  international characters or lowercase
+               x"vfat"* | xmsdos*)
+                   FSLABEL="GRUBTEST ;_";;
+           # FS LIMITATION: AFFS is latin1. At most 29 characters
+               x"affs" | xaffs_intl)
+                   FSLABEL="grub_tt? #*w;/e£@¡¤½¾{[]}<>.,";;
+           # FS LIMITATION: SFS is latin1. At most 30 characters
+               x"sfs"*)
+                   FSLABEL="GRUB tt öäüé;/àèç åø¿ª©þð׫»µ¬";;
+           # FS LIMITATION:  HFS is Mac-Roman. At most 27 characters
+               x"hfs")
+                   FSLABEL="grub_t;/estéàèèéie fiucnree";;
+               # FS LIMITATION: UDF label is either up to 127 latin1 characters or 63 UTF-16 ones
+               # OS LIMITATION: Linux UDF tools force ASCII label ...
+               x"udf")
+                   FSLABEL="grub_;/testurewfceniuewruevrewnuuireurevueurnievr";;
+           # FS LIMITATION:  ZFS doesn't accept non-ASCII in label
+           # FIXME: since this is used as a path component for mount it's very limited in length
+               xzfs_* | xzfs)
+                   FSLABEL="grub_testieufiue r";;
+           esac
+           case x"$fs" in
+               xmdraid*)
+                   DISKSIZE=314572800;;
+               xlvm*)
+                   LVMBLKMUL=$(((5800 * 1048576) / (8 * BLKSIZE * NDEVICES)))
+                   DISKSIZE=$((8*BLKSIZE*LVMBLKMUL));;
+                   # FS LIMITATION: some fs have disk size limit
+               x"vfat12" | xmsdos12)
+                   DISKSIZE=$((4000*BLKSIZE));;
+               x"vfat12a" | xmsdos12a)
+                   if [ $BLKSIZE -ge 2048 ]; then
+                       DISKSIZE=$((2500*BLKSIZE))
+                   else
+                       DISKSIZE=$((3000*BLKSIZE))
+                   fi
+                   if [ $DISKSIZE -gt $((60000*SECSIZE)) ]; then
+                       DISKSIZE=$((60000*SECSIZE))
+                   fi;;
+               x"vfat16" | xmsdos16)
+                   DISKSIZE=$((65000*BLKSIZE));;
+               x"vfat16a" | xmsdos16a)
+                   DISKSIZE=$((60000*SECSIZE))
+                   ;;
+               *)
+                   DISKSIZE=10737418240;;
+           esac
+
+           if [ $DISKSIZE -ge $(((5800/NDEVICES)*1048576)) ]; then
+               DISKSIZE=$(((5800/NDEVICES)*1048576))
+           fi
+
+           case x"$fs" in
+               xvfat* | xmsdos* | xexfat* | xhfs | xhfsplus | xhfsplus_wrap | xaffs \
+                   | xaffs_intl | xjfs_caseins | xsfs_caseins \
+                   | xzfs_caseins | xiso9660)
+                   CASESENS=n;;
+               *)
+                   CASESENS=y;;
+           esac
+
+           BIGBLOCKCNT=$((5000 * 1048576))
+           case x"$fs" in
+                   # FS LIMITATION: small filesystems
+               x"vfat12" | xmsdos12)
+                   if [ $BLKSIZE -le 4096 ]; then
+                       BIGBLOCKCNT=0
+                   elif [ $BLKSIZE = 8192 ]; then
+                       BIGBLOCKCNT=1500000
+                   else
+                       BIGBLOCKCNT=$((2000*BLKSIZE))
+                   fi
+                   ;;
+               x"vfat12a" | xmsdos12a)
+                   if [ $BLKSIZE -le 4096 ] || [ $((128*SECSIZE)) = $BLKSIZE ]; then
+                       BIGBLOCKCNT=0
+                   else
+                       BIGBLOCKCNT=700000
+                   fi;;
+               x"vfat16a" | xmsdos16a)
+                   if [ $((128*SECSIZE)) = $BLKSIZE ]; then
+                       BIGBLOCKCNT=0
+                   else
+                       BIGBLOCKCNT=$((2500*SECSIZE))
+                   fi
+                   ;;
+               x"vfat16" | xmsdos16)
+                   BIGBLOCKCNT=$((25000 * BLKSIZE))
+                   if [ $BIGBLOCKCNT -gt $((16#ffffffff)) ]; then
+                       BIGBLOCKCNT=$((16#ffffffff))
+                   fi
+                   ;;
+               x"minix")
+                   BIGBLOCKCNT=30000000;;
+
+               xexfat)
+                       # Big blocks waste really a lot of space.
+                       # Not much is left.
+                   if [ $BLKSIZE = 2097152 ]; then
+                       BIGBLOCKCNT=4500000000
+                   fi
+                   if [ $BLKSIZE = 4194304 ]; then
+                       BIGBLOCKCNT=3500000000
+                   fi
+                   ;;
+                   # FS LIMITATION: romfs image is limited to 4G.
+               x"romfs")
+                   BIGBLOCKCNT=$((4000 * 1048576));;
+                   # FS LIMITATION: These FS have uint32 as file size field
+               x"vfat"* | xmsdos* | x"cpio_crc" | x"cpio_newc" | x"cpio_bin" | x"cpio_hpbin" | xsfs*)
+                   BIGBLOCKCNT=$((16#ffffffff));;
+                   # FS LIMITATION: These FS have int32 as file size field
+                   # FIXME: not so sure about AFFS
+                   # OS LIMITATION: minix2/minix3 could be formatted in a way to permit more.
+               x"minix3" | x"minix2" | x"hfs"| x"affs" | xaffs_intl | xreiserfs_old | xext2_old)
+                   BIGBLOCKCNT=$((16#7fffffff));;
+
+                   # FS LIMITATION: redundant storage
+                   # We have only limited space. Mirroring multiplies it very effectively.
+               xmdraid* | xlvm* | xzfs_mirror | xbtrfs_raid1)
+                   BIGBLOCKCNT=$((100 * 1048576));;
+                   # We already test the FS for big files separately. Save some time here.
+               x"zfs_raid"* | x"zfs_stripe"* | x"zfs_mirror"* | x"btrfs_raid"*)
+                   BIGBLOCKCNT=$((100 * 1048576));;
+
+                    # OS LIMITATION: bfs_fuse bugs beyond that
+               xbfs)
+                   BIGBLOCKCNT=$((800 * 1048576));;
+           esac
+
+           NOSYMLINK=n
+           case x"$fs" in
+        # FS LIMITATION: no symlinks on FAT, exFAT, HFS, plain ISO9660 and Joliet
+        # OS LIMITATION: ntfs-3g  creates interix symlinks which aren't real symlinks
+               x"vfat"* | xmsdos* | x"hfs" | x"exfat" | x"ntfs"* \
+                   | xiso9660 | xjoliet| xiso9660_1999 | xjoliet_1999)
+                   NOSYMLINK=y;;
+           esac
+           NOHARDLINK=n
+           case x"$fs" in
+                    # FS LIMITATION: no hardlinks on BFS, exfat, fat, hfs and SFS
+               xbfs | xexfat | x"vfat"* | xmsdos* | xhfs | xsfs | xsfs_caseins)
+                   NOHARDLINK=y;;
+                   # GRUB LIMITATION: no hardlink support on newc and hfs+
+               xcpio_crc | xcpio_newc | xhfsplus*)
+                   NOHARDLINK=y;;
+           esac
+
+                # FS LIMITATION: some filesystems limit file name size
+           case x"$fs" in
+               x"cpio_ustar")
+                   LONGNAME="`echo $LONGNAME |head -c 99`";;
+               x"hfs")
+                   LONGNAME="`echo $LONGNAME |head -c 31`";;
+               x"minix" | x"minix2" | x"affs" | xaffs_intl | xiso9660)
+                   LONGNAME="`echo $LONGNAME |head -c 30`";;
+               x"sfs"*)
+                   LONGNAME="`echo $LONGNAME |head -c 105`";;
+               x"minix3")
+                   LONGNAME="`echo $LONGNAME |head -c 60`";;
+               x"udf")
+                   LONGNAME="`echo $LONGNAME |head -c 192`";;
+                   # GRUB LIMITATION: GRUB prefers Joliet over ISO9660:1999
+               xjoliet | xjoliet_1999)
+                   LONGNAME="`echo $LONGNAME |head -c 103`";;
+               xiso9660_1999)
+                   LONGNAME="`echo $LONGNAME |head -c 207`";;
+                   # FS LIMITATION: 8.3
+               xmsdos*)
+                   LONGNAME="qwertzui.opa";;
+           esac
+           NOFILETIME=n
+           NOFSTIME=n
+           case x"$fs" in
+           # FIXME: Not sure about BtrFS, NTFS, JFS, AFS, UDF and SFS. Check it.
+       # FS LIMITATION: as far as I know those FS don't store their last modification date.
+               x"jfs_caseins" | x"jfs" | x"xfs"| x"btrfs"* | x"reiserfs_old" | x"reiserfs" \
+                   | x"bfs" | x"afs" \
+                   | x"tarfs" | x"cpio_"* | x"minix" | x"minix2" \
+                   | x"minix3" | x"ntfs"* | x"udf" | x"sfs"*)
+                   NOFSTIME=y;;
+                   # OS LIMITATION: Linux doesn't update fstime.
+               # OS LIMITATION: Linux apparently uses localtime instead of UTC
+               xhfs)
+                   NOFILETIME=y; NOFSTIME=y;;
+           # GRUB LIMITATION:  FAT and exFAT use localtime. Unusable for GRUB
+               x"vfat"* | x"msdos"* | x"exfat")
+                   NOFILETIME=y; NOFSTIME=y;;
+       # FS LIMITATION: romfs has no timestamps.
+               x"romfs")
+                   NOFILETIME=y; NOFSTIME=y;;
+           esac
+
+           NOFSLABEL=n
+           case x"$fs" in
+                   # FS LIMITATION: these filesystems have no label.
+               x"cpio_"* | x"tarfs" | x"squash4_"* | x"minix" | x"minix2" \
+                   | x"minix3" | xreiserfs_old)
+                   NOFSLABEL=y;;
+           esac
+
+           PDIRCOMPNUM=220
+           PDIR2COMPNUM=220
+
+           case x$fs in
+                   # OS LIMITATION: bfs_fuse bugs beyond that
+               xbfs)
+                   PDIRCOMPNUM=10
+                   PDIR2COMPNUM=10;;
+                   # OS LIMITATION: Linux supports only inline symlinks
+               xudf)
+                   if [ $BLKSIZE = 1024 ]; then
+                       PDIR2COMPNUM=113
+                   fi ;;
+                   # FS LIMITATION: at most 255 on path length
+                   # FS LIMITATION: at most 100 on symlink length
+               xcpio_ustar)
+                   PDIRCOMPNUM=85
+                   PDIR2COMPNUM=30;;
+                   # OS LIMITATION: Linux supports only symlink at most one block long on reiserfs
+               xreiserfs | xreiserfs_old)
+                   if [ $BLKSIZE = 512 ]; then
+                       PDIR2COMPNUM=114
+                   fi ;;
+                   # FS LIMITATION: SFS assumes that symlink
+                   # with header fit in one block.
+                   # FIXME: not sure about it.
+               xsfs | xsfs_caseins)
+                   if [ $BLKSIZE = 512 ]; then
+                       PDIR2COMPNUM=147
+                   fi ;;
+                   # FS LIMITATION: AFFS assumes that symlink
+                   # with rather larger header fit in one block.
+                   # FIXME: not sure about it.
+               xaffs | xaffs_intl)
+                   if [ $BLKSIZE = 512 ]; then
+                       PDIR2COMPNUM=97
+                   fi ;;
+           esac
+
+
+           PDIR=""
+               # OS LIMITATION: Limited by PATH_MAX (usually 1024)
+           for ((i=0;i<PDIRCOMPNUM;i++)); do
+               PDIR="$PDIR/$i";
+               if [ $((i%3)) == 0 ]; then
+                   PDIR="$PDIR/"
+               fi
+           done
+
+           PDIR2=""
+               # OS LIMITATION: Limited by PATH_MAX (usually 1024)
+           for ((i=0;i<PDIR2COMPNUM;i++)); do
+               PDIR2="${PDIR2}/$i";
+               if [ $((i%3)) == 0 ]; then
+                   PDIR2="${PDIR2}/"
+               fi
+           done
+
+           PFIL="p.img"
+
+           unset LODEVICES
+           GENERATED=n
+
+           case x"$fs" in
+               x"tarfs" | x"cpio_"*| x"ziso9660" | x"romfs" | x"squash4_"*\
+                    | x"iso9660" | xjoliet | xrockridge | xrockridge_joliet \
+                   | x"iso9660_1999" | xjoliet_1999 | xrockridge_1999 \
+                   | xrockridge_joliet_1999)
+                   MNTPOINTRW="$MASTER"
+                   MNTPOINTRO="$MASTER"
+                   GENERATED=y
+                   mkdir -p "$MASTER";;
+                   # No mkfs for GNU/Linux. Just unpack preformatted empty image
+               *)
+                   mkdir -p "$MNTPOINTRW"
+                   mkdir -p "$MNTPOINTRO"
+                   for ((i=0; i < NDEVICES; i++)); do
+                       dd if=/dev/zero of="${FSIMAGES[i]}" count=1 bs=1 seek=$((DISKSIZE-1)) &> /dev/null
+                       LODEVICES[i]=`losetup -f`
+                       losetup "${LODEVICES[i]}" "${FSIMAGES[i]}"
+                   done ;;
+           esac
+
+           MOUNTDEVICE="${LODEVICES[0]}"
+           case x"$fs" in
+               x"afs")
+                   ;;
+               x"btrfs")
+                   "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${LODEVICES[0]}" ;;
+               x"btrfs_zlib" | x"btrfs_lzo")
+                   "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${LODEVICES[0]}"
+                   MOUNTOPTS="compress=${fs/btrfs_/},"
+                   MOUNTFS="btrfs"
+                   ;;
+               x"btrfs_raid0")
+                   "mkfs.btrfs" -s $SECSIZE -d raid0 -m raid0 -L "$FSLABEL" "${LODEVICES[@]}"
+                   MOUNTFS="btrfs"
+                   ;;
+               x"btrfs_raid1")
+                   "mkfs.btrfs" -s $SECSIZE -d raid1 -m raid1 -L "$FSLABEL" "${LODEVICES[@]}"
+                   MOUNTFS="btrfs"
+                   ;;
+               x"btrfs_raid10")
+                   "mkfs.btrfs" -s $SECSIZE -d raid10 -m raid10 -L "$FSLABEL" "${LODEVICES[@]}"
+                   MOUNTFS="btrfs"
+                   ;;
+               x"btrfs_single")
+                   "mkfs.btrfs" -s $SECSIZE -d single -L "$FSLABEL" "${LODEVICES[@]}"
+                   MOUNTFS="btrfs"
+                   ;;
+               x"exfat")
+                   "mkfs.$fs" -s $((BLKSIZE/512)) -n "$FSLABEL" "${LODEVICES[0]}"
+                   MOUNTOPTS="iocharset=utf8,"
+                   MOUNTFS="exfat-fuse";;
+               x"minix")
+                   "mkfs.minix" "${LODEVICES[0]}"
+                   ;;
+       # mkfs.hfs and mkfs.hfsplus don't fill UUID.
+               x"hfsplus")
+                   "mkfs.hfsplus" -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+                   dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8 ;;
+               x"hfsplus_wrap")
+                   "mkfs.hfsplus" -w -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+                   dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8
+                   MOUNTFS="hfsplus";;
+               x"hfsplus_casesens")
+                   "mkfs.hfsplus" -s -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+                   dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8
+                   MOUNTFS="hfsplus";;
+               x"hfs")
+                   "mkfs.hfs" -b $BLKSIZE -v "`echo $FSLABEL |recode utf8..macroman`" -h "${LODEVICES[0]}"
+                   dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#474)) conv=notrunc count=8
+                   MOUNTOPTS="iocharset=utf8,codepage=macroman,"
+                   ;;
+               x"vfat"*|xmsdos*)
+                   BITS="${fs/vfat/}"
+                   BITS="${BITS/msdos/}"
+                   if [ "x${BITS:2:1}" = xa ]; then
+                       A=-A
+                   else
+                       A=
+                   fi
+                   "mkfs.vfat" -a $A -S $SECSIZE -s $((BLKSIZE/SECSIZE)) -F "${BITS:0:2}" -n "$FSLABEL" "${LODEVICES[0]}"
+                   MOUNTOPTS="iocharset=utf8,codepage=437,"
+                   MOUNTFS="$(echo "$fs"|sed 's,[0-9]*a\?$,,')";;
+               x"minix2")
+                   "mkfs.minix" -v "${LODEVICES[0]}"
+                   MOUNTFS="minix";;
+               x"minix3")
+                   "mkfs.minix" -B $BLKSIZE -3 "${LODEVICES[0]}"
+                   MOUNTFS="minix";;
+               x"ntfs"*)
+                   "mkfs.ntfs" -s "$SECSIZE" -c "$BLKSIZE" -L "$FSLABEL" -Q -q "${LODEVICES[0]}"
+                   MOUNTOPTS="iocharset=utf8,compression,"
+                   MOUNTFS="ntfs-3g";;
+               x"udf")
+                   "/usr/bin/mkudffs" -b $BLKSIZE --utf8 --lvid="$FSLABEL" "${LODEVICES[0]}"
+                   MOUNTOPTS="iocharset=utf8,bs=$BLKSIZE,";;
+               x"ufs2")
+                   "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 2 "${LODEVICES[0]}"
+                   MOUNTOPTS="ufstype=ufs2,"
+                   MOUNTFS="ufs";;
+               x"ufs1")
+                   "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${LODEVICES[0]}"
+                   MOUNTOPTS="ufstype=44bsd,"
+                   MOUNTFS="ufs";;
+               x"ufs1_sun")
+                   "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${LODEVICES[0]}"
+                   MOUNTOPTS="ufstype=sun,"
+                   MOUNTFS="ufs";;
+               x"zfs")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_caseins")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
+                   sleep 1
+                   "zfs" create -o casesensitivity=insensitive "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_lzjb" | xzfs_gzip | xzfs_zle)
+                   "zpool" create -O compression=${fs/zfs_/} -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
+                   sleep 1
+                   "zfs" create -o compression=${fs/zfs_/} "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_raidz")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz1 "${LODEVICES[@]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_raidz2")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz2 "${LODEVICES[@]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_raidz3")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz3 "${LODEVICES[@]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_mirror")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" mirror "${LODEVICES[@]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"zfs_stripe")
+                   "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[@]}"
+                   sleep 1
+                   "zfs" create "$FSLABEL"/"grub fs"
+                   sleep 1;;
+               x"tarfs" | x"cpio_"* | x"iso9660" | xjoliet | xrockridge | xrockridge_joliet | x"iso9660_1999" | xjoliet_1999 | xrockridge_1999 | xrockridge_joliet_1999 | x"ziso9660" | x"romfs" | x"squash4_"*)
+                   INSTDEVICE=/dev/null;;
+               x"reiserfs")
+                   "mkfs.reiserfs" --format=3.6 -b $BLKSIZE -l "$FSLABEL" -q "${LODEVICES[0]}" ;;
+               x"reiserfs_old")
+                   "mkfs.reiserfs" --format=3.5 -b $BLKSIZE -l "$FSLABEL" -q "${LODEVICES[0]}"
+                   MOUNTFS=reiserfs;;
+               x"jfs")
+                   "mkfs.jfs" -L "$FSLABEL" -q "${LODEVICES[0]}"
+                   MOUNTOPTS="iocharset=utf8,";;
+               x"jfs_caseins")
+                   "mkfs.jfs" -O -L "$FSLABEL" -q "${LODEVICES[0]}"
+                   MOUNTFS=jfs
+                   MOUNTOPTS="iocharset=utf8,";;
+               x"mdraid"*)
+                   mdadm -C --chunk=$((BLKSIZE/1024)) --force -e "${fs:6:1}.${fs:7:1}" "/dev/md/${fs}_${NDEVICES}" --level="${fs:13}" --raid-devices="$NDEVICES" "${LODEVICES[@]}"
+                   MOUNTDEVICE="/dev/md/${fs}_${NDEVICES}"
+                   MOUNTFS=ext2
+                   "mkfs.ext2" -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+               x"lvm"*)
+                   for ((i=0;i<NDEVICES;i++)); do
+                       pvcreate "${LODEVICES[i]}"
+                   done
+                   vgcreate -s $((BLKSIZE/1024))K grub_test "${LODEVICES[@]}"
+                   if [ x$fs = xlvm ] ; then
+                       lvcreate -l "$((NDEVICES*7*LVMBLKMUL))" -n testvol grub_test
+                   elif [ x$fs = xlvm_stripe ] ; then
+                       lvcreate -l "$((NDEVICES*7*LVMBLKMUL))" -i "$NDEVICES" -n testvol grub_test
+                   elif [ x$fs = xlvm_mirror1 ] ; then
+                       lvcreate -m 1 -l "$((NDEVICES*2*LVMBLKMUL))" -n testvol grub_test
+                   elif [ x$fs = xlvm_mirrorall ] ; then
+                       lvcreate -m "$((NDEVICES-1))" -l "$((6*LVMBLKMUL))" -n testvol grub_test
+                   elif [ x$fs = xlvm_raid4 ] || [ x$fs = xlvm_raid5 ]; then
+                       lvcreate -l "$(((NDEVICES-1) * 5*LVMBLKMUL))" -i "$((NDEVICES-1))" --type "${fs/lvm_/}" -n testvol grub_test
+                   elif [ x$fs = xlvm_raid6 ]; then
+                       lvcreate -l "$(((NDEVICES-2) * 5*LVMBLKMUL))" -i "$((NDEVICES-2))" --type "${fs/lvm_/}" -n testvol grub_test
+                   fi
+                   MOUNTDEVICE="/dev/mapper/grub_test-testvol"
+                   MOUNTFS=ext2
+                   "mkfs.ext2" -L "$FSLABEL" -q "${MOUNTDEVICE}"  ;;
+               xnilfs2)
+                   "mkfs.nilfs2" -L "$FSLABEL" -b $BLKSIZE  -q "${LODEVICES[0]}" ;;
+               xext2_old)
+                   MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext2" -r 0 -b $BLKSIZE -L "$FSLABEL" -q "${LODEVICES[0]}"
+                   MOUNTFS=ext2
+                   ;;
+               xext*)
+                   MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.$fs" -b $BLKSIZE -L "$FSLABEL" -q "${LODEVICES[0]}" ;;
+               xxfs)
+                   "mkfs.xfs" -b size=$BLKSIZE -s size=$SECSIZE -L "$FSLABEL" -q "${LODEVICES[0]}" ;;
+               *)
+                   echo "Add appropriate mkfs command here"
+                   exit 1
+                   ;;
+           esac
+           BASEFILE="1.img"
+           NASTYFILE=".?*\\!\"#%@\$%&'()+ ,-.:;<=>^{_}[]\`|~."
+           case x"$fs" in
+
+                   # FS LIMITATION: AFFS and SFS don't accept :
+               xsfs*)
+                   NASTYFILE=".?*\\!\"#%@\$%&'()+ ,-.;<=>^{_}[]\`|~.";;
+                   # FS LIMITATION: AFFS is limited in file name length (30)
+               x"affs" | xaffs_intl)
+                   NASTYFILE=".?*\\!\"#@\$'()+ ,-;<=>^{_}[]\`|~.";;
+           # FS LIMITATION: hfs, minix and minix2 are limited in file name length (30 or 31)
+               x"hfs" | x"minix" | x"minix2")
+                   NASTYFILE=".?*\\!\"#@\$&'()+ ,-:;<=>{}[]\`|~.";;
+           # FS LIMITATION: FAT doesn't accept ?, *, \, ", :,  <, >, |
+           # FS LIMITATION: FAT discards dots at the end.
+               x"vfat"* | x"exfat")
+                   NASTYFILE=".!#%@\$%&'()+ ,-.;=^{_}[]\`~";;
+           # FS LIMITATION: 8.3 limitations apply
+               x"msdos"*)
+                   NASTYFILE="!#%@\$%&.;=^";;
+                   # FS LIMITATION: No ' ', '*', '/', ':', ';', '?', '\\' in joliet
+                   # GRUB LIMITATION: GRUB prefers Joliet over ISO9660:1999
+               xjoliet | xjoliet_1999)
+                   NASTYFILE=".!\"#%@\$%&'()+,-.<=>^{_}[]\`|~.";;
+                   # FS LIMITATION: iso9660 accepts only [0-9A-Z_]*, 32 characters at most
+               xiso9660)
+                   NASTYFILE="0123456789_acefghijknopqrvwxyz";;
+           esac
+
+           case x"$fs" in
+                   # FS LIMITATION: HFS, AFFS and SFS use legacy codepage (mac-roman or latin1)
+               x"sfs"* | x"hfs" | x"affs" | xaffs_intl)
+                   IFILE="éàèüöäëñ"
+                   ISYM="ëñéüöäàè"
+                   ;;
+                   # FS LIMITATION: filename length limitation.
+               x"minix" | x"minix2")
+                   IFILE="éàèüö😁ñкиΕλκά"
+                   ISYM="Ελκάкиéà😁öäëñ"
+                   ;;
+               xminix3)
+                   IFILE="éàèüöäëñкирица莭茝Ελλικά😁😜😒"
+                   ISYM="Ελλικά😁😜😒莭茝кирицаéàèüöäëñ";;
+               # GRUB LIMITATION: HFS+ uses NFD. GRUB doesn't handle NF conversion.
+               # OS LIMITATION: Linux doesn't handle out-of-BMP characters for UTF-16
+               x"hfsplus" | x"hfsplus_casesens" | x"hfsplus_wrap")
+                   IFILE="éàèüöäëñкирилица䏌䐓䏕Ελληνικα̍䏌䐓䏕"
+                   ISYM="Ελληνικα̍кирилица䏌䐓䏕éàèüöäëñ䏌䐓䏕"
+                   ;;
+                   # GRUB LIMITATION: On case-insensitive ZFS isn't supported with non-uppercase characters
+               xzfs_caseins)
+                   IFILE="ÉÀÈÜÖÄËÑКИРИЛИЦА莭莽茝ΕΛΛΗΝΙΚΆ😁😜😒"
+                   ISYM="ΕΛΛΗΝΙΚΆКИРИЛИЦА😁😜😒ÉÀÈÜÖÄËÑ莭莽茝";;
+                   # FS LIMITATION: 8.3 CP437
+               x"msdos"*)
+                   IFILE="éàèüöäëñ.éàè"
+                   ;;
+                   # FS LIMITATION: iso9660 is ASCII-only.
+               x"iso9660")
+                   IFILE="abcdefghijkmmnop"
+                   ;;
+               # OS LIMITATION: Linux doesn't handle out-of-BMP characters for UTF-16
+               # OS LIMITATION: xorriso doesn't handle out-of-BMP characters
+               xjoliet | xjoliet_1999 | x"vfat"* | x"jfs"* | x"udf"*)
+                   IFILE="éàèüöäëñкирилица䏌䐓䏕Ελληνικά䏌䐓䏕"
+                   ISYM="Ελληνικάкирилица䏌䐓䏕éàèüöäëñ䏌䐓䏕";;
+               *)
+                   IFILE="éàèüöäëñкирилица莭莽茝Ελληνικά😁😜😒"
+                   ISYM="Ελληνικάкирилица😁😜😒éàèüöäëñ莭莽茝";;
+           esac
+           BIGFILE="big.img"
+           BASESYM="sym"
+           BASEHARD="hard"
+           SSYM="///sdir////ssym"
+           USYM="///sdir////usym"
+           LONGSYM="longsym"
+           PSYM="psym"
+           OSDIR=""
+           GRUBDEVICE=loop0
+           case x"$fs" in
+               xmdraid*)
+                   GRUBDEVICE="mduuid/`mdadm --detail --export $MOUNTDEVICE | grep MD_UUID=|sed 's,MD_UUID=,,g;s,:,,g'`";;
+               xlvm*)
+                   GRUBDEVICE="lvm/grub_test-testvol";;
+           esac
+           GRUBDIR="($GRUBDEVICE)"
+           case x"$fs" in
+               x"zfs"*)
+                   OSDIR="grub fs/"
+                   GRUBDIR="($GRUBDEVICE)/grub fs@";;
+               x"tarfs" | x"cpio_"* | x"iso9660" | xjoliet | xrockridge | xrockridge_joliet | x"iso9660_1999" | xjoliet_1999 | xrockridge_1999 | xrockridge_joliet_1999 | x"ziso9660" | x"romfs" | x"squash4_"* | xafs)
+                   ;;
+               *)
+                   if ! mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRW" -o ${MOUNTOPTS}${SELINUXOPTS}rw  ; then
+                       echo "MOUNT FAILED."
+                       for ((i=0; i < NDEVICES; i++)); do
+                           while ! losetup -d "${LODEVICES[i]}"; do
+                               sleep 1
+                           done
+                           rm "${FSIMAGES[i]}"
+                       done
+                       exit 1;
+                   fi
+                   ;;
+           esac
+           case x"$fs" in
+                   # FS LIMITATION: redundant storage
+               xmdraid* | xlvm*)
+                   BLOCKCNT=1048576;;
+               x"zfs_raid"* | x"zfs_stripe"* | x"zfs_mirror"* | x"btrfs_raid"*)
+                   BLOCKCNT=1048576;;
+
+                   # FS LIMITATION: small filesystems
+               x"vfat16a" | x"msdos16a")
+                   BLOCKCNT=65536;;
+               x"vfat12a" | xmsdos12a)
+                   BLOCKCNT=32768;;
+               xminix)
+                   BLOCKCNT=2621440;;
+               xvfat16 | xmsdos16)
+                   if [ $BLKSIZE = 512 ] || [ $BLKSIZE = 1024 ]; then
+                       BLOCKCNT=1048576
+                   else
+                       BLOCKCNT=5242880
+                   fi
+                   ;;
+               xvfat12 | xmsdos12)
+                   BLOCKCNT=$((100*BLKSIZE))
+                   if [ $BLOCKCNT -gt 5242880 ]; then
+                       BLOCKCNT=5242880;
+                   fi
+                   ;;
+               *)
+                   BLOCKCNT=5242880;;
+           esac
+           case x"$fs" in
+               x"ntfscomp")
+                   setfattr -h -v 0x00000800 -n system.ntfs_attrib_be "$MNTPOINTRW/$OSDIR";;
+           esac
+               # OS LIMITATION: No AFS support under GNU/Linux
+           mkdir "$MNTPOINTRW/$OSDIR/sdir"
+           mkdir -p "$MNTPOINTRW/$OSDIR/$PDIR"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/sdir/2.img"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/$BASEFILE"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/$NASTYFILE"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/$IFILE"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/$LONGNAME"
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/$PDIR/$PFIL"
+           if [ $PDIR != $PDIR2 ]; then
+               "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/${PDIR2}/$PFIL"
+           fi
+           "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/CaSe"
+           if [ x$CASESENS = xy ]; then
+               "@builddir@"/garbage-gen $BLOCKCNT > "$MNTPOINTRW/$OSDIR/cAsE"
+           fi
+           if (test x$fs = xvfat12a || test x$fs = xmsdos12a) && test x$BLKSIZE = x131072; then
+                   # With this config there isn't enough space for full copy.
+                   # Copy as much as we can
+               cp "${CFILESSRC[0]}" "$MNTPOINTRW/$OSDIR/${CFILES[0]}" &> /dev/null;
+           else
+               for ((i=0;i<$CFILESN;i++)); do
+                   cp "${CFILESSRC[i]}" "$MNTPOINTRW/$OSDIR/${CFILES[i]}";
+               done
+           fi
+
+           if [ x$NOSYMLINK != xy ]; then
+               ln -s "$BASEFILE" "$MNTPOINTRW/$OSDIR/$BASESYM"
+               ln -s "2.img" "$MNTPOINTRW/$OSDIR/$SSYM"
+               ln -s "../1.img" "$MNTPOINTRW/$OSDIR/$USYM"
+               ln -s "$LONGNAME" "$MNTPOINTRW/$OSDIR/$LONGSYM"
+               ln -s "${PDIR2}/$PFIL" "$MNTPOINTRW/$OSDIR/$PSYM"
+               ln -s "$IFILE" "$MNTPOINTRW/$OSDIR/$ISYM"
+           fi
+           if [ x$NOHARDLINK != xy ]; then
+               ln "$MNTPOINTRW/$OSDIR/$BASEFILE" "$MNTPOINTRW/$OSDIR/$BASEHARD"
+           fi
+
+           case x"$fs" in
+               x"afs")
+                   ;;
+               x"zfs"*)
+                   while ! zpool export "$FSLABEL" ; do
+                       sleep 1;
+                   done
+                   sleep 2
+                   ;;
+               x"tarfs")
+                   (cd "$MASTER"; tar cf "${FSIMAGES[0]}" .) ;;
+               x"cpio_"*)
+                   (cd "$MASTER"; find . | cpio -o -H "${fs/cpio_/}" > "${FSIMAGES[0]}" ) ;;
+               x"ziso9660")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   xorriso -compliance rec_mtime -set_filter_r --zisofs -- -zisofs default -as mkisofs -iso-level 3 -graft-points -R -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}"  -- -set_filter_r --zisofs -- -zisofs default -add /="$MASTER" ;;
+               x"iso9660")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"joliet")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"rockridge")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"rockridge_joliet")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"iso9660_1999")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"joliet_1999")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"rockridge_1999")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"rockridge_joliet_1999")
+                   FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+                   /usr/local/bin/xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
+               x"romfs")
+                   genromfs -V "$FSLABEL" -f "${FSIMAGES[0]}" -d "$MASTER" ;;
+               xsquash4_*)
+                   echo mksquashfs "$MASTER" "${FSIMAGES[0]}" -comp "${fs/squash4_/}" -b $BLKSIZE
+                   mksquashfs "$MASTER" "${FSIMAGES[0]}" -comp "${fs/squash4_/}" -b $BLKSIZE ;;
+               x"bfs")
+                   sleep 1
+                   fusermount -u "$MNTPOINTRW"
+                   ;;
+               xlvm*)
+                   sleep 1
+                   for ((try=0;try < 20; try++)); do
+                       if umount "$MNTPOINTRW" ; then
+                           break;
+                       fi
+                       sleep 1;
+                   done
+                   sleep 1
+                   vgchange -a n grub_test
+                   ;;
+               xmdraid*)
+                   sleep 1
+                   for ((try=0;try < 20; try++)); do
+                       if umount "$MNTPOINTRW" ; then
+                           break;
+                       fi
+                       sleep 1;
+                   done
+                   sleep 1
+                   mdadm --stop /dev/md/"${fs}_$NDEVICES"
+                   ;;
+               *)
+                   sleep 1
+                   for ((try=0;try < 20; try++)); do
+                       if umount "$MNTPOINTRW" ; then
+                           break;
+                       fi
+                       sleep 1;
+                   done
+                   ;;
+           esac
+           sleep 1
+
+           case x"$fs" in
+               x"zfs"*)
+                   "zpool" import -d /dev -R "$MNTPOINTRO" "$FSLABEL"
+                   ;;
+               x"tarfs")
+                   ;;
+               x"cpio_"*)
+                   ;;
+               x"ziso9660")
+                   ;;
+               xiso9660 | xrockridge | xjoliet | xrockridge_joliet)
+                   ;;
+               xiso9660_1999 | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999)
+                   ;;
+               x"romfs")
+                   ;;
+               xsquash4_*)
+                   ;;
+               xlvm*)
+                   vgchange -a y grub_test
+                   sleep 1
+                   mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRO" -o ${MOUNTOPTS}${SELINUXOPTS}ro ;;
+               xmdraid*)
+                   mdadm --assemble /dev/md/"${fs}_$NDEVICES" "${LODEVICES[@]}"
+                   sleep 1
+                   mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRO" -o ${MOUNTOPTS}${SELINUXOPTS}ro ;;
+               *)
+                   mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRO" -o ${MOUNTOPTS}${SELINUXOPTS}ro ;;
+           esac
+
+           run_grubfstest ls -- -la
+           case x"$fs" in
+               x"zfs"*)
+                   LSROUT=$(run_grubfstest ls -- -la "($GRUBDEVICE)/grub fs@/");;
+               *)
+                   LSROUT=$(run_grubfstest ls -- -la "($GRUBDEVICE)/");;
+           esac
+           if echo "$LSROUT" | grep -F " $BASEFILE" | grep "$BLOCKCNT" > /dev/null; then
+               :
+           else
+               echo LIST FAIL
+               echo "$LSROUT"
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
+               exit 1
+           fi
+
+           if echo "$LSROUT" | grep -F " $NASTYFILE" | grep "$BLOCKCNT"> /dev/null; then
+               :
+           else
+               echo NLIST FAIL
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -lA "$MNTPOINTRO"
+               exit 1
+           fi
+
+           if echo "$LSROUT" | grep -F " $IFILE" | grep "$BLOCKCNT"> /dev/null; then
+               :
+           else
+               echo ILIST FAIL
+               echo "$LSROUT"
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
+               exit 1
+           fi
+
+           if echo "$LSROUT" | grep -F " $LONGNAME" | grep "$BLOCKCNT"> /dev/null; then
+               :
+           else
+               echo LONG LIST FAIL
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
+               exit 1
+           fi
+
+           if [ x$NOFILETIME != xy ]; then
+               filtime=$(TZ=UTC ls --time-style=+%Y%m%d%H%M%S -l -d "$MNTPOINTRO/$OSDIR/$BASEFILE"|awk '{print $6; }')
+               if echo "$LSROUT" | grep -F "$filtime $BASEFILE" > /dev/null; then
+                   :
+               else
+                   echo TIME FAIL
+                   echo "$LSROUT"
+                   TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
+                   exit 1
+               fi
+
+               filtime=$(TZ=UTC ls --time-style=+%Y%m%d%H%M%S -l -d "$MNTPOINTRO/$OSDIR/$LONGNAME"|awk '{print $6; }')
+               if echo "$LSROUT" | grep -F "$filtime $LONGNAME" > /dev/null; then
+                   :
+               else
+                   echo LONG TIME FAIL
+                   echo "$LSROUT"
+                   TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
+                   exit 1
+               fi
+           fi
+
+           case x"$fs" in
+               x"zfs"*)
+                   LSROUT=$(run_grubfstest ls -- -l "($GRUBDEVICE)/grub fs@/////sdir");;
+               *)
+                   LSROUT=$(run_grubfstest ls -- -l "($GRUBDEVICE)/////sdir");;
+           esac
+           if echo "$LSROUT" | grep -F " 2.img" | grep $BLOCKCNT > /dev/null; then
+               :
+           else
+               echo SLIST FAIL
+               echo "$LSROUT"
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/sdir"
+               exit 1
+           fi
+
+           case x"$fs" in
+               x"zfs"*)
+                   LSROUT=$(run_grubfstest ls -- -l "($GRUBDEVICE)/grub fs@/$PDIR");;
+               *)
+                   LSROUT=$(run_grubfstest ls -- -l "($GRUBDEVICE)/$PDIR");;
+           esac
+           if echo "$LSROUT" | grep -F " p.img" | grep $BLOCKCNT > /dev/null; then
+               :
+           else
+               echo PLIST FAIL
+               echo "$LSROUT"
+               TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/$PDIR"
+               exit 1
+           fi
+
+           LSOUT=`run_grubfstest ls -- -l "($GRUBDEVICE)"`
+           if [ x"$NOFSLABEL" = xy ]; then
+               :
+           elif echo "$LSOUT" | grep -F "Label \`$FSLABEL'" > /dev/null; then
+               :
+           else
+               echo LABEL FAIL
+               echo "$LSOUT"
+               blkid "${MOUNTDEVICE}"
+               exit 1
+           fi
+
+    # Inconsistencies between GRUB and blkid.
+           case x"$fs" in
+               x"iso9660" | x"ziso9660" | xrockridge | xjoliet | xrockridge_joliet | x"iso9660_1999" | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999) ;;
+               x"zfs"*)
+                   for ((i=0;i<NDEVICES;i++)); do
+                       FSUUID=$(printf "%016x\n" $(blkid -o export "${LODEVICES[i]}" |grep -F UUID=|sed s,UUID=,,g))
+                       if [ "$FSUUID" != 0000000000000000 ]; then
+                           break;
+                       fi
+                   done;;
+               *)
+                   FSUUID=`blkid -o export "${MOUNTDEVICE}" |grep -F UUID=|sed s,UUID=,,g`
+                   ;;
+           esac
+           case x"$fs" in
+               x"hfs"*)
+                   GRUBUUID="`run_grubfstest xnu_uuid "$GRUBDEVICE"`"
+                   if [ x"$GRUBUUID" = x"$FSUUID" ]; then
+                       :
+                   else
+                       echo UUID FAIL
+                       echo "$LSOUT"
+                       echo "$GRUBUUID"
+                       for ((i=0;i<NDEVICES;i++)); do
+                           blkid "${LODEVICES[i]}"
+                       done
+                       exit 1
+                   fi
+                   ;;
+        # FS LIMITATION: romfs, cpio, tar, squash4, minix, AFS, old reiserfs and minix2
+       # have no UUID.
+                   # GRUB LIMITATION: use creation date for squash4, AFFS and SFS?
+                   # GRUB LIMITATION: use tags serials on UDF?
+                   # GRUB LIMITATION: use root ctime on cpio, tar, minix*, UDF, reiserfs_old?
+                   # GRUB LIMITATION: Support Atari UUIDs
+               x"romfs" | x"cpio_"* | x"tarfs" | x"squash4_"* | x"minix" \
+                   | x"minix2" | x"minix3" | x"affs" | xaffs_intl \
+                   | x"udf" | xvfat12a | xvfat16a | xmsdos12a | xmsdos16a | xafs | xsfs* \
+                   | xreiserfs_old)
+                   ;;
+               *)
+                   if [ x"$FSUUID" = x ]; then
+                       echo "Warning: blkid couldn't retrieve UUID"
+                   elif echo "$LSOUT" | grep -F 'UUID '"$FSUUID"' ' > /dev/null; then
+                       :
+                   else
+                       echo UUID FAIL
+                       echo "$FSUUID"
+                       echo "$LSOUT"
+                       blkid "${LODEVICES[0]}"
+                       exit 1
+                   fi
+                   ;;
+           esac
+
+           case x$fs in
+               xiso9660 | xziso9660 | xrockridge | xjoliet | xrockridge_joliet | xiso9660_1999 | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999)
+                   FSTIME="$(date -d "$(echo ${FSUUID} | awk -F - '{ print $1"-"$2"-"$3" "$4":"$5":"$6 ;}')" '+%Y-%m-%d %H:%M:%S')";;
+               *)
+                   FSTIME="$(TZ=UTC ls --time-style="+%Y-%m-%d_%H:%M:%S" -l -d "${FSIMAGES[0]}"|awk '{print $6; }'|sed 's,_, ,g')";;
+           esac
+               # With some abstractions like mdraid it may take up to 2 seconds for the data to reach the disks after it was flushed by FS in these tests.
+           FSTIMEM1="$(date -d "$FSTIME UTC -1 second" -u "+%Y-%m-%d %H:%M:%S")"
+           FSTIMEM2="$(date -d "$FSTIME UTC -2 second" -u "+%Y-%m-%d %H:%M:%S")"
+
+           if [ x$NOFSTIME = xy ]; then
+               :
+           elif echo "$LSOUT" | grep -F 'Last modification time '"$FSTIME" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM1" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM2" > /dev/null; then
+               :
+           else
+               echo FSTIME FAIL
+               echo "$FSTIME"
+               echo "$LSOUT"
+               exit 1
+           fi
+
+           if [ x$NOHARDLINK != xy ]; then
+               if run_grubfstest cmp "$GRUBDIR/$BASEHARD" "$MNTPOINTRO/$OSDIR/$BASEFILE"  ; then
+                   :
+               else
+                   echo HARDLINK FAIL
+                   exit 1
+               fi
+           fi
+
+           if [ x$NOSYMLINK != xy ]; then
+               if run_grubfstest cmp "$GRUBDIR/$BASESYM" "$MNTPOINTRO/$OSDIR/$BASEFILE"  ; then
+                   :
+               else
+                   echo SYMLINK FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/$LONGSYM" "$MNTPOINTRO/$OSDIR/$LONGNAME"  ; then
+                   :
+               else
+                   echo LONG SYMLINK FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/$ISYM" "$MNTPOINTRO/$OSDIR/$IFILE"  ; then
+                   :
+               else
+                   echo INTL SYMLINK FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/$SSYM" "$MNTPOINTRO/$OSDIR/////sdir/////2.img"  ; then
+                   :
+               else
+                   echo SDIR SYMLINK FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/$USYM" "$MNTPOINTRO/$OSDIR/1.img"  ; then
+                   :
+               else
+                   echo SDIR SYMLINK FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/$PSYM" "$MNTPOINTRO/$OSDIR/${PDIR2}/$PFIL"  ; then
+                   :
+               else
+                   echo PATH LONG SYMLINK FAIL
+                   exit 1
+               fi
+           fi
+
+           if run_grubfstest cmp "$GRUBDIR/$BASEFILE" "$MNTPOINTRO/$OSDIR/$BASEFILE"  ; then
+               :
+           else
+               echo READ FAIL
+               exit 1
+           fi
+           if run_grubfstest cmp "$GRUBDIR/$NASTYFILE" "$MNTPOINTRO/$OSDIR/$NASTYFILE"  ; then
+               :
+           else
+               echo NREAD FAIL
+               exit 1
+           fi
+               # Reference archive contains original name
+           if run_grubfstest cmp "$GRUBDIR/$LONGNAME" "$MNTPOINTRO/$OSDIR/$LONGNAME"  ; then
+               :
+           else
+               echo LONG NAME READ FAIL
+               exit 1
+           fi
+           if run_grubfstest cmp "$GRUBDIR/////sdir/////2.img" "$MNTPOINTRO/$OSDIR/sdir/2.img"  ; then
+               :
+           else
+               echo LONG NAME READ FAIL
+               exit 1
+           fi
+           if run_grubfstest cmp "$GRUBDIR/$IFILE" "$MNTPOINTRO/$OSDIR/$IFILE"  ; then
+               :
+           else
+               echo IREAD FAIL
+               exit 1
+           fi
+           if run_grubfstest cmp "$GRUBDIR/$PDIR/$PFIL" "$MNTPOINTRO/$OSDIR/$PDIR/$PFIL"  ; then
+               :
+           else
+               echo PREAD FAIL
+               echo cmp "$GRUBDIR/$PDIR/$PFIL" "$MNTPOINTRO/$OSDIR/$PDIR/$PFIL"
+               exit 1
+           fi
+           ok=true
+           for ((i=0;i<$CFILESN;i++)); do
+               if ! run_grubfstest cmp "$GRUBDIR/${CFILES[i]}" "$MNTPOINTRO/$OSDIR/${CFILES[i]}"  ; then
+                   ok=false;
+               fi
+           done
+           if  test x$ok = xtrue; then
+               :
+           else
+               echo CREAD FAIL
+               exit 1
+           fi
+
+           if [ x$CASESENS = xy ]; then
+               if run_grubfstest cmp "$GRUBDIR/CaSe" "$MNTPOINTRO/$OSDIR/CaSe"  ; then
+                   :
+               else
+                   echo CASE1 READ FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/cAsE" "$MNTPOINTRO/$OSDIR/cAsE"  ; then
+                   :
+               else
+                   exit 1
+               fi
+               if cmp "$MNTPOINTRO/$OSDIR/cAsE" "$MNTPOINTRO/$OSDIR/CaSe" > /dev/null ; then
+                   exit 1
+               fi
+               if  test x$ok = xtrue; then
+                   :
+               else
+                   echo CASE READ FAIL
+                   exit 1
+               fi
+           else
+               # OS LIMITATION: Linux make FAT (partially) case-sensitive...
+               # ISO9660 is generated and master doesn't change
+               case x$fs in
+                   xiso9660 | xvfat*)
+                       CASEX=CaSe;;
+                   *)
+                       CASEX=cAsE;;
+               esac
+               if run_grubfstest cmp "$GRUBDIR/CaSe" "$MNTPOINTRO/$OSDIR/${CASEX}"  ; then
+                   :
+               else
+                   echo CASE1 READ FAIL
+                   exit 1
+               fi
+               if run_grubfstest cmp "$GRUBDIR/cAsE" "$MNTPOINTRO/$OSDIR/CaSe"  ; then
+                   :
+               else
+                   echo CASE2 READ FAIL
+                   exit 1
+               fi
+               if ! cmp "$MNTPOINTRO/$OSDIR/CaSe" "$MNTPOINTRO/$OSDIR/${CASEX}" > /dev/null ; then
+                   echo CASE CMP READ FAIL
+                   exit 1
+               fi
+               if  test x$ok = xtrue; then
+                   :
+               else
+                   echo CASE READ FAIL
+                   exit 1
+               fi
+           fi
+
+           case x"$fs" in
+               x"zfs"*)
+                   while ! zpool export "$FSLABEL" ; do
+                       sleep 1;
+                   done
+                   sleep 5;;
+               x"tarfs" | x"cpio_"* | xrockridge | xjoliet | xrockridge_joliet | x"ziso9660" | x"romfs" | x"squash4_"* | xiso9660 | xiso9660_1999 | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999)
+                   rm -rf "$MNTPOINTRW";;
+               x"afs")
+                   rm -rf "$MNTPOINTRO"
+                   ;;
+               *)
+                   sleep 1
+                   umount "$MNTPOINTRO"  || true
+                   umount "$MNTPOINTRW" || true
+           esac
+           sleep 1
+           case x"$fs" in
+               xmdraid*)
+                   mdadm --stop /dev/md/"${fs}_$NDEVICES"
+                   sleep 1
+                   ;;
+               xlvm*)
+                   vgchange -a n grub_test
+                   sleep 1
+                   ;;
+           esac
+           for ((i=0; i < NDEVICES; i++)); do
+               case x"$fs" in
+                   x"tarfs" | x"cpio_"* | x"iso9660" | xrockridge | xjoliet | xrockridge_joliet | x"ziso9660" | x"romfs" | x"squash4_"* | x"iso9660_1999" | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999) ;;
+                   *)
+                       while ! losetup -d "${LODEVICES[i]}"; do
+                           sleep 1
+                       done;;
+               esac
+               rm "${FSIMAGES[i]}"
+           done
+           if [ x"$fs" = x"zfs" ]; then
+               rmdir "$MNTPOINTRW"/"grub fs"  || true
+               rmdir "$MNTPOINTRO"/"grub fs"  || true
+           fi
+           rm -rf "$MNTPOINTRW"  || true
+           rm -rf "$MNTPOINTRO"  || true
+       done
+    done
+done
diff --git a/tests/xfs_test.in b/tests/xfs_test.in
new file mode 100644 (file)
index 0000000..173b1cf
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which mkfs.xfs >/dev/null 2>&1; then
+   echo "mkfs.xfs not installed; cannot test xfs."
+   exit 77
+fi
+
+
+"@builddir@/grub-fs-tester" xfs
diff --git a/tests/zfs_test.in b/tests/zfs_test.in
new file mode 100644 (file)
index 0000000..047120e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+set -e
+
+if [ "x$EUID" = "x" ] ; then
+  EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+   exit 77
+fi
+
+if ! which zpool >/dev/null 2>&1; then
+   echo "zpool not installed; cannot test zfs."
+   exit 77
+fi
+
+"@builddir@/grub-fs-tester" zfs
+"@builddir@/grub-fs-tester" zfs_lzjb
+"@builddir@/grub-fs-tester" zfs_gzip
+"@builddir@/grub-fs-tester" zfs_zle
+"@builddir@/grub-fs-tester" zfs_raidz3
+"@builddir@/grub-fs-tester" zfs_raidz2
+"@builddir@/grub-fs-tester" zfs_raidz
+"@builddir@/grub-fs-tester" zfs_mirror
+"@builddir@/grub-fs-tester" zfs_stripe
+"@builddir@/grub-fs-tester" zfs_caseins
diff --git a/util/garbage-gen.c b/util/garbage-gen.c
new file mode 100644 (file)
index 0000000..0e0155b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB 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.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Standard random generator is slow. For FS testing we need just some
+   garbage files, we don't need them to be high-quality random.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+static unsigned long long buffer[1048576];
+
+int
+main (int argc, char **argv)
+{
+  unsigned long long high = 0, low = 1;
+  unsigned long i, j;
+  unsigned long long cnt = strtoull (argv[1], 0, 0);
+  struct timeval tv;
+  gettimeofday (&tv, NULL);
+  high = tv.tv_sec;
+  low = tv.tv_usec;
+  if (!high)
+    high = 1;
+  if (!low)
+    low = 2;
+
+  for (j = 0; j < (cnt + sizeof (buffer) - 1)  / sizeof (buffer); j++)
+    {
+      for (i = 0; i < sizeof (buffer) / sizeof (buffer[0]); i += 2)
+       {
+         int c1 = 0, c2 = 0;
+         buffer[i] = low;
+         buffer[i+1] = high;
+         if (low & (1ULL << 63))
+           c1 = 1;
+         low <<= 1;
+         if (high & (1ULL << 63))
+           c2 = 1;
+         high = (high << 1) | c1;
+         if (c2)
+           low ^= 0x87;
+       }
+      if (sizeof (buffer) < cnt - sizeof (buffer) * j)
+       fwrite (buffer, 1, sizeof (buffer), stdout);
+      else
+       fwrite (buffer, 1, cnt - sizeof (buffer) * j, stdout);
+    }
+  return 0;
+}