changeset 866:08bb8e0ae066

comments
author eschrock
date Mon, 07 Nov 2005 18:10:17 -0800
parents 4223fbdac5f3
children 1d5e94400592
files usr/src/cmd/zfs/zfs_main.c usr/src/common/zfs/zfs_prop.c usr/src/lib/libzfs/common/libzfs.h usr/src/lib/libzfs/spec/libzfs.spec
diffstat 4 files changed, 180 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/zfs/zfs_main.c	Mon Nov 07 17:56:47 2005 -0800
+++ b/usr/src/cmd/zfs/zfs_main.c	Mon Nov 07 18:10:17 2005 -0800
@@ -611,8 +611,8 @@
 }
 
 /*
- * zfs get [-rH] [-o field[,field]...] [-s source[,source]...]
- * 	prop[,prop...] < fs | snap | vol > ...
+ * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...]
+ * 	< all | property[,property]... > < fs | snap | vol > ...
  *
  *	-r	recurse over any child datasets
  *	-H	scripted mode.  Headers are stripped, and fields are separated
@@ -634,6 +634,7 @@
 	int cb_columns[4];
 	zfs_prop_t cb_prop[ZFS_NPROP_ALL];
 	int cb_nprop;
+	int cb_isall;
 } get_cbdata_t;
 
 #define	GET_COL_NAME		1
@@ -732,32 +733,18 @@
 	get_cbdata_t *cbp = data;
 	int i;
 
-	/*
-	 * If we've been given a list of properties, always list properties
-	 * in the order given.  Otherwise, iterate over all properties and
-	 * determine if we should display them.
-	 */
-	if (cbp->cb_nprop != 0) {
-		for (i = 0; i < cbp->cb_nprop; i++) {
-			if (zfs_prop_get(zhp, cbp->cb_prop[i], buf,
-			    sizeof (buf), &sourcetype, source, sizeof (source),
-			    cbp->cb_literal) != 0) {
-				(void) strlcpy(buf, "-", sizeof (buf));
-				sourcetype = ZFS_SRC_NONE;
-			}
+	for (i = 0; i < cbp->cb_nprop; i++) {
+		if (zfs_prop_get(zhp, cbp->cb_prop[i], buf,
+		    sizeof (buf), &sourcetype, source, sizeof (source),
+		    cbp->cb_literal) != 0) {
+			if (cbp->cb_isall)
+				continue;
+			(void) strlcpy(buf, "-", sizeof (buf));
+			sourcetype = ZFS_SRC_NONE;
+		}
 
-			print_one_property(zhp, cbp, cbp->cb_prop[i],
-			    buf, sourcetype, source);
-		}
-	} else {
-		for (i = 0; i < ZFS_NPROP_VISIBLE; i++) {
-			if (zfs_prop_get(zhp, i, buf,
-			    sizeof (buf), &sourcetype, source, sizeof (source),
-			    cbp->cb_literal) == 0) {
-				print_one_property(zhp, cbp, i,
-				    buf, sourcetype, source);
-			}
-		}
+		print_one_property(zhp, cbp, cbp->cb_prop[i],
+		    buf, sourcetype, source);
 	}
 
 	return (0);
@@ -769,11 +756,9 @@
 	get_cbdata_t cb = { 0 };
 	int recurse = 0;
 	int c;
-	char **subopts = zfs_prop_column_subopts();
-	char **shortsubopts = zfs_prop_column_short_subopts();
-	int prop;
-	char *value, *fields, *save_fields;
+	char *value, *fields, *badopt;
 	int i;
+	int ret;
 
 	/*
 	 * Set up default columns and sources.
@@ -895,43 +880,22 @@
 	fields = argv[0];
 
 	/*
-	 * Leaving 'cb_nprop' at 0 will cause the callback to iterate over all
-	 * known properties.
+	 * If the user specifies 'all', the behavior of 'zfs get' is slightly
+	 * different, because we don't show properties which don't apply to the
+	 * given dataset.
 	 */
-	if (strcmp(fields, "all") != 0) {
-		while (*fields != '\0') {
-			if (cb.cb_nprop == ZFS_NPROP_ALL) {
-				(void) fprintf(stderr, gettext("too many "
-				    "properties given to -o option\n"));
-				usage(FALSE);
-			}
-
-			save_fields = fields;
-			if ((prop = getsubopt(&fields, subopts,
-			    &value)) == -1) {
-				fields = save_fields;
-				prop = getsubopt(&fields, shortsubopts, &value);
-			}
+	if (strcmp(fields, "all") == 0)
+		cb.cb_isall = TRUE;
 
-			if (prop == -1) {
-				(void) fprintf(stderr,
-				    gettext("invalid property '%s'\n"), value);
-				usage(FALSE);
-			}
-
-			/*
-			 * The 'name' property is a one-off special for 'zfs
-			 * list', but is not a valid property for 'zfs get'.
-			 */
-			if (zfs_prop_column_name(prop) == NULL ||
-			    prop == ZFS_PROP_NAME) {
-				(void) fprintf(stderr, gettext("invalid "
-				    "property '%s'\n"), zfs_prop_to_name(prop));
-				usage(FALSE);
-			}
-
-			cb.cb_prop[cb.cb_nprop++] = prop;
-		}
+	if ((ret = zfs_get_proplist(fields, cb.cb_prop, ZFS_NPROP_ALL,
+	    &cb.cb_nprop, &badopt)) != 0) {
+		if (ret == EINVAL)
+			(void) fprintf(stderr, gettext("invalid property "
+			    "'%s'\n"), badopt);
+		else
+			(void) fprintf(stderr, gettext("too many properties "
+			    "specified\n"));
+		usage(FALSE);
 	}
 
 	argc--;
@@ -967,12 +931,6 @@
 		(void) printf("\n");
 	}
 
-	free(subopts);
-	for (i = 0; i < ZFS_NPROP_ALL; i++)
-		if (shortsubopts[i][0])
-			free(shortsubopts[i]);
-	free(shortsubopts);
-
 	/* run for each object */
 	return (zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY,
 	    get_callback, &cb));
