diff options
author | Nathan Scott <nathans@sgi.com> | 2002-02-25 23:00:28 +0000 |
---|---|---|
committer | Nathan Scott <nathans@sgi.com> | 2002-02-25 23:00:28 +0000 |
commit | af208e0a7308642f1cfcca8fb97d5a6bb2558a30 (patch) | |
tree | 38a4aa110c53f7ef39b24ff7550e225655ffe7c1 | |
parent | 9a1f53a06b83d155c82cab65f85ce691d7bf31c6 (diff) | |
download | attr-af208e0a7308642f1cfcca8fb97d5a6bb2558a30.tar.gz |
Merge of xfs-cmds-2.4.18:slinx:112535a by nathans.
merge with AndreasG latest snapshot - long options, rename a couple of
options to his prefered letters, -5 is gone, use ntfw instead of doing
it ourselves.
-rw-r--r-- | getfattr/Makefile | 3 | ||||
-rw-r--r-- | getfattr/getfattr.c | 633 | ||||
-rw-r--r-- | getfattr/walk_tree.c | 94 | ||||
-rw-r--r-- | getfattr/walk_tree.h | 18 | ||||
-rw-r--r-- | include/xattr.h | 6 | ||||
-rw-r--r-- | man/man1/getfattr.1 | 21 | ||||
-rw-r--r-- | setfattr/setfattr.c | 221 |
7 files changed, 489 insertions, 507 deletions
diff --git a/getfattr/Makefile b/getfattr/Makefile index 6b11226..fc23850 100644 --- a/getfattr/Makefile +++ b/getfattr/Makefile @@ -34,8 +34,7 @@ TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = getfattr -CFILES = walk_tree.c getfattr.c -HFILES = walk_tree.h +CFILES = getfattr.c LLDLIBS = $(LIBATTR) LTDEPENDENCIES = $(LIBATTR) diff --git a/getfattr/getfattr.c b/getfattr/getfattr.c index 390a8c9..74c2d65 100644 --- a/getfattr/getfattr.c +++ b/getfattr/getfattr.c @@ -1,185 +1,87 @@ /* - * Original getfattr.c: - * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org> - * Changes to use revised EA syscall interface: - * Copyright (C) 2001 by SGI XFS development <linux-xfs@oss.sgi.com> - */ + File: getfattr.c + (Linux Extended Attributes) + + Copyright (C) 2001-2002 Andreas Gruenbacher <a.gruenbacher@computer.org> + Copyright (C) 2001-2002 SGI XFS development <linux-xfs@oss.sgi.com> + + 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 <string.h> +#include <errno.h> #include <ctype.h> #include <getopt.h> #include <regex.h> #include <attr/xattr.h> -#include "walk_tree.h" +#include <ftw.h> #include <locale.h> #include <libintl.h> #define _(String) gettext (String) -#define CMD_LINE_OPTIONS "ade:hln:r:vR5LPV" -#define CMD_LINE_SPEC "[-n name|-d] [-ahvR5LPV] [-e en] [-r regex] path..." - -int opt_dump; -int opt_symlink; -char *opt_encoding; -char opt_value_only; -int opt_strip_leading_slash = 1; +#define CMD_LINE_OPTIONS "ade:hm:n:v:HRLP" +#define CMD_LINE_SPEC "[-ahvRLP] [-n name|-d] [-e en] [-m pattern] path..." + +struct option long_options[] = { + { "name", 1, 0, 'n' }, + { "dump", 0, 0, 'd' }, + { "encoding", 1, 0, 'e' }, + { "match", 1, 0, 'm' }, + { "only-values", 0, 0, 'v' }, + { "no-dereference", 0, 0, 'h' }, + { "absolute-names", 0, 0, 'a' }, + { "recursive", 0, 0, 'R' }, + { "logical", 0, 0, 'L' }, + { "physical", 0, 0, 'P' }, + { "version", 0, 0, 'V' }, + { "help", 0, 0, 'H' }, + { NULL, 0, 0, 0 } +}; + +int opt_recursive; /* recurse into sub-directories? */ +int opt_walk_logical; /* always follow symbolic links */ +int opt_walk_physical; /* never follow symbolic links */ +int opt_dump; /* dump attribute values (or only list the names) */ +int opt_deref = 1; /* dereference symbolic links */ +char *opt_name; /* dump named attributes */ +char *opt_name_pattern = "^user\\."; /* include only matching names */ +char *opt_encoding; /* encode values automatically (NULL), or as "text", + "hex", or "base64" */ +char opt_value_only; /* dump the value only, without any decoration */ +int opt_strip_leading_slash = 1; /* strip leading '/' from path names */ const char *progname; int absolute_warning; -int header_printed; int had_errors; -regex_t re; - -int do_get_all(const char *, struct stat *, void *); -int do_get_one(const char *, struct stat *, void *); -int get_one(const char *, const char *); -const char *encode(const char *value, size_t *size); - - -void help(void) -{ - printf(_("%s %s -- get extended attributes\n"), - progname, VERSION); - printf(_("Usage: %s %s\n"), - progname, CMD_LINE_SPEC); - printf(_("\t-n name\tdump value of extended attribute `name'\n" - "\t-a\tabsolute pathnames - leading '/' not stripped\n" - "\t-d\tdump all extended attribute values\n" - "\t-e en\tencode values (en = text|hex|base64)\n" - "\t-l\tdump extended attribute values of a symlink\n" - "\t-s\tdump extended system and user attribute values\n" - "\t-v\tprint the attribute value(s) only\n" - "\t-R\trecurse into subdirectories (-5 = post-order)\n" - "\t-L\tlogical walk, follow symbolic links\n" - "\t-P\tphysical walk, do not follow symbolic links\n" - "\t-V\tprint version and exit\n" - "\t-h\tthis help text\n")); -} - -int main(int argc, char *argv[]) -{ - char *pattern = "^user\\."; - char *name = NULL; - - progname = basename(argv[0]); - setlocale(LC_ALL, ""); - - while ((optopt = getopt(argc, argv, CMD_LINE_OPTIONS)) != -1) { - switch(optopt) { - case 'a': /* absolute names */ - opt_strip_leading_slash = 0; - break; - - case 'd': /* dump attribute values */ - opt_dump = 1; - break; - - case 'e': /* encoding */ - if (strcmp(optarg, "text") != 0 && - strcmp(optarg, "hex") != 0 && - strcmp(optarg, "base64") != 0) - goto synopsis; - opt_encoding = optarg; - break; - - case 'h': - help(); - return 0; - - case 'l': /* dump attribute(s) of symlink itself */ - opt_symlink = 1; - break; - - case 'n': /* get named attribute */ - opt_dump = 1; - name = optarg; - break; - - case 'r': /* regular expression for filtering names */ - if (!strcmp(optarg, "-")) - pattern = ""; - else - pattern = optarg; - break; - - case 'v': /* get attribute values only */ - opt_value_only = 1; - break; - - case 'H': - walk_symlinks = WALK_HALF_LOGICAL; - break; - - case 'L': - walk_symlinks = WALK_FULL_LOGICAL; - break; - - case 'P': - walk_symlinks = WALK_PHYSICAL; - break; - - case 'R': - walk_recurse = 1; - walk_postorder = 0; - break; - - case '5': - walk_recurse = 1; - walk_postorder = 1; - break; - - case 'V': - printf("%s " VERSION "\n", progname); - return 0; - - default: - goto synopsis; - } - } - if (optind >= argc) - goto synopsis; - - if (regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB) != 0) { - fprintf(stderr, _("%s: invalid regular expression \"%s\"\n"), - progname, pattern); - return 1; - } +regex_t name_regex; - while (optind < argc) { - if (name) - had_errors += walk_tree(argv[optind], do_get_one, name); - else - had_errors += walk_tree(argv[optind], do_get_all, NULL); - optind++; - } - - return (had_errors ? 1 : 0); - -synopsis: - fprintf(stderr, _("Usage: %s %s\n" - "Try `%s -h' for more information.\n"), - progname, CMD_LINE_SPEC, progname); - return 2; -} int do_getxattr(const char *path, const char *name, void *value, size_t size) { - if (opt_symlink) - return lgetxattr(path, name, value, size); - return getxattr(path, name, value, size); + return (opt_deref ? getxattr : lgetxattr)(path, name, value, size); } int do_listxattr(const char *path, char *list, size_t size) { - if (opt_symlink) - return llistxattr(path, list, size); - return listxattr(path, list, size); + return (opt_deref ? listxattr : llistxattr)(path, list, size); } -int high_water_alloc(void **buf, int *bufsize, int newsize) +int high_water_alloc(void **buf, size_t *bufsize, size_t newsize) { #define CHUNK_SIZE 256 /* @@ -188,149 +90,32 @@ int high_water_alloc(void **buf, int *bufsize, int newsize) * Size is increased in fixed size chunks (CHUNK_SIZE). */ if (*bufsize < newsize) { + void *newbuf; + newsize = (newsize + CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); - *buf = realloc(*buf, newsize); - if (!*buf) { + newbuf = realloc(*buf, newsize); + if (!newbuf) { perror(progname); had_errors++; - *bufsize = 0; return 1; } + + *buf = newbuf; *bufsize = newsize; } return 0; } -int pstrcmp(const char **a, const char **b) -{ - return strcmp(*a, *b); -} - -int do_get_all(const char *path, struct stat *stat, void *dummy) -{ - static char *list; - static ssize_t bufsize; - static char **names; - static int ncount; - - char *v; - ssize_t listsize; - int n, count = 0; - - listsize = do_listxattr(path, NULL, 0); - if (listsize < 0) { - perror(path); - had_errors++; - return 1; - } else if (listsize > 0) { - if (high_water_alloc((void **)&list, &bufsize, listsize)) - return 1; - - listsize = do_listxattr(path, list, bufsize); - if (listsize < 0) { - perror(path); - had_errors++; - return 1; - } - - for (v = list; (v - list) < listsize; v += strlen(v)+1) - if (regexec(&re, v, (size_t) 0, NULL, 0) == 0) - count++; - if (count) { - n = count * sizeof(char *); - if (high_water_alloc((void **)&names, &ncount, n)) - return 1; - n = 0; - for (v = list; (v - list) < listsize; v += strlen(v)+1) - if (regexec(&re, v, (size_t) 0, NULL, 0) == 0) - names[n++] = v; - qsort(names, count, sizeof(char *), - (int (*)(const void *,const void *))pstrcmp); - } - } - if (names) { - header_printed = 0; - for (n = 0; n < count; n++) - get_one(path, names[n]); - if (header_printed) - puts(""); - } - return 0; -} - -int do_get_one(const char *path, struct stat *stat, void *name) +const char *strerror_ea(int err) { - int error; - - header_printed = 0; - error = get_one(path, (const char *)name); - if (header_printed) - puts(""); - return error; + if (err == ENOATTR) + return _("No such attribute"); + return strerror(err); } -int get_one(const char *path, const char *name) +int pstrcmp(const void *a, const void *b) { - static char *value; - static size_t vsize; - - int error, lsize = 0; - - if (opt_dump || opt_value_only) { - error = do_getxattr(path, name, NULL, 0); - if (error < 0) { - const char *strerr; -syscall_failed: - if (!strncmp("system.", name, 7) && errno == ENOATTR) - return 0; /* expected */ - else if (errno == ENOATTR) - strerr = _("No such attribute"); - else - strerr = strerror(errno); - fprintf(stderr, "%s: %s: %s\n", path, name, strerr); - return 1; - } - if (high_water_alloc((void **)&value, &vsize, error + 1)) - return 1; - error = do_getxattr(path, name, value, vsize); - if (error < 0) - goto syscall_failed; - lsize = error; - value[lsize] = '\0'; - } - - if (opt_strip_leading_slash) { - if (*path == '/') { - if (!absolute_warning) { - fprintf(stderr, _("%s: Removing leading '/' " - "from absolute path names\n"), - progname); - absolute_warning = 1; - } - while (*path == '/') - path++; - } else if (*path == '.' && *(path+1) == '/') - while (*++path == '/') - /* nothing */ ; - if (*path == '\0') - path = "."; - } - - if (!header_printed && !opt_value_only) { - printf("# file: %s\n", path); - header_printed = 1; - } - if (opt_value_only) - puts(value); - else if (lsize) { - const char *e = encode(value, &lsize); - - if (e) - printf("%s=%s\n", name, e); - } else - puts(name); - - return 0; + return strcmp(*(const char **)a, *(const char **)b); } int well_enough_printable(const char *value, size_t size) @@ -341,7 +126,7 @@ int well_enough_printable(const char *value, size_t size) if (!isprint(*value++)) nonpr++; - return (size >= nonpr*8); /* no more than 1/8 non-printable */ + return (size >= nonpr*8); /* no more than 1/8 non-printable chars */ } const char *encode(const char *value, size_t *size) @@ -449,3 +234,283 @@ const char *encode(const char *value, size_t *size) } return encoded; } + +int print_attribute(const char *path, const char *name, int *header_printed) +{ + static char *value; + static size_t value_size; + ssize_t length = 0; + + if (opt_dump || opt_value_only) { + length = do_getxattr(path, name, NULL, 0); + if (length < 0) { + if (errno == ENOATTR) { + /* + * Occasionally there are attribute + * names in the name list that are not + * accessible, or don't really exist. + * Silently ignore this case. + */ + return 0; + } + fprintf(stderr, "%s: %s: %s\n", path, name, + strerror_ea(errno)); + return 1; + } + if (high_water_alloc((void **)&value, &value_size, length)) + return 1; + length = do_getxattr(path, name, value, value_size); + if (length < 0) { + fprintf(stderr, "%s: %s: %s\n", path, name, + strerror_ea(errno)); + return 1; + } + } + + if (opt_strip_leading_slash) { + if (*path == '/') { + if (!absolute_warning) { + fprintf(stderr, _("%s: Removing leading '/' " + "from absolute path names\n"), + progname); + absolute_warning = 1; + } + while (*path == '/') + path++; + } else if (*path == '.' && *(path+1) == '/') + while (*++path == '/') + /* nothing */ ; + if (*path == '\0') + path = "."; + } + + if (!*header_printed && !opt_value_only) { + printf("# file: %s\n", path); + *header_printed = 1; + } + + if (opt_value_only) + fwrite(value, length, 1, stdout); + else if (length) { + const char *enc = encode(value, &length); + + if (enc) + printf("%s=%s\n", name, enc); + } else + puts(name); + + return 0; +} + +int list_attributes(const char *path, int *header_printed) +{ + static char *list; + static size_t list_size; + static char **names; + static size_t names_size; + int num_names = 0; + ssize_t length; + char *l; + + length = do_listxattr(path, NULL, 0); + if (length < 0) { + if (errno != ENOTSUP || errno != ENOSYS) { + fprintf(stderr, "%s: %s: %s\n", + progname, path, strerror_ea(errno)); + had_errors++; + return 1; + } + } else if (length == 0) + return 0; + + if (high_water_alloc((void **)&list, &list_size, length)) + return 1; + + length = do_listxattr(path, list, list_size); + if (length < 0) { + perror(path); + had_errors++; + return 1; + } + + for (l = list; l != list + length; l = strchr(l, '\0')+1) { + if (regexec(&name_regex, l, 0, NULL, 0) != 0) + continue; + + if (names_size < (num_names+1) * sizeof(*names)) { + if (high_water_alloc((void **)&names, &names_size, + (num_names+1) * sizeof(*names))) + return 1; + } + + names[num_names++] = l; + } + + qsort(names, num_names, sizeof(*names), pstrcmp); + + if (num_names) { + int n; + + for (n = 0; n < num_names; n++) + print_attribute(path, names[n], header_printed); + } + return 0; +} + +int do_print(const char *path, const struct stat *stat, + int flag, struct FTW *ftw) +{ + int header_printed = 0; + + /* + * Process the target of a symbolic link, and traverse the + * link, only if doing a logical walk, or if the symbolic link + * was specified on the command line. Always skip symbolic + * links if doing a physical walk. + */ + + if (S_ISLNK(stat->st_mode) && + (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical))) + return 0; + + if (opt_name) + print_attribute(path, opt_name, &header_printed); + else + list_attributes(path, &header_printed); + + if (header_printed) + puts(""); + + /* + * We also get here in non-recursive mode. In that case, + * return something != 0 to abort nftw. + */ + + if (!opt_recursive) + return 1; + return 0; +} + +void help(void) +{ + printf(_("%s %s -- get extended attributes\n"), + progname, VERSION); + printf(_("Usage: %s %s\n"), + progname, _(CMD_LINE_SPEC)); + printf(_( +" -n, --name=name get the named extended attribute value\n" +" -d, --dump get all extended attribute values\n" +" -e, --encoding=... encode values (as 'text', 'hex' or 'base64')\n" +" --match=pattern only get attributes with names matching pattern\n" +" --only-values print the bare values only\n" +" -h, --no-dereference do not dereference symbolic links\n" +" --absolute-names don't strip leading '/' in pathnames\n" +" -R, --recursive recurse into subdirectories\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P --physical physical walk, do not follow symbolic links\n" +" --version print version and exit\n" +" --help this help text\n")); +} + + +int main(int argc, char *argv[]) +{ + int opt; + + progname = basename(argv[0]); + setlocale(LC_ALL, ""); + + while ((opt = getopt_long(argc, argv, CMD_LINE_OPTIONS, + long_options, NULL)) != -1) { + switch(opt) { + case 'a': /* absolute names */ + opt_strip_leading_slash = 0; + break; + + case 'd': /* dump attribute values */ + opt_dump = 1; + break; + + case 'e': /* encoding */ + if (strcmp(optarg, "text") != 0 && + strcmp(optarg, "hex") != 0 && + strcmp(optarg, "base64") != 0) + goto synopsis; + opt_encoding = optarg; + break; + + case 'H': + help(); + return 0; + + case 'h': /* do not dereference symlinks */ + opt_deref = 0; + break; + + case 'n': /* get named attribute */ + opt_dump = 1; + opt_name = optarg; + break; + + case 'm': /* regular expression for filtering names */ + opt_name_pattern = optarg; + if (strcmp(opt_name_pattern, "-") == 0) + opt_name_pattern = ""; + break; + + case 'v': /* get attribute values only */ + opt_value_only = 1; + break; + + case 'L': + opt_walk_logical = 1; + opt_walk_physical = 0; + break; + + case 'P': + opt_walk_logical = 0; + opt_walk_physical = 1; + break; + + case 'R': + opt_recursive = 1; + break; + + case 'V': + printf("%s " VERSION "\n", progname); + return 0; + + case ':': /* option missing */ + case '?': /* unknown option */ + default: + goto synopsis; + } + } + if (optind >= argc) + goto synopsis; + + if (regcomp(&name_regex, opt_name_pattern, + REG_EXTENDED | REG_NOSUB) != 0) { + fprintf(stderr, _("%s: invalid regular expression \"%s\"\n"), + progname, opt_name_pattern); + return 1; + } + + while (optind < argc) { + if (nftw(argv[optind], do_print, 0, + opt_walk_physical * FTW_PHYS) < 0) { + fprintf(stderr, "%s: %s\n", progname, + strerror_ea(errno)); + } + optind++; + } + + return (had_errors ? 1 : 0); + +synopsis: + fprintf(stderr, _("Usage: %s %s\n" + "Try `%s --help' for more information.\n"), + progname, CMD_LINE_SPEC, progname); + return 2; +} + diff --git a/getfattr/walk_tree.c b/getfattr/walk_tree.c deleted file mode 100644 index 468fef4..0000000 --- a/getfattr/walk_tree.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org> - * - * TODO: should this be replaced by using nftw(3)? - */ -#include <sys/stat.h> -#include <dirent.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "walk_tree.h" - -int walk_recurse = 0; -int walk_postorder = 0; -int walk_symlinks = WALK_HALF_LOGICAL; - -int walk_tree(const char *path_p, int (*call)(const char *, struct stat *, - void *), void *arg) -{ - static struct stat st; - static int level = 0; - int follow; - int errors = 0; - - level++; - if (lstat(path_p, &st) != 0) - goto fail; - - if (S_ISLNK(st.st_mode)) { - if (walk_symlinks == WALK_PHYSICAL) - follow = 0; - else { - if (stat(path_p, &st) != 0) - goto fail; - follow = ((walk_symlinks == WALK_HALF_LOGICAL && - level == 1) || - walk_symlinks == WALK_FULL_LOGICAL); - } - } else - follow = 1; - - if (!follow) - goto cleanup; - - if (!walk_postorder) - errors += call(path_p, &st, arg); - - if (walk_recurse && S_ISDIR(st.st_mode)) { - struct dirent *dirent; - DIR *dir; - - char *ipath_p = (char *)path_p; - int ipath_length = strlen(ipath_p); - if (ipath_p[ipath_length-1] != '/') { - ipath_p = (char*)alloca(ipath_length + - _POSIX_PATH_MAX + 2); - if (ipath_p == NULL) - goto fail; - strcpy(ipath_p, path_p); - strcpy(ipath_p + ipath_length, "/"); - ipath_length++; - } - - dir = opendir(path_p); - if (dir == NULL) - goto fail; - while ((dirent = readdir(dir)) != NULL) { - if (!strcmp(dirent->d_name, ".") || - !strcmp(dirent->d_name, "..")) - continue; - strncpy(ipath_p + ipath_length, - dirent->d_name, _POSIX_PATH_MAX); - ipath_p[ipath_length + _POSIX_PATH_MAX] = '\0'; - walk_tree(ipath_p, call, arg); /* recurse */ - } - ipath_p[ipath_length] = '\0'; - closedir(dir); - } - - if (walk_postorder) - errors += call(path_p, &st, arg); - -cleanup: - level--; - return errors; - -fail: - fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno)); - errors++; - goto cleanup; -} - diff --git a/getfattr/walk_tree.h b/getfattr/walk_tree.h deleted file mode 100644 index c84c742..0000000 --- a/getfattr/walk_tree.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org> - * - * TODO: should this be replaced by using nftw(3)? - */ -#include <sys/stat.h> - -extern const char *progname; - -#define WALK_FULL_LOGICAL 1 /* follow all symlinks */ -#define WALK_HALF_LOGICAL 2 /* follow symlink arguments */ -#define WALK_PHYSICAL 3 /* don't follow symlinks */ - -extern int walk_recurse; /* recurse into sudirectories */ -extern int walk_postorder; /* walk tree in postorder */ -extern int walk_symlinks; /* follow symbolic links */ - -int walk_tree(const char *, int (*call)(const char *, struct stat *, void *), void *); diff --git a/include/xattr.h b/include/xattr.h index ee17360..14752f2 100644 --- a/include/xattr.h +++ b/include/xattr.h @@ -47,11 +47,11 @@ __BEGIN_DECLS extern int setxattr (const char *__path, const char *__name, - void *__value, size_t __size, int __flags) __THROW; + const void *__value, size_t __size, int __flags) __THROW; extern int lsetxattr (const char *__path, const char *__name, - void *__value, size_t __size, int __flags) __THROW; + const void *__value, size_t __size, int __flags) __THROW; extern int fsetxattr (int __filedes, const char *__name, - void *__value, size_t __size, int __flags) __THROW; + const void *__value, size_t __size, int __flags) __THROW; extern ssize_t getxattr (const char *__path, const char *__name, void *__value, size_t __size) __THROW; diff --git a/man/man1/getfattr.1 b/man/man1/getfattr.1 index 58642a2..7fadfc5 100644 --- a/man/man1/getfattr.1 +++ b/man/man1/getfattr.1 @@ -3,11 +3,11 @@ getfattr \- get extended attributes of filesystem objects .SH SYNOPSIS .nf -\f3getfattr\f1 [\f3\-lvRLP\f1] \f3\-n name\f1 [\f3\-e en\f1] \c +\f3getfattr\f1 [\f3\-hvRLP\f1] \f3\-n name\f1 [\f3\-e en\f1] \c \f3pathname\f1... -\f3getfattr\f1 [\f3\-lvRLP\f1] \f3\-d\f1 [\f3\-e en\f1] \c -[\f3\-r regex\f1] \f3pathname\f1... -\f3getfattr\f1 [\f3\-Vh\f1] +\f3getfattr\f1 [\f3\-hvRLP\f1] \f3\-d\f1 [\f3\-e en\f1] \c +[\f3\-m pattern\f1] \f3pathname\f1... +\f3getfattr\f1 [\f3\-VH\f1] .fi .SH DESCRIPTION For each file, @@ -57,14 +57,14 @@ Valid values of .I en are "text", "hex", and "base64". .TP -.I \-l +.I \-h Do not follow symlinks - if .I pathname is a symbolic link, it is not followed, but is instead itself the inode being examined. .TP -.I \-r -.I regex +.I \-m +.I pattern is a regular expression pattern to apply to the set of extended attribute names being returned. It defaults to "^user\\." if no @@ -83,14 +83,11 @@ Dump out the extended attribute value(s) only. Recurse into subdirectories, dumping extended attributes for each file encountered (breadth first). .TP -.I \-5 -Same as \-R, except done in post-order (depth first). -.TP .I \-L -Refines the \-R or \-5 option - "logical walk" (do follow symbolic links). +Refines the \-R option - "logical walk" (do follow symbolic links). .TP .I \-P -Refines the \-R or \-5 option - "physical walk" (do not follow symbolic links). +Refines the \-R option - "physical walk" (do not follow symbolic links). .TP .I \-V Print the version of diff --git a/setfattr/setfattr.c b/setfattr/setfattr.c index 1cc6150..f38e98f 100644 --- a/setfattr/setfattr.c +++ b/setfattr/setfattr.c @@ -1,9 +1,24 @@ /* - * Original setfattr.c: - * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org> - * Changes to use revised EA syscall interface: - * Copyright (C) 2001 by SGI XFS development <linux-xfs@oss.sgi.com> - */ + File: setfattr.c + (Linux Extended Attributes) + + Copyright (C) 2001-2002 Andreas Gruenbacher <a.gruenbacher@computer.org> + Copyright (C) 2001-2002 SGI XFS development <linux-xfs@oss.sgi.com> + + 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 <limits.h> #include <stdio.h> @@ -18,31 +33,72 @@ #include <libintl.h> #define _(String) gettext (String) -#define CMD_LINE_OPTIONS "n:lv:x:B:Vh" -#define CMD_LINE_SPEC1 "{-n name|-x name} [-v value] [-lVh] file..." -#define CMD_LINE_SPEC2 "{-B filename} [-lVh] file..." - -char *opt_name; -char *opt_remove; -char *opt_value; -int opt_restore; -int opt_symlink; +#define CMD_LINE_OPTIONS "n:x:v:hB:HV" +#define CMD_LINE_SPEC "{-n name|-x name} [-v value] [-h] file..." + +struct option long_options[] = { + { "name", 1, 0, 'n' }, + { "remove", 1, 0, 'x' }, + { "value", 1, 0, 'v' }, + { "no-dereference", 0, 0, 'h' }, + { "restore", 1, 0, 'B' }, + { "version", 0, 0, 'V' }, + { "help", 0, 0, 'H' }, + { NULL, 0, 0, 0 } +}; + +char *opt_name; /* attribute name to set */ +char *opt_value; /* attribute value */ +int opt_set; /* set an attribute */ +int opt_remove; /* remove an attribute */ +int opt_restore; /* restore has been run */ +int opt_deref = 1; /* dereference symbolic links */ int had_errors; const char *progname; -int do_set(const char *name, const char *value, const char *path); +int do_set(const char *path, const char *name, const char *value); const char *decode(const char *value, size_t *size); -int restore(FILE *file, const char *filename); +int restore(const char *filename); char *next_line(FILE *file); int hex_digit(char c); int base64_digit(char c); -int restore(FILE *file, const char *filename) +const char *strerror_ea(int err) { - char *path_p = NULL, *l; + if (err == ENOATTR) + return _("No such attribute"); + return strerror(err); +} + +int do_setxattr(const char *path, const char *name, + const void *value, size_t size) +{ + return (opt_deref ? setxattr : lsetxattr)(path, name, value, size, 0); +} + +int do_removexattr(const char *path, const char *name) +{ + return (opt_deref ? removexattr : lremovexattr)(path, name); +} + +int restore(const char *filename) +{ + FILE *file; + char *path = NULL, *l; int line = 0, backup_line, status = 0; + if (strcmp(filename, "-") == 0) + file = stdin; + else { + file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, "%s: %s: %s\n", + progname, filename, strerror_ea(errno)); + return 1; + } + } + for(;;) { backup_line = line; while ((l = next_line(file)) != NULL && *l == '\0') @@ -65,45 +121,48 @@ int restore(FILE *file, const char *filename) goto cleanup; } else l += 8; - if (path_p) - free(path_p); - path_p = (char *)malloc(strlen(l) + 1); - if (!path_p) { + if (path) + free(path); + path = (char *)malloc(strlen(l) + 1); + if (!path) { status = 1; goto cleanup; } - strcpy(path_p, l); + strcpy(path, l); while ((l = next_line(file)) != NULL && *l != '\0') { char *name = l, *value = strchr(l, '='); line++; if (value) *value++ = '\0'; - status = do_set(name, value, path_p); + status = do_set(path, name, value); } if (l != NULL) line++; } cleanup: - if (path_p) - free(path_p); + if (path) + free(path); + if (file != stdin) + fclose(file); + if (status) + had_errors++; return status; } void help(void) { printf(_("%s %s -- set extended attributes\n"), progname, VERSION); - printf(_("Usage: %s %s\n"), progname, CMD_LINE_SPEC1); - printf(_(" %s %s\n"), progname, CMD_LINE_SPEC2); - printf(_("Options:\n")); - printf(_("\t-n name\tset value of extended attribute `name'\n" - "\t-l\tset extended attribute values of a symlink\n" - "\t-x name\tremove extended attribute `name'\n" - "\t-v value\n\t\tvalue for extended attribute `name'\n" - "\t-B filename\n\t\trestore extended attributes (inverse of `getfattr -sdlR')\n" - "\t-V\tprint version and exit\n" - "\t-h\tthis help text\n")); + printf(_("Usage: %s %s\n"), progname, CMD_LINE_SPEC); + printf(_( +" -n, --name=name set the value of the named extended attribute\n" +" -x, --remove=name remove the named extended attribute\n" +" -v, --value=value use value as the attribute value\n" +" -h, --no-dereference do not dereference symbolic links\n" +" --restore=file restore extended attributes\n" +" --version print version and exit\n" +" --help this help text\n")); } char *next_line(FILE *file) @@ -123,21 +182,22 @@ char *next_line(FILE *file) int main(int argc, char *argv[]) { - FILE *file; - int status; + int opt; progname = basename(argv[0]); - while ((optopt = getopt(argc, argv, CMD_LINE_OPTIONS)) != -1) { - switch(optopt) { + while ((opt = getopt_long(argc, argv, CMD_LINE_OPTIONS, + long_options, NULL)) != -1) { + switch(opt) { case 'n': /* attribute name */ - if (opt_remove) + if (opt_name || opt_remove) goto synopsis; opt_name = optarg; + opt_set = 1; break; - case 'l': /* set attribute on symlink itself */ - opt_symlink = 1; + case 'h': /* set attribute on symlink itself */ + opt_deref = 0; break; case 'v': /* attribute value */ @@ -147,37 +207,22 @@ int main(int argc, char *argv[]) break; case 'x': /* remove attribute */ - if (opt_name) + if (opt_name || opt_set) goto synopsis; - opt_remove = optarg; + opt_name = optarg; + opt_remove = 1; break; case 'B': /* restore */ opt_restore = 1; - if (strcmp(optarg, "-") == 0) - file = stdin; - else { - file = fopen(optarg, "r"); - if (file == NULL) { - fprintf(stderr, "%s: %s: %s\n", - progname, optarg, - strerror(errno)); - return 1; - } - } - status = restore(file, - (file == stdin) ? NULL : optarg); - if (file != stdin) - fclose(file); - if (status != 0) - return 1; + restore(optarg); break; case 'V': printf("%s " VERSION "\n", progname); return 0; - case 'h': + case 'H': help(); return 0; @@ -185,15 +230,11 @@ int main(int argc, char *argv[]) goto synopsis; } } - if (((opt_name && opt_remove) || (!opt_name && !opt_remove) || - optind >= argc) && !opt_restore) + if (!(((opt_remove || opt_set) && optind < argc) || opt_restore)) goto synopsis; - if (!opt_name) { - opt_name = opt_remove; - opt_value = NULL; - } + while (optind < argc) { - do_set(opt_name, opt_value, argv[optind]); + do_set(argv[optind], opt_name, opt_value); optind++; } @@ -201,27 +242,12 @@ int main(int argc, char *argv[]) synopsis: fprintf(stderr, _("Usage: %s %s\n" - " %s %s\n" - "Try `%s -h' for more information.\n"), - progname, CMD_LINE_SPEC1, progname, CMD_LINE_SPEC2, progname); + "Try `%s --help' for more information.\n"), + progname, CMD_LINE_SPEC, progname); return 2; } -int do_setxattr(const char *path, const char *name, void *value, size_t size) -{ - if (opt_symlink) - return lsetxattr(path, name, value, size, 0); - return setxattr(path, name, value, size, 0); -} - -int do_removexattr(const char *path, const char *name) -{ - if (opt_symlink) - return lremovexattr(path, name); - return removexattr(path, name); -} - -int do_set(const char *name, const char *value, const char *path) +int do_set(const char *path, const char *name, const char *value) { size_t size = 0; int error; @@ -232,10 +258,14 @@ int do_set(const char *name, const char *value, const char *path) if (!value) return 1; } - error = opt_remove? do_removexattr(path, name): - do_setxattr(path, name, (void *)value, size); + if (opt_set) + error = do_setxattr(path, name, value, size); + else + error = do_removexattr(path, name); + if (error < 0) { - perror(path); + fprintf(stderr, "%s: %s: %s\n", + progname, path, strerror_ea(errno)); had_errors++; return 1; } @@ -256,7 +286,8 @@ const char *decode(const char *value, size_t *size) decoded = d = (char *)malloc(*size / 2); if (!decoded) { - perror(""); + fprintf(stderr, "%s: %s\n", + progname, strerror_ea(errno)); had_errors++; return NULL; } @@ -289,7 +320,8 @@ const char *decode(const char *value, size_t *size) decoded = d = (char *)malloc(*size / 4 * 3); if (!decoded) { - perror(""); + fprintf(stderr, "%s: %s\n", + progname, strerror_ea(errno)); had_errors++; return NULL; } @@ -360,7 +392,8 @@ const char *decode(const char *value, size_t *size) decoded = d = (char *)malloc(*size); if (!decoded) { - perror(""); + fprintf(stderr, "%s: %s\n", + progname, strerror_ea(errno)); had_errors++; return NULL; } |