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