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