summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Scott <nathans@sgi.com>2003-07-21 03:56:40 +0000
committerNathan Scott <nathans@sgi.com>2003-07-21 03:56:40 +0000
commitff170d22ca9ae0b1c362e33a4ab2fbd85ca79b86 (patch)
tree1dc25ab85853d3f48a76756502b950f9739e7f2e
parent63f3fb80cd6410a10c4e76dc66b16d6d8dd07c88 (diff)
downloadattr-ff170d22ca9ae0b1c362e33a4ab2fbd85ca79b86.tar.gz
attr updates from Andreas - emphasis on improved handling of special characters, and creates an little library for helper functions
-rw-r--r--Makefile2
-rw-r--r--VERSION2
-rw-r--r--debian/changelog6
-rw-r--r--doc/CHANGES7
-rw-r--r--getfattr/Makefile4
-rw-r--r--getfattr/getfattr.c82
-rw-r--r--include/Makefile5
-rw-r--r--include/builddefs.in1
-rw-r--r--include/misc.h10
-rw-r--r--libmisc/Makefile45
-rw-r--r--libmisc/high_water_alloc.c45
-rw-r--r--libmisc/quote.c59
-rw-r--r--libmisc/unquote.c54
-rw-r--r--setfattr/Makefile4
-rw-r--r--setfattr/setfattr.c39
-rw-r--r--test/attr.test469
-rw-r--r--test/run193
17 files changed, 708 insertions, 319 deletions
diff --git a/Makefile b/Makefile
index 9284767..b1eced2 100644
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@ LSRCFILES = configure configure.in aclocal.m4 Makepkgs install-sh exports \
LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \
Logs/* built .census install.* install-dev.* install-lib.* *.gz
-SUBDIRS = include libattr attr getfattr setfattr \
+SUBDIRS = include libmisc libattr attr getfattr setfattr \
examples test m4 man doc po debian build
default: $(CONFIGURE)
diff --git a/VERSION b/VERSION
index defdf95..ffa0cc7 100644
--- a/VERSION
+++ b/VERSION
@@ -3,5 +3,5 @@
#
PKG_MAJOR=2
PKG_MINOR=4
-PKG_REVISION=5
+PKG_REVISION=6
PKG_BUILD=0
diff --git a/debian/changelog b/debian/changelog
index ab3496d..437e172 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+attr (2.4.6-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Nathan Scott <nathans@debian.org> Mon, 21 Jul 2003 13:38:45 +1000
+
attr (2.4.5-1) unstable; urgency=low
* New upstream release
diff --git a/doc/CHANGES b/doc/CHANGES
index 93ea44f..f49d129 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -1,3 +1,10 @@
+attr-2.4.6 (21 July 2003)
+ - Add internal library for misc. functions: quote, unquote,
+ high_water_alloc.
+ - Quote special characters in path names and attribute names.
+ - Use high_water_alloc everywhere instead of malloc/realloc.
+ - Update the test scripts.
+
attr-2.4.5 (03 July 2003)
- Tweak the build so we don't always run msgmerge,
fix from Steve Langasek originally.
diff --git a/getfattr/Makefile b/getfattr/Makefile
index b96ef52..000645a 100644
--- a/getfattr/Makefile
+++ b/getfattr/Makefile
@@ -36,8 +36,8 @@ include $(TOPDIR)/include/builddefs
LTCOMMAND = getfattr
CFILES = getfattr.c
-LLDLIBS = $(LIBATTR)
-LTDEPENDENCIES = $(LIBATTR)
+LLDLIBS = $(LIBATTR) $(LIBMISC)
+LTDEPENDENCIES = $(LIBATTR) $(LIBMISC)
default: $(LTCOMMAND)
diff --git a/getfattr/getfattr.c b/getfattr/getfattr.c
index 30c751c..0b3bd31 100644
--- a/getfattr/getfattr.c
+++ b/getfattr/getfattr.c
@@ -32,6 +32,7 @@
#include <attr/xattr.h>
#include "config.h"
+#include "misc.h"
#define CMD_LINE_OPTIONS "n:de:m:hRLP"
#define CMD_LINE_SPEC "[-hRLP] [-n name|-d] [-e en] [-m pattern] path..."
@@ -80,31 +81,6 @@ int do_listxattr(const char *path, char *list, size_t size)
return (opt_deref ? listxattr : llistxattr)(path, list, size);
}
-int high_water_alloc(void **buf, size_t *bufsize, size_t newsize)
-{
-#define CHUNK_SIZE 256
- /*
- * Goal here is to avoid unnecessary memory allocations by
- * using static buffers which only grow when necessary.
- * Size is increased in fixed size chunks (CHUNK_SIZE).
- */
- if (*bufsize < newsize) {
- void *newbuf;
-
- newsize = (newsize + CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);
- newbuf = realloc(*buf, newsize);
- if (!newbuf) {
- perror(progname);
- had_errors++;
- return 1;
- }
-
- *buf = newbuf;
- *bufsize = newsize;
- }
- return 0;
-}
-
const char *strerror_ea(int err)
{
if (err == ENODATA)
@@ -130,11 +106,10 @@ int well_enough_printable(const char *value, size_t size)
const char *encode(const char *value, size_t *size)
{
- static char *encoded = NULL, *e;
- char *enc;
+ static char *encoded;
+ static size_t encoded_size;
+ char *enc, *e;
- if (encoded)
- free(encoded);
if (opt_encoding == NULL) {
if (well_enough_printable(value, *size))
enc = "text";
@@ -152,8 +127,8 @@ const char *encode(const char *value, size_t *size)
else if (*e == '\\' || *e == '"')
extra++;
}
- encoded = (char *)malloc(*size + extra + 3);
- if (!encoded) {
+ if (high_water_alloc((void **)&encoded, &encoded_size,
+ *size + extra + 3)) {
perror(progname);
had_errors++;
return NULL;
@@ -180,8 +155,8 @@ const char *encode(const char *value, size_t *size)
static const char *digits = "0123456789abcdef";
size_t n;
- encoded = (char *)malloc(*size * 2 + 4);
- if (!encoded) {
+ if (high_water_alloc((void **)&encoded, &encoded_size,
+ *size * 2 + 4)) {
perror(progname);
had_errors++;
return NULL;
@@ -199,8 +174,8 @@ const char *encode(const char *value, size_t *size)
"ghijklmnopqrstuvwxyz0123456789+/";
size_t n;
- encoded = (char *)malloc((*size + 2) / 3 * 4 + 1);
- if (!encoded) {
+ if (high_water_alloc((void **)&encoded, &encoded_size,
+ (*size + 2) / 3 * 4 + 1)) {
perror(progname);
had_errors++;
return NULL;
@@ -243,15 +218,20 @@ int print_attribute(const char *path, const char *name, int *header_printed)
if (opt_dump || opt_value_only) {
length = do_getxattr(path, name, NULL, 0);
if (length < 0) {
- fprintf(stderr, "%s: %s: %s\n", path, name,
+ fprintf(stderr, "%s: ", quote(path));
+ fprintf(stderr, "%s: %s\n", quote(name),
strerror_ea(errno));
return 1;
}
- if (high_water_alloc((void **)&value, &value_size, length))
+ if (high_water_alloc((void **)&value, &value_size, length)) {
+ perror(progname);
+ had_errors++;
return 1;
+ }
length = do_getxattr(path, name, value, value_size);
if (length < 0) {
- fprintf(stderr, "%s: %s: %s\n", path, name,
+ fprintf(stderr, "%s: ", quote(path));
+ fprintf(stderr, "%s: %s\n", quote(name),
strerror_ea(errno));
return 1;
}
@@ -275,7 +255,7 @@ int print_attribute(const char *path, const char *name, int *header_printed)
}
if (!*header_printed && !opt_value_only) {
- printf("# file: %s\n", path);
+ printf("# file: %s\n", quote(path));
*header_printed = 1;
}
@@ -285,9 +265,9 @@ int print_attribute(const char *path, const char *name, int *header_printed)
const char *enc = encode(value, &length);
if (enc)
- printf("%s=%s\n", name, enc);
+ printf("%s=%s\n", quote(name), enc);
} else
- puts(name);
+ puts(quote(name));
return 0;
}
@@ -304,19 +284,22 @@ int list_attributes(const char *path, int *header_printed)
length = do_listxattr(path, NULL, 0);
if (length < 0) {
- fprintf(stderr, "%s: %s: %s\n",
- progname, path, strerror_ea(errno));
+ fprintf(stderr, "%s: %s: %s\n", progname, quote(path),
+ strerror_ea(errno));
had_errors++;
return 1;
} else if (length == 0)
return 0;
- if (high_water_alloc((void **)&list, &list_size, length))
+ if (high_water_alloc((void **)&list, &list_size, length)) {
+ perror(progname);
+ had_errors++;
return 1;
+ }
length = do_listxattr(path, list, list_size);
if (length < 0) {
- perror(path);
+ perror(quote(path));
had_errors++;
return 1;
}
@@ -330,8 +313,11 @@ int list_attributes(const char *path, int *header_printed)
if (names_size < (num_names+1) * sizeof(*names)) {
if (high_water_alloc((void **)&names, &names_size,
- (num_names+1) * sizeof(*names)))
+ (num_names+1) * sizeof(*names))) {
+ perror(progname);
+ had_errors++;
return 1;
+ }
}
names[num_names++] = l;
@@ -355,8 +341,8 @@ int do_print(const char *path, const struct stat *stat,
if (flag & FTW_DNR) {
/* Item is a directory which can't be read. */
- fprintf(stderr, "%s: %s: %s\n",
- progname, path, strerror(errno));
+ fprintf(stderr, "%s: %s: %s\n", progname, quote(path),
+ strerror(errno));
return 0;
}
diff --git a/include/Makefile b/include/Makefile
index 305d948..2098409 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -34,7 +34,8 @@ TOPDIR = ..
include $(TOPDIR)/include/builddefs
INCDIR = attr
-HFILES = attributes.h xattr.h error_context.h libattr.h
+INST_HFILES = attributes.h xattr.h error_context.h libattr.h
+HFILES = $(INST_HFILES) misc.h
LSRCFILES = builddefs.in buildmacros buildrules config.h.in
LDIRT = $(INCDIR)
@@ -46,5 +47,5 @@ include $(BUILDRULES)
install-dev: default
$(INSTALL) -m 755 -d $(PKG_INC_DIR)
- $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR)
+ $(INSTALL) -m 644 $(INST_HFILES) $(PKG_INC_DIR)
install install-lib:
diff --git a/include/builddefs.in b/include/builddefs.in
index 716acff..ca81852 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -40,6 +40,7 @@ OPTIMIZER = @opt_build@
MALLOCLIB = @malloc_lib@
LIBATTR = $(TOPDIR)/libattr/libattr.la
+LIBMISC = $(TOPDIR)/libmisc/libmisc.la
prefix = @prefix@
exec_prefix = @exec_prefix@
diff --git a/include/misc.h b/include/misc.h
new file mode 100644
index 0000000..58a6e78
--- /dev/null
+++ b/include/misc.h
@@ -0,0 +1,10 @@
+extern int high_water_alloc(void **buf, size_t *bufsize, size_t newsize);
+
+extern const char *quote(const char *str);
+extern char *unquote(char *str);
+
+extern int high_water_alloc(void **buf, size_t *bufsize, size_t newsize);
+
+extern const char *quote(const char *str);
+extern char *unquote(char *str);
+
diff --git a/libmisc/Makefile b/libmisc/Makefile
new file mode 100644
index 0000000..de3a761
--- /dev/null
+++ b/libmisc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTLIBRARY = libmisc.la
+LTLDFLAGS =
+
+CFILES = quote.c unquote.c high_water_alloc.c
+
+default: $(LTLIBRARY)
+install install-dev install-lib:
+
+include $(BUILDRULES)
+
diff --git a/libmisc/high_water_alloc.c b/libmisc/high_water_alloc.c
new file mode 100644
index 0000000..db925d3
--- /dev/null
+++ b/libmisc/high_water_alloc.c
@@ -0,0 +1,45 @@
+/*
+ File: high_water_alloc.c
+
+ Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "misc.h"
+
+int high_water_alloc(void **buf, size_t *bufsize, size_t newsize)
+{
+#define CHUNK_SIZE 256
+ /*
+ * Goal here is to avoid unnecessary memory allocations by
+ * using static buffers which only grow when necessary.
+ * Size is increased in fixed size chunks (CHUNK_SIZE).
+ */
+ if (*bufsize < newsize) {
+ void *newbuf;
+
+ newsize = (newsize + CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);
+ newbuf = realloc(*buf, newsize);
+ if (!newbuf)
+ return 1;
+
+ *buf = newbuf;
+ *bufsize = newsize;
+ }
+ return 0;
+}
diff --git a/libmisc/quote.c b/libmisc/quote.c
new file mode 100644
index 0000000..e5737e7
--- /dev/null
+++ b/libmisc/quote.c
@@ -0,0 +1,59 @@
+/*
+ File: quote.c
+
+ Copyright (C) 2003 Andreas Gruenbacher <a.gruenbacher@computer.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "misc.h"
+
+extern const char *progname;
+
+const char *quote(const char *str)
+{
+ static char *quoted_str;
+ static size_t quoted_str_len;
+ const unsigned char *s;
+ char *q;
+ size_t nonpr;
+
+ for (nonpr = 0, s = (unsigned char *)str; *s != '\0'; s++)
+ if (!isprint(*s) || isspace(*s) || *s == '\\')
+ nonpr++;
+ if (nonpr == 0)
+ return str;
+
+ if (high_water_alloc((void **)&quoted_str, &quoted_str_len,
+ nonpr * 3 + 1)) {
+ perror(progname);
+ exit(1);
+ }
+ for (s = (unsigned char *)str, q = quoted_str; *s != '\0'; s++) {
+ if (!isprint(*s) || isspace(*s) || *s == '\\') {
+ *q++ = '\\';
+ *q++ = '0' + ((*s >> 6) );
+ *q++ = '0' + ((*s >> 3) & 7);
+ *q++ = '0' + ((*s ) & 7);
+ } else
+ *q++ = *s;
+ }
+ *q++ = '\0';
+
+ return quoted_str;
+}
diff --git a/libmisc/unquote.c b/libmisc/unquote.c
new file mode 100644
index 0000000..5444b65
--- /dev/null
+++ b/libmisc/unquote.c
@@ -0,0 +1,54 @@
+/*
+ File: unquote.c
+
+ Copyright (C) 2003 Andreas Gruenbacher <a.gruenbacher@computer.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "misc.h"
+
+extern const char *progname;
+
+char *unquote(char *str)
+{
+ unsigned char *s, *t;
+
+ for (s = (unsigned char *)str; *s != '\0'; s++)
+ if (*s == '\\')
+ break;
+ if (*s == '\0')
+ return str;
+
+#define isoctal(c) \
+ ((c) >= '0' && (c) <= '7')
+
+ t = s;
+ do {
+ if (*s == '\\' &&
+ isoctal(*(s+1)) && isoctal(*(s+2)) && isoctal(*(s+3))) {
+ *t++ = ((*(s+1) - '0') << 6) +
+ ((*(s+2) - '0') << 3) +
+ ((*(s+3) - '0') );
+ s += 3;
+ } else
+ *t++ = *s;
+ } while (*s++ != '\0');
+
+ return str;
+}
diff --git a/setfattr/Makefile b/setfattr/Makefile
index 02fcdb2..426210a 100644
--- a/setfattr/Makefile
+++ b/setfattr/Makefile
@@ -36,8 +36,8 @@ include $(TOPDIR)/include/builddefs
LTCOMMAND = setfattr
CFILES = setfattr.c
-LLDLIBS = $(LIBATTR)
-LTDEPENDENCIES = $(LIBATTR)
+LLDLIBS = $(LIBATTR) $(LIBMISC)
+LTDEPENDENCIES = $(LIBATTR) $(LIBMISC)
default: $(LTCOMMAND)
diff --git a/setfattr/setfattr.c b/setfattr/setfattr.c
index 0f2362c..d9d1ad2 100644
--- a/setfattr/setfattr.c
+++ b/setfattr/setfattr.c
@@ -30,6 +30,7 @@
#include <attr/xattr.h>
#include "config.h"
+#include "misc.h"
#define CMD_LINE_OPTIONS "n:x:v:h"
#define CMD_LINE_SPEC "{-n name|-x name} [-v value] [-h] file..."
@@ -82,8 +83,10 @@ int do_removexattr(const char *path, const char *name)
int restore(const char *filename)
{
+ static char *path;
+ static size_t path_size;
FILE *file;
- char *path = NULL, *l;
+ char *l;
int line = 0, backup_line, status = 0;
if (strcmp(filename, "-") == 0)
@@ -119,10 +122,9 @@ int restore(const char *filename)
goto cleanup;
} else
l += 8;
- if (path)
- free(path);
- path = (char *)malloc(strlen(l) + 1);
- if (!path) {
+ l = unquote(l);
+ if (high_water_alloc((void **)&path, &path_size, strlen(l)+1)) {
+ perror(progname);
status = 1;
goto cleanup;
}
@@ -133,7 +135,7 @@ int restore(const char *filename)
line++;
if (value)
*value++ = '\0';
- status = do_set(path, name, value);
+ status = do_set(path, unquote(name), value);
}
if (l != NULL)
line++;
@@ -237,7 +239,7 @@ int main(int argc, char *argv[])
goto synopsis;
while (optind < argc) {
- do_set(argv[optind], opt_name, opt_value);
+ do_set(argv[optind], unquote(opt_name), opt_value);
optind++;
}
@@ -268,7 +270,7 @@ int do_set(const char *path, const char *name, const char *value)
if (error < 0) {
fprintf(stderr, "%s: %s: %s\n",
- progname, path, strerror_ea(errno));
+ progname, quote(path), strerror_ea(errno));
had_errors++;
return 1;
}
@@ -277,23 +279,21 @@ int do_set(const char *path, const char *name, const char *value)
const char *decode(const char *value, size_t *size)
{
- static char *decoded = NULL;
+ static char *decoded;
+ static size_t decoded_size;
- if (decoded != NULL) {
- free(decoded);
- decoded = NULL;
- }
if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) {
const char *v = value+2, *end = value + *size;
char *d;
- decoded = d = (char *)malloc(*size / 2);
- if (!decoded) {
+ if (high_water_alloc((void **)&decoded, &decoded_size,
+ *size / 2)) {
fprintf(stderr, "%s: %s\n",
progname, strerror_ea(errno));
had_errors++;
return NULL;
}
+ d = decoded;
while (v < end) {
int d1, d0;
@@ -321,13 +321,14 @@ const char *decode(const char *value, size_t *size)
int d0, d1, d2, d3;
char *d;
- decoded = d = (char *)malloc(*size / 4 * 3);
- if (!decoded) {
+ if (high_water_alloc((void **)&decoded, &decoded_size,
+ *size / 4 * 3)) {
fprintf(stderr, "%s: %s\n",
progname, strerror_ea(errno));
had_errors++;
return NULL;
}
+ d = decoded;
for(;;) {
while (v < end && isspace(*v))
v++;
@@ -393,13 +394,13 @@ const char *decode(const char *value, size_t *size)
end--;
}
- decoded = d = (char *)malloc(*size);
- if (!decoded) {
+ if (high_water_alloc((void **)&decoded, &decoded_size, *size)) {
fprintf(stderr, "%s: %s\n",
progname, strerror_ea(errno));
had_errors++;
return NULL;
}
+ d = decoded;
while (v < end) {
if (v[0] == '\\') {
diff --git a/test/attr.test b/test/attr.test
index 91c6874..d777518 100644
--- a/test/attr.test
+++ b/test/attr.test
@@ -1,204 +1,265 @@
-!
-! Tests for extended attributes on ext2/ext3 file systems. The initial
-! size checks and the file size checks are ext2/ext3 specific. The
-! other setfattr/getfattr operations are designed to cover all special
-! cases in the ext27ext3 kernel patches, but they should work on other
-! filesystems as well.
-!
-! Execute this test using the `run' script in this directory:
-!
-! $ run attr.text
-!
-! === try various valid and invalid names
-$ touch f
-$ setfattr -n user -v value f
-setfattr: f: Operation not supported
-$ setfattr -n user. -v value f
-setfattr: f: Invalid argument
-$ setfattr -n user.name f
-$ getfattr -d f
-# file: f
-user.name
-
-$ setfattr -n user.n -v value f
-$ rm f
-! === size checks, for an ext2/ext3 file system with a block size of 1K
-$ touch f
-$ setfattr -n user.name -v 968+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ f
-$ setfattr -n user.name -v 969++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ f
-setfattr: f: No space left on device
-$ rm f
-!
-! Editing values
-!
-$ touch f
-$ setfattr -n user.vvvvvvvvvvvv -v vvvvvvvvvvvv f
-$ setfattr -n user.wwwwwwww -v wwwwwwww f
-$ setfattr -n user.xxxx -v xxxx f
-$ getfattr -d f
-# file: f
-user.vvvvvvvvvvvv="vvvvvvvvvvvv"
-user.wwwwwwww="wwwwwwww"
-user.xxxx="xxxx"
-
-$ setfattr -n user.wwwwwwww -v wwww f
-$ getfattr -d f
-# file: f
-user.vvvvvvvvvvvv="vvvvvvvvvvvv"
-user.wwwwwwww="wwww"
-user.xxxx="xxxx"
-
-$ setfattr -n user.xxxx -v xxxxxxxx f
-$ getfattr -d f
-# file: f
-user.vvvvvvvvvvvv="vvvvvvvvvvvv"
-user.wwwwwwww="wwww"
-user.xxxx="xxxxxxxx"
-
-$ rm f
-!
-! Value encodings
-!
-$ touch f
-$ setfattr -n user.name -v 0xbabe f
-$ setfattr -n user.name2 -v 0s3q2+7w== f
-$ setfattr -n user.name3 -v 0xdeface f
-$ getfattr -d -e hex f
-# file: f
-user.name=0xbabe
-user.name2=0xdeadbeef
-user.name3=0xdeface
-
-$ getfattr -d -e base64 f
-# file: f
-user.name=0sur4=
-user.name2=0s3q2+7w==
-user.name3=0s3vrO
-
-$ getfattr -d -e text f
-# file: f
-user.name="º¾"
-user.name2="Þ­¾ï"
-user.name3="ÞúÎ"
-
-$ rm f
-!
-! Everything with one file
-!
-$ touch f
-$ setfattr -n user.novalue f
-$ setfattr -n user.somename -v somevalue f
-$ setfattr -n user.somename -v somevalue f
-$ setfattr -n user.longername -v longervalue f
-$ setfattr -n user.short -v value f
-$ setfattr -n user.novalue-yet f
-$ ls -s f
- 1 f
-$ getfattr -d f
-# file: f
-user.longername="longervalue"
-user.novalue
-user.novalue-yet
-user.short="value"
-user.somename="somevalue"
-
-$ setfattr -n user.novalue-yet -v avalue-now f
-$ getfattr -d f
-# file: f
-user.longername="longervalue"
-user.novalue
-user.novalue-yet="avalue-now"
-user.short="value"
-user.somename="somevalue"
-
-$ setfattr -x user.noname f
-setfattr: f: No such attribute
-$ setfattr -x user.somename f
-$ setfattr -x user.short f
-$ getfattr -d f
-# file: f
-user.longername="longervalue"
-user.novalue
-user.novalue-yet="avalue-now"
-
-$ setfattr -x user.longername f
-$ setfattr -x user.novalue f
-$ setfattr -x user.novalue-yet f
-$ getfattr -d f
-$ ls -s f
- 0 f
-$ rm f
-!
-! Test extended attribute block sharing
-!
-$ touch f g h
-$ setfattr -n user.novalue f g h
-$ ls -s f g h
- 1 f
- 1 g
- 1 h
-$ setfattr -n user.name -v value f
-$ ls -s f g h
- 1 f
- 1 g
- 1 h
-$ getfattr -d f g h
-# file: f
-user.name="value"
-user.novalue
-
-# file: g
-user.novalue
-
-# file: h
-user.novalue
-
-$ setfattr -n user.name -v value g
-$ ls -s f g h
- 1 f
- 1 g
- 1 h
-$ setfattr -x user.novalue h
-$ ls -s f g h
- 1 f
- 1 g
- 0 h
-$ getfattr -d f g h
-# file: f
-user.name="value"
-user.novalue
-
-# file: g
-user.name="value"
-user.novalue
-
-$ setfattr -n user.name -v other-value g
-$ setfattr -n user.name -v value g
-$ setfattr -x user.name f g
-$ setfattr -x user.novalue f g
-$ ls -s f g h
- 0 f
- 0 g
- 0 h
-$ rm f g h
-!
-! Attributes of symlinks vs. the files pointed to
-!
-$ touch f
-$ ln -s f l
-$ setfattr -n user.filename -v f l
-$ setfattr -n user.filename -v l l
-$ setfattr -h -n user.filename -v l l
-setfattr: l: Operation not permitted
-$ getfattr -d f l
-# file: f
-user.filename="l"
-
-# file: l
-user.filename="l"
-
-! Some POSIX ACL tests...
-$ setfattr -n system.posix_acl_access -v 0sAgAAAAEABgD/////AgAGAAEAAAAEAAQA/////xAABgD/////IAAEAP////8= f
-$ setfattr -n system.posix_acl_accessFOO -v 0sAgAAAAEABgD/////AgAGAAEAAAAEAAQA/////xAABgD/////IAAEAP////8= f
-setfattr: f: Invalid argument
-$ rm f l
+Tests for extended attributes on ext2/ext3 file systems. The initial
+size checks and the file size checks are ext2/ext3 specific. The
+other setfattr/getfattr operations are designed to cover all special
+cases in the ext27ext3 kernel patches, but they should work on other
+filesystems as well.
+
+Execute this test using the `run' script in this directory:
+
+ run attr.text
+
+Try various valid and invalid names
+
+ $ touch f
+ $ setfattr -n user -v value f
+ > setfattr: f: Operation not supported
+
+ $ setfattr -n user. -v value f
+ > setfattr: f: Invalid argument
+
+ $ setfattr -n user.name f
+ $ getfattr -d f
+ > # file: f
+ > user.name
+ >
+
+ $ setfattr -n user.n -v value f
+ $ rm f
+
+Size checks, for an ext2/ext3 file system with a block size of 4K
+
+ $ touch f
+ $ setfattr -n user.name -v 4040+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ f
+ $ setfattr -n user.name -v 4041++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ f
+ > setfattr: f: No space left on device
+
+ $ rm f
+
+Editing values
+
+ $ touch f
+ $ setfattr -n user.vvvvvvvvvvvv -v vvvvvvvvvvvv f
+ $ setfattr -n user.wwwwwwww -v wwwwwwww f
+ $ setfattr -n user.xxxx -v xxxx f
+ $ getfattr -d f
+ > # file: f
+ > user.vvvvvvvvvvvv="vvvvvvvvvvvv"
+ > user.wwwwwwww="wwwwwwww"
+ > user.xxxx="xxxx"
+ >
+
+ $ setfattr -n user.wwwwwwww -v wwww f
+ $ getfattr -d f
+ > # file: f
+ > user.vvvvvvvvvvvv="vvvvvvvvvvvv"
+ > user.wwwwwwww="wwww"
+ > user.xxxx="xxxx"
+ >
+
+ $ setfattr -n user.xxxx -v xxxxxxxx f
+ $ getfattr -d f
+ > # file: f
+ > user.vvvvvvvvvvvv="vvvvvvvvvvvv"
+ > user.wwwwwwww="wwww"
+ > user.xxxx="xxxxxxxx"
+ >
+
+ $ rm f
+
+Value encodings
+
+ $ touch f
+ $ setfattr -n user.name -v 0xbabe f
+ $ setfattr -n user.name2 -v 0s3q2+7w== f
+ $ setfattr -n user.name3 -v 0xdeface f
+ $ getfattr -d -e hex f
+ > # file: f
+ > user.name=0xbabe
+ > user.name2=0xdeadbeef
+ > user.name3=0xdeface
+ >
+
+ $ getfattr -d -e base64 f
+ > # file: f
+ > user.name=0sur4=
+ > user.name2=0s3q2+7w==
+ > user.name3=0s3vrO
+ >
+
+ $ getfattr -d -e text f
+ > # file: f
+ > user.name="º¾"
+ > user.name2="Þ­¾ï"
+ > user.name3="ÞúÎ"
+ >
+
+ $ rm f
+
+Everything with one file
+
+ $ touch f
+ $ setfattr -n user.novalue f
+ $ setfattr -n user.somename -v somevalue f
+ $ setfattr -n user.somename -v somevalue f
+ $ setfattr -n user.longername -v longervalue f
+ $ setfattr -n user.short -v value f
+ $ setfattr -n user.novalue-yet f
+ $ ls -s f
+ > 4 f
+
+ $ getfattr -d f
+ > # file: f
+ > user.longername="longervalue"
+ > user.novalue
+ > user.novalue-yet
+ > user.short="value"
+ > user.somename="somevalue"
+ >
+
+ $ setfattr -n user.novalue-yet -v avalue-now f
+ $ getfattr -d f
+ > # file: f
+ > user.longername="longervalue"
+ > user.novalue
+ > user.novalue-yet="avalue-now"
+ > user.short="value"
+ > user.somename="somevalue"
+ >
+
+ $ setfattr -x user.noname f
+ > setfattr: f: No such attribute
+
+ $ setfattr -x user.somename f
+ $ setfattr -x user.short f
+ $ getfattr -d f
+ > # file: f
+ > user.longername="longervalue"
+ > user.novalue
+ > user.novalue-yet="avalue-now"
+ >
+
+ $ setfattr -x user.longername f
+ $ setfattr -x user.novalue f
+ $ setfattr -x user.novalue-yet f
+ $ getfattr -d f
+ $ ls -s f
+ > 0 f
+
+ $ rm f
+
+Test extended attribute block sharing
+
+ $ touch f g h
+ $ setfattr -n user.novalue f g h
+ $ ls -s f g h
+ > 4 f
+ > 4 g
+ > 4 h
+
+ $ setfattr -n user.name -v value f
+ $ ls -s f g h
+ > 4 f
+ > 4 g
+ > 4 h
+
+ $ getfattr -d f g h
+ > # file: f
+ > user.name="value"
+ > user.novalue
+ >
+ > # file: g
+ > user.novalue
+ >
+ > # file: h
+ > user.novalue
+ >
+
+ $ setfattr -n user.name -v value g
+ $ ls -s f g h
+ > 4 f
+ > 4 g
+ > 4 h
+
+ $ setfattr -x user.novalue h
+ $ ls -s f g h
+ > 4 f
+ > 4 g
+ > 0 h
+
+ $ getfattr -d f g h
+ > # file: f
+ > user.name="value"
+ > user.novalue
+ >
+ > # file: g
+ > user.name="value"
+ > user.novalue
+ >
+
+ $ setfattr -n user.name -v other-value g
+ $ setfattr -n user.name -v value g
+ $ setfattr -x user.name f g
+ $ setfattr -x user.novalue f g
+ $ ls -s f g h
+ > 0 f
+ > 0 g
+ > 0 h
+
+ $ rm f g h
+
+Attributes of symlinks vs. the files pointed to
+
+ $ touch f
+ $ ln -s f l
+ $ setfattr -n user.filename -v f l
+ $ setfattr -n user.filename -v l l
+ $ setfattr -h -n user.filename -v l l
+ > setfattr: l: Operation not permitted
+
+ $ getfattr -d f l
+ > # file: f
+ > user.filename="l"
+ >
+ > # file: l
+ > user.filename="l"
+ >
+
+ $ rm f
+
+Tests for file name that contain special characters
+
+ $ touch "f "
+ $ setfattr -n user.name -v value "f "
+ $ getfattr -d "f "
+ > # file: f\040
+ > user.name="value"
+ >
+
+ $ rm "f "
+
+Tests for attribute names that contains special characters
+
+ $ touch f
+ $ setfattr -n "user.sp ace" -v value f
+ $ setfattr -n "user.special\\007" -v value f
+ $ getfattr f
+ > # file: f
+ > user.sp\040ace
+ > user.special\007
+ >
+
+ $ getfattr -d f
+ > # file: f
+ > user.sp\040ace="value"
+ > user.special\007="value"
+ >
+
+ $ setfattr -x "user.sp ace" f
+ $ setfattr -n "user.sp ace" -v value f
+ $ setfattr -x "user.sp\\040ace" f
+ $ setfattr -x "user.special\\007" f
+ $ rm f
+
+Some POSIX ACL tests...
+
+ $ touch f
diff --git a/test/run b/test/run
index 1b7287a..c4d017a 100644
--- a/test/run
+++ b/test/run
@@ -1,11 +1,23 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w -U
+
+#
+# Possible improvements:
+#
+# - distinguish stdout and stderr output
+# - add environment variable like assignments
+# - run up to a specific line
+# - resume at a specific line
+#
use strict;
use FileHandle;
-use POSIX qw(geteuid getegid isatty);
+use Getopt::Std;
+use POSIX qw(isatty setuid);
+use vars qw($opt_v);
+
+no warnings qw(taint);
-my $owner = getpwuid(geteuid());
-my $group = getgrgid(getegid());
+getopts('v');
my ($OK, $FAILED) = ("ok", "failed");
if (isatty(fileno(STDOUT))) {
@@ -13,19 +25,61 @@ if (isatty(fileno(STDOUT))) {
$FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
}
+sub exec_test($$);
+
my ($prog, $in, $out) = ([], [], []);
-my $line = 0;
+my $line_number = 0;
my $prog_line;
-my ($tests, $failed);
+my ($tests, $failed) = (0,0);
for (;;) {
- my $script = <>; $line++;
- $script =~ s/\@OWNER\@/$owner/g;
- $script =~ s/\@GROUP\@/$group/g;
- next if (defined($script) && $script =~ /^!/);
- if (!defined($script) || $script =~ s/^\$ ?//) {
- if (@$prog) {
- #print "[$prog_line] \$ ", join(' ', @$prog), " -- ";
+ my $line = <>; $line_number++;
+ if (defined $line) {
+ # Substitute %VAR and %{VAR} with environment variables.
+ $line =~ s[%(?:(\w+)|\{(\w+)\})][$ENV{"$1$2"}]eg;
+ }
+ if (defined $line) {
+ if ($line =~ s/^\s*< ?//) {
+ push @$in, $line;
+ } elsif ($line =~ s/^\s*> ?//) {
+ push @$out, $line;
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+
+ $prog = [];
+ $prog_line = 0;
+ }
+ if ($line =~ s/^\s*\$ ?//) {
+ $line =~ s/\s+#.*//; # remove comments here...
+ $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $line ];
+ $prog_line = $line_number;
+ $in = [];
+ $out = [];
+ }
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+ last;
+ }
+}
+
+my $status = sprintf("%d commands (%d passed, %d failed)",
+ $tests, $tests-$failed, $failed);
+if (isatty(fileno(STDOUT))) {
+ if ($failed) {
+ $status = "\033[31m\033[1m" . $status . "\033[m";
+ } else {
+ $status = "\033[32m" . $status . "\033[m";
+ }
+}
+print $status, "\n";
+exit $failed ? 1 : 0;
+
+
+sub process_test($$$$) {
+ my ($prog, $prog_line, $in, $out) = @_;
+
+ return unless @$prog;
+
my $p = [ @$prog ];
print "[$prog_line] \$ ", join(' ',
map { s/\s/\\$&/g; $_ } @$p), " -- ";
@@ -36,9 +90,6 @@ for (;;) {
if (!defined($out->[$n]) || !defined($result->[$n]) ||
$out->[$n] ne $result->[$n]) {
$good = 0;
- #chomp $out->[$n];
- #chomp $result->[$n];
- #print "$out->[$n] != $result->[$n]";
}
}
$tests++;
@@ -50,37 +101,88 @@ for (;;) {
chomp $l;
my $r = defined($result->[$n]) ? $result->[$n] : "~";
chomp $r;
- print sprintf("%-37s | %-39s\n", $l, $r);
+ print sprintf("%-37s %s %-39s\n", $l, $l eq $r ? "|" : "?", $r);
}
+ } elsif ($opt_v) {
+ print join('', @$result);
}
+}
+
+
+sub su($) {
+ my ($user) = @_;
+
+ $user ||= "root";
+
+ my ($login, $pass, $uid, $gid) = getpwnam($user)
+ or return [ "su: user $user does not exist\n" ];
+ my @groups = ();
+ my $fh = new FileHandle("/etc/group")
+ or return [ "opening /etc/group: $!\n" ];
+ while (<$fh>) {
+ chomp;
+ my ($group, $passwd, $gid, $users) = split /:/;
+ foreach my $u (split /,/, $users) {
+ push @groups, $gid
+ if ($user eq $u);
}
- #$prog = [ split /\s+/, $script ] if $script;
- $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $script ] if $script;
- $prog_line = $line;
- $in = [];
- $out = [];
- } elsif ($script =~ s/^> ?//) {
- push @$in, $script;
- } else {
- push @$out, $script;
}
- last unless defined($script);
+ $fh->close;
+
+ my $groups = join(" ", ($gid, $gid, @groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ if ($!) {
+ return [ "su: $!\n" ];
+ }
+ if ($uid != 0) {
+ $> = $uid;
+ #$< = $uid;
+ if ($!) {
+ return [ "su: $prog->[1]: $!\n" ];
+ }
+ }
+ #print STDERR "[($>,$<)($(,$))]";
+ return [];
}
-my $status = sprintf("%d commands (%d passed, %d failed)",
- $tests, $tests-$failed, $failed);
-if (isatty(fileno(STDOUT))) {
- if ($failed) {
- $status = "\033[31m\033[1m" . $status . "\033[m";
- } else {
- $status = "\033[32m" . $status . "\033[m";
- }
+
+
+sub sg($) {
+ my ($group) = @_;
+
+ my $gid = getgrnam($group)
+ or return [ "sg: group $group does not exist\n" ];
+ my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $));
+
+ #print STDERR "<<", join("/", keys %groups), ">>\n";
+ my $groups = join(" ", ($gid, $gid, keys %groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ if ($> != 0) {
+ my $uid = $>;
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ $> = $uid;
+ } else {
+ $( = $gid;
+ $) = $groups;
+ }
+ if ($!) {
+ return [ "sg: $!\n" ];
+ }
+ print STDERR "[($>,$<)($(,$))]";
+ return [];
}
-print $status, "\n";
-exit $failed ? 1 : 0;
+
sub exec_test($$) {
my ($prog, $in) = @_;
local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+ my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/);
if ($prog->[0] eq "umask") {
umask oct $prog->[1];
@@ -90,6 +192,10 @@ sub exec_test($$) {
return [ "chdir: $prog->[1]: $!\n" ];
}
return [];
+ } elsif ($prog->[0] eq "su") {
+ return su($prog->[1]);
+ } elsif ($prog->[0] eq "sg") {
+ return sg($prog->[1]);
}
pipe *IN2, *OUT
@@ -134,11 +240,15 @@ sub exec_test($$) {
my $result = [];
while (<IN>) {
#print "< $_";
+ if ($needs_shell) {
+ s#^/bin/sh: line \d+: ##;
+ }
push @$result, $_;
}
return $result;
} else {
# Client
+ $< = $>;
close IN
or die "Can't close read end for input pipe: $!";
close OUT
@@ -151,9 +261,12 @@ sub exec_test($$) {
open STDERR, ">&STDOUT"
or die "Can't join STDOUT and STDERR: $!";
- #print ERR_DUP "<", join(' ', @$prog), ">\n";
- exec @$prog;
- print ERR_DUP $prog->[0], ": $!\n";
+ if ($needs_shell) {
+ exec ('/bin/sh', '-c', join(" ", @$prog));
+ } else {
+ exec @$prog;
+ }
+ print STDERR $prog->[0], ": $!\n";
exit;
}
}