fsmagic: sort array by value and use bsearch for faster lookup

* defs.h (xlat_search): New prototype.
* util.c (xlat_bsearch_compare, xlat_search): New functions.
* file.c (sprintfstype): Use xlat_search for fsmagic lookup.
* xlat/fsmagic.in: Sort by value and mark as not NULL-terminated.
* tests/statfs.c: New file.
* tests/statfs.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add statfs.
(statfs_CFLAGS): Define.
(TESTS): Add statfs.test.
* tests/.gitignore: Add statfs.
diff --git a/defs.h b/defs.h
index 21c7b2e..cd9817b 100644
--- a/defs.h
+++ b/defs.h
@@ -648,6 +648,7 @@
 extern int getfdpath(struct tcb *, int, char *, unsigned);
 
 extern const char *xlookup(const struct xlat *, const unsigned int);
+extern const char *xlat_search(const struct xlat *, const size_t, const unsigned int);
 
 extern int string_to_uint(const char *str);
 extern int string_quote(const char *, char *, long, int);
diff --git a/file.c b/file.c
index f788bd6..971f6a7 100644
--- a/file.c
+++ b/file.c
@@ -1421,7 +1421,7 @@
 	static char buf[32];
 	const char *s;
 
-	s = xlookup(fsmagic, magic);
+	s = xlat_search(fsmagic, ARRAY_SIZE(fsmagic), magic);
 	if (s) {
 		sprintf(buf, "\"%s\"", s);
 		return buf;
diff --git a/tests/.gitignore b/tests/.gitignore
index 03c1051..cf7aaf0 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -3,6 +3,7 @@
 set_ptracer_any
 sigaction
 stack-fcall
+statfs
 uio
 *.log
 *.log.*
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 843fa1d..3b97b2c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,8 +8,10 @@
 	set_ptracer_any \
 	sigaction \
 	stack-fcall \
+	statfs \
 	uio
 
+statfs_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
 uio_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
 stack_fcall_SOURCES = stack-fcall.c \
 	stack-fcall-0.c stack-fcall-1.c stack-fcall-2.c stack-fcall-3.c
@@ -22,6 +24,7 @@
 	scm_rights-fd.test \
 	sigaction.test \
 	stat.test \
+	statfs.test \
 	net.test \
 	net-fd.test \
 	uio.test \
diff --git a/tests/statfs.c b/tests/statfs.c
new file mode 100644
index 0000000..0c8feab
--- /dev/null
+++ b/tests/statfs.c
@@ -0,0 +1,13 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <sys/statfs.h>
+#include <assert.h>
+
+int
+main(void)
+{
+	struct statfs stb;
+	assert(statfs("/proc/self/status", &stb) == 0);
+	return 0;
+}
diff --git a/tests/statfs.test b/tests/statfs.test
new file mode 100755
index 0000000..9c95989
--- /dev/null
+++ b/tests/statfs.test
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Check how statfs/statfs64 syscalls are traced.
+
+. "${srcdir=.}/init.sh"
+
+check_prog grep
+
+# this test probes /proc/self/status
+[ -f /proc/self/status ] ||
+        framework_skip_ '/proc/self/status is not available'
+
+./statfs ||
+	fail_ 'statfs failed'
+
+args="-efile ./statfs"
+$STRACE $args > $LOG 2>&1 || {
+	cat $LOG
+	fail_ "$STRACE $args failed"
+}
+
+grep_log()
+{
+	local syscall="$1"; shift
+
+	LC_ALL=C grep -E -x "$syscall$*" $LOG > /dev/null || {
+		cat $LOG
+		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
+	}
+}
+
+grep_log 'statfs(64)?' '\("/proc/self/status"(, [1-9][0-9]*)?, {f_type="PROC_SUPER_MAGIC", f_bsize=[1-9][0-9]*, f_blocks=[0-9]+, f_bfree=[0-9]+, f_bavail=[0-9]+, f_files=[0-9]+, f_ffree=[0-9]+, f_fsid={[0-9]+, [0-9]+}, f_namelen=[1-9][0-9]*(, f_frsize=[0-9]+)?(, f_flags=[0-9]+)?}\) += 0'
+
+exit 0
diff --git a/util.c b/util.c
index f10c011..4e62a8a 100644
--- a/util.c
+++ b/util.c
@@ -149,6 +149,24 @@
 	return NULL;
 }
 
