summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--attr/attr.c90
-rw-r--r--debian/changelog4
-rw-r--r--doc/CHANGES5
-rw-r--r--exports7
-rw-r--r--include/attributes.h12
-rw-r--r--libattr/libattr.c175
-rw-r--r--man/man1/attr.126
-rw-r--r--man/man3/attr_get.36
-rw-r--r--man/man3/attr_list.3263
-rw-r--r--man/man3/attr_multi.39
-rw-r--r--man/man3/attr_remove.33
-rw-r--r--man/man3/attr_set.33
13 files changed, 558 insertions, 47 deletions
diff --git a/VERSION b/VERSION
index e0a1ccb..77f8905 100644
--- a/VERSION
+++ b/VERSION
@@ -3,5 +3,5 @@
#
PKG_MAJOR=2
PKG_MINOR=4
-PKG_REVISION=27
+PKG_REVISION=28
PKG_BUILD=0
diff --git a/attr/attr.c b/attr/attr.c
index d3776ff..c362580 100644
--- a/attr/attr.c
+++ b/attr/attr.c
@@ -33,6 +33,9 @@
#define SETOP 1 /* do a SET operation */
#define GETOP 2 /* do a GET operation */
#define REMOVEOP 3 /* do a REMOVE operation */
+#define LISTOP 4 /* do a LIST operation */
+
+#define BUFSIZE (60*1024) /* buffer size for LIST operations */
static char *progname;
@@ -43,17 +46,21 @@ usage(void)
"Usage: %s [-LRSq] -s attrname [-V attrvalue] pathname # set value\n"
" %s [-LRSq] -g attrname pathname # get value\n"
" %s [-LRSq] -r attrname pathname # remove attr\n"
+" %s [-LRq] -l pathname # list attrs \n"
" -s reads a value from stdin and -g writes a value to stdout\n"),
- progname, progname, progname);
+ progname, progname, progname, progname);
exit(1);
}
int
main(int argc, char **argv)
{
- char *attrname, *attrvalue, *filename;
- int attrlength;
- int opflag, ch, error, follow, verbose, rootflag, secureflag;
+ char *attrname, *attrvalue, *filename, *buffer;
+ int attrlength, attrflags;
+ int opflag, i, ch, error, follow, verbose, rootflag, secureflag;
+ attrlist_t *alist;
+ attrlist_ent_t *aep;
+ attrlist_cursor_t cursor;
progname = basename(argv[0]);
@@ -68,12 +75,12 @@ main(int argc, char **argv)
verbose = 1;
follow = opflag = rootflag = secureflag = 0;
attrname = attrvalue = NULL;
- while ((ch = getopt(argc, argv, "s:V:g:r:qLRS")) != EOF) {
+ while ((ch = getopt(argc, argv, "s:V:g:r:lqLRS")) != EOF) {
switch (ch) {
case 's':
if ((opflag != 0) && (opflag != SETOP)) {
fprintf(stderr,
- _("Only one of -s, -g, or -r allowed\n"));
+ _("Only one of -s, -g, -r, or -l allowed\n"));
usage();
}
opflag = SETOP;
@@ -81,8 +88,7 @@ main(int argc, char **argv)
break;
case 'V':
if ((opflag != 0) && (opflag != SETOP)) {
- fprintf(stderr,
- _("-V only allowed with -s\n"));
+ fprintf(stderr, _("-V only allowed with -s\n"));
usage();
}
opflag = SETOP;
@@ -91,7 +97,7 @@ main(int argc, char **argv)
case 'g':
if (opflag) {
fprintf(stderr,
- _("Only one of -s, -g, or -r allowed\n"));
+ _("Only one of -s, -g, -r, or -l allowed\n"));
usage();
}
opflag = GETOP;
@@ -100,12 +106,20 @@ main(int argc, char **argv)
case 'r':
if (opflag) {
fprintf(stderr,
- _("Only one of -s, -g, or -r allowed\n"));
+ _("Only one of -s, -g, -r, or -l allowed\n"));
usage();
}
opflag = REMOVEOP;
attrname = optarg;
break;
+ case 'l':
+ if (opflag) {
+ fprintf(stderr,
+ _("Only one of -s, -g, -r, or -l allowed\n"));
+ usage();
+ }
+ opflag = LISTOP;
+ break;
case 'L':
follow++;
break;
@@ -119,8 +133,8 @@ main(int argc, char **argv)
verbose = 0;
break;
default:
- fprintf(stderr,
- _("Unrecognized option: %c\n"), (char)ch);
+ fprintf(stderr, _("Unrecognized option: %c\n"),
+ (char)ch);
usage();
break;
}
@@ -131,6 +145,9 @@ main(int argc, char **argv)
}
filename = argv[optind];
+ attrflags = ((!follow ? ATTR_DONTFOLLOW : 0) |
+ (secureflag ? ATTR_SECURE : 0) |
+ (rootflag ? ATTR_ROOT : 0));
/*
* Break out into option-specific processing.
*/
@@ -148,10 +165,7 @@ main(int argc, char **argv)
attrlength = strlen(attrvalue);
}
error = attr_set(filename, attrname, attrvalue,
- attrlength,
- (!follow ? ATTR_DONTFOLLOW : 0) |
- (secureflag ? ATTR_SECURE : 0) |
- (rootflag ? ATTR_ROOT : 0));
+ attrlength, attrflags);
if (error) {
perror("attr_set");
fprintf(stderr, _("Could not set \"%s\" for %s\n"),
@@ -174,10 +188,7 @@ main(int argc, char **argv)
}
attrlength = ATTR_MAX_VALUELEN;
error = attr_get(filename, attrname, attrvalue,
- &attrlength,
- (!follow ? ATTR_DONTFOLLOW : 0) |
- (secureflag ? ATTR_SECURE : 0) |
- (rootflag ? ATTR_ROOT : 0));
+ &attrlength, attrflags);
if (error) {
perror("attr_get");
fprintf(stderr, _("Could not get \"%s\" for %s\n"),
@@ -195,10 +206,7 @@ main(int argc, char **argv)
break;
case REMOVEOP:
- error = attr_remove(filename, attrname,
- (!follow ? ATTR_DONTFOLLOW : 0) |
- (secureflag ? ATTR_SECURE : 0) |
- (rootflag ? ATTR_ROOT : 0));
+ error = attr_remove(filename, attrname, attrflags);
if (error) {
perror("attr_remove");
fprintf(stderr, _("Could not remove \"%s\" for %s\n"),
@@ -207,9 +215,41 @@ main(int argc, char **argv)
}
break;
+ case LISTOP:
+ if ((buffer = malloc(BUFSIZE)) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ bzero((char *)&cursor, sizeof(cursor));
+ do {
+ error = attr_list(filename, buffer, BUFSIZE,
+ attrflags, &cursor);
+ if (error) {
+ perror("attr_list");
+ fprintf(stderr,
+ _("Could not list \"%s\" for %s\n"),
+ attrname, filename);
+ exit(1);
+ }
+
+ alist = (attrlist_t *)buffer;
+ for (i = 0; i < alist->al_count; i++) {
+ aep = (attrlist_ent_t *)&buffer[ alist->al_offset[i] ];
+ if (verbose) {
+ printf(
+ _("Attribute \"%s\" has a %d byte value for %s\n"),
+ aep->a_name, aep->a_valuelen,
+ filename);
+ } else {
+ printf("%s\n", aep->a_name);
+ }
+ }
+ } while (alist->al_more);
+ break;
+
default:
fprintf(stderr,
- _("At least one of -s, -g, or -r is required\n"));
+ _("At least one of -s, -g, -r, or -l is required\n"));
usage();
break;
}
diff --git a/debian/changelog b/debian/changelog
index f27908c..eb607c6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,8 @@
-attr (2.4.27-1) unstable; urgency=low
+attr (2.4.28-1) unstable; urgency=low
* New upstream release
- -- Nathan Scott <nathans@debian.org> Mon, 05 Dec 2005 16:07:38 +1100
+ -- Nathan Scott <nathans@debian.org> Fri, 13 Jan 2006 10:44:06 +1100
attr (2.4.25-1) unstable; urgency=low
diff --git a/doc/CHANGES b/doc/CHANGES
index 7474a11..6955b82 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -1,3 +1,8 @@
+attr-2.4.28 (13 January 2006)
+ - Implement the IRIX list_attr interfaces in libattr.so,
+ the final piece of the IRIX attr compatibility API.
+ - Put back the -L (list) option in attr(1).
+
attr-2.4.27 (05 December 2005)
- Revert xattr.h/attributes.h to stating "Lesser GPL",
accidentally marked "GPL" in previous version.
diff --git a/exports b/exports
index 53facbb..19fe54a 100644
--- a/exports
+++ b/exports
@@ -31,3 +31,10 @@ ATTR_1.1 {
attr_copy_file;
attr_copy_check_permissions;
} ATTR_1.0;
+
+ATTR_1.2 {
+ global:
+ # Additional SGI Irix compatibility extensions
+ attr_list;
+ attr_listf;
+} ATTR_1.1;
diff --git a/include/attributes.h b/include/attributes.h
index 3afd9ac..006114b 100644
--- a/include/attributes.h
+++ b/include/attributes.h
@@ -144,6 +144,18 @@ extern int attr_remove (const char *__path, const char *__attrname,
extern int attr_removef (int __fd, const char *__attrname, int __flags);
/*
+ * List the names and sizes of the values of all the attributes of an object.
+ * "Cursor" must be allocated and zeroed before the first call, it is used
+ * to maintain context between system calls if all the attribute names won't
+ * fit into the buffer on the first system call.
+ * The return value is -1 on error (w/errno set appropriately), 0 on success.
+ */
+int attr_list(const char *__path, char *__buffer, const int __buffersize,
+ int __flags, attrlist_cursor_t *__cursor);
+int attr_listf(int __fd, char *__buffer, const int __buffersize,
+ int __flags, attrlist_cursor_t *__cursor);
+
+/*
* Operate on multiple attributes of the same object simultaneously.
*
* This call will save on system call overhead when many attributes are
diff --git a/libattr/libattr.c b/libattr/libattr.c
index 32cca06..df39134 100644
--- a/libattr/libattr.c
+++ b/libattr/libattr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2003 Silicon Graphics, Inc.
+ * Copyright (c) 2001-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -27,18 +27,24 @@
#undef MAXNAMELEN
#define MAXNAMELEN 256
+#undef MAXLISTLEN
+#define MAXLISTLEN 65536
+
+#undef roundup
+#define roundup(x,y) ((((x)+((y)-1))/(y))*(y))
+
+static const char *user_name = "user.";
+static const char *secure_name = "security.";
+static const char *trusted_name = "trusted.";
+static const char *xfsroot_name = "xfsroot.";
/*
- * Convert IRIX API components into Linux/XFS API components
+ * Convert IRIX API components into Linux/XFS API components,
+ * and vice-versa.
*/
static int
api_convert(char *name, const char *irixname, int irixflags, int compat)
{
- static const char *user_name = "user.";
- static const char *secure_name = "security.";
- static const char *trusted_name = "trusted.";
- static const char *xfsroot_name = "xfsroot.";
-
if (strlen(irixname) >= MAXNAMELEN) {
errno = EINVAL;
return -1;
@@ -57,6 +63,43 @@ api_convert(char *name, const char *irixname, int irixflags, int compat)
return 0;
}
+static int
+api_unconvert(char *name, const char *linuxname, int irixflags)
+{
+ int type, length;
+
+ length = strlen(user_name);
+ if (strncmp(linuxname, user_name, length) == 0) {
+ type = 0; /*ATTR_USER*/
+ goto found;
+ }
+ length = strlen(secure_name);
+ if (strncmp(linuxname, secure_name, length) == 0) {
+ type = ATTR_SECURE;
+ goto found;
+ }
+ length = strlen(trusted_name);
+ if (strncmp(linuxname, trusted_name, length) == 0) {
+ type = ATTR_ROOT;
+ goto found;
+ }
+ length = strlen(xfsroot_name);
+ if (strncmp(linuxname, xfsroot_name, length) == 0) {
+ type = ATTR_ROOT;
+ goto found;
+ }
+ return 1;
+
+found:
+ if ((irixflags & ATTR_SECURE) != 0 && (type != ATTR_SECURE))
+ return 1;
+ if ((irixflags & ATTR_ROOT) != 0 && (type != ATTR_ROOT))
+ return 1;
+ strcpy(name, linuxname + length);
+ return 0;
+}
+
+
int
attr_get(const char *path, const char *attrname, char *attrvalue,
int *valuelength, int flags)
@@ -192,6 +235,122 @@ attr_removef(int fd, const char *attrname, int flags)
/*
+ * Helper routine for attr_list functions.
+ */
+
+static int
+attr_list_pack(const char *name, const int valuelen,
+ char *buffer, const int buffersize,
+ int *start_offset, int *end_offset)
+{
+ attrlist_ent_t *aentp;
+ attrlist_t *alist = (attrlist_t *)buffer;
+ int size = roundup(strlen(name) + 1 + sizeof(aentp->a_valuelen), 8);
+
+ if ((*end_offset - size) < (*start_offset + sizeof(alist->al_count))) {
+ alist->al_more = 1;
+ return 1;
+ }
+
+ *end_offset -= size;
+ aentp = (attrlist_ent_t *)&buffer[ *end_offset ];
+ aentp->a_valuelen = valuelen;
+ strncpy(aentp->a_name, name, size - sizeof(aentp->a_valuelen));
+
+ *start_offset += sizeof(alist->al_offset);
+ alist->al_offset[alist->al_count] = *end_offset;
+ alist->al_count++;
+ return 0;
+}
+
+int
+attr_list(const char *path, char *buffer, const int buffersize, int flags,
+ attrlist_cursor_t *cursor)
+{
+ const char *l;
+ int length, count = 0;
+ char lbuf[MAXLISTLEN];
+ char name[MAXNAMELEN+16];
+ unsigned int start_offset, end_offset;
+
+ if (buffersize < sizeof(attrlist_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ bzero(buffer, sizeof(attrlist_t));
+
+ if (flags & ATTR_DONTFOLLOW)
+ length = llistxattr(path, lbuf, sizeof(lbuf));
+ else
+ length = listxattr(path, lbuf, sizeof(lbuf));
+ if (length <= 0)
+ return length;
+
+ start_offset = sizeof(attrlist_t);
+ end_offset = buffersize & ~(8-1); /* 8 byte align */
+
+ for (l = lbuf; l != lbuf + length; l = strchr(l, '\0') + 1) {
+ if (api_unconvert(name, l, flags))
+ continue;
+ if (flags & ATTR_DONTFOLLOW)
+ length = lgetxattr(path, l, NULL, 0);
+ else
+ length = getxattr(path, l, NULL, 0);
+ if (length < 0 && (errno == ENOATTR || errno == ENOTSUP))
+ continue;
+ if (count++ < cursor->opaque[0])
+ continue;
+ if (attr_list_pack(name, length, buffer, buffersize,
+ &start_offset, &end_offset)) {
+ cursor->opaque[0] = count;
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+attr_listf(int fd, char *buffer, const int buffersize, int flags,
+ attrlist_cursor_t *cursor)
+{
+ const char *l;
+ int c, count = 0;
+ char lbuf[MAXLISTLEN];
+ char name[MAXNAMELEN+16];
+ unsigned int start_offset, end_offset;
+
+ if (buffersize < sizeof(attrlist_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ bzero(buffer, sizeof(attrlist_t));
+
+ c = flistxattr(fd, lbuf, sizeof(lbuf));
+ if (c < 0)
+ return c;
+
+ start_offset = sizeof(attrlist_t);
+ end_offset = buffersize & ~(8-1); /* 8 byte align */
+
+ for (l = lbuf; l != lbuf + c; l = strchr(l, '\0') + 1) {
+ if (api_unconvert(name, l, flags))
+ continue;
+ c = fgetxattr(fd, l, NULL, 0);
+ if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
+ continue;
+ if (count++ < cursor->opaque[0])
+ continue;
+ if (attr_list_pack(name, c, buffer, buffersize,
+ &start_offset, &end_offset)) {
+ cursor->opaque[0] = count;
+ break;
+ }
+ }
+ return 0;
+}
+
+
+/*
* Helper routines for the attr_multi functions. In IRIX, the
* multi routines are a single syscall - in Linux, we break em
* apart in userspace and make individual syscalls for each.
@@ -235,7 +394,7 @@ attr_singlef(const int fd, attr_multiop_t *op, int flags)
/*
* Operate on multiple attributes of the same object simultaneously
- *
+ *
* From the manpage: "attr_multi will fail if ... a bit other than
* ATTR_DONTFOLLOW was set in the flag argument." flags must be
* checked here as they are not passed into the kernel.
diff --git a/man/man1/attr.1 b/man/man1/attr.1
index 9c1d905..ab555f1 100644
--- a/man/man1/attr.1
+++ b/man/man1/attr.1
@@ -3,12 +3,14 @@
attr \- extended attributes on XFS filesystem objects
.SH SYNOPSIS
.nf
-\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-s attrname\f1 [ \f3\-V attrvalue\f1 ] \c
+\f3attr\f1 [ \f3\-LRSq\f1 ] \f3\-s attrname\f1 [ \f3\-V attrvalue\f1 ] \c
\f3pathname\f1
.sp .8v
-\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-g attrname pathname\f1
+\f3attr\f1 [ \f3\-LRSq\f1 ] \f3\-g attrname pathname\f1
.sp .8v
-\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-r attrname pathname\f1
+\f3attr\f1 [ \f3\-LRSq\f1 ] \f3\-r attrname pathname\f1
+.sp .8v
+\f3attr\f1 [ \f3\-LRSq\f1 ] \f3\-l pathname\f1
.sp .8v
.fi
.SH OVERVIEW
@@ -84,6 +86,18 @@ With the
flag, \f4stdout\fP will be exactly and only the value of the attribute,
suitable for storage directly into a file or processing via a piped command.
.TP
+.B LIST
+The
+.B \-l
+option tells
+.I attr
+to list the names of all the attributes that are associated with the object,
+and the number of bytes in the value of each of those attributes.
+With the
+.B \-q
+flag, \f4stdout\fP will be a simple list of only the attribute names,
+one per line, suitable for input into a script.
+.TP
.B REMOVE
The
.B \-r attrname
@@ -131,6 +145,12 @@ attribute namespace rather that the
.I USER
attribute namespace.
.PP
+The
+.B \-S
+option is similar, except it specifies use of the
+.I security
+attribute namespace.
+.PP
When the
.B \-q
option is given
diff --git a/man/man3/attr_get.3 b/man/man3/attr_get.3
index 2f97f8d..c0ab084 100644
--- a/man/man3/attr_get.3
+++ b/man/man3/attr_get.3
@@ -2,6 +2,7 @@
.SH NAME
attr_get, attr_getf \- get the value of a user attribute of a filesystem object
.SH C SYNOPSIS
+.PP
.sp
.nf
.B #include <attr/attributes.h>
@@ -20,7 +21,7 @@ and
functions provide a way to retrieve the value of an attribute.
.P
.I Path\^
-points to a path name for a filesystem object, and
+points to a path name for a filesystem object, and
.I fd\^
refers to the file descriptor associated with a file.
If the attribute
@@ -32,7 +33,7 @@ The
.I valuelength
argument is an input/output argument that on the call to
.B attr_get
-should contain the maximum size of attribute value the
+should contain the maximum size of attribute value the
process is willing to accept.
On return, the
.I valuelength
@@ -171,6 +172,7 @@ On success, zero is returned. On error, \-1 is returned, and
is set appropriately.
.SH "SEE ALSO"
.BR attr (1),
+.BR attr_list (3),
.BR attr_multi (3),
.BR attr_remove (3),
and
diff --git a/man/man3/attr_list.3 b/man/man3/attr_list.3
index e69de29..79013be 100644
--- a/man/man3/attr_list.3
+++ b/man/man3/attr_list.3
@@ -0,0 +1,263 @@
+.TH ATTR_LIST 3 "Extended Attributes" "Dec 2005" "XFS Compatibility API"
+.SH NAME
+attr_list, attr_listf \- list the names of the user attributes of a filesystem object
+.SH C SYNOPSIS
+.PP
+.sp
+.nf
+.B #include <sys/attributes.h>
+.sp
+.B "int attr_list (const char \(**path, char \(**buffer, "
+.B " const int buffersize, int flags,"
+.B " attrlist_cursor_t \(**cursor);"
+.PP
+.B "int attr_listf (int fd, char \(**buffer, "
+.B " const int buffersize, int flags,"
+.B " attrlist_cursor_t \(**cursor);"
+.Op
+.SH DESCRIPTION
+The
+.B attr_list
+and
+.B attr_listf
+functions provide a way to list the existing attributes of a
+filesystem object.
+.P
+.I Path\^
+points to a path name for a filesystem object, and
+.I fd\^
+refers to the file descriptor associated with a file.
+The
+.I buffer
+will be filled with a structure describing at least a portion of the
+attributes associated with the given filesystem object.
+.I Buffer
+will be overwritten with an \f4attrlist_t\fP structure
+containing a list of the attributes associated with
+that filesystem object, up to a maximum of
+.I buffersize
+bytes.
+The
+.I buffer
+must be sufficiently large to hold the appropriate data structures
+plus at least one maximally sized attribute name,
+but cannot be more than ATTR_MAX_VALUELEN (currently 64KB) bytes in length.
+.PP
+.Op c p a
+The contents of an \f4attrlist_t\fP structure include the following members:
+.P
+.RS 3
+.nf
+.ft 4
+.ta 9n 22n
+__int32_t al_count; /\(** number of entries in attrlist \(**/
+__int32_t al_more; /\(** T/F: more attrs (do syscall again) \(**/
+__int32_t al_offset[1]; /\(** byte offsets of attrs [var-sized] \(**/
+.ft 1
+.fi
+.RE
+.PP
+The
+.I al_count
+field shows the number of attributes represented in this buffer,
+which is also the number of elements in the
+.I al_offset
+array.
+The
+.I al_more
+field will be non-zero if another
+.B attr_list
+call would result in more attributes.
+The
+.I al_offset
+array contains the byte offset within the
+.I buffer
+of the structure describing each of the attributes,
+an \f4attrlist_ent_t\fP structure.
+The \f4ATTR_ENTRY(buffer, index)\fP macro will help with decoding the list.
+It takes a pointer to the
+.I buffer
+and an
+.I index
+into the
+.I al_offset
+array and returns a pointer to the corresponding
+\f4attrlist_ent_t\fP structure.
+.PP
+The contents of an \f4attrlist_ent_t\fP structure
+include the following members:
+.P
+.RS 3
+.nf
+.ft 4
+.ta 9n 22n
+u_int32_t a_valuelen; /\(** number bytes in value of attr \(**/
+char a_name[]; /\(** attr name (NULL terminated) \(**/
+.ft 1
+.fi
+.Op
+.RE
+.PP
+The
+.I a_valuelen
+field shows the size in bytes of the value
+associated with the attribute whose name is stored in the
+.I a_name
+field.
+The name is a NULL terminated string.
+.PP
+Note that the value of the attribute cannot be obtained through
+this interface, the
+.B attr_get
+call should be used to get the value.
+The
+.B attr_list
+interface tells the calling process how large of a buffer
+it must have in order to get the attribute\'s value.
+.PP
+The
+.I flags
+argument can contain the following symbols bitwise OR\'ed together:
+.TP
+.SM
+\%ATTR_ROOT
+List the attributes that are in the
+.B root
+address space, not in the
+.B user
+address space.
+(limited to use by super-user only)
+.TP
+.SM
+\%ATTR_DONTFOLLOW
+Do not follow symbolic links when resolving a
+.I path
+on an
+.B attr_list
+function call.
+The default is to follow symbolic links.
+.PP
+The
+.I cursor
+argument is a pointer to an opaque data structure that the kernel uses
+to track the calling process\'s position in the attribute list.
+The only valid operations on a
+.I cursor
+are to pass it into an
+.B attr_list
+function call or to zero it out.
+It should be zero\'ed out before the first
+.B attr_list
+call.
+Note that multi-threaded applications may keep more than one
+.I cursor
+in order to serve multiple contexts, ie: the
+.B attr_list
+call is "thread-safe".
+.PP
+.B attr_list
+will fail if one or more of the following are true:
+.TP 17
+.SM
+\%[ENOENT]
+The named file does not exist.
+.TP
+.SM
+\%[EPERM]
+The effective user
+.SM ID
+does not match the owner of the file
+and the effective user
+.SM ID
+is not super-user.
+.TP
+.SM
+\%[ENOTDIR]
+A component of the
+path prefix
+is not a directory.
+.TP
+.SM
+\%[EACCES]
+Search permission is denied on a
+component of the
+path prefix.
+.TP
+.SM
+\%[EINVAL]
+A bit was set in the
+.I flag
+argument that is not defined for this system call,
+or the buffer was too small or too large.
+.TP
+.SM
+\%[EFAULT]
+Either
+.I Path
+or
+.I buffer
+points outside the allocated address space of the process, or
+.I buffer
+or
+.I bufsize
+are not 32bit aligned.
+.TP
+.SM
+\%[ELOOP]
+A path name lookup involved too many symbolic links.
+.TP
+.SM
+\%[ENAMETOOLONG]
+The length of
+.I path
+exceeds
+.SM
+.RI { MAXPATHLEN },
+or a pathname component is longer than
+.SM
+.RI { MAXNAMELEN }.
+.TP
+.SM
+\%[ENOATTR]
+.I attribute\^
+does not exist for this file.
+.PP
+.B attr_listf\^
+will fail if:
+.TP 15
+.SM
+\%[EINVAL]
+A bit was set in the
+.I flag
+argument that is not defined for this system call, or
+.I fd\^
+refers to a socket, not a file,
+or the buffer was too small or too large.
+.TP
+.SM
+\%[EFAULT]
+Either
+.I Path
+or
+.I buffer
+points outside the allocated address space of the process, or
+.I buffer
+or
+.I bufsize
+are not 32bit aligned.
+.TP
+.SM
+\%[EBADF]
+.I Fd\^
+does not refer to a valid descriptor.
+.SH "DIAGNOSTICS"
+Upon successful completion, a value of 0 is returned.
+Otherwise, a value of \-1 is returned and
+.I errno\^
+is set to indicate the error.
+.SH "SEE ALSO"
+.BR attr (1),
+.BR attr_multi (3),
+.BR attr_remove (3),
+and
+.BR attr_set (3).
diff --git a/man/man3/attr_multi.3 b/man/man3/attr_multi.3
index aee9072..ed30869 100644
--- a/man/man3/attr_multi.3
+++ b/man/man3/attr_multi.3
@@ -22,10 +22,10 @@ functions provide a way to operate on multiple attributes of a
filesystem object at once.
.P
.I Path
-points to a path name for a filesystem object, and
+points to a path name for a filesystem object, and
.I fd
refers to the file descriptor associated with a file.
-The
+The
.I oplist
is an array of \f4attr_multiop_t\fP structures.
Each element in that array describes a single attribute operation
@@ -133,7 +133,7 @@ If the process has appropriate priviledges,
the ROOT namespace will be searched for the named attribute,
otherwise the USER namespace will be searched.
The \f4ATTR_CREATE\fP and the \f4ATTR_REPLACE\fP flags
-may also be set in the
+may also be set in the
.I am_flags
field (but not simultaneously).
If the \f4ATTR_CREATE\fP flag is set,
@@ -257,7 +257,7 @@ is set appropriately.
Note that the individual operations listed in the
.I oplist
array each have their own error return fields.
-The
+The
.I errno
variable only records the result of the
.I attr_multi
@@ -265,6 +265,7 @@ call itself, not the result of any of the sub-operations.
.SH "SEE ALSO"
.BR attr (1),
.BR attr_get (3),
+.BR attr_list (3),
.BR attr_remove (3),
and
.BR attr_set (3).
diff --git a/man/man3/attr_remove.3 b/man/man3/attr_remove.3
index 9068e11..90fbb72 100644
--- a/man/man3/attr_remove.3
+++ b/man/man3/attr_remove.3
@@ -20,7 +20,7 @@ functions provide a way to remove previously created attributes
from filesystem objects.
.P
.I Path\^
-points to a path name for a filesystem object, and
+points to a path name for a filesystem object, and
.I fd\^
refers to the file descriptor associated with a file.
If the attribute
@@ -143,6 +143,7 @@ is set appropriately.
.SH "SEE ALSO"
.BR attr (1),
.BR attr_get (3),
+.BR attr_list (3),
.BR attr_multi (3),
and
.BR attr_set (3).
diff --git a/man/man3/attr_set.3 b/man/man3/attr_set.3
index 63c6b7e..9637700 100644
--- a/man/man3/attr_set.3
+++ b/man/man3/attr_set.3
@@ -23,7 +23,7 @@ and
functions provide a way to create attributes and set/change their values.
.P
.I Path\^
-points to a path name for a filesystem object, and
+points to a path name for a filesystem object, and
.I fd\^
refers to the file descriptor associated with a file.
If the attribute
@@ -203,6 +203,7 @@ is set appropriately.
.SH "SEE ALSO"
.BR attr (1),
.BR attr_get (3),
+.BR attr_list (3),
.BR attr_multi (3),
and
.BR attr_remove (3).