From owner-svn-src-head@freebsd.org Wed May 4 20:20:56 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id DB7BFB2DECC; Wed, 4 May 2016 20:20:56 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 947D618A6; Wed, 4 May 2016 20:20:56 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u44KKtCQ012206; Wed, 4 May 2016 20:20:55 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u44KKtik012202; Wed, 4 May 2016 20:20:55 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201605042020.u44KKtik012202@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Wed, 4 May 2016 20:20:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r299085 - in head/usr.sbin/extattr: . tests X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 May 2016 20:20:57 -0000 Author: asomers Date: Wed May 4 20:20:55 2016 New Revision: 299085 URL: https://svnweb.freebsd.org/changeset/base/299085 Log: 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 Modified: head/usr.sbin/extattr/Makefile head/usr.sbin/extattr/rmextattr.8 head/usr.sbin/extattr/rmextattr.c head/usr.sbin/extattr/tests/extattr_test.sh Modified: head/usr.sbin/extattr/Makefile ============================================================================== --- head/usr.sbin/extattr/Makefile Wed May 4 20:06:20 2016 (r299084) +++ head/usr.sbin/extattr/Makefile Wed May 4 20:20:55 2016 (r299085) @@ -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 Modified: head/usr.sbin/extattr/rmextattr.8 ============================================================================== --- head/usr.sbin/extattr/rmextattr.8 Wed May 4 20:06:20 2016 (r299084) +++ head/usr.sbin/extattr/rmextattr.8 Wed May 4 20:20:55 2016 (r299085) @@ -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 th .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 direc .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. Modified: head/usr.sbin/extattr/rmextattr.c ============================================================================== --- head/usr.sbin/extattr/rmextattr.c Wed May 4 20:06:20 2016 (r299084) +++ head/usr.sbin/extattr/rmextattr.c Wed May 4 20:20:55 2016 (r299085) @@ -37,6 +37,7 @@ */ #include +#include #include #include @@ -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 newle 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; Modified: head/usr.sbin/extattr/tests/extattr_test.sh ============================================================================== --- head/usr.sbin/extattr/tests/extattr_test.sh Wed May 4 20:06:20 2016 (r299084) +++ head/usr.sbin/extattr/tests/extattr_test.sh Wed May 4 20:20:55 2016 (r299085) @@ -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