xref: /illumos-gate/usr/src/common/zfs/zfs_prop.c (revision d3c8f894e9437d361ba78d09f792b0cb1ac89b6a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Master property table.
30  *
31  * This table keeps track of all the properties supported by ZFS, and their
32  * various attributes.  Not all of these are needed by the kernel, and several
33  * are only used by a single libzfs client.  But having them here centralizes
34  * all property information in one location.
35  *
36  * 	name		The human-readable string representing this property
37  * 	proptype	Basic type (string, boolean, number)
38  * 	default		Default value for the property.  Sadly, C only allows
39  * 			you to initialize the first member of a union, so we
40  * 			have two default members for each property.
41  * 	attr		Attributes (readonly, inheritable) for the property
42  * 	types		Valid dataset types to which this applies
43  * 	values		String describing acceptable values for the property
44  * 	colname		The column header for 'zfs list'
45  *	colfmt		The column formatting for 'zfs list'
46  *
47  * This table must match the order of property types in libzfs.h.
48  */
49 
50 #include <sys/zio.h>
51 #include <sys/spa.h>
52 #include <sys/zfs_acl.h>
53 #include <sys/zfs_ioctl.h>
54 #include <sys/zfs_znode.h>
55 
56 #include "zfs_prop.h"
57 #include "zfs_deleg.h"
58 
59 #if defined(_KERNEL)
60 #include <sys/systm.h>
61 #include <util/qsort.h>
62 #else
63 #include <stdlib.h>
64 #include <string.h>
65 #include <ctype.h>
66 #endif
67 
68 typedef enum {
69 	prop_default,
70 	prop_readonly,
71 	prop_inherit
72 } prop_attr_t;
73 
74 typedef struct {
75 	const char	*pd_name;
76 	zfs_proptype_t	pd_proptype;
77 	uint64_t	pd_numdefault;
78 	const char	*pd_strdefault;
79 	prop_attr_t	pd_attr;
80 	int		pd_types;
81 	const char	*pd_values;
82 	const char	*pd_colname;
83 	boolean_t	pd_rightalign;
84 	boolean_t	pd_visible;
85 	const char	*pd_perm;
86 } prop_desc_t;
87 
88 static prop_desc_t zfs_prop_table[] = {
89 	{ "type",	prop_type_string,	0,	NULL,	prop_readonly,
90 	    ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", B_TRUE,
91 	    B_TRUE, ZFS_DELEG_PERM_NONE },
92 	{ "creation",	prop_type_number,	0,	NULL,	prop_readonly,
93 	    ZFS_TYPE_ANY, "<date>", "CREATION", B_FALSE, B_TRUE,
94 	    ZFS_DELEG_PERM_NONE },
95 	{ "used",	prop_type_number,	0,	NULL,	prop_readonly,
96 	    ZFS_TYPE_ANY, "<size>",	"USED", B_TRUE, B_TRUE,
97 	    ZFS_DELEG_PERM_NONE },
98 	{ "available",	prop_type_number,	0,	NULL,	prop_readonly,
99 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", B_TRUE,
100 	    B_TRUE, ZFS_DELEG_PERM_NONE },
101 	{ "referenced",	prop_type_number,	0,	NULL,	prop_readonly,
102 	    ZFS_TYPE_ANY,
103 	    "<size>", "REFER", B_TRUE, B_TRUE, ZFS_DELEG_PERM_NONE },
104 	{ "compressratio", prop_type_number,	0,	NULL,	prop_readonly,
105 	    ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", B_TRUE,
106 	    B_TRUE, ZFS_DELEG_PERM_NONE },
107 	{ "mounted",	prop_type_boolean,	0,	NULL,	prop_readonly,
108 	    ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", B_TRUE, B_TRUE,
109 	    ZFS_DELEG_PERM_NONE },
110 	{ "origin",	prop_type_string,	0,	NULL,	prop_readonly,
111 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN",
112 	    B_FALSE, B_TRUE, ZFS_DELEG_PERM_NONE },
113 	{ "quota",	prop_type_number,	0,	NULL,	prop_default,
114 	    ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_TRUE, B_TRUE,
115 	    ZFS_DELEG_PERM_QUOTA },
116 	{ "reservation", prop_type_number,	0,	NULL,	prop_default,
117 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
118 	    "<size> | none", "RESERV", B_TRUE, B_TRUE,
119 	    ZFS_DELEG_PERM_RESERVATION },
120 	{ "volsize",	prop_type_number,	0,	NULL,	prop_default,
121 	    ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", B_TRUE, B_TRUE,
122 	    ZFS_DELEG_PERM_VOLSIZE },
123 	{ "volblocksize", prop_type_number,	8192,	NULL,	prop_readonly,
124 	    ZFS_TYPE_VOLUME, "512 to 128k, power of 2",	"VOLBLOCK", B_TRUE,
125 	    B_TRUE, ZFS_DELEG_PERM_NONE },
126 	{ "recordsize",	prop_type_number,	SPA_MAXBLOCKSIZE,	NULL,
127 	    prop_inherit,
128 	    ZFS_TYPE_FILESYSTEM,
129 	    "512 to 128k, power of 2", "RECSIZE", B_TRUE, B_TRUE,
130 	    ZFS_DELEG_PERM_RECORDSIZE },
131 	{ "mountpoint",	prop_type_string,	0,	"/",	prop_inherit,
132 	    ZFS_TYPE_FILESYSTEM,
133 	    "<path> | legacy | none", "MOUNTPOINT", B_FALSE, B_TRUE,
134 	    ZFS_DELEG_PERM_MOUNTPOINT },
135 	{ "sharenfs",	prop_type_string,	0,	"off",	prop_inherit,
136 	    ZFS_TYPE_FILESYSTEM,
137 	    "on | off | share(1M) options", "SHARENFS", B_FALSE, B_TRUE,
138 	    ZFS_DELEG_PERM_SHARENFS },
139 	{ "checksum",	prop_type_index,	ZIO_CHECKSUM_DEFAULT,	"on",
140 	    prop_inherit,	ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
141 	    "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", B_TRUE,
142 	    B_TRUE, ZFS_DELEG_PERM_CHECKSUM },
143 	{ "compression", prop_type_index,	ZIO_COMPRESS_DEFAULT,	"off",
144 	    prop_inherit,	ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
145 	    "on | off | lzjb | gzip | gzip-[1-9]", "COMPRESS", B_TRUE, B_TRUE,
146 	    ZFS_DELEG_PERM_COMPRESSION },
147 	{ "atime",	prop_type_boolean,	1,	NULL,	prop_inherit,
148 	    ZFS_TYPE_FILESYSTEM,
149 	    "on | off", "ATIME", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ATIME },
150 	{ "devices",	prop_type_boolean,	1,	NULL,	prop_inherit,
151 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
152 	    "on | off", "DEVICES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_DEVICES },
153 	{ "exec",	prop_type_boolean,	1,	NULL,	prop_inherit,
154 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
155 	    "on | off", "EXEC", B_TRUE, B_TRUE, ZFS_DELEG_PERM_EXEC },
156 	{ "setuid",	prop_type_boolean,	1,	NULL,	prop_inherit,
157 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID",
158 	    B_TRUE, B_TRUE, ZFS_DELEG_PERM_SETUID },
159 	{ "readonly",	prop_type_boolean,	0,	NULL,	prop_inherit,
160 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
161 	    "on | off", "RDONLY", B_TRUE, B_TRUE, ZFS_DELEG_PERM_READONLY },
162 	{ "zoned",	prop_type_boolean,	0,	NULL,	prop_inherit,
163 	    ZFS_TYPE_FILESYSTEM,
164 	    "on | off", "ZONED", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ZONED },
165 	{ "snapdir",	prop_type_index,	ZFS_SNAPDIR_HIDDEN, "hidden",
166 	    prop_inherit,
167 	    ZFS_TYPE_FILESYSTEM,
168 	    "hidden | visible", "SNAPDIR", B_TRUE, B_TRUE,
169 	    ZFS_DELEG_PERM_SNAPDIR },
170 	{ "aclmode", prop_type_index,	ZFS_ACL_GROUPMASK, "groupmask",
171 	    prop_inherit, ZFS_TYPE_FILESYSTEM,
172 	    "discard | groupmask | passthrough", "ACLMODE", B_TRUE,
173 	    B_TRUE, ZFS_DELEG_PERM_ACLMODE },
174 	{ "aclinherit", prop_type_index,	ZFS_ACL_SECURE,	"secure",
175 	    prop_inherit, ZFS_TYPE_FILESYSTEM,
176 	    "discard | noallow | secure | passthrough", "ACLINHERIT", B_TRUE,
177 	    B_TRUE, ZFS_DELEG_PERM_ACLINHERIT },
178 	{ "createtxg",	prop_type_number,	0,	NULL,	prop_readonly,
179 	    ZFS_TYPE_ANY, NULL, NULL, B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
180 	{ "name",	prop_type_string,	0,	NULL,	prop_readonly,
181 	    ZFS_TYPE_ANY, NULL, "NAME", B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
182 	{ "canmount",	prop_type_boolean,	1,	NULL,	prop_default,
183 	    ZFS_TYPE_FILESYSTEM,
184 	    "on | off", "CANMOUNT", B_TRUE, B_TRUE, ZFS_DELEG_PERM_CANMOUNT },
185 	{ "shareiscsi",	prop_type_string,	0,	"off",	prop_inherit,
186 	    ZFS_TYPE_ANY,
187 	    "on | off | type=<type>", "SHAREISCSI", B_FALSE, B_TRUE,
188 	    ZFS_DELEG_PERM_SHAREISCSI },
189 	{ "iscsioptions", prop_type_string,	0,	NULL,	prop_inherit,
190 	    ZFS_TYPE_VOLUME, NULL, "ISCSIOPTIONS", B_FALSE, B_FALSE,
191 	    ZFS_DELEG_PERM_NONE },
192 	{ "xattr",	prop_type_boolean,	1,	NULL,	prop_inherit,
193 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
194 	    "on | off", "XATTR", B_TRUE, B_TRUE, ZFS_DELEG_PERM_XATTR },
195 	{ "numclones", prop_type_number,	0,	NULL,	prop_readonly,
196 	    ZFS_TYPE_SNAPSHOT, NULL, NULL, B_FALSE, B_FALSE,
197 	    ZFS_DELEG_PERM_NONE },
198 	{ "copies",	prop_type_index,	1,	"1",	prop_inherit,
199 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
200 	    "1 | 2 | 3", "COPIES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_COPIES },
201 	{ "bootfs", prop_type_string,	0,	NULL,	prop_default,
202 	    ZFS_TYPE_POOL, "<filesystem>", "BOOTFS", B_FALSE,
203 	    B_TRUE, ZFS_DELEG_PERM_NONE },
204 	{ "autoreplace", prop_type_boolean,	0,	NULL, prop_default,
205 	    ZFS_TYPE_POOL, "on | off", "REPLACE", B_FALSE, B_TRUE,
206 	    ZFS_DELEG_PERM_NONE },
207 	{ "delegation", prop_type_boolean,	1,	NULL,	prop_default,
208 	    ZFS_TYPE_POOL, "on | off", "DELEGATION", B_TRUE,
209 	    B_TRUE, ZFS_DELEG_PERM_NONE },
210 	{ "version",	prop_type_index,	0,	NULL,	prop_default,
211 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "1 | 2 | current",
212 	    "VERSION", B_TRUE, B_TRUE, ZFS_DELEG_PERM_VERSION },
213 };
214 
215 #define	ZFS_PROP_COUNT	((sizeof (zfs_prop_table))/(sizeof (prop_desc_t)))
216 
217 /*
218  * Returns TRUE if the property applies to the given dataset types.
219  */
220 int
221 zfs_prop_valid_for_type(zfs_prop_t prop, int types)
222 {
223 	return ((zfs_prop_table[prop].pd_types & types) != 0);
224 }
225 
226 /*
227  * Determine if the specified property is visible or not.
228  */
229 boolean_t
230 zfs_prop_is_visible(zfs_prop_t prop)
231 {
232 	if (prop < 0)
233 		return (B_FALSE);
234 
235 	return (zfs_prop_table[prop].pd_visible);
236 }
237 
238 /*
239  * A comparison function we can use to order indexes into the
240  * zfs_prop_table[]
241  */
242 static int
243 zfs_prop_compare(const void *p1, const void *p2)
244 {
245 	int i, j;
246 	prop_attr_t iattr, jattr;
247 
248 	i = *((int *)p1);
249 	j = *((int *)p2);
250 
251 	iattr = zfs_prop_table[i].pd_attr;
252 	jattr = zfs_prop_table[j].pd_attr;
253 
254 	/* first, sort by whether the property is readonly or not */
255 	if (iattr != prop_readonly &&
256 	    jattr == prop_readonly)
257 		return (1);
258 	if (iattr == prop_readonly &&
259 	    jattr != prop_readonly)
260 		return (-1);
261 
262 	/* otherwise, sort by the property name */
263 	return (strcmp(zfs_prop_table[i].pd_name,
264 	    zfs_prop_table[j].pd_name));
265 }
266 
267 /*
268  * Iterate over all properties, calling back into the specified function
269  * for each property. We will continue to iterate until we either
270  * reach the end or the callback function something other than
271  * ZFS_PROP_CONT.
272  */
273 zfs_prop_t
274 zfs_prop_iter_common(zfs_prop_f func, void *cb, zfs_type_t type,
275     boolean_t show_all, boolean_t ordered)
276 {
277 	int i;
278 	int order[ZFS_PROP_COUNT];
279 
280 	for (int j = 0; j < ZFS_PROP_COUNT; j++) {
281 		order[j] = j;
282 	}
283 
284 
285 	if (ordered) {
286 		qsort((void *)order, ZFS_PROP_COUNT, sizeof (zfs_prop_t),
287 		    zfs_prop_compare);
288 	}
289 
290 	for (i = 0; i < ZFS_PROP_COUNT; i++) {
291 		if (zfs_prop_valid_for_type(order[i], type) &&
292 		    (zfs_prop_is_visible(order[i]) || show_all)) {
293 			if (func(order[i], cb) != ZFS_PROP_CONT)
294 				return (order[i]);
295 		}
296 	}
297 	return (ZFS_PROP_CONT);
298 }
299 
300 zfs_prop_t
301 zfs_prop_iter(zfs_prop_f func, void *cb, boolean_t show_all)
302 {
303 	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
304 	    B_FALSE));
305 }
306 
307 zfs_prop_t
308 zfs_prop_iter_ordered(zfs_prop_f func, void *cb, boolean_t show_all)
309 {
310 	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
311 	    B_TRUE));
312 }
313 
314 zpool_prop_t
315 zpool_prop_iter(zpool_prop_f func, void *cb, boolean_t show_all)
316 {
317 	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_POOL, show_all,
318 	    B_FALSE));
319 }
320 
321 zfs_proptype_t
322 zfs_prop_get_type(zfs_prop_t prop)
323 {
324 	return (zfs_prop_table[prop].pd_proptype);
325 }
326 
327 zfs_proptype_t
328 zpool_prop_get_type(zfs_prop_t prop)
329 {
330 	return (zfs_prop_table[prop].pd_proptype);
331 }
332 
333 static boolean_t
334 propname_match(const char *p, zfs_prop_t prop, size_t len)
335 {
336 	const char *propname = zfs_prop_table[prop].pd_name;
337 #ifndef _KERNEL
338 	const char *colname = zfs_prop_table[prop].pd_colname;
339 	int c;
340 #endif
341 
342 #ifndef _KERNEL
343 	if (colname == NULL)
344 		return (B_FALSE);
345 #endif
346 
347 	if (len == strlen(propname) &&
348 	    strncmp(p, propname, len) == 0)
349 		return (B_TRUE);
350 
351 #ifndef _KERNEL
352 	if (len != strlen(colname))
353 		return (B_FALSE);
354 
355 	for (c = 0; c < len; c++)
356 		if (p[c] != tolower(colname[c]))
357 			break;
358 
359 	return (colname[c] == '\0');
360 #else
361 	return (B_FALSE);
362 #endif
363 }
364 
365 zfs_prop_t
366 zfs_name_to_prop_cb(zfs_prop_t prop, void *cb_data)
367 {
368 	const char *propname = cb_data;
369 
370 	if (propname_match(propname, prop, strlen(propname))) {
371 		return (prop);
372 	}
373 
374 	return (ZFS_PROP_CONT);
375 }
376 
377 /*
378  * Given a property name and its type, returns the corresponding property ID.
379  */
380 zfs_prop_t
381 zfs_name_to_prop_common(const char *propname, zfs_type_t type)
382 {
383 	zfs_prop_t prop;
384 
385 	prop = zfs_prop_iter_common(zfs_name_to_prop_cb, (void *)propname,
386 	    type, B_TRUE, B_FALSE);
387 	return (prop == ZFS_PROP_CONT ? ZFS_PROP_INVAL : prop);
388 }
389 
390 /*
391  * Given a zfs dataset property name, returns the corresponding property ID.
392  */
393 zfs_prop_t
394 zfs_name_to_prop(const char *propname)
395 {
396 	return (zfs_name_to_prop_common(propname, ZFS_TYPE_ANY));
397 }
398 
399 /*
400  * Given a pool property name, returns the corresponding property ID.
401  */
402 zpool_prop_t
403 zpool_name_to_prop(const char *propname)
404 {
405 	return (zfs_name_to_prop_common(propname, ZFS_TYPE_POOL));
406 }
407 
408 const char *
409 zfs_prop_perm(zfs_prop_t prop)
410 {
411 	return (zfs_prop_table[prop].pd_perm);
412 }
413 
414 /*
415  * For user property names, we allow all lowercase alphanumeric characters, plus
416  * a few useful punctuation characters.
417  */
418 static int
419 valid_char(char c)
420 {
421 	return ((c >= 'a' && c <= 'z') ||
422 	    (c >= '0' && c <= '9') ||
423 	    c == '-' || c == '_' || c == '.' || c == ':');
424 }
425 
426 /*
427  * Returns true if this is a valid user-defined property (one with a ':').
428  */
429 boolean_t
430 zfs_prop_user(const char *name)
431 {
432 	int i;
433 	char c;
434 	boolean_t foundsep = B_FALSE;
435 
436 	for (i = 0; i < strlen(name); i++) {
437 		c = name[i];
438 		if (!valid_char(c))
439 			return (B_FALSE);
440 		if (c == ':')
441 			foundsep = B_TRUE;
442 	}
443 
444 	if (!foundsep)
445 		return (B_FALSE);
446 
447 	return (B_TRUE);
448 }
449 
450 /*
451  * Return the default value for the given property.
452  */
453 const char *
454 zfs_prop_default_string(zfs_prop_t prop)
455 {
456 	return (zfs_prop_table[prop].pd_strdefault);
457 }
458 
459 const char *
460 zpool_prop_default_string(zpool_prop_t prop)
461 {
462 	return (zfs_prop_table[prop].pd_strdefault);
463 }
464 
465 uint64_t
466 zfs_prop_default_numeric(zfs_prop_t prop)
467 {
468 	return (zfs_prop_table[prop].pd_numdefault);
469 }
470 
471 uint64_t
472 zpool_prop_default_numeric(zpool_prop_t prop)
473 {
474 	return (zfs_prop_table[prop].pd_numdefault);
475 }
476 
477 /*
478  * Returns TRUE if the property is readonly.
479  */
480 int
481 zfs_prop_readonly(zfs_prop_t prop)
482 {
483 	return (zfs_prop_table[prop].pd_attr == prop_readonly);
484 }
485 
486 /*
487  * Given a dataset property ID, returns the corresponding name.
488  * Assuming the zfs dataset property ID is valid.
489  */
490 const char *
491 zfs_prop_to_name(zfs_prop_t prop)
492 {
493 	return (zfs_prop_table[prop].pd_name);
494 }
495 
496 /*
497  * Given a pool property ID, returns the corresponding name.
498  * Assuming the pool property ID is valid.
499  */
500 const char *
501 zpool_prop_to_name(zpool_prop_t prop)
502 {
503 	return (zfs_prop_table[prop].pd_name);
504 }
505 
506 /*
507  * Returns TRUE if the property is inheritable.
508  */
509 int
510 zfs_prop_inheritable(zfs_prop_t prop)
511 {
512 	return (zfs_prop_table[prop].pd_attr == prop_inherit);
513 }
514 
515 typedef struct zfs_index {
516 	const char *name;
517 	uint64_t index;
518 } zfs_index_t;
519 
520 static zfs_index_t checksum_table[] = {
521 	{ "on",		ZIO_CHECKSUM_ON },
522 	{ "off",	ZIO_CHECKSUM_OFF },
523 	{ "fletcher2",	ZIO_CHECKSUM_FLETCHER_2 },
524 	{ "fletcher4",	ZIO_CHECKSUM_FLETCHER_4 },
525 	{ "sha256",	ZIO_CHECKSUM_SHA256 },
526 	{ NULL }
527 };
528 
529 static zfs_index_t compress_table[] = {
530 	{ "on",		ZIO_COMPRESS_ON },
531 	{ "off",	ZIO_COMPRESS_OFF },
532 	{ "lzjb",	ZIO_COMPRESS_LZJB },
533 	{ "gzip",	ZIO_COMPRESS_GZIP_6 },	/* the default gzip level */
534 	{ "gzip-1",	ZIO_COMPRESS_GZIP_1 },
535 	{ "gzip-2",	ZIO_COMPRESS_GZIP_2 },
536 	{ "gzip-3",	ZIO_COMPRESS_GZIP_3 },
537 	{ "gzip-4",	ZIO_COMPRESS_GZIP_4 },
538 	{ "gzip-5",	ZIO_COMPRESS_GZIP_5 },
539 	{ "gzip-6",	ZIO_COMPRESS_GZIP_6 },
540 	{ "gzip-7",	ZIO_COMPRESS_GZIP_7 },
541 	{ "gzip-8",	ZIO_COMPRESS_GZIP_8 },
542 	{ "gzip-9",	ZIO_COMPRESS_GZIP_9 },
543 	{ NULL }
544 };
545 
546 static zfs_index_t snapdir_table[] = {
547 	{ "hidden",	ZFS_SNAPDIR_HIDDEN },
548 	{ "visible",	ZFS_SNAPDIR_VISIBLE },
549 	{ NULL }
550 };
551 
552 static zfs_index_t acl_mode_table[] = {
553 	{ "discard",	ZFS_ACL_DISCARD },
554 	{ "groupmask",	ZFS_ACL_GROUPMASK },
555 	{ "passthrough", ZFS_ACL_PASSTHROUGH },
556 	{ NULL }
557 };
558 
559 static zfs_index_t acl_inherit_table[] = {
560 	{ "discard",	ZFS_ACL_DISCARD },
561 	{ "noallow",	ZFS_ACL_NOALLOW },
562 	{ "secure",	ZFS_ACL_SECURE },
563 	{ "passthrough", ZFS_ACL_PASSTHROUGH },
564 	{ NULL }
565 };
566 
567 static zfs_index_t copies_table[] = {
568 	{ "1",	1 },
569 	{ "2",	2 },
570 	{ "3",	3 },
571 	{ NULL }
572 };
573 
574 static zfs_index_t version_table[] = {
575 	{ "1",		1 },
576 	{ "2",		2 },
577 	{ "current",	ZPL_VERSION },
578 	{ NULL }
579 };
580 
581 static zfs_index_t *
582 zfs_prop_index_table(zfs_prop_t prop)
583 {
584 	switch (prop) {
585 	case ZFS_PROP_CHECKSUM:
586 		return (checksum_table);
587 	case ZFS_PROP_COMPRESSION:
588 		return (compress_table);
589 	case ZFS_PROP_SNAPDIR:
590 		return (snapdir_table);
591 	case ZFS_PROP_ACLMODE:
592 		return (acl_mode_table);
593 	case ZFS_PROP_ACLINHERIT:
594 		return (acl_inherit_table);
595 	case ZFS_PROP_COPIES:
596 		return (copies_table);
597 	case ZFS_PROP_VERSION:
598 		return (version_table);
599 	default:
600 		return (NULL);
601 	}
602 }
603 
604 /*
605  * Tables of index types, plus functions to convert between the user view
606  * (strings) and internal representation (uint64_t).
607  */
608 int
609 zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
610 {
611 	zfs_index_t *table;
612 	int i;
613 
614 	if ((table = zfs_prop_index_table(prop)) == NULL)
615 		return (-1);
616 
617 	for (i = 0; table[i].name != NULL; i++) {
618 		if (strcmp(string, table[i].name) == 0) {
619 			*index = table[i].index;
620 			return (0);
621 		}
622 	}
623 
624 	return (-1);
625 }
626 
627 int
628 zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string)
629 {
630 	zfs_index_t *table;
631 	int i;
632 
633 	if ((table = zfs_prop_index_table(prop)) == NULL)
634 		return (-1);
635 
636 	for (i = 0; table[i].name != NULL; i++) {
637 		if (table[i].index == index) {
638 			*string = table[i].name;
639 			return (0);
640 		}
641 	}
642 
643 	return (-1);
644 }
645 
646 #ifndef _KERNEL
647 
648 /*
649  * Returns a string describing the set of acceptable values for the given
650  * zfs property, or NULL if it cannot be set.
651  */
652 const char *
653 zfs_prop_values(zfs_prop_t prop)
654 {
655 	if (zfs_prop_table[prop].pd_types == ZFS_TYPE_POOL)
656 		return (NULL);
657 
658 	return (zfs_prop_table[prop].pd_values);
659 }
660 
661 /*
662  * Returns a string describing the set of acceptable values for the given
663  * zpool property, or NULL if it cannot be set.
664  */
665 const char *
666 zpool_prop_values(zfs_prop_t prop)
667 {
668 	if (zfs_prop_table[prop].pd_types != ZFS_TYPE_POOL)
669 		return (NULL);
670 
671 	return (zfs_prop_table[prop].pd_values);
672 }
673 
674 /*
675  * Returns TRUE if this property is a string type.  Note that index types
676  * (compression, checksum) are treated as strings in userland, even though they
677  * are stored numerically on disk.
678  */
679 int
680 zfs_prop_is_string(zfs_prop_t prop)
681 {
682 	return (zfs_prop_table[prop].pd_proptype == prop_type_string ||
683 	    zfs_prop_table[prop].pd_proptype == prop_type_index);
684 }
685 
686 /*
687  * Returns the column header for the given property.  Used only in
688  * 'zfs list -o', but centralized here with the other property information.
689  */
690 const char *
691 zfs_prop_column_name(zfs_prop_t prop)
692 {
693 	return (zfs_prop_table[prop].pd_colname);
694 }
695 
696 /*
697  * Returns whether the given property should be displayed right-justified for
698  * 'zfs list'.
699  */
700 boolean_t
701 zfs_prop_align_right(zfs_prop_t prop)
702 {
703 	return (zfs_prop_table[prop].pd_rightalign);
704 }
705 
706 /*
707  * Determines the minimum width for the column, and indicates whether it's fixed
708  * or not.  Only string columns are non-fixed.
709  */
710 size_t
711 zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
712 {
713 	prop_desc_t *pd = &zfs_prop_table[prop];
714 	zfs_index_t *idx;
715 	size_t ret;
716 	int i;
717 
718 	*fixed = B_TRUE;
719 
720 	/*
721 	 * Start with the width of the column name.
722 	 */
723 	ret = strlen(pd->pd_colname);
724 
725 	/*
726 	 * For fixed-width values, make sure the width is large enough to hold
727 	 * any possible value.
728 	 */
729 	switch (pd->pd_proptype) {
730 	case prop_type_number:
731 		/*
732 		 * The maximum length of a human-readable number is 5 characters
733 		 * ("20.4M", for example).
734 		 */
735 		if (ret < 5)
736 			ret = 5;
737 		/*
738 		 * 'creation' is handled specially because it's a number
739 		 * internally, but displayed as a date string.
740 		 */
741 		if (prop == ZFS_PROP_CREATION)
742 			*fixed = B_FALSE;
743 		break;
744 	case prop_type_boolean:
745 		/*
746 		 * The maximum length of a boolean value is 3 characters, for
747 		 * "off".
748 		 */
749 		if (ret < 3)
750 			ret = 3;
751 		break;
752 	case prop_type_index:
753 		idx = zfs_prop_index_table(prop);
754 		for (i = 0; idx[i].name != NULL; i++) {
755 			if (strlen(idx[i].name) > ret)
756 				ret = strlen(idx[i].name);
757 		}
758 		break;
759 
760 	case prop_type_string:
761 		*fixed = B_FALSE;
762 		break;
763 	}
764 
765 	return (ret);
766 }
767 
768 #endif
769