15094Slling /*
25094Slling * CDDL HEADER START
35094Slling *
45094Slling * The contents of this file are subject to the terms of the
55094Slling * Common Development and Distribution License (the "License").
65094Slling * You may not use this file except in compliance with the License.
75094Slling *
85094Slling * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95094Slling * or http://www.opensolaris.org/os/licensing.
105094Slling * See the License for the specific language governing permissions
115094Slling * and limitations under the License.
125094Slling *
135094Slling * When distributing Covered Code, include this CDDL HEADER in each
145094Slling * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155094Slling * If applicable, add the following below this CDDL HEADER, with the
165094Slling * fields enclosed by brackets "[]" replaced with your own identifying
175094Slling * information: Portions Copyright [yyyy] [name of copyright owner]
185094Slling *
195094Slling * CDDL HEADER END
205094Slling */
215094Slling /*
22*11976STom.Erickson@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
235094Slling * Use is subject to license terms.
245094Slling */
255094Slling
265094Slling /*
275094Slling * Common routines used by zfs and zpool property management.
285094Slling */
295094Slling
305094Slling #include <sys/zio.h>
315094Slling #include <sys/spa.h>
325094Slling #include <sys/zfs_acl.h>
335094Slling #include <sys/zfs_ioctl.h>
345094Slling #include <sys/zfs_znode.h>
355094Slling #include <sys/fs/zfs.h>
365094Slling
375094Slling #include "zfs_prop.h"
385094Slling #include "zfs_deleg.h"
395094Slling
405094Slling #if defined(_KERNEL)
415094Slling #include <sys/systm.h>
425094Slling #include <util/qsort.h>
435094Slling #else
445094Slling #include <stdlib.h>
455094Slling #include <string.h>
465094Slling #include <ctype.h>
475094Slling #endif
485094Slling
495094Slling static zprop_desc_t *
zprop_get_proptable(zfs_type_t type)505094Slling zprop_get_proptable(zfs_type_t type)
515094Slling {
525094Slling if (type == ZFS_TYPE_POOL)
535094Slling return (zpool_prop_get_table());
545094Slling else
555094Slling return (zfs_prop_get_table());
565094Slling }
575094Slling
585094Slling static int
zprop_get_numprops(zfs_type_t type)595094Slling zprop_get_numprops(zfs_type_t type)
605094Slling {
615094Slling if (type == ZFS_TYPE_POOL)
625094Slling return (ZPOOL_NUM_PROPS);
635094Slling else
645094Slling return (ZFS_NUM_PROPS);
655094Slling }
665094Slling
675094Slling void
zprop_register_impl(int prop,const char * name,zprop_type_t type,uint64_t numdefault,const char * strdefault,zprop_attr_t attr,int objset_types,const char * values,const char * colname,boolean_t rightalign,boolean_t visible,const zprop_index_t * idx_tbl)68*11976STom.Erickson@Sun.COM zprop_register_impl(int prop, const char *name, zprop_type_t type,
695094Slling uint64_t numdefault, const char *strdefault, zprop_attr_t attr,
705094Slling int objset_types, const char *values, const char *colname,
715094Slling boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl)
725094Slling {
735094Slling zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types);
745094Slling zprop_desc_t *pd;
755094Slling
765094Slling pd = &prop_tbl[prop];
775094Slling
785094Slling ASSERT(pd->pd_name == NULL || pd->pd_name == name);
7910922SJeff.Bonwick@Sun.COM ASSERT(name != NULL);
8010922SJeff.Bonwick@Sun.COM ASSERT(colname != NULL);
815094Slling
825094Slling pd->pd_name = name;
835094Slling pd->pd_propnum = prop;
845094Slling pd->pd_proptype = type;
855094Slling pd->pd_numdefault = numdefault;
865094Slling pd->pd_strdefault = strdefault;
875094Slling pd->pd_attr = attr;
885094Slling pd->pd_types = objset_types;
895094Slling pd->pd_values = values;
905094Slling pd->pd_colname = colname;
915094Slling pd->pd_rightalign = rightalign;
925094Slling pd->pd_visible = visible;
935094Slling pd->pd_table = idx_tbl;
9410922SJeff.Bonwick@Sun.COM pd->pd_table_size = 0;
9510922SJeff.Bonwick@Sun.COM while (idx_tbl && (idx_tbl++)->pi_name != NULL)
9610922SJeff.Bonwick@Sun.COM pd->pd_table_size++;
975094Slling }
985094Slling
995094Slling void
zprop_register_string(int prop,const char * name,const char * def,zprop_attr_t attr,int objset_types,const char * values,const char * colname)100*11976STom.Erickson@Sun.COM zprop_register_string(int prop, const char *name, const char *def,
1015094Slling zprop_attr_t attr, int objset_types, const char *values,
1025094Slling const char *colname)
1035094Slling {
104*11976STom.Erickson@Sun.COM zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
1055094Slling objset_types, values, colname, B_FALSE, B_TRUE, NULL);
1065094Slling
1075094Slling }
1085094Slling
1095094Slling void
zprop_register_number(int prop,const char * name,uint64_t def,zprop_attr_t attr,int objset_types,const char * values,const char * colname)110*11976STom.Erickson@Sun.COM zprop_register_number(int prop, const char *name, uint64_t def,
111*11976STom.Erickson@Sun.COM zprop_attr_t attr, int objset_types, const char *values,
112*11976STom.Erickson@Sun.COM const char *colname)
1135094Slling {
114*11976STom.Erickson@Sun.COM zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
1155094Slling objset_types, values, colname, B_TRUE, B_TRUE, NULL);
1165094Slling }
1175094Slling
1185094Slling void
zprop_register_index(int prop,const char * name,uint64_t def,zprop_attr_t attr,int objset_types,const char * values,const char * colname,const zprop_index_t * idx_tbl)119*11976STom.Erickson@Sun.COM zprop_register_index(int prop, const char *name, uint64_t def,
120*11976STom.Erickson@Sun.COM zprop_attr_t attr, int objset_types, const char *values,
121*11976STom.Erickson@Sun.COM const char *colname, const zprop_index_t *idx_tbl)
1225094Slling {
123*11976STom.Erickson@Sun.COM zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr,
1245094Slling objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl);
1255094Slling }
1265094Slling
1275094Slling void
zprop_register_hidden(int prop,const char * name,zprop_type_t type,zprop_attr_t attr,int objset_types,const char * colname)128*11976STom.Erickson@Sun.COM zprop_register_hidden(int prop, const char *name, zprop_type_t type,
1295094Slling zprop_attr_t attr, int objset_types, const char *colname)
1305094Slling {
131*11976STom.Erickson@Sun.COM zprop_register_impl(prop, name, type, 0, NULL, attr,
1325094Slling objset_types, NULL, colname, B_FALSE, B_FALSE, NULL);
1335094Slling }
1345094Slling
1355094Slling
1365094Slling /*
1375094Slling * A comparison function we can use to order indexes into property tables.
1385094Slling */
1395094Slling static int
zprop_compare(const void * arg1,const void * arg2)1405094Slling zprop_compare(const void *arg1, const void *arg2)
1415094Slling {
1425094Slling const zprop_desc_t *p1 = *((zprop_desc_t **)arg1);
1435094Slling const zprop_desc_t *p2 = *((zprop_desc_t **)arg2);
1445094Slling boolean_t p1ro, p2ro;
1455094Slling
1465094Slling p1ro = (p1->pd_attr == PROP_READONLY);
1475094Slling p2ro = (p2->pd_attr == PROP_READONLY);
1485094Slling
1495094Slling if (p1ro == p2ro)
1505094Slling return (strcmp(p1->pd_name, p2->pd_name));
1515094Slling
1525094Slling return (p1ro ? -1 : 1);
1535094Slling }
1545094Slling
1555094Slling /*
1565094Slling * Iterate over all properties in the given property table, calling back
1575094Slling * into the specified function for each property. We will continue to
1585094Slling * iterate until we either reach the end or the callback function returns
1595094Slling * something other than ZPROP_CONT.
1605094Slling */
1615094Slling int
zprop_iter_common(zprop_func func,void * cb,boolean_t show_all,boolean_t ordered,zfs_type_t type)1625094Slling zprop_iter_common(zprop_func func, void *cb, boolean_t show_all,
1635094Slling boolean_t ordered, zfs_type_t type)
1645094Slling {
1655094Slling int i, num_props, size, prop;
1665094Slling zprop_desc_t *prop_tbl;
1675094Slling zprop_desc_t **order;
1685094Slling
1695094Slling prop_tbl = zprop_get_proptable(type);
1705094Slling num_props = zprop_get_numprops(type);
1715094Slling size = num_props * sizeof (zprop_desc_t *);
1725094Slling
1735094Slling #if defined(_KERNEL)
1745094Slling order = kmem_alloc(size, KM_SLEEP);
1755094Slling #else
1765094Slling if ((order = malloc(size)) == NULL)
1775094Slling return (ZPROP_CONT);
1785094Slling #endif
1795094Slling
1805094Slling for (int j = 0; j < num_props; j++)
1815094Slling order[j] = &prop_tbl[j];
1825094Slling
1835094Slling if (ordered) {
1845094Slling qsort((void *)order, num_props, sizeof (zprop_desc_t *),
1855094Slling zprop_compare);
1865094Slling }
1875094Slling
1885094Slling prop = ZPROP_CONT;
1895094Slling for (i = 0; i < num_props; i++) {
1905094Slling if ((order[i]->pd_visible || show_all) &&
1915094Slling (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) {
1925094Slling prop = order[i]->pd_propnum;
1935094Slling break;
1945094Slling }
1955094Slling }
1965094Slling
1975094Slling #if defined(_KERNEL)
1985094Slling kmem_free(order, size);
1995094Slling #else
2005094Slling free(order);
2015094Slling #endif
2025094Slling return (prop);
2035094Slling }
2045094Slling
2055094Slling static boolean_t
propname_match(const char * p,size_t len,zprop_desc_t * prop_entry)2065094Slling propname_match(const char *p, size_t len, zprop_desc_t *prop_entry)
2075094Slling {
2085094Slling const char *propname = prop_entry->pd_name;
2095094Slling #ifndef _KERNEL
2105094Slling const char *colname = prop_entry->pd_colname;
2115094Slling int c;
2125094Slling #endif
2135094Slling
2145094Slling if (len == strlen(propname) &&
2155094Slling strncmp(p, propname, len) == 0)
2165094Slling return (B_TRUE);
2175094Slling
2185094Slling #ifndef _KERNEL
2199396SMatthew.Ahrens@Sun.COM if (colname == NULL || len != strlen(colname))
2205094Slling return (B_FALSE);
2215094Slling
2225094Slling for (c = 0; c < len; c++)
2235094Slling if (p[c] != tolower(colname[c]))
2245094Slling break;
2255094Slling
2265094Slling return (colname[c] == '\0');
2275094Slling #else
2285094Slling return (B_FALSE);
2295094Slling #endif
2305094Slling }
2315094Slling
2325094Slling typedef struct name_to_prop_cb {
2335094Slling const char *propname;
2345094Slling zprop_desc_t *prop_tbl;
2355094Slling } name_to_prop_cb_t;
2365094Slling
2375094Slling static int
zprop_name_to_prop_cb(int prop,void * cb_data)2385094Slling zprop_name_to_prop_cb(int prop, void *cb_data)
2395094Slling {
2405094Slling name_to_prop_cb_t *data = cb_data;
2415094Slling
2425094Slling if (propname_match(data->propname, strlen(data->propname),
2435094Slling &data->prop_tbl[prop]))
2445094Slling return (prop);
2455094Slling
2465094Slling return (ZPROP_CONT);
2475094Slling }
2485094Slling
2495094Slling int
zprop_name_to_prop(const char * propname,zfs_type_t type)2505094Slling zprop_name_to_prop(const char *propname, zfs_type_t type)
2515094Slling {
2525094Slling int prop;
2535094Slling name_to_prop_cb_t cb_data;
2545094Slling
2555094Slling cb_data.propname = propname;
2565094Slling cb_data.prop_tbl = zprop_get_proptable(type);
2575094Slling
2585094Slling prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data,
2595094Slling B_TRUE, B_FALSE, type);
2605094Slling
2615094Slling return (prop == ZPROP_CONT ? ZPROP_INVAL : prop);
2625094Slling }
2635094Slling
2645094Slling int
zprop_string_to_index(int prop,const char * string,uint64_t * index,zfs_type_t type)2655094Slling zprop_string_to_index(int prop, const char *string, uint64_t *index,
2665094Slling zfs_type_t type)
2675094Slling {
2685094Slling zprop_desc_t *prop_tbl;
2695094Slling const zprop_index_t *idx_tbl;
2705094Slling int i;
2715094Slling
2726692Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
2736692Sgw25295 return (-1);
2746692Sgw25295
2756692Sgw25295 ASSERT(prop < zprop_get_numprops(type));
2765094Slling prop_tbl = zprop_get_proptable(type);
2775094Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
2785094Slling return (-1);
2795094Slling
2805094Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
2815094Slling if (strcmp(string, idx_tbl[i].pi_name) == 0) {
2825094Slling *index = idx_tbl[i].pi_value;
2835094Slling return (0);
2845094Slling }
2855094Slling }
2865094Slling
2875094Slling return (-1);
2885094Slling }
2895094Slling
2905094Slling int
zprop_index_to_string(int prop,uint64_t index,const char ** string,zfs_type_t type)2915094Slling zprop_index_to_string(int prop, uint64_t index, const char **string,
2925094Slling zfs_type_t type)
2935094Slling {
2945094Slling zprop_desc_t *prop_tbl;
2955094Slling const zprop_index_t *idx_tbl;
2965094Slling int i;
2975094Slling
2986692Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
2996692Sgw25295 return (-1);
3006692Sgw25295
3016692Sgw25295 ASSERT(prop < zprop_get_numprops(type));
3025094Slling prop_tbl = zprop_get_proptable(type);
3035094Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
3045094Slling return (-1);
3055094Slling
3065094Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
3075094Slling if (idx_tbl[i].pi_value == index) {
3085094Slling *string = idx_tbl[i].pi_name;
3095094Slling return (0);
3105094Slling }
3115094Slling }
3125094Slling
3135094Slling return (-1);
3145094Slling }
3155094Slling
31610922SJeff.Bonwick@Sun.COM /*
31710922SJeff.Bonwick@Sun.COM * Return a random valid property value. Used by ztest.
31810922SJeff.Bonwick@Sun.COM */
31910922SJeff.Bonwick@Sun.COM uint64_t
zprop_random_value(int prop,uint64_t seed,zfs_type_t type)32010922SJeff.Bonwick@Sun.COM zprop_random_value(int prop, uint64_t seed, zfs_type_t type)
32110922SJeff.Bonwick@Sun.COM {
32210922SJeff.Bonwick@Sun.COM zprop_desc_t *prop_tbl;
32310922SJeff.Bonwick@Sun.COM const zprop_index_t *idx_tbl;
32410922SJeff.Bonwick@Sun.COM
32510922SJeff.Bonwick@Sun.COM ASSERT((uint_t)prop < zprop_get_numprops(type));
32610922SJeff.Bonwick@Sun.COM prop_tbl = zprop_get_proptable(type);
32710922SJeff.Bonwick@Sun.COM idx_tbl = prop_tbl[prop].pd_table;
32810922SJeff.Bonwick@Sun.COM
32910922SJeff.Bonwick@Sun.COM if (idx_tbl == NULL)
33010922SJeff.Bonwick@Sun.COM return (seed);
33110922SJeff.Bonwick@Sun.COM
33210922SJeff.Bonwick@Sun.COM return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value);
33310922SJeff.Bonwick@Sun.COM }
33410922SJeff.Bonwick@Sun.COM
3355094Slling const char *
zprop_values(int prop,zfs_type_t type)3365094Slling zprop_values(int prop, zfs_type_t type)
3375094Slling {
3385094Slling zprop_desc_t *prop_tbl;
3395094Slling
3406692Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
3416692Sgw25295 ASSERT(prop < zprop_get_numprops(type));
3426692Sgw25295
3435094Slling prop_tbl = zprop_get_proptable(type);
3445094Slling
3455094Slling return (prop_tbl[prop].pd_values);
3465094Slling }
3475094Slling
3485094Slling /*
3495094Slling * Returns TRUE if the property applies to any of the given dataset types.
3505094Slling */
3516692Sgw25295 boolean_t
zprop_valid_for_type(int prop,zfs_type_t type)3525094Slling zprop_valid_for_type(int prop, zfs_type_t type)
3535094Slling {
3546692Sgw25295 zprop_desc_t *prop_tbl;
3555094Slling
3566692Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
3576692Sgw25295 return (B_FALSE);
3586692Sgw25295
3596692Sgw25295 ASSERT(prop < zprop_get_numprops(type));
3606692Sgw25295 prop_tbl = zprop_get_proptable(type);
3615094Slling return ((prop_tbl[prop].pd_types & type) != 0);
3625094Slling }
3635094Slling
3645094Slling #ifndef _KERNEL
3655094Slling
3665094Slling /*
3675094Slling * Determines the minimum width for the column, and indicates whether it's fixed
3685094Slling * or not. Only string columns are non-fixed.
3695094Slling */
3705094Slling size_t
zprop_width(int prop,boolean_t * fixed,zfs_type_t type)3715094Slling zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
3725094Slling {
3735094Slling zprop_desc_t *prop_tbl, *pd;
3745094Slling const zprop_index_t *idx;
3755094Slling size_t ret;
3765094Slling int i;
3775094Slling
3786692Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
3796692Sgw25295 ASSERT(prop < zprop_get_numprops(type));
3806692Sgw25295
3815094Slling prop_tbl = zprop_get_proptable(type);
3825094Slling pd = &prop_tbl[prop];
3835094Slling
3845094Slling *fixed = B_TRUE;
3855094Slling
3865094Slling /*
3875094Slling * Start with the width of the column name.
3885094Slling */
3895094Slling ret = strlen(pd->pd_colname);
3905094Slling
3915094Slling /*
3925094Slling * For fixed-width values, make sure the width is large enough to hold
3935094Slling * any possible value.
3945094Slling */
3955094Slling switch (pd->pd_proptype) {
3965094Slling case PROP_TYPE_NUMBER:
3975094Slling /*
3985094Slling * The maximum length of a human-readable number is 5 characters
3995094Slling * ("20.4M", for example).
4005094Slling */
4015094Slling if (ret < 5)
4025094Slling ret = 5;
4035094Slling /*
4045094Slling * 'creation' is handled specially because it's a number
4055094Slling * internally, but displayed as a date string.
4065094Slling */
4075094Slling if (prop == ZFS_PROP_CREATION)
4085094Slling *fixed = B_FALSE;
4095094Slling break;
4105094Slling case PROP_TYPE_INDEX:
4115094Slling idx = prop_tbl[prop].pd_table;
4125094Slling for (i = 0; idx[i].pi_name != NULL; i++) {
4135094Slling if (strlen(idx[i].pi_name) > ret)
4145094Slling ret = strlen(idx[i].pi_name);
4155094Slling }
4165094Slling break;
4175094Slling
4185094Slling case PROP_TYPE_STRING:
4195094Slling *fixed = B_FALSE;
4205094Slling break;
4215094Slling }
4225094Slling
4235094Slling return (ret);
4245094Slling }
4255094Slling
4265094Slling #endif
427