diff options
author | eschrock <none@none> | 2006-09-05 11:37:36 -0700 |
---|---|---|
committer | eschrock <none@none> | 2006-09-05 11:37:36 -0700 |
commit | e9dbad6f263d5570ed7ff5443ec5b958af8c24d7 (patch) | |
tree | 7bd6d85273a4462fc4699aa9ed69e33bd69e2613 /usr/src/common/zfs/zfs_prop.c | |
parent | f724721be86f2d808bc08cd6be299acc214e3dc5 (diff) | |
download | illumos-joyent-e9dbad6f263d5570ed7ff5443ec5b958af8c24d7.tar.gz |
PSARC 2006/486 ZFS canmount property
PSARC 2006/497 ZFS create time properties
PSARC 2006/502 ZFS get all datasets
PSARC 2006/504 ZFS user properties
6269805 properties should be set via an nvlist.
6281585 user defined properties
6349494 'zfs list' output annoying for even moderately long dataset names
6366244 'canmount' option for container-like functionality
6367103 create-time properties
6416639 RFE: provide zfs get -a
6437808 ZFS module version should match on-disk version
6454551 'zfs create -b blocksize filesystem' should fail.
6457478 unrecognized character in error message with 'zpool create -R' command
6457865 missing device name in the error message of 'zpool clear' command
6458571 zfs_ioc_set_prop() doesn't validate input
6458614 zfs ACL #defines should use prefix
6458638 get_configs() accesses bogus memory
6458678 zvol functions should be moved out of zfs_ioctl.h
6458683 zfs_cmd_t could use more cleanup
6458691 common routines to manage zfs_cmd_t nvlists
6460398 zpool import cores on zfs_prop_get
6461029 zpool status -x noexisting-pool has incorrect error message.
6461223 index translations should live with property definitions
6461424 zpool_unmount_datasets() has some busted logic
6461427 zfs_realloc() would be useful
6461757 'zpool status' can report the wrong number of persistent errors
6461784 recursive zfs_snapshot() leaks memory
Diffstat (limited to 'usr/src/common/zfs/zfs_prop.c')
-rw-r--r-- | usr/src/common/zfs/zfs_prop.c | 348 |
1 files changed, 231 insertions, 117 deletions
diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c index fe9e11019f..8b2e7c3f93 100644 --- a/usr/src/common/zfs/zfs_prop.c +++ b/usr/src/common/zfs/zfs_prop.c @@ -77,86 +77,89 @@ typedef struct { int pd_types; const char *pd_values; const char *pd_colname; - const char *pd_colfmt; + boolean_t pd_rightalign; } prop_desc_t; static prop_desc_t zfs_prop_table[ZFS_NPROP_ALL] = { { "type", prop_type_string, 0, NULL, prop_readonly, - ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", "%10s" }, + ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", B_TRUE }, { "creation", prop_type_number, 0, NULL, prop_readonly, - ZFS_TYPE_ANY, "<date>", "CREATION", "%-20s" }, + ZFS_TYPE_ANY, "<date>", "CREATION", B_FALSE }, { "used", prop_type_number, 0, NULL, prop_readonly, - ZFS_TYPE_ANY, "<size>", "USED", "%5s" }, + ZFS_TYPE_ANY, "<size>", "USED", B_TRUE }, { "available", prop_type_number, 0, NULL, prop_readonly, - ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", "%5s" }, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", B_TRUE }, { "referenced", prop_type_number, 0, NULL, prop_readonly, ZFS_TYPE_ANY, - "<size>", "REFER", "%5s" }, + "<size>", "REFER", B_TRUE }, { "compressratio", prop_type_number, 0, NULL, prop_readonly, - ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", "%5s" }, + ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", B_TRUE }, { "mounted", prop_type_boolean, 0, NULL, prop_readonly, - ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", "%7s" }, + ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", B_TRUE }, { "origin", prop_type_string, 0, NULL, prop_readonly, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN", - "%-20s" }, + B_FALSE }, { "quota", prop_type_number, 0, NULL, prop_default, - ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", "%5s" }, + ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_TRUE }, { "reservation", prop_type_number, 0, NULL, prop_default, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "<size> | none", "RESERV", "%6s" }, + "<size> | none", "RESERV", B_TRUE }, { "volsize", prop_type_number, 0, NULL, prop_default, - ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", "%7s" }, + ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", B_TRUE }, { "volblocksize", prop_type_number, 8192, NULL, prop_readonly, - ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", "%8s" }, + ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", B_TRUE }, { "recordsize", prop_type_number, SPA_MAXBLOCKSIZE, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM, - "512 to 128k, power of 2", "RECSIZE", "%7s" }, + "512 to 128k, power of 2", "RECSIZE", B_TRUE }, { "mountpoint", prop_type_string, 0, "/", prop_inherit, ZFS_TYPE_FILESYSTEM, - "<path> | legacy | none", "MOUNTPOINT", "%-20s" }, + "<path> | legacy | none", "MOUNTPOINT", B_FALSE }, { "sharenfs", prop_type_string, 0, "off", prop_inherit, ZFS_TYPE_FILESYSTEM, - "on | off | share(1M) options", "SHARENFS", "%-15s" }, + "on | off | share(1M) options", "SHARENFS", B_FALSE }, { "checksum", prop_type_index, ZIO_CHECKSUM_DEFAULT, "on", prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", "%10s" }, + "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", B_TRUE }, { "compression", prop_type_index, ZIO_COMPRESS_DEFAULT, "off", prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "on | off | lzjb", "COMPRESS", "%8s" }, + "on | off | lzjb", "COMPRESS", B_TRUE }, { "atime", prop_type_boolean, 1, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM, - "on | off", "ATIME", "%5s" }, + "on | off", "ATIME", B_TRUE }, { "devices", prop_type_boolean, 1, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, - "on | off", "DEVICES", "%7s" }, + "on | off", "DEVICES", B_TRUE }, { "exec", prop_type_boolean, 1, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, - "on | off", "EXEC", "%4s" }, + "on | off", "EXEC", B_TRUE }, { "setuid", prop_type_boolean, 1, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID", - "%6s" }, + B_TRUE }, { "readonly", prop_type_boolean, 0, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "on | off", "RDONLY", "%6s" }, + "on | off", "RDONLY", B_TRUE }, { "zoned", prop_type_boolean, 0, NULL, prop_inherit, ZFS_TYPE_FILESYSTEM, - "on | off", "ZONED", "%5s" }, + "on | off", "ZONED", B_TRUE }, { "snapdir", prop_type_index, ZFS_SNAPDIR_HIDDEN, "hidden", prop_inherit, ZFS_TYPE_FILESYSTEM, - "hidden | visible", "SNAPDIR", "%7s" }, - { "aclmode", prop_type_index, GROUPMASK, "groupmask", prop_inherit, + "hidden | visible", "SNAPDIR", B_TRUE }, + { "aclmode", prop_type_index, ZFS_ACL_GROUPMASK, "groupmask", + prop_inherit, ZFS_TYPE_FILESYSTEM, + "discard | groupmask | passthrough", "ACLMODE", B_TRUE }, + { "aclinherit", prop_type_index, ZFS_ACL_SECURE, "secure", + prop_inherit, ZFS_TYPE_FILESYSTEM, + "discard | noallow | secure | passthrough", "ACLINHERIT", B_TRUE }, + { "canmount", prop_type_boolean, 1, NULL, prop_default, ZFS_TYPE_FILESYSTEM, - "discard | groupmask | passthrough", "ACLMODE", "%11s" }, - { "aclinherit", prop_type_index, SECURE, "secure", prop_inherit, - ZFS_TYPE_FILESYSTEM, - "discard | noallow | secure | passthrough", "ACLINHERIT", "%11s" }, + "on | off", "CANMOUNT", B_TRUE }, { "createtxg", prop_type_number, 0, NULL, prop_readonly, ZFS_TYPE_ANY, NULL, NULL, NULL}, { "name", prop_type_string, 0, NULL, prop_readonly, ZFS_TYPE_ANY, - NULL, "NAME", "%-20s" }, + NULL, "NAME", B_FALSE }, }; zfs_proptype_t @@ -165,8 +168,8 @@ zfs_prop_get_type(zfs_prop_t prop) return (zfs_prop_table[prop].pd_proptype); } -static int -propname_match(const char *p, int prop, size_t len) +static boolean_t +propname_match(const char *p, zfs_prop_t prop, size_t len) { const char *propname = zfs_prop_table[prop].pd_name; #ifndef _KERNEL @@ -176,16 +179,16 @@ propname_match(const char *p, int prop, size_t len) #ifndef _KERNEL if (colname == NULL) - return (0); + return (B_FALSE); #endif if (len == strlen(propname) && strncmp(p, propname, len) == 0) - return (1); + return (B_TRUE); #ifndef _KERNEL if (len != strlen(colname)) - return (0); + return (B_FALSE); for (c = 0; c < len; c++) if (p[c] != tolower(colname[c])) @@ -193,7 +196,7 @@ propname_match(const char *p, int prop, size_t len) return (colname[c] == '\0'); #else - return (0); + return (B_FALSE); #endif } @@ -215,6 +218,42 @@ zfs_name_to_prop(const char *propname) } /* + * For user property names, we allow all lowercase alphanumeric characters, plus + * a few useful punctuation characters. + */ +static int +valid_char(char c) +{ + return ((c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_' || c == '.' || c == ':'); +} + +/* + * Returns true if this is a valid user-defined property (one with a ':'). + */ +boolean_t +zfs_prop_user(const char *name) +{ + int i; + char c; + boolean_t foundsep = B_FALSE; + + for (i = 0; i < strlen(name); i++) { + c = name[i]; + if (!valid_char(c)) + return (B_FALSE); + if (c == ':') + foundsep = B_TRUE; + } + + if (!foundsep) + return (B_FALSE); + + return (B_TRUE); +} + +/* * Return the default value for the given property. */ const char * @@ -238,7 +277,6 @@ zfs_prop_readonly(zfs_prop_t prop) return (zfs_prop_table[prop].pd_attr == prop_readonly); } -#ifndef _KERNEL /* * Given a property ID, returns the corresponding name. */ @@ -257,6 +295,117 @@ zfs_prop_inheritable(zfs_prop_t prop) return (zfs_prop_table[prop].pd_attr == prop_inherit); } +#ifndef _KERNEL + +typedef struct zfs_index { + const char *name; + uint64_t index; +} zfs_index_t; + +static zfs_index_t checksum_table[] = { + { "on", ZIO_CHECKSUM_ON }, + { "off", ZIO_CHECKSUM_OFF }, + { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 }, + { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 }, + { "sha256", ZIO_CHECKSUM_SHA256 }, + { NULL } +}; + +static zfs_index_t compress_table[] = { + { "on", ZIO_COMPRESS_ON }, + { "off", ZIO_COMPRESS_OFF }, + { "lzjb", ZIO_COMPRESS_LZJB }, + { NULL } +}; + +static zfs_index_t snapdir_table[] = { + { "hidden", ZFS_SNAPDIR_HIDDEN }, + { "visible", ZFS_SNAPDIR_VISIBLE }, + { NULL } +}; + +static zfs_index_t acl_mode_table[] = { + { "discard", ZFS_ACL_DISCARD }, + { "groupmask", ZFS_ACL_GROUPMASK }, + { "passthrough", ZFS_ACL_PASSTHROUGH }, + { NULL } +}; + +static zfs_index_t acl_inherit_table[] = { + { "discard", ZFS_ACL_DISCARD }, + { "noallow", ZFS_ACL_NOALLOW }, + { "secure", ZFS_ACL_SECURE }, + { "passthrough", ZFS_ACL_PASSTHROUGH }, + { NULL } +}; + +static zfs_index_t * +zfs_prop_index_table(zfs_prop_t prop) +{ + switch (prop) { + case ZFS_PROP_CHECKSUM: + return (checksum_table); + break; + case ZFS_PROP_COMPRESSION: + return (compress_table); + break; + case ZFS_PROP_SNAPDIR: + return (snapdir_table); + break; + case ZFS_PROP_ACLMODE: + return (acl_mode_table); + break; + case ZFS_PROP_ACLINHERIT: + return (acl_inherit_table); + break; + default: + return (NULL); + } +} + + +/* + * Tables of index types, plus functions to convert between the user view + * (strings) and internal representation (uint64_t). + */ +int +zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index) +{ + zfs_index_t *table; + int i; + + if ((table = zfs_prop_index_table(prop)) == NULL) + return (-1); + + for (i = 0; table[i].name != NULL; i++) { + if (strcmp(string, table[i].name) == 0) { + *index = table[i].index; + return (0); + } + } + + return (-1); +} + +int +zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string) +{ + zfs_index_t *table; + int i; + + if ((table = zfs_prop_index_table(prop)) == NULL) + return (-1); + + for (i = 0; table[i].name != NULL; i++) { + if (table[i].index == index) { + *string = table[i].name; + return (0); + } + } + + return (-1); +} + /* * Returns TRUE if the property applies to the given dataset types. */ @@ -299,110 +448,75 @@ zfs_prop_column_name(zfs_prop_t prop) } /* - * Returns the column formatting for the given property. Used only in - * 'zfs list -o', but centralized here with the other property information. + * Returns whether the given property should be displayed right-justified for + * 'zfs list'. */ -const char * -zfs_prop_column_format(zfs_prop_t prop) +boolean_t +zfs_prop_align_right(zfs_prop_t prop) { - return (zfs_prop_table[prop].pd_colfmt); + return (zfs_prop_table[prop].pd_rightalign); } /* - * 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. + * Determines the minimum width for the column, and indicates whether it's fixed + * or not. Only string columns are non-fixed. */ -int -zfs_get_proplist(char *fields, zfs_prop_t *props, int max, - int *count, char **badopt) +size_t +zfs_prop_width(zfs_prop_t prop, boolean_t *fixed) { + prop_desc_t *pd = &zfs_prop_table[prop]; + zfs_index_t *idx; + size_t ret; int i; - size_t len; - char *s, *p; - *count = 0; + *fixed = B_TRUE; /* - * Check for the special value "all", which indicates all properties - * should be displayed. + * Start with the width of the column name. */ - 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); - } + ret = strlen(pd->pd_colname); /* - * It would be nice to use getsubopt() here, but the inclusion of column - * aliases makes this more effort than it's worth. + * For fixed-width values, make sure the width is large enough to hold + * any possible value. */ - s = fields; - while (*s != '\0') { - if ((p = strchr(s, ',')) == NULL) { - len = strlen(s); - p = s + len; - } else { - len = p - s; - } - + switch (pd->pd_proptype) { + case prop_type_number: /* - * Check for empty options. + * The maximum length of a human-readable number is 5 characters + * ("20.4M", for example). */ - if (len == 0) { - *badopt = ""; - return (EINVAL); - } - + if (ret < 5) + ret = 5; /* - * Check all regular property names. + * 'creation' is handled specially because it's a number + * internally, but displayed as a date string. */ - for (i = 0; i < ZFS_NPROP_ALL; i++) { - if (propname_match(s, i, len)) - break; - } - + if (prop == ZFS_PROP_CREATION) + *fixed = B_FALSE; + break; + case prop_type_boolean: /* - * If no column is specified, then return failure, setting - * 'badopt' to point to the invalid option. + * The maximum length of a boolean value is 3 characters, for + * "off". */ - if (i == ZFS_NPROP_ALL) { - s[len] = '\0'; - *badopt = s; - return (EINVAL); + if (ret < 3) + ret = 3; + break; + case prop_type_index: + idx = zfs_prop_index_table(prop); + for (i = 0; idx[i].name != NULL; i++) { + if (strlen(idx[i].name) > ret) + ret = strlen(idx[i].name); } + break; - /* - * 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); + case prop_type_string: + *fixed = B_FALSE; + break; } - return (0); + return (ret); } #endif |