summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasomers <asomers@FreeBSD.org>2016-05-04 20:20:55 +0000
committerasomers <asomers@FreeBSD.org>2016-05-04 20:20:55 +0000
commit7dca2250f02904af6d8336dd00d555fb550333c6 (patch)
treed59e06a667a1e8ead9f5cc94836c806349814491
parent4be5f4b925430624ba065927300a52301bc06f18 (diff)
downloadFreeBSD-src-7dca2250f02904af6d8336dd00d555fb550333c6.zip
FreeBSD-src-7dca2250f02904af6d8336dd00d555fb550333c6.tar.gz
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
-rw-r--r--usr.sbin/extattr/Makefile2
-rw-r--r--usr.sbin/extattr/rmextattr.817
-rw-r--r--usr.sbin/extattr/rmextattr.c76
-rwxr-xr-xusr.sbin/extattr/tests/extattr_test.sh32
4 files changed, 93 insertions, 34 deletions
diff --git a/usr.sbin/extattr/Makefile b/usr.sbin/extattr/Makefile
index a8b5b87..9feaa59 100644
--- a/usr.sbin/extattr/Makefile
+++ b/usr.sbin/extattr/Makefile
@@ -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
diff --git a/usr.sbin/extattr/rmextattr.8 b/usr.sbin/extattr/rmextattr.8
index c51fa6d..5075503 100644
--- a/usr.sbin/extattr/rmextattr.8
+++ b/usr.sbin/extattr/rmextattr.8
@@ -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.
diff --git a/usr.sbin/extattr/rmextattr.c b/usr.sbin/extattr/rmextattr.c
index c061943..7f6fdc2f 100644
--- a/usr.sbin/extattr/rmextattr.c
+++ b/usr.sbin/extattr/rmextattr.c
@@ -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;
diff --git a/usr.sbin/extattr/tests/extattr_test.sh b/usr.sbin/extattr/tests/extattr_test.sh
index 67e10c7..ac0f113 100755
--- a/usr.sbin/extattr/tests/extattr_test.sh
+++ b/usr.sbin/extattr/tests/extattr_test.sh
@@ -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
OpenPOWER on IntegriCloud