From ff170d22ca9ae0b1c362e33a4ab2fbd85ca79b86 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 21 Jul 2003 03:56:40 +0000 Subject: attr updates from Andreas - emphasis on improved handling of special characters, and creates an little library for helper functions --- Makefile | 2 +- VERSION | 2 +- debian/changelog | 6 + doc/CHANGES | 7 + getfattr/Makefile | 4 +- getfattr/getfattr.c | 82 ++++---- include/Makefile | 5 +- include/builddefs.in | 1 + include/misc.h | 10 + libmisc/Makefile | 45 +++++ libmisc/high_water_alloc.c | 45 +++++ libmisc/quote.c | 59 ++++++ libmisc/unquote.c | 54 ++++++ setfattr/Makefile | 4 +- setfattr/setfattr.c | 39 ++-- test/attr.test | 469 +++++++++++++++++++++++++-------------------- test/run | 193 +++++++++++++++---- 17 files changed, 708 insertions(+), 319 deletions(-) create mode 100644 include/misc.h create mode 100644 libmisc/Makefile create mode 100644 libmisc/high_water_alloc.c create mode 100644 libmisc/quote.c create mode 100644 libmisc/unquote.c 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 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 #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 +#include +#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 + + 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 +#include +#include +#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 **)"ed_str, "ed_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 + + 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 +#include +#include +#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 #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 /(?[$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 /(? ?//) { - 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 () { #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; } } -- cgit v1.2.3