Allow setextattr(8) to take attribute values from stdin
Add the -i option to setextattr. This option allow extended attribute data to be provided via stdin. Add a -qq option to getextattr, which omits the trailing newline. Together these options can be used to work with extended attributes whose values are large and/or binary. usr.sbin/extattr/Makefile: Link against libsbuf which is used for processing stdin data. usr.sbin/extattr/rmextattr.8: Document setextattr's -i option, getextattr's -qq option, and remove the BUG about setextattr only being useful for strings. usr.sbin/extattr/rmextattr.c: For setextattr operations, buffer attribute data in an sbuf. If -i is specified, pull the data from stdin, otherwise from the appropriate argurment. Update usage text and argument validation code for setextattr's -i option. usr.sbin/extattr/tests/extattr_test.sh Add tests for -q and -i. Reviewed by: wblock (manpage) MFC after: 4 weeks Sponsored by: Spectra Logic Corp Differential Revision: https://reviews.freebsd.org/D6090
This commit is contained in:
parent
d3810ff91c
commit
c29930cfd6
@ -3,6 +3,8 @@
|
||||
PROG= rmextattr
|
||||
MAN= rmextattr.8
|
||||
|
||||
LIBADD= sbuf
|
||||
|
||||
LINKS+= ${BINDIR}/rmextattr ${BINDIR}/getextattr
|
||||
LINKS+= ${BINDIR}/rmextattr ${BINDIR}/setextattr
|
||||
LINKS+= ${BINDIR}/rmextattr ${BINDIR}/lsextattr
|
||||
|
@ -31,7 +31,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 30, 2000
|
||||
.Dd April 27, 2016
|
||||
.Dt RMEXTATTR 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -61,6 +61,12 @@
|
||||
.Ar attrname
|
||||
.Ar attrvalue
|
||||
.Ar filename ...
|
||||
.Nm setextattr
|
||||
.Fl i
|
||||
.Op Fl fhnq
|
||||
.Ar attrnamespace
|
||||
.Ar attrname
|
||||
.Ar filename ...
|
||||
.Sh DESCRIPTION
|
||||
These
|
||||
utilities
|
||||
@ -91,6 +97,9 @@ the remaining arguments.
|
||||
(No follow.)
|
||||
If the file is a symbolic link, perform the operation on the
|
||||
link itself rather than the file that the link points to.
|
||||
.It Fl i
|
||||
(From stdin.)
|
||||
Read attribute data from stdin instead of as an argument.
|
||||
.It Fl n
|
||||
.Dv ( NUL Ns
|
||||
-terminate.)
|
||||
@ -99,6 +108,7 @@ link itself rather than the file that the link points to.
|
||||
.It Fl q
|
||||
(Quiet.)
|
||||
Do not print out the pathname and suppress error messages.
|
||||
When given twice, do not print a trailing newline.
|
||||
.It Fl s
|
||||
(Stringify.)
|
||||
Escape nonprinting characters and put quotes around the output.
|
||||
@ -109,6 +119,7 @@ Print the output in hexadecimal.
|
||||
.Sh EXAMPLES
|
||||
.Bd -literal
|
||||
setextattr system md5 `md5 -q /boot/kernel/kernel` /boot/kernel/kernel
|
||||
md5 -q /boot/kernel/kernel | setextattr -i system md5 /boot/kernel/kernel
|
||||
getextattr system md5 /boot/kernel/kernel
|
||||
lsextattr system /boot/kernel/kernel
|
||||
rmextattr system md5 /boot/kernel/kernel
|
||||
@ -129,7 +140,3 @@ to be associated with each file or directory.
|
||||
.Sh AUTHORS
|
||||
.An Robert N M Watson
|
||||
.An Poul-Henning Kamp
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm setextattr
|
||||
utility can only be used to set attributes to strings.
|
||||
|
@ -37,6 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/extattr.h>
|
||||
|
||||
@ -64,6 +65,8 @@ usage(void)
|
||||
case EASET:
|
||||
fprintf(stderr, "usage: setextattr [-fhnq] attrnamespace");
|
||||
fprintf(stderr, " attrname attrvalue filename ...\n");
|
||||
fprintf(stderr, " or setextattr -i [-fhnq] attrnamespace");
|
||||
fprintf(stderr, " attrname filename ...\n");
|
||||
exit(-1);
|
||||
case EARM:
|
||||
fprintf(stderr, "usage: rmextattr [-fhq] attrnamespace");
|
||||
@ -99,24 +102,28 @@ mkbuf(char **buf, int *oldlen, int newlen)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *buf, *visbuf, *p;
|
||||
#define STDIN_BUF_SZ 1024
|
||||
char stdin_data[STDIN_BUF_SZ];
|
||||
char *p;
|
||||
|
||||
const char *options, *attrname;
|
||||
size_t len;
|
||||
ssize_t ret;
|
||||
int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace,
|
||||
minargc;
|
||||
int ch, error, i, arg_counter, attrnamespace, minargc;
|
||||
|
||||
char *visbuf = NULL;
|
||||
int visbuflen = 0;
|
||||
char *buf = NULL;
|
||||
int buflen = 0;
|
||||
struct sbuf *attrvalue = NULL;
|
||||
int flag_force = 0;
|
||||
int flag_nofollow = 0;
|
||||
int flag_null = 0;
|
||||
int flag_quiet = 0;
|
||||
int count_quiet = 0;
|
||||
int flag_from_stdin = 0;
|
||||
int flag_string = 0;
|
||||
int flag_hex = 0;
|
||||
|
||||
visbuflen = buflen = 0;
|
||||
visbuf = buf = NULL;
|
||||
|
||||
p = basename(argv[0]);
|
||||
if (p == NULL)
|
||||
p = argv[0];
|
||||
@ -126,8 +133,8 @@ main(int argc, char *argv[])
|
||||
minargc = 3;
|
||||
} else if (!strcmp(p, "setextattr")) {
|
||||
what = EASET;
|
||||
options = "fhnq";
|
||||
minargc = 4;
|
||||
options = "fhinq";
|
||||
minargc = 3;
|
||||
} else if (!strcmp(p, "rmextattr")) {
|
||||
what = EARM;
|
||||
options = "fhq";
|
||||
@ -148,11 +155,14 @@ main(int argc, char *argv[])
|
||||
case 'h':
|
||||
flag_nofollow = 1;
|
||||
break;
|
||||
case 'i':
|
||||
flag_from_stdin = 1;
|
||||
break;
|
||||
case 'n':
|
||||
flag_null = 1;
|
||||
break;
|
||||
case 'q':
|
||||
flag_quiet = 1;
|
||||
count_quiet += 1;
|
||||
break;
|
||||
case 's':
|
||||
flag_string = 1;
|
||||
@ -169,6 +179,9 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (what == EASET && flag_from_stdin == 0)
|
||||
minargc++;
|
||||
|
||||
if (argc < minargc)
|
||||
usage();
|
||||
|
||||
@ -184,9 +197,15 @@ main(int argc, char *argv[])
|
||||
attrname = NULL;
|
||||
|
||||
if (what == EASET) {
|
||||
mkbuf(&buf, &buflen, strlen(argv[0]) + 1);
|
||||
strcpy(buf, argv[0]);
|
||||
argc--; argv++;
|
||||
attrvalue = sbuf_new_auto();
|
||||
if (flag_from_stdin) {
|
||||
while ((error = read(0, stdin_data, STDIN_BUF_SZ)) > 0)
|
||||
sbuf_bcat(attrvalue, stdin_data, error);
|
||||
} else {
|
||||
sbuf_cpy(attrvalue, argv[0]);
|
||||
argc--; argv++;
|
||||
}
|
||||
sbuf_finish(attrvalue);
|
||||
}
|
||||
|
||||
for (arg_counter = 0; arg_counter < argc; arg_counter++) {
|
||||
@ -202,15 +221,17 @@ main(int argc, char *argv[])
|
||||
continue;
|
||||
break;
|
||||
case EASET:
|
||||
len = strlen(buf) + flag_null;
|
||||
len = sbuf_len(attrvalue) + flag_null;
|
||||
if (flag_nofollow)
|
||||
ret = extattr_set_link(argv[arg_counter],
|
||||
attrnamespace, attrname, buf, len);
|
||||
attrnamespace, attrname,
|
||||
sbuf_data(attrvalue), len);
|
||||
else
|
||||
ret = extattr_set_file(argv[arg_counter],
|
||||
attrnamespace, attrname, buf, len);
|
||||
attrnamespace, attrname,
|
||||
sbuf_data(attrvalue), len);
|
||||
if (ret >= 0) {
|
||||
if ((size_t)ret != len && !flag_quiet) {
|
||||
if ((size_t)ret != len && !count_quiet) {
|
||||
warnx("Set %zd bytes of %zu for %s",
|
||||
ret, len, attrname);
|
||||
}
|
||||
@ -235,7 +256,7 @@ main(int argc, char *argv[])
|
||||
attrnamespace, buf, buflen);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (!flag_quiet)
|
||||
if (!count_quiet)
|
||||
printf("%s\t", argv[arg_counter]);
|
||||
for (i = 0; i < ret; i += ch + 1) {
|
||||
/* The attribute name length is unsigned. */
|
||||
@ -243,7 +264,7 @@ main(int argc, char *argv[])
|
||||
printf("%s%*.*s", i ? "\t" : "",
|
||||
ch, ch, buf + i + 1);
|
||||
}
|
||||
if (!flag_quiet || ret > 0)
|
||||
if (!count_quiet || ret > 0)
|
||||
printf("\n");
|
||||
continue;
|
||||
case EAGET:
|
||||
@ -264,29 +285,26 @@ main(int argc, char *argv[])
|
||||
attrnamespace, attrname, buf, buflen);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (!flag_quiet)
|
||||
if (!count_quiet)
|
||||
printf("%s\t", argv[arg_counter]);
|
||||
if (flag_string) {
|
||||
mkbuf(&visbuf, &visbuflen, ret * 4 + 1);
|
||||
strvisx(visbuf, buf, ret,
|
||||
VIS_SAFE | VIS_WHITE);
|
||||
printf("\"%s\"\n", visbuf);
|
||||
continue;
|
||||
printf("\"%s\"", visbuf);
|
||||
} else if (flag_hex) {
|
||||
for (i = 0; i < ret; i++)
|
||||
printf("%s%02x", i ? " " : "",
|
||||
buf[i]);
|
||||
printf("\n");
|
||||
continue;
|
||||
printf("%s%02x", i ? " " : "", buf[i]);
|
||||
} else {
|
||||
fwrite(buf, ret, 1, stdout);
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
if (count_quiet < 2)
|
||||
printf("\n");
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!flag_quiet)
|
||||
if (!count_quiet)
|
||||
warn("%s: failed", argv[arg_counter]);
|
||||
if (flag_force)
|
||||
continue;
|
||||
|
@ -66,6 +66,23 @@ long_name_body() {
|
||||
atf_check -s exit:0 -o empty lsextattr -q user foo
|
||||
}
|
||||
|
||||
atf_test_case loud
|
||||
loud_head() {
|
||||
atf_set "descr" "Loud (non -q) output for each command"
|
||||
}
|
||||
loud_body() {
|
||||
touch foo
|
||||
# setextattr(8) and friends print hard tabs. Use printf to convert
|
||||
# them to spaces before checking the output.
|
||||
atf_check -s exit:0 -o empty setextattr user myattr myvalue foo
|
||||
atf_check -s exit:0 -o inline:"foo myattr" \
|
||||
printf "%s %s" $(lsextattr user foo)
|
||||
atf_check -s exit:0 -o inline:"foo myvalue" \
|
||||
printf "%s %s" $(getextattr user myattr foo)
|
||||
atf_check -s exit:0 -o empty rmextattr user myattr foo
|
||||
atf_check -s exit:0 -o inline:"foo" printf %s $(lsextattr user foo)
|
||||
}
|
||||
|
||||
atf_test_case noattrs
|
||||
noattrs_head() {
|
||||
atf_set "descr" "A file with no extended attributes"
|
||||
@ -127,6 +144,19 @@ one_system_attr_body() {
|
||||
atf_check -s exit:0 -o empty lsextattr -q system foo
|
||||
}
|
||||
|
||||
atf_test_case stdin
|
||||
stdin_head() {
|
||||
atf_set "descr" "Set attribute value from stdin"
|
||||
}
|
||||
stdin_body() {
|
||||
dd if=/dev/random of=infile bs=1k count=8
|
||||
touch foo
|
||||
setextattr -i user myattr foo < infile || atf_fail "setextattr failed"
|
||||
atf_check -s exit:0 -o inline:"myattr\n" lsextattr -q user foo
|
||||
getextattr -qq user myattr foo > outfile || atf_fail "getextattr failed"
|
||||
atf_check -s exit:0 cmp -s infile outfile
|
||||
}
|
||||
|
||||
atf_test_case stringify
|
||||
stringify_head() {
|
||||
atf_set "descr" "Stringify the output of getextattr"
|
||||
@ -273,12 +303,14 @@ atf_init_test_cases() {
|
||||
atf_add_test_case bad_namespace
|
||||
atf_add_test_case hex
|
||||
atf_add_test_case long_name
|
||||
atf_add_test_case loud
|
||||
atf_add_test_case noattrs
|
||||
atf_add_test_case nonexistent_file
|
||||
atf_add_test_case null
|
||||
atf_add_test_case symlink_nofollow
|
||||
atf_add_test_case one_user_attr
|
||||
atf_add_test_case one_system_attr
|
||||
atf_add_test_case stdin
|
||||
atf_add_test_case stringify
|
||||
atf_add_test_case symlink
|
||||
atf_add_test_case symlink_nofollow
|
||||
|
Loading…
Reference in New Issue
Block a user