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 <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 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
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to