@@ -1063,35 +1021,29 @@
 }
 
 /*
- * list [-rH] [-a | -s] [-o prop[,prop]*] [fs | vol] ...
+ * list [-rH] [-o property[,property]...] [-t type[,type]...] <dataset> ...
  *
  * 	-r	Recurse over all children
  * 	-H	Scripted mode; elide headers and separate colums by tabs
- * 	-a	Display all datasets
- * 	-s	Display only snapshots
  * 	-o	Control which fields to display.
+ * 	-t	Control which object types to display.
  *
  * When given no arguments, lists all filesystems in the system.
  * Otherwise, list the specified datasets, optionally recursing down them if
  * '-r' is specified.
- *
- * If '-a' is given, then all datasets (including snapshots) are displayed.  If
- * '-s' is given, then only snapshots are displayed.  Use of these options
- * change the default set of fields output, which can still be overridden with
- * '-o'.
  */
 typedef struct list_cbdata {
-	int	cb_first;
-	int	cb_scripted;
-	int	cb_fields[ZFS_NPROP_ALL];
-	int	cb_fieldcount;
+	int		cb_first;
+	int		cb_scripted;
+	zfs_prop_t	cb_fields[ZFS_NPROP_ALL];
+	int		cb_fieldcount;
 } list_cbdata_t;
 
 /*
  * Given a list of columns to display, output appropriate headers for each one.
  */
 static void
-print_header(int *fields, size_t count)
+print_header(zfs_prop_t *fields, size_t count)
 {
 	int i;
 
@@ -1113,7 +1065,7 @@
  * to the described layout.
  */
 static void
-print_dataset(zfs_handle_t *zhp, int *fields, size_t count, int scripted)
+print_dataset(zfs_handle_t *zhp, zfs_prop_t *fields, size_t count, int scripted)
 {
 	int i;
 	char property[ZFS_MAXPROPLEN];
@@ -1130,7 +1082,13 @@
 		    sizeof (property), NULL, NULL, 0, FALSE) != 0)
 			(void) strlcpy(property, "-", sizeof (property));
 
