1990b4856Slling /* 2990b4856Slling * CDDL HEADER START 3990b4856Slling * 4990b4856Slling * The contents of this file are subject to the terms of the 5990b4856Slling * Common Development and Distribution License (the "License"). 6990b4856Slling * You may not use this file except in compliance with the License. 7990b4856Slling * 8990b4856Slling * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9990b4856Slling * or http://www.opensolaris.org/os/licensing. 10990b4856Slling * See the License for the specific language governing permissions 11990b4856Slling * and limitations under the License. 12990b4856Slling * 13990b4856Slling * When distributing Covered Code, include this CDDL HEADER in each 14990b4856Slling * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15990b4856Slling * If applicable, add the following below this CDDL HEADER, with the 16990b4856Slling * fields enclosed by brackets "[]" replaced with your own identifying 17990b4856Slling * information: Portions Copyright [yyyy] [name of copyright owner] 18990b4856Slling * 19990b4856Slling * CDDL HEADER END 20990b4856Slling */ 21990b4856Slling /* 2214843421SMatthew Ahrens * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23990b4856Slling * Use is subject to license terms. 24990b4856Slling */ 25990b4856Slling 26990b4856Slling /* 27990b4856Slling * Common routines used by zfs and zpool property management. 28990b4856Slling */ 29990b4856Slling 30990b4856Slling #include <sys/zio.h> 31990b4856Slling #include <sys/spa.h> 32990b4856Slling #include <sys/zfs_acl.h> 33990b4856Slling #include <sys/zfs_ioctl.h> 34990b4856Slling #include <sys/zfs_znode.h> 35990b4856Slling #include <sys/fs/zfs.h> 36990b4856Slling 37990b4856Slling #include "zfs_prop.h" 38990b4856Slling #include "zfs_deleg.h" 39990b4856Slling 40990b4856Slling #if defined(_KERNEL) 41990b4856Slling #include <sys/systm.h> 42990b4856Slling #include <util/qsort.h> 43990b4856Slling #else 44990b4856Slling #include <stdlib.h> 45990b4856Slling #include <string.h> 46990b4856Slling #include <ctype.h> 47990b4856Slling #endif 48990b4856Slling 49990b4856Slling static zprop_desc_t * 50990b4856Slling zprop_get_proptable(zfs_type_t type) 51990b4856Slling { 52990b4856Slling if (type == ZFS_TYPE_POOL) 53990b4856Slling return (zpool_prop_get_table()); 54990b4856Slling else 55990b4856Slling return (zfs_prop_get_table()); 56990b4856Slling } 57990b4856Slling 58990b4856Slling static int 59990b4856Slling zprop_get_numprops(zfs_type_t type) 60990b4856Slling { 61990b4856Slling if (type == ZFS_TYPE_POOL) 62990b4856Slling return (ZPOOL_NUM_PROPS); 63990b4856Slling else 64990b4856Slling return (ZFS_NUM_PROPS); 65990b4856Slling } 66990b4856Slling 67990b4856Slling void 68990b4856Slling register_impl(int prop, const char *name, zprop_type_t type, 69990b4856Slling uint64_t numdefault, const char *strdefault, zprop_attr_t attr, 70990b4856Slling int objset_types, const char *values, const char *colname, 71990b4856Slling boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl) 72990b4856Slling { 73990b4856Slling zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); 74990b4856Slling zprop_desc_t *pd; 75990b4856Slling 76990b4856Slling pd = &prop_tbl[prop]; 77990b4856Slling 78990b4856Slling ASSERT(pd->pd_name == NULL || pd->pd_name == name); 79*b24ab676SJeff Bonwick ASSERT(name != NULL); 80*b24ab676SJeff Bonwick ASSERT(colname != NULL); 81990b4856Slling 82990b4856Slling pd->pd_name = name; 83990b4856Slling pd->pd_propnum = prop; 84990b4856Slling pd->pd_proptype = type; 85990b4856Slling pd->pd_numdefault = numdefault; 86990b4856Slling pd->pd_strdefault = strdefault; 87990b4856Slling pd->pd_attr = attr; 88990b4856Slling pd->pd_types = objset_types; 89990b4856Slling pd->pd_values = values; 90990b4856Slling pd->pd_colname = colname; 91990b4856Slling pd->pd_rightalign = rightalign; 92990b4856Slling pd->pd_visible = visible; 93990b4856Slling pd->pd_table = idx_tbl; 94*b24ab676SJeff Bonwick pd->pd_table_size = 0; 95*b24ab676SJeff Bonwick while (idx_tbl && (idx_tbl++)->pi_name != NULL) 96*b24ab676SJeff Bonwick pd->pd_table_size++; 97990b4856Slling } 98990b4856Slling 99990b4856Slling void 100990b4856Slling register_string(int prop, const char *name, const char *def, 101990b4856Slling zprop_attr_t attr, int objset_types, const char *values, 102990b4856Slling const char *colname) 103990b4856Slling { 104990b4856Slling register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, 105990b4856Slling objset_types, values, colname, B_FALSE, B_TRUE, NULL); 106990b4856Slling 107990b4856Slling } 108990b4856Slling 109990b4856Slling void 110990b4856Slling register_number(int prop, const char *name, uint64_t def, zprop_attr_t attr, 111990b4856Slling int objset_types, const char *values, const char *colname) 112990b4856Slling { 113990b4856Slling register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 114990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, NULL); 115990b4856Slling } 116990b4856Slling 117990b4856Slling void 118990b4856Slling register_index(int prop, const char *name, uint64_t def, zprop_attr_t attr, 119990b4856Slling int objset_types, const char *values, const char *colname, 120990b4856Slling const zprop_index_t *idx_tbl) 121990b4856Slling { 122990b4856Slling register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 123990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); 124990b4856Slling } 125990b4856Slling 126990b4856Slling void 127990b4856Slling register_hidden(int prop, const char *name, zprop_type_t type, 128990b4856Slling zprop_attr_t attr, int objset_types, const char *colname) 129990b4856Slling { 130990b4856Slling register_impl(prop, name, type, 0, NULL, attr, 131990b4856Slling objset_types, NULL, colname, B_FALSE, B_FALSE, NULL); 132990b4856Slling } 133990b4856Slling 134990b4856Slling 135990b4856Slling /* 136990b4856Slling * A comparison function we can use to order indexes into property tables. 137990b4856Slling */ 138990b4856Slling static int 139990b4856Slling zprop_compare(const void *arg1, const void *arg2) 140990b4856Slling { 141990b4856Slling const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 142990b4856Slling const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 143990b4856Slling boolean_t p1ro, p2ro; 144990b4856Slling 145990b4856Slling p1ro = (p1->pd_attr == PROP_READONLY); 146990b4856Slling p2ro = (p2->pd_attr == PROP_READONLY); 147990b4856Slling 148990b4856Slling if (p1ro == p2ro) 149990b4856Slling return (strcmp(p1->pd_name, p2->pd_name)); 150990b4856Slling 151990b4856Slling return (p1ro ? -1 : 1); 152990b4856Slling } 153990b4856Slling 154990b4856Slling /* 155990b4856Slling * Iterate over all properties in the given property table, calling back 156990b4856Slling * into the specified function for each property. We will continue to 157990b4856Slling * iterate until we either reach the end or the callback function returns 158990b4856Slling * something other than ZPROP_CONT. 159990b4856Slling */ 160990b4856Slling int 161990b4856Slling zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 162990b4856Slling boolean_t ordered, zfs_type_t type) 163990b4856Slling { 164990b4856Slling int i, num_props, size, prop; 165990b4856Slling zprop_desc_t *prop_tbl; 166990b4856Slling zprop_desc_t **order; 167990b4856Slling 168990b4856Slling prop_tbl = zprop_get_proptable(type); 169990b4856Slling num_props = zprop_get_numprops(type); 170990b4856Slling size = num_props * sizeof (zprop_desc_t *); 171990b4856Slling 172990b4856Slling #if defined(_KERNEL) 173990b4856Slling order = kmem_alloc(size, KM_SLEEP); 174990b4856Slling #else 175990b4856Slling if ((order = malloc(size)) == NULL) 176990b4856Slling return (ZPROP_CONT); 177990b4856Slling #endif 178990b4856Slling 179990b4856Slling for (int j = 0; j < num_props; j++) 180990b4856Slling order[j] = &prop_tbl[j]; 181990b4856Slling 182990b4856Slling if (ordered) { 183990b4856Slling qsort((void *)order, num_props, sizeof (zprop_desc_t *), 184990b4856Slling zprop_compare); 185990b4856Slling } 186990b4856Slling 187990b4856Slling prop = ZPROP_CONT; 188990b4856Slling for (i = 0; i < num_props; i++) { 189990b4856Slling if ((order[i]->pd_visible || show_all) && 190990b4856Slling (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 191990b4856Slling prop = order[i]->pd_propnum; 192990b4856Slling break; 193990b4856Slling } 194990b4856Slling } 195990b4856Slling 196990b4856Slling #if defined(_KERNEL) 197990b4856Slling kmem_free(order, size); 198990b4856Slling #else 199990b4856Slling free(order); 200990b4856Slling #endif 201990b4856Slling return (prop); 202990b4856Slling } 203990b4856Slling 204990b4856Slling static boolean_t 205990b4856Slling propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 206990b4856Slling { 207990b4856Slling const char *propname = prop_entry->pd_name; 208990b4856Slling #ifndef _KERNEL 209990b4856Slling const char *colname = prop_entry->pd_colname; 210990b4856Slling int c; 211990b4856Slling #endif 212990b4856Slling 213990b4856Slling if (len == strlen(propname) && 214990b4856Slling strncmp(p, propname, len) == 0) 215990b4856Slling return (B_TRUE); 216990b4856Slling 217990b4856Slling #ifndef _KERNEL 21814843421SMatthew Ahrens if (colname == NULL || len != strlen(colname)) 219990b4856Slling return (B_FALSE); 220990b4856Slling 221990b4856Slling for (c = 0; c < len; c++) 222990b4856Slling if (p[c] != tolower(colname[c])) 223990b4856Slling break; 224990b4856Slling 225990b4856Slling return (colname[c] == '\0'); 226990b4856Slling #else 227990b4856Slling return (B_FALSE); 228990b4856Slling #endif 229990b4856Slling } 230990b4856Slling 231990b4856Slling typedef struct name_to_prop_cb { 232990b4856Slling const char *propname; 233990b4856Slling zprop_desc_t *prop_tbl; 234990b4856Slling } name_to_prop_cb_t; 235990b4856Slling 236990b4856Slling static int 237990b4856Slling zprop_name_to_prop_cb(int prop, void *cb_data) 238990b4856Slling { 239990b4856Slling name_to_prop_cb_t *data = cb_data; 240990b4856Slling 241990b4856Slling if (propname_match(data->propname, strlen(data->propname), 242990b4856Slling &data->prop_tbl[prop])) 243990b4856Slling return (prop); 244990b4856Slling 245990b4856Slling return (ZPROP_CONT); 246990b4856Slling } 247990b4856Slling 248990b4856Slling int 249990b4856Slling zprop_name_to_prop(const char *propname, zfs_type_t type) 250990b4856Slling { 251990b4856Slling int prop; 252990b4856Slling name_to_prop_cb_t cb_data; 253990b4856Slling 254990b4856Slling cb_data.propname = propname; 255990b4856Slling cb_data.prop_tbl = zprop_get_proptable(type); 256990b4856Slling 257990b4856Slling prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 258990b4856Slling B_TRUE, B_FALSE, type); 259990b4856Slling 260990b4856Slling return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 261990b4856Slling } 262990b4856Slling 263990b4856Slling int 264990b4856Slling zprop_string_to_index(int prop, const char *string, uint64_t *index, 265990b4856Slling zfs_type_t type) 266990b4856Slling { 267990b4856Slling zprop_desc_t *prop_tbl; 268990b4856Slling const zprop_index_t *idx_tbl; 269990b4856Slling int i; 270990b4856Slling 27179912923Sgw if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 27279912923Sgw return (-1); 27379912923Sgw 27479912923Sgw ASSERT(prop < zprop_get_numprops(type)); 275990b4856Slling prop_tbl = zprop_get_proptable(type); 276990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 277990b4856Slling return (-1); 278990b4856Slling 279990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 280990b4856Slling if (strcmp(string, idx_tbl[i].pi_name) == 0) { 281990b4856Slling *index = idx_tbl[i].pi_value; 282990b4856Slling return (0); 283990b4856Slling } 284990b4856Slling } 285990b4856Slling 286990b4856Slling return (-1); 287990b4856Slling } 288990b4856Slling 289990b4856Slling int 290990b4856Slling zprop_index_to_string(int prop, uint64_t index, const char **string, 291990b4856Slling zfs_type_t type) 292990b4856Slling { 293990b4856Slling zprop_desc_t *prop_tbl; 294990b4856Slling const zprop_index_t *idx_tbl; 295990b4856Slling int i; 296990b4856Slling 29779912923Sgw if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 29879912923Sgw return (-1); 29979912923Sgw 30079912923Sgw ASSERT(prop < zprop_get_numprops(type)); 301990b4856Slling prop_tbl = zprop_get_proptable(type); 302990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 303990b4856Slling return (-1); 304990b4856Slling 305990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 306990b4856Slling if (idx_tbl[i].pi_value == index) { 307990b4856Slling *string = idx_tbl[i].pi_name; 308990b4856Slling return (0); 309990b4856Slling } 310990b4856Slling } 311990b4856Slling 312990b4856Slling return (-1); 313990b4856Slling } 314990b4856Slling 315*b24ab676SJeff Bonwick /* 316*b24ab676SJeff Bonwick * Return a random valid property value. Used by ztest. 317*b24ab676SJeff Bonwick */ 318*b24ab676SJeff Bonwick uint64_t 319*b24ab676SJeff Bonwick zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 320*b24ab676SJeff Bonwick { 321*b24ab676SJeff Bonwick zprop_desc_t *prop_tbl; 322*b24ab676SJeff Bonwick const zprop_index_t *idx_tbl; 323*b24ab676SJeff Bonwick 324*b24ab676SJeff Bonwick ASSERT((uint_t)prop < zprop_get_numprops(type)); 325*b24ab676SJeff Bonwick prop_tbl = zprop_get_proptable(type); 326*b24ab676SJeff Bonwick idx_tbl = prop_tbl[prop].pd_table; 327*b24ab676SJeff Bonwick 328*b24ab676SJeff Bonwick if (idx_tbl == NULL) 329*b24ab676SJeff Bonwick return (seed); 330*b24ab676SJeff Bonwick 331*b24ab676SJeff Bonwick return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 332*b24ab676SJeff Bonwick } 333*b24ab676SJeff Bonwick 334990b4856Slling const char * 335990b4856Slling zprop_values(int prop, zfs_type_t type) 336990b4856Slling { 337990b4856Slling zprop_desc_t *prop_tbl; 338990b4856Slling 33979912923Sgw ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 34079912923Sgw ASSERT(prop < zprop_get_numprops(type)); 34179912923Sgw 342990b4856Slling prop_tbl = zprop_get_proptable(type); 343990b4856Slling 344990b4856Slling return (prop_tbl[prop].pd_values); 345990b4856Slling } 346990b4856Slling 347990b4856Slling /* 348990b4856Slling * Returns TRUE if the property applies to any of the given dataset types. 349990b4856Slling */ 35079912923Sgw boolean_t 351990b4856Slling zprop_valid_for_type(int prop, zfs_type_t type) 352990b4856Slling { 35379912923Sgw zprop_desc_t *prop_tbl; 35479912923Sgw 35579912923Sgw if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 35679912923Sgw return (B_FALSE); 357990b4856Slling 35879912923Sgw ASSERT(prop < zprop_get_numprops(type)); 35979912923Sgw prop_tbl = zprop_get_proptable(type); 360990b4856Slling return ((prop_tbl[prop].pd_types & type) != 0); 361990b4856Slling } 362990b4856Slling 363990b4856Slling #ifndef _KERNEL 364990b4856Slling 365990b4856Slling /* 366990b4856Slling * Determines the minimum width for the column, and indicates whether it's fixed 367990b4856Slling * or not. Only string columns are non-fixed. 368990b4856Slling */ 369990b4856Slling size_t 370990b4856Slling zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 371990b4856Slling { 372990b4856Slling zprop_desc_t *prop_tbl, *pd; 373990b4856Slling const zprop_index_t *idx; 374990b4856Slling size_t ret; 375990b4856Slling int i; 376990b4856Slling 37779912923Sgw ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 37879912923Sgw ASSERT(prop < zprop_get_numprops(type)); 37979912923Sgw 380990b4856Slling prop_tbl = zprop_get_proptable(type); 381990b4856Slling pd = &prop_tbl[prop]; 382990b4856Slling 383990b4856Slling *fixed = B_TRUE; 384990b4856Slling 385990b4856Slling /* 386990b4856Slling * Start with the width of the column name. 387990b4856Slling */ 388990b4856Slling ret = strlen(pd->pd_colname); 389990b4856Slling 390990b4856Slling /* 391990b4856Slling * For fixed-width values, make sure the width is large enough to hold 392990b4856Slling * any possible value. 393990b4856Slling */ 394990b4856Slling switch (pd->pd_proptype) { 395990b4856Slling case PROP_TYPE_NUMBER: 396990b4856Slling /* 397990b4856Slling * The maximum length of a human-readable number is 5 characters 398990b4856Slling * ("20.4M", for example). 399990b4856Slling */ 400990b4856Slling if (ret < 5) 401990b4856Slling ret = 5; 402990b4856Slling /* 403990b4856Slling * 'creation' is handled specially because it's a number 404990b4856Slling * internally, but displayed as a date string. 405990b4856Slling */ 406990b4856Slling if (prop == ZFS_PROP_CREATION) 407990b4856Slling *fixed = B_FALSE; 408990b4856Slling break; 409990b4856Slling case PROP_TYPE_INDEX: 410990b4856Slling idx = prop_tbl[prop].pd_table; 411990b4856Slling for (i = 0; idx[i].pi_name != NULL; i++) { 412990b4856Slling if (strlen(idx[i].pi_name) > ret) 413990b4856Slling ret = strlen(idx[i].pi_name); 414990b4856Slling } 415990b4856Slling break; 416990b4856Slling 417990b4856Slling case PROP_TYPE_STRING: 418990b4856Slling *fixed = B_FALSE; 419990b4856Slling break; 420990b4856Slling } 421990b4856Slling 422990b4856Slling return (ret); 423990b4856Slling } 424990b4856Slling 425990b4856Slling #endif 426