summaryrefslogtreecommitdiff
path: root/getfattr
diff options
context:
space:
mode:
Diffstat (limited to 'getfattr')
-rw-r--r--getfattr/Makefile51
-rw-r--r--getfattr/getfattr.c422
-rw-r--r--getfattr/walk_tree.c94
-rw-r--r--getfattr/walk_tree.h18
4 files changed, 585 insertions, 0 deletions
diff --git a/getfattr/Makefile b/getfattr/Makefile
new file mode 100644
index 0000000..d474763
--- /dev/null
+++ b/getfattr/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2000 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
+
+LTCOMMAND = getfattr
+CFILES = walk_tree.c getfattr.c
+HFILES = walk_tree.h
+
+LLDLIBS = $(LIBATTR)
+LTDEPENDENCIES = $(LIBATTR)
+
+default: $(LTCOMMAND)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 -d $(PKG_BIN_DIR)
+ $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
+ $(INSTALL) -S $(LTCOMMAND) $(PKG_BIN_DIR)/aget
+install-dev:
diff --git a/getfattr/getfattr.c b/getfattr/getfattr.c
new file mode 100644
index 0000000..bd642cf
--- /dev/null
+++ b/getfattr/getfattr.c
@@ -0,0 +1,422 @@
+/*
+ * 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>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <regex.h>
+#include <xattr.h>
+#include "walk_tree.h"
+
+#include <locale.h>
+#include <libintl.h>
+#define _(String) gettext (String)
+
+#define CMD_LINE_OPTIONS "ade:hln:r:svR5LPV"
+#define CMD_LINE_SPEC "[-n name|-d] [-ahsvR5LPV] [-e en] [-r regex] path..."
+
+int opt_dump;
+int opt_symlink;
+char *opt_encoding;
+char opt_value_only;
+int opt_strip_leading_slash = 1;
+
+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 sys_pattern[] = "^system\\.|^user\\.";
+ char usr_pattern[] = "^user\\.";
+ char *pattern = usr_pattern;
+ 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':
+ pattern = optarg;
+ break;
+
+ case 's':
+ pattern = sys_pattern;
+ 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;
+ }
+
+ 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);
+}
+
+int do_listxattr(const char *path, char *list, size_t size)
+{
+ if (opt_symlink)
+ return llistxattr(path, list, size);
+ return listxattr(path, list, size);
+}
+
+int pstrcmp(const char **a, const char **b)
+{
+ return strcmp(*a, *b);
+}
+
+int do_get_all(const char *path, struct stat *stat, void *dummy)
+{
+ /* nathans TODO - use a high-water-mark allocation here! */
+ char *v;
+ char *list; /* ie. make list & lbufsize "static" & realloc */
+ int n = 0, count = 0;
+ ssize_t listsize, lbufsize;
+ const char **names = NULL;
+
+ lbufsize = do_listxattr(path, NULL, 0);
+ if (lbufsize < 0) {
+ if (errno != ENOATTR && errno != ENOTSUP) {
+ perror(path);
+ had_errors++;
+ return 1;
+ }
+ } else {
+ /* nathans TODO - use a high-water-mark allocation here! */
+ list = malloc(++lbufsize);
+ if (!list) {
+ perror(progname);
+ had_errors++;
+ return 1;
+ }
+ memset(list, 0, lbufsize);
+ listsize = do_listxattr(path, list, lbufsize - 1);
+ 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) {
+ names = (const char **)malloc(count * sizeof(char *));
+ if (!names) {
+ perror(progname);
+ had_errors++;
+ return 1;
+ }
+ 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)
+{
+ int error;
+
+ header_printed = 0;
+ error = get_one(path, (const char *)name);
+ if (header_printed)
+ puts("");
+ return error;
+}
+
+int get_one(const char *path, const char *name)
+{
+ char *value = NULL;
+ size_t size = 0;
+ int error;
+
+ 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;
+ }
+ /* nathans TODO - high-water-mark allocate here too? */
+ size = error;
+ value = (char *)malloc(size+1);
+ if (!value) {
+ perror(progname);
+ return 1;
+ }
+ error = do_getxattr(path, name, value, size);
+ if (error < 0)
+ goto syscall_failed;
+ value[size] = '\0';
+ size = error;
+ }
+
+ 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 (size) {
+ const char *e = encode(value, &size);
+
+ if (e)
+ printf("%s=%s\n", name, e);
+ } else
+ puts(name);
+
+ return 0;
+}
+
+const char *encode(const char *value, size_t *size)
+{
+ static char *encoded = NULL, *e;
+
+ if (encoded)
+ free(encoded);
+ if (opt_encoding == NULL || strcmp(opt_encoding, "text") == 0) {
+ int n, extra = 0;
+
+ for (e=(char *)value; e < value + *size; e++) {
+ if (*e < 32 || *e >= 127)
+ extra += 4;
+ else if (*e == '\\' || *e == '"')
+ extra++;
+ }
+ encoded = (char *)malloc(*size + extra + 3);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='"';
+ for (n = 0; n < *size; n++, value++) {
+ if (*value < 32 || *value >= 127) {
+ *e++ = '\\';
+ *e++ = '0' + ((unsigned char)*value >> 6);
+ *e++ = '0' + (((unsigned char)*value & 070) >> 3);
+ *e++ = '0' + ((unsigned char)*value & 07);
+ } else if (*value == '\\' || *value == '"') {
+ *e++ = '\\';
+ *e++ = *value;
+ } else {
+ *e++ = *value;
+ }
+ }
+ *e++ = '"';
+ *e = '\0';
+ *size = (e - encoded);
+ } else if (strcmp(opt_encoding, "hex") == 0) {
+ static const char *digits = "0123456789abcdef";
+ int n;
+
+ encoded = (char *)malloc(*size * 2 + 4);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='0'; *e++ = 'x';
+ for (n = 0; n < *size; n++, value++) {
+ *e++ = digits[((unsigned char)*value >> 4)];
+ *e++ = digits[((unsigned char)*value & 0x0F)];
+ }
+ *e = '\0';
+ *size = (e - encoded);
+ } else if (strcmp(opt_encoding, "base64") == 0) {
+ static const char *digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
+ "ghijklmnopqrstuvwxyz0123456789+/";
+ int n;
+
+ encoded = (char *)malloc((*size + 2) / 3 * 4 + 1);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='0'; *e++ = 's';
+ for (n=0; n + 2 < *size; n += 3) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[(((unsigned char)value[0] & 0x03) << 4) |
+ (((unsigned char)value[1] & 0xF0) >> 4)];
+ *e++ = digits[(((unsigned char)value[1] & 0x0F) << 2) |
+ ((unsigned char)value[2] >> 6)];
+ *e++ = digits[(unsigned char)value[2] & 0x3F];
+ value += 3;
+ }
+ if (*size - n == 2) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[(((unsigned char)value[0] & 0x03) << 4) |
+ (((unsigned char)value[1] & 0xF0) >> 4)];
+ *e++ = digits[((unsigned char)value[1] & 0x0F) << 2];
+ *e++ = '=';
+ } else if (*size - n == 1) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[((unsigned char)value[0] & 0x03) << 4];
+ *e++ = '=';
+ *e++ = '=';
+ }
+ *e = '\0';
+ *size = (e - encoded);
+ }
+ return encoded;
+}
diff --git a/getfattr/walk_tree.c b/getfattr/walk_tree.c
new file mode 100644
index 0000000..468fef4
--- /dev/null
+++ b/getfattr/walk_tree.c
@@ -0,0 +1,94 @@
+/*
+ * 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
new file mode 100644
index 0000000..c84c742
--- /dev/null
+++ b/getfattr/walk_tree.h
@@ -0,0 +1,18 @@
+/*
+ * 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 *);