Module Name:    src
Committed By:   manu
Date:           Thu Jul 14 15:25:27 UTC 2011

Modified Files:
        src/usr.bin/extattr: getextattr.1 getextattr.c

Log Message:
Improve extended attribute commands:
- allow namespace to be omitted when using a namespace-prefixed attribute
  name, a la Linux.
- Improve hexdump for getextattr -x
- Add more display option for binary attributes, using vis(3)
- Add a -i option to setextattr to get the attribute value from file, so
  that we can set binary values


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/usr.bin/extattr/getextattr.1
cvs rdiff -u -r1.7 -r1.8 src/usr.bin/extattr/getextattr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/extattr/getextattr.1
diff -u src/usr.bin/extattr/getextattr.1:1.3 src/usr.bin/extattr/getextattr.1:1.4
--- src/usr.bin/extattr/getextattr.1:1.3	Fri Jun 17 18:19:58 2011
+++ src/usr.bin/extattr/getextattr.1	Thu Jul 14 15:25:27 2011
@@ -1,4 +1,4 @@
-.\"	$NetBSD: getextattr.1,v 1.3 2011/06/17 18:19:58 wiz Exp $
+.\"	$NetBSD: getextattr.1,v 1.4 2011/07/14 15:25:27 manu Exp $
 .\"
 .\"-
 .\" Copyright (c) 2000, 2001 Robert N. M. Watson
@@ -44,35 +44,61 @@
 .Nd manipulate extended attributes
 .Sh SYNOPSIS
 .Nm getextattr
-.Op Fl fhqsx
-.Ar attrnamespace
+.Op Fl fhq 
+.Op Fl s | Fl x | Fl v Ar style
+.Op Ar namespace
 .Ar attrname
 .Ar filename ...
 .Nm lsextattr
 .Op Fl fhq
-.Ar attrnamespace
+.Ar namespace
 .Ar filename ...
 .Nm rmextattr
 .Op Fl fhq
-.Ar attrnamespace
+.Op Ar namespace
 .Ar attrname
 .Ar filename ...
 .Nm setextattr
 .Op Fl fhnq
-.Ar attrnamespace
+.Op Ar namespace
 .Ar attrname
 .Ar attrvalue
 .Ar filename ...
+.Nm setextattr
+.Op Fl fhnq
+.Fl i Ar valuefile
+.Op Ar namespace
+.Ar attrname
+.Ar filename ...
 .Sh DESCRIPTION
 These utilities are user tools to manipulate the named extended
 attributes on files and directories.
+.Pp
 The
-.Ar attrnamespace
+.Ar namespace
 argument should be the namespace of the attribute to retrieve: legal
 values are
 .Cm user
 and
 .Cm system .
+For all operations except
+.Nm lsextattr ,
+the namespace argument may be omitted if the attribute name is namespace
+prefixed, like in
+.Cm user.test .
+In that later case, the 
+.Cm user
+namespace prefix obviously selects 
+.Cm user
+namespace.
+.Cm system ,
+.Cm security ,
+and
+.Cm trusted 
+namespace prefixes select the
+.Cm system
+namespace.
+.Pp
 The
 .Ar attrname
 argument should be the name of the attribute,