-		if (scripted || i == count - 1)
+		/*
+		 * If this is being called in scripted mode, or if this is the
+		 * last column and it is left-justified, don't include a width
+		 * format specifier.
+		 */
+		if (scripted || (i == count - 1 &&
+		    strchr(zfs_prop_column_format(fields[i]), '-') != NULL))
 			(void) printf("%s", property);
 		else	/* LINTED - format specifier */
 			(void) printf(zfs_prop_column_format(fields[i]),
@@ -1174,12 +1132,9 @@
 	list_cbdata_t cb = { 0 };
 	char *value;
 	int ret;
-	char **subopts = zfs_prop_column_subopts();
-	char **shortsubopts = zfs_prop_column_short_subopts();
-	int prop;
 	char *type_subopts[] = { "filesystem", "volume", "snapshot", NULL };
-	char *save_fields;
-	int i;
+	char *badopt;
+	int alloffset;
 
 	/* check options */
 	while ((c = getopt(argc, argv, ":o:rt:H")) != -1) {
@@ -1233,34 +1188,30 @@
 	if (fields == NULL)
 		fields = basic_fields;
 
-	while (*fields != '\0') {
-		if (cb.cb_fieldcount == ZFS_NPROP_ALL) {
-			(void) fprintf(stderr, gettext("too many "
-			    "properties given to -o option\n"));
-			usage(FALSE);
-		}
-
-		save_fields = fields;
-		if ((prop = getsubopt(&fields, subopts, &value)) == -1) {
-			fields = save_fields;
-			prop = getsubopt(&fields, shortsubopts, &value);
-		}
-
-		if (prop == -1) {
-			(void) fprintf(stderr, gettext("invalid property "
-			    "'%s'\n"), value);
-			usage(FALSE);
-		}
-
-		if (zfs_prop_column_name(prop) == NULL) {
-			(void) fprintf(stderr, gettext("invalid property "
-			    "'%s'\n"), zfs_prop_to_name(prop));
-			usage(FALSE);
-		}
-
-		cb.cb_fields[cb.cb_fieldcount++] = prop;
+	/*
+	 * If the user specifies '-o all', the zfs_get_proplist() doesn't
+	 * normally include the name of the dataset.  For 'zfs list', we always
+	 * want this property to be first.
+	 */
+	if (strcmp(fields, "all") == 0) {
+		cb.cb_fields[0] = ZFS_PROP_NAME;
+		alloffset = 1;
+	} else {
+		alloffset = 0;
 	}
 
+	if ((ret = zfs_get_proplist(fields, cb.cb_fields + alloffset,
+	    ZFS_NPROP_ALL - alloffset, &cb.cb_fieldcount, &badopt)) != 0) {
+		if (ret == EINVAL)
+			(void) fprintf(stderr, gettext("invalid property "
+			    "'%s'\n"), badopt);
+		else
+			(void) fprintf(stderr, gettext("too many properties "
+			    "specified\n"));
+		usage(FALSE);
+	}
+
+	cb.cb_fieldcount += alloffset;
 	cb.cb_scripted = scripted;
 	cb.cb_first = TRUE;
 
@@ -1269,12 +1220,6 @@
 	if (ret == 0 && cb.cb_first == TRUE)
 		(void) printf(gettext("no datasets available\n"));
 
-	free(subopts);
-	for (i = 0; i < ZFS_NPROP_ALL; i++)
-		if (shortsubopts[i][0])
-			free(shortsubopts[i]);
-	free(shortsubopts);
-
 	return (ret);
 }
 
--- a/usr/src/common/zfs/zfs_prop.c	Mon Nov 07 17:56:47 2005 -0800
+++ b/usr/src/common/zfs/zfs_prop.c	Mon Nov 07 18:10:17 2005 -0800
@@ -289,47 +289,120 @@
 }
 
 /*
- * Returns an array of names suitable for passing to getsubopt() to determine
- * the property index.
+ * Given a comma-separated list of fields, fills in the specified array with a
+ * list of properties.  The keyword "all" can be used to specify all properties.
+ * The 'count' parameter returns the number of matching properties placed into
+ * the list.  The 'props' parameter must point to an array of at least
+ * ZFS_NPROP_ALL elements.
  */
-char **
-zfs_prop_column_subopts(void)
+int
+zfs_get_proplist(char *fields, zfs_prop_t *props, int max,
+    int *count, char **badopt)
 {
-	char **ret = malloc((ZFS_NPROP_ALL + 1) * sizeof (char *));
 	int i;
-
-	for (i = 0; i < ZFS_NPROP_ALL; i++)
-		ret[i] = (char *)zfs_prop_table[i].pd_name;
-
-	ret[i] = NULL;
-
-	return (ret);
-}
+	size_t len;
+	char *s, *p;
 
-/*
- * Same as above, but using the short (abbreviated) column names as indices.
- */
-char **
-zfs_prop_column_short_subopts(void)
-{
-	char **ret = malloc((ZFS_NPROP_ALL + 1) * sizeof (char *) * 2);
-	char *cur;
-	int i;
+	*count = 0;
 
-	for (i = 0; i < ZFS_NPROP_ALL; i++) {
-		if (zfs_prop_table[i].pd_colname == NULL) {
-			ret[i] = "";
-		} else {
-			ret[i] = strdup(zfs_prop_table[i].pd_colname);
-			for (cur = ret[i]; *cur != '\0'; cur++)
-				*cur = tolower(*cur);
-		}
+	/*
+	 * Check for the special value "all", which indicates all properties
+	 * should be displayed.
+	 */
+	if (strcmp(fields, "all") == 0) {
+		if (max < ZFS_NPROP_VISIBLE)
+			return (EOVERFLOW);
+
+		for (i = 0; i < ZFS_NPROP_VISIBLE; i++)
+			props[i] = i;
+		*count = ZFS_NPROP_VISIBLE;
+		return (0);
 	}
 
+	/*
+	 * It would be nice to use getsubopt() here, but the inclusion of column
+	 * aliases makes this more effort than it's worth.
+	 */
+	s = fields;
+	while (*s != '\0') {
+		if ((p = strchr(s, ',')) == NULL) {
+			len = strlen(s);
+			p = s + len;
+		} else {
+			len = p - s;
+		}
 
-	ret[i] = NULL;
+		/*
+		 * Check for empty options.
+		 */
+		if (len == 0) {
+			*badopt = "";
+			return (EINVAL);
+		}
+
+		/*
+		 * Check all regular property names.
+		 */
+		for (i = 0; i < ZFS_NPROP_ALL; i++) {
+			if (zfs_prop_table[i].pd_colname == NULL)
+				continue;
+
+			if (len == strlen(zfs_prop_table[i].pd_name) &&
+			    strncmp(s, zfs_prop_table[i].pd_name, len) == 0)
+				break;
+		}
+
+		/*
+		 * Check all abbreviated column names.
+		 */
+		if (i == ZFS_NPROP_ALL) {
+			for (i = 0; i < ZFS_NPROP_ALL; i++) {
+				if (zfs_prop_table[i].pd_colname == NULL)
+					continue;
+
+				if (len ==
+				    strlen(zfs_prop_table[i].pd_colname) &&
+				    strncasecmp(s, zfs_prop_table[i].pd_colname,
+				    len) == 0)
+					break;
+			}
+		}
 
-	return (ret);
+		/*
+		 * If no column is specified, then return failure, setting
+		 * 'badopt' to point to the invalid option.
+		 */
+		if (i == ZFS_NPROP_ALL) {
+			s[len] = '\0';
+			*badopt = s;
+			return (EINVAL);
+		}
+
+		/*
+		 * If the user specified too many options (by using the same one
+		 * multiple times). return an error with 'badopt' set to NULL to
+		 * indicate this condition.
+		 */
+		if (*count == max)
+			return (EOVERFLOW);
+
+		props[*count] = i;
+		*count += 1;
+
+		s = p;
+		if (*s == ',')
+			s++;
+	}
+
+	/*
+	 * If no fields were specified, return an error.
+	 */
+	if (*count == 0) {
+		*badopt = "";
+		return (EINVAL);
+	}
+
+	return (0);
 }
 
 #endif
--- a/usr/src/lib/libzfs/common/libzfs.h	Mon Nov 07 17:56:47 2005 -0800
+++ b/usr/src/lib/libzfs/common/libzfs.h	Mon Nov 07 18:10:17 2005 -0800
@@ -184,8 +184,8 @@
 int zfs_prop_is_string(zfs_prop_t prop);
 const char *zfs_prop_column_name(zfs_prop_t);
 const char *zfs_prop_column_format(zfs_prop_t);
-char ** zfs_prop_column_subopts(void);
-char ** zfs_prop_column_short_subopts(void);
+int zfs_get_proplist(char *fields, zfs_prop_t *proplist, int max, int *count,
+    char **badopt);
 
 #define	ZFS_MOUNTPOINT_NONE	"none"
 #define	ZFS_MOUNTPOINT_LEGACY	"legacy"
--- a/usr/src/lib/libzfs/spec/libzfs.spec	Mon Nov 07 17:56:47 2005 -0800
+++ b/usr/src/lib/libzfs/spec/libzfs.spec	Mon Nov 07 18:10:17 2005 -0800
@@ -52,6 +52,10 @@
 version SUNWprivate_1.1
 end
 
+function zfs_get_proplist
+version SUNWprivate_1.1
+end
+
 function zfs_get_type
 version SUNWprivate_1.1
 end
@@ -112,14 +116,6 @@
 version SUNWprivate_1.1
 end
 
-function zfs_prop_column_subopts
-version SUNWprivate_1.1
-end
-
-function zfs_prop_column_short_subopts
-version SUNWprivate_1.1
-end
-
 function zfs_prop_default_numeric
 version SUNWprivate_1.1
 end