+static int
+xlat_bsearch_compare(const void *a, const void *b)
+{
+	const unsigned int val1 = (const unsigned long) a;
+	const unsigned int val2 = ((const struct xlat *) b)->val;
+	return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
+}
+
+const char *
+xlat_search(const struct xlat *xlat, const size_t nmemb, const unsigned int val)
+{
+	const struct xlat *e =
+		bsearch((const void*) (const unsigned long) val,
+			xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
+
+	return e ? e->str : NULL;
+}
+
 #if !defined HAVE_STPCPY
 char *
 stpcpy(char *dst, const char *src)
diff --git a/xlat/fsmagic.in b/xlat/fsmagic.in
index de17bc8..b8c6468 100644
--- a/xlat/fsmagic.in
+++ b/xlat/fsmagic.in
@@ -1,67 +1,69 @@
-	{ 0xadf5,	"ADFS_SUPER_MAGIC"	},
-	{ 0xadff,	"AFFS_SUPER_MAGIC"	},
-	{ 0x5346414F,	"AFS_SUPER_MAGIC"	},
-	{ 0x09041934,	"ANON_INODE_FS_MAGIC"	},
-	{ 0x0187,	"AUTOFS_SUPER_MAGIC"	},
-	{ 0x62646576,	"BDEVFS_MAGIC"		},
-	{ 0x42494e4d,	"BINFMTFS_MAGIC"	},
-	{ 0x9123683E,	"BTRFS_SUPER_MAGIC"	},
-	{ 0x73727279,	"BTRFS_TEST_MAGIC"	},
-	{ 0x27e0eb,	"CGROUP_SUPER_MAGIC"	},
-	{ 0x73757245,	"CODA_SUPER_MAGIC"	},
-	{ 0x012ff7b7,	"COH_SUPER_MAGIC"	},
-	{ 0x28cd3d45,	"CRAMFS_MAGIC"		},
-	{ 0x453dcd28,	"CRAMFS_MAGIC_WEND"	},
-	{ 0x64626720,	"DEBUGFS_MAGIC"		},
-	{ 0x1373,	"DEVFS_SUPER_MAGIC"	},
-	{ 0x1cd1,	"DEVPTS_SUPER_MAGIC"	},
-	{ 0xf15f,	"ECRYPTFS_SUPER_MAGIC"	},
-	{ 0xde5e81e4,	"EFIVARFS_MAGIC"	},
-	{ 0x414A53,	"EFS_SUPER_MAGIC"	},
-	{ 0xef51,	"EXT2_OLD_SUPER_MAGIC"	},
-	{ 0xef53,	"EXT2_SUPER_MAGIC"	},
-	{ 0x137d,	"EXT_SUPER_MAGIC"	},
-	{ 0xF2F52010,	"F2FS_SUPER_MAGIC"	},
-	{ 0xBAD1DEA,	"FUTEXFS_SUPER_MAGIC"	},
-	{ 0x00c0ffee,	"HOSTFS_SUPER_MAGIC"	},
-	{ 0xf995e849,	"HPFS_SUPER_MAGIC"	},
-	{ 0x958458f6,	"HUGETLBFS_MAGIC"	},
-	{ 0x9660,	"ISOFS_SUPER_MAGIC"	},
-	{ 0x72b6,	"JFFS2_SUPER_MAGIC"	},
-	{ 0x137f,	"MINIX_SUPER_MAGIC"	},
-	{ 0x138f,	"MINIX_SUPER_MAGIC2"	},
-	{ 0x2468,	"MINIX2_SUPER_MAGIC"	},
-	{ 0x2478,	"MINIX2_SUPER_MAGIC2"	},
-	{ 0x4d5a,	"MINIX3_SUPER_MAGIC"	},
-	{ 0x4d44,	"MSDOS_SUPER_MAGIC"	},
-	{ 0x11307854,	"MTD_INODE_FS_MAGIC"	},
-	{ 0x564c,	"NCP_SUPER_MAGIC"	},
-	{ 0x6969,	"NFS_SUPER_MAGIC"	},
-	{ 0x3434,	"NILFS_SUPER_MAGIC"	},
-	{ 0x9fa1,	"OPENPROM_SUPER_MAGIC"	},
-	{ 0x50495045,	"PIPEFS_MAGIC"		},
-	{ 0x9fa0,	"PROC_SUPER_MAGIC"	},
-	{ 0x6165676C,	"PSTOREFS_MAGIC"	},
-	{ 0x002f,	"QNX4_SUPER_MAGIC"	},
-	{ 0x68191122,	"QNX6_SUPER_MAGIC"	},
-	{ 0x858458f6,	"RAMFS_MAGIC"		},
-	{ 0x52654973,	"REISERFS_SUPER_MAGIC"	},
-	{ 0x73636673,	"SECURITYFS_MAGIC"	},
-	{ 0xf97cff8c,	"SELINUX_MAGIC"		},
-	{ 0x02011994,	"SHMFS_SUPER_MAGIC"	},
-	{ 0x43415d53,	"SMACK_MAGIC"		},
-	{ 0x517b,	"SMB_SUPER_MAGIC"	},
-	{ 0x534F434B,	"SOCKFS_MAGIC"		},
-	{ 0x73717368,	"SQUASHFS_MAGIC"	},
-	{ 0x57AC6E9D,	"STACK_END_MAGIC"	},
-	{ 0x62656572,	"SYSFS_MAGIC"		},
-	{ 0x012ff7b6,	"SYSV2_SUPER_MAGIC"	},
-	{ 0x012ff7b5,	"SYSV4_SUPER_MAGIC"	},
-	{ 0x01021994,	"TMPFS_MAGIC"		},
-	{ 0x54190100,	"UFS_CIGAM"		},
-	{ 0x00011954,	"UFS_MAGIC"		},
-	{ 0x9fa2,	"USBDEVICE_SUPER_MAGIC"	},
-	{ 0x01021997,	"V9FS_MAGIC"		},
-	{ 0xabba1974,	"XENFS_SUPER_MAGIC"	},
-	{ 0x012ff7b4,	"XENIX_SUPER_MAGIC"	},
-	{ 0x012fd16d,	"XIAFS_SUPER_MAGIC"	},
+/* sorted by value, suitable for bsearch(3) */
+{ 0x0000002f,	"QNX4_SUPER_MAGIC"	},
+{ 0x00000187,	"AUTOFS_SUPER_MAGIC"	},
+{ 0x00001373,	"DEVFS_SUPER_MAGIC"	},
+{ 0x0000137d,	"EXT_SUPER_MAGIC"	},
+{ 0x0000137f,	"MINIX_SUPER_MAGIC"	},
+{ 0x0000138f,	"MINIX_SUPER_MAGIC2"	},
+{ 0x00001cd1,	"DEVPTS_SUPER_MAGIC"	},
+{ 0x00002468,	"MINIX2_SUPER_MAGIC"	},
+{ 0x00002478,	"MINIX2_SUPER_MAGIC2"	},
+{ 0x00003434,	"NILFS_SUPER_MAGIC"	},
+{ 0x00004d44,	"MSDOS_SUPER_MAGIC"	},
+{ 0x00004d5a,	"MINIX3_SUPER_MAGIC"	},
+{ 0x0000517b,	"SMB_SUPER_MAGIC"	},
+{ 0x0000564c,	"NCP_SUPER_MAGIC"	},
+{ 0x00006969,	"NFS_SUPER_MAGIC"	},
+{ 0x000072b6,	"JFFS2_SUPER_MAGIC"	},
+{ 0x00009660,	"ISOFS_SUPER_MAGIC"	},
+{ 0x00009fa0,	"PROC_SUPER_MAGIC"	},
+{ 0x00009fa1,	"OPENPROM_SUPER_MAGIC"	},
+{ 0x00009fa2,	"USBDEVICE_SUPER_MAGIC"	},
+{ 0x0000adf5,	"ADFS_SUPER_MAGIC"	},
+{ 0x0000adff,	"AFFS_SUPER_MAGIC"	},
+{ 0x0000ef51,	"EXT2_OLD_SUPER_MAGIC"	},
+{ 0x0000ef53,	"EXT2_SUPER_MAGIC"	},
+{ 0x0000f15f,	"ECRYPTFS_SUPER_MAGIC"	},
+{ 0x00011954,	"UFS_MAGIC"		},
+{ 0x0027e0eb,	"CGROUP_SUPER_MAGIC"	},
+{ 0x00414a53,	"EFS_SUPER_MAGIC"	},
+{ 0x00c0ffee,	"HOSTFS_SUPER_MAGIC"	},
+{ 0x01021994,	"TMPFS_MAGIC"		},
+{ 0x01021997,	"V9FS_MAGIC"		},
+{ 0x012fd16d,	"XIAFS_SUPER_MAGIC"	},
+{ 0x012ff7b4,	"XENIX_SUPER_MAGIC"	},
+{ 0x012ff7b5,	"SYSV4_SUPER_MAGIC"	},
+{ 0x012ff7b6,	"SYSV2_SUPER_MAGIC"	},
+{ 0x012ff7b7,	"COH_SUPER_MAGIC"	},
+{ 0x02011994,	"SHMFS_SUPER_MAGIC"	},
+{ 0x09041934,	"ANON_INODE_FS_MAGIC"	},
+{ 0x0bad1dea,	"FUTEXFS_SUPER_MAGIC"	},
+{ 0x11307854,	"MTD_INODE_FS_MAGIC"	},
+{ 0x28cd3d45,	"CRAMFS_MAGIC"		},
+{ 0x42494e4d,	"BINFMTFS_MAGIC"	},
+{ 0x43415d53,	"SMACK_MAGIC"		},
+{ 0x453dcd28,	"CRAMFS_MAGIC_WEND"	},
+{ 0x50495045,	"PIPEFS_MAGIC"		},
+{ 0x52654973,	"REISERFS_SUPER_MAGIC"	},
+{ 0x5346414f,	"AFS_SUPER_MAGIC"	},
+{ 0x534f434b,	"SOCKFS_MAGIC"		},
+{ 0x54190100,	"UFS_CIGAM"		},
+{ 0x57ac6e9d,	"STACK_END_MAGIC"	},
+{ 0x6165676c,	"PSTOREFS_MAGIC"	},
+{ 0x62646576,	"BDEVFS_MAGIC"		},
+{ 0x62656572,	"SYSFS_MAGIC"		},
+{ 0x64626720,	"DEBUGFS_MAGIC"		},
+{ 0x68191122,	"QNX6_SUPER_MAGIC"	},
+{ 0x73636673,	"SECURITYFS_MAGIC"	},
+{ 0x73717368,	"SQUASHFS_MAGIC"	},
+{ 0x73727279,	"BTRFS_TEST_MAGIC"	},
+{ 0x73757245,	"CODA_SUPER_MAGIC"	},
+{ 0x858458f6,	"RAMFS_MAGIC"		},
+{ 0x9123683e,	"BTRFS_SUPER_MAGIC"	},
+{ 0x958458f6,	"HUGETLBFS_MAGIC"	},
+{ 0xabba1974,	"XENFS_SUPER_MAGIC"	},
+{ 0xde5e81e4,	"EFIVARFS_MAGIC"	},
+{ 0xf2f52010,	"F2FS_SUPER_MAGIC"	},
+{ 0xf97cff8c,	"SELINUX_MAGIC"		},
+{ 0xf995e849,	"HPFS_SUPER_MAGIC"	},
+#unterminated