@@ -91,6 +117,11 @@
 (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 Ar valuefile
+(Input file.)
+Read the attribute value from file
+.Ar valuefile .
+Use this flag in order to set a binary value for an attribute.
 .It Fl n
 .Dv ( NUL Ns
 -terminate.)
@@ -102,6 +133,39 @@
 .It Fl s
 (Stringify.)
 Escape nonprinting characters and put quotes around the output.
+.It Fl v Ar style
+(Visual.)
+Process the attribute value through 
+.Xr vis 3 ,
+using 
+.Ar style .
+Valid values for 
+.Ar style 
+are: 
+.Bl -tag -width indent
+.It Ar default
+Use default
+.Xr vis 3
+encoding.
+.It Ar c
+Use C-style backslash sequences, like in 
+.Nm vis Fl c .
+.It Ar http
+Use URI encoding from RFC 1808, like in
+.Nm vis Fl h .
+.It Ar octal
+Display in octal, like in 
+.Nm vis Fl o .
+.It Ar vis
+Alias for 
+.Ar default .
+.It Ar cstyle
+Alias for 
+.Ar c .
+.It Ar httpstyle
+Alias for 
+.Ar http .
+.El
 .It Fl x
 (Hex.)
 Print the output in hexadecimal.
@@ -113,6 +177,12 @@
 lsextattr system /boot/kernel/kernel
 rmextattr system md5 /boot/kernel/kernel
 .Ed
+.Pp
+Examples omitting namespace (and attribute value) argument:
+.Bd -literal
+setextattr -i valuefile trusted.gfid /export/wd3a
+getextattr -x trusted.gfid /export/wd3a
+.Ed
 .Sh SEE ALSO
 .\" .Xr extattr 2 ,
 .Xr extattr 3 ,
@@ -128,10 +198,10 @@
 .Nx 3.0 .
 It was developed to support security extensions requiring additional labels
 to be associated with each file or directory.
+.Pp
+Exented attribute support was resurected and made more usable in
+.Nx 5.2 .
 .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.
+.An Emmanuel Dreyfus

Index: src/usr.bin/extattr/getextattr.c
diff -u src/usr.bin/extattr/getextattr.c:1.7 src/usr.bin/extattr/getextattr.c:1.8
--- src/usr.bin/extattr/getextattr.c:1.7	Mon Jul  4 08:07:32 2011
+++ src/usr.bin/extattr/getextattr.c	Thu Jul 14 15:25:27 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: getextattr.c,v 1.7 2011/07/04 08:07:32 manu Exp $	*/
+/*	$NetBSD: getextattr.c,v 1.8 2011/07/14 15:25:27 manu Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
@@ -50,6 +50,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <vis.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 //#include <util.h>
 
 static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO;
@@ -60,7 +62,7 @@
 
 	switch (what) {
 	case EAGET:
-		fprintf(stderr, "usage: %s [-fhqsx] "
+		fprintf(stderr, "usage: %s [-fhq] [-s | -x | -v style] "
 		    "attrnamespace attrname filename ...\n", getprogname());
 		exit(1);
 
@@ -68,6 +70,9 @@
 		fprintf(stderr, "usage: %s [-fhnq] "
 		    "attrnamespace attrname attrvalue filename ...\n",
 		    getprogname());
+		fprintf(stderr, "usage: %s [-fhnq] -i attrvalue_file "
+		    "attrnamespace attrname filename ...\n",
+		    getprogname());
 		exit(1);
 
 	case EARM:
@@ -103,6 +108,58 @@
 	return;
 }
 
+static int
+parse_flag_vis(const char *opt)
+{
+	if (strcmp(opt, "default") == 0)
+		return 0;
+	else if (strcmp(opt, "cstyle") == 0)
+		return VIS_CSTYLE;
+	else if (strcmp(opt, "octal") == 0)
+		return VIS_OCTAL;
+	else if (strcmp(opt, "httpstyle") == 0)
+		return VIS_HTTPSTYLE;
+
+	/* Convenient aliases */
+	else if (strcmp(opt, "vis") == 0)
+		return 0;
+	else if (strcmp(opt, "c") == 0)
+		return VIS_CSTYLE;
+	else if (strcmp(opt, "http") == 0)
+		return VIS_HTTPSTYLE;
+	else
+		fprintf(stderr, "%s: invalid -s option \"%s\"", 
+			getprogname(), opt);
+
+	return -1;
+}
+
+#define HEXDUMP_PRINT(x) ((uint8_t)x >= 32 && (uint8_t)x < 128)  ? x : '.'
+static void
+hexdump(const char *addr, size_t len)
+{
+	unsigned int i, j;
+
+	for (i = 0; i < len; i += 16) {
+		printf("   %03x   ", i);
+		for (j = 0; j < 16; j++) {
+			if (i + j > len)
+				printf("   ");
+			else
+				printf("%02x ", addr[i + j] & 0xff);
+		}
+		printf("   ");
+		for (j = 0; j < 16; j++) {
+			if (i + j > len)
+				printf(" ");
+			else
+				printf("%c", HEXDUMP_PRINT(addr[i + j]));
+		}
+		printf("\n");
+	}
+}
+#undef HEXDUMP_PRINT
+
 int
 main(int argc, char *argv[])
 {
@@ -111,14 +168,15 @@
 
 	const char *options, *attrname;
 	int	 buflen, visbuflen, ch, error, i, arg_counter, attrnamespace,
-		 minargc;
+		 minargc, val_len = 0;
 
 	int	flag_force = 0;
 	int	flag_nofollow = 0;
 	int	flag_null = 0;
 	int	flag_quiet = 0;
-	int	flag_string = 0;
+	int	flag_vis = -1;
 	int	flag_hex = 0;
+	char	*filename = NULL;
 
 	options = NULL;
 	minargc = 0;
@@ -128,16 +186,16 @@
 	p = getprogname();
 	if (strcmp(p, "getextattr") == 0) {
 		what = EAGET;
-		options = "fhqsx";
-		minargc = 3;
+		options = "fhqsxv:";
+		minargc = 2;
 	} else if (strcmp(p, "setextattr") == 0) {
 		what = EASET;
-		options = "fhnq";
-		minargc = 4;
+		options = "fhnqi:";
+		minargc = 3;
 	} else if (strcmp(p, "rmextattr") == 0) {
 		what = EARM;
 		options = "fhq";
-		minargc = 3;
+		minargc = 2;
 	} else if (strcmp(p, "lsextattr") == 0) {
 		what = EALS;
 		options = "fhq";
@@ -160,11 +218,18 @@
 			flag_quiet = 1;
 			break;
 		case 's':
-			flag_string = 1;
+			flag_vis = VIS_SAFE | VIS_WHITE;
+			break;
+		case 'v':
+			flag_vis = parse_flag_vis(optarg);
 			break;
 		case 'x':
 			flag_hex = 1;
 			break;
+		case 'i':
+			filename = optarg;
+			minargc--;
+			break;
 		default:
 			usage();
 		}
@@ -173,13 +238,43 @@
 	argc -= optind;
 	argv += optind;
 
+	/*
+	 * Check for missing argument.
+	 */
 	if (argc < minargc)
 		usage();
 
+	/*
+	 * Normal case "namespace attribute".
+	 */
 	error = extattr_string_to_namespace(argv[0], &attrnamespace);
-	if (error)
-		err(1, "%s", argv[0]);
-	argc--; argv++;
+	if (error == 0) {
+		/*
+		 * Namespace was specified, so we need one more argument
+		 * for the attribute (except for listing)
+		 */
+		if ((what != EALS) && (argc < minargc + 1))
+			usage();
+		argc--; argv++;
+	} else {
+		/*
+		 * The namespace was not valid. Perhaps it was omited.
+		 * Try to guess a missing namespace by using
+		 * linux layout "namespace.attribute". While
+		 * we are here, also test the Linux namespaces.
+		 */
+		if (strstr(argv[0], "user.") == argv[0]) {
+			attrnamespace = EXTATTR_NAMESPACE_USER;
+		} else
+		if ((strstr(argv[0], "system.") == argv[0]) ||
+		    (strstr(argv[0], "trusted.") == argv[0]) ||
+		    (strstr(argv[0], "security.") == argv[0])) {
+			attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+		} else {
+			err(1, "%s", argv[0]);
+		}
+	}
+
 
 	if (what != EALS) {
 		attrname = argv[0];
@@ -188,9 +283,38 @@
 		attrname = NULL;
 
 	if (what == EASET) {
-		mkbuf(&buf, &buflen, strlen(argv[0]) + 1);
-		strcpy(buf, argv[0]); /* safe */
-		argc--; argv++;
+		/*
+		 * Handle -i option, reading value from a file.
+		 */
+		if (filename != NULL) {
+			int fd;
+			struct stat st;
+			ssize_t readen, remain;
+
+			if ((fd = open(filename, O_RDONLY, 0)) == -1)
+				err(1, "%s: cannot open \"%s\"",
+				     getprogname(), filename);
+
+			if (fstat(fd, &st) != 0)
+				err(1, "%s: cannot stat \"%s\"",
+				     getprogname(), filename);
+
+			val_len = st.st_size;
+			mkbuf(&buf, &buflen, val_len);
+
+			for (remain = val_len; remain > 0; remain -= readen) {
+				if ((readen = read(fd, buf, remain)) == -1)
+					err(1, "%s: cannot read \"%s\"",
+					    getprogname(), filename);
+			}
+
+			(void)close(fd);
+		} else {
+			val_len = strlen(argv[0]) + 1;
+			mkbuf(&buf, &buflen, val_len);
+			strcpy(buf, argv[0]); /* safe */
+			argc--; argv++;
+		}
 	}
 
 	for (arg_counter = 0; arg_counter < argc; arg_counter++) {
@@ -209,11 +333,11 @@
 			if (flag_nofollow)
 				error = extattr_set_link(argv[arg_counter],
 				    attrnamespace, attrname, buf,
-				    strlen(buf) + flag_null);
+				    val_len + flag_null);
 			else
 				error = extattr_set_file(argv[arg_counter],
 				    attrnamespace, attrname, buf,
-				    strlen(buf) + flag_null);
+				    val_len + flag_null);
 			if (error >= 0)
 				continue;
 			break;
@@ -262,17 +386,24 @@
 				break;
 			if (!flag_quiet)
 				printf("%s\t", argv[arg_counter]);
-			if (flag_string) {
+			
+			/*
+			 * Check for binary string and terminal output
+			 */
+#if 0
+			for (i = 0; i < error; i++)
+				if (!isprint((int)buf[i]))
+					err(1, "binary data, use -x flag");
+#endif
+
+			if (flag_vis != -1) {
 				mkbuf(&visbuf, &visbuflen, error * 4 + 1);
-				strvisx(visbuf, buf, error,
-				    VIS_SAFE | VIS_WHITE);
+				strvisx(visbuf, buf, error, flag_vis);
 				printf("\"%s\"\n", visbuf);
 				continue;
 			} else if (flag_hex) {
-				for (i = 0; i < error; i++)
-					printf("%s%02x", i ? " " : "",
-					    buf[i]);
 				printf("\n");
+				hexdump(buf, error);
 				continue;
 			} else {
 				fwrite(buf, buflen, 1, stdout);

Reply via email to