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 /* 22*83d7f9feSTom Erickson * Copyright 2010 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 68*83d7f9feSTom Erickson zprop_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); 79b24ab676SJeff Bonwick ASSERT(name != NULL); 80b24ab676SJeff 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; 94b24ab676SJeff Bonwick pd->pd_table_size = 0; 95b24ab676SJeff Bonwick while (idx_tbl && (idx_tbl++)->pi_name != NULL) 96b24ab676SJeff Bonwick pd->pd_table_size++; 97990b4856Slling } 98990b4856Slling 99990b4856Slling void 100*83d7f9feSTom Erickson zprop_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 { 104*83d7f9feSTom Erickson zprop_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 110*83d7f9feSTom Erickson zprop_register_number(int prop, const char *name, uint64_t def, 111*83d7f9feSTom Erickson zprop_attr_t attr, int objset_types, const char *values, 112*83d7f9feSTom Erickson const char *colname) 113990b4856Slling { 114*83d7f9feSTom Erickson zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 115990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, NULL); 116990b4856Slling } 117990b4856Slling 118990b4856Slling void 119*83d7f9feSTom Erickson zprop_register_index(int prop, const char *name, uint64_t def, 120*83d7f9feSTom Erickson zprop_attr_t attr, int objset_types, const char *values, 121*83d7f9feSTom Erickson const char *colname, const zprop_index_t *idx_tbl) 122990b4856Slling { 123*83d7f9feSTom Erickson zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 124990b4856Slling objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); 125990b4856Slling } 126990b4856Slling 127990b4856Slling void 128*83d7f9feSTom Erickson zprop_register_hidden(int prop, const char *name, zprop_type_t type, 129990b4856Slling zprop_attr_t attr, int objset_types, const char *colname) 130990b4856Slling { 131*83d7f9feSTom Erickson zprop_register_impl(prop, name, type, 0, NULL, attr, 132990b4856Slling objset_types, NULL, colname, B_FALSE, B_FALSE, NULL); 133990b4856Slling } 134990b4856Slling 135990b4856Slling 136990b4856Slling /* 137990b4856Slling * A comparison function we can use to order indexes into property tables. 138990b4856Slling */ 139990b4856Slling static int 140990b4856Slling zprop_compare(const void *arg1, const void *arg2) 141990b4856Slling { 142990b4856Slling const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 143990b4856Slling const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 144990b4856Slling boolean_t p1ro, p2ro; 145990b4856Slling 146990b4856Slling p1ro = (p1->pd_attr == PROP_READONLY); 147990b4856Slling p2ro = (p2->pd_attr == PROP_READONLY); 148990b4856Slling 149990b4856Slling if (p1ro == p2ro) 150990b4856Slling return (strcmp(p1->pd_name, p2->pd_name)); 151990b4856Slling 152990b4856Slling return (p1ro ? -1 : 1); 153990b4856Slling } 154990b4856Slling 155990b4856Slling /* 156990b4856Slling * Iterate over all properties in the given property table, calling back 157990b4856Slling * into the specified function for each property. We will continue to 158990b4856Slling * iterate until we either reach the end or the callback function returns 159990b4856Slling * something other than ZPROP_CONT. 160990b4856Slling */ 161990b4856Slling int 162990b4856Slling zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 163990b4856Slling boolean_t ordered, zfs_type_t type) 164990b4856Slling { 165990b4856Slling int i, num_props, size, prop; 166990b4856Slling zprop_desc_t *prop_tbl; 167990b4856Slling zprop_desc_t **order; 168990b4856Slling 169990b4856Slling prop_tbl = zprop_get_proptable(type); 170990b4856Slling num_props = zprop_get_numprops(type); 171990b4856Slling size = num_props * sizeof (zprop_desc_t *); 172990b4856Slling 173990b4856Slling #if defined(_KERNEL) 174990b4856Slling order = kmem_alloc(size, KM_SLEEP); 175990b4856Slling #else 176990b4856Slling if ((order = malloc(size)) == NULL) 177990b4856Slling return (ZPROP_CONT); 178990b4856Slling #endif 179990b4856Slling 180990b4856Slling for (int j = 0; j < num_props; j++) 181990b4856Slling order[j] = &prop_tbl[j]; 182990b4856Slling 183990b4856Slling if (ordered) { 184990b4856Slling qsort((void *)order, num_props, sizeof (zprop_desc_t *), 185990b4856Slling zprop_compare); 186990b4856Slling } 187990b4856Slling 188990b4856Slling prop = ZPROP_CONT; 189990b4856Slling for (i = 0; i < num_props; i++) { 190990b4856Slling if ((order[i]->pd_visible || show_all) && 191990b4856Slling (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 192990b4856Slling prop = order[i]->pd_propnum; 193990b4856Slling break; 194990b4856Slling } 195990b4856Slling } 196990b4856Slling 197990b4856Slling #if defined(_KERNEL) 198990b4856Slling kmem_free(order, size); 199990b4856Slling #else 200990b4856Slling free(order); 201990b4856Slling #endif 202990b4856Slling return (prop); 203990b4856Slling } 204990b4856Slling 205990b4856Slling static boolean_t 206990b4856Slling propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 207990b4856Slling { 208990b4856Slling const char *propname = prop_entry->pd_name; 209990b4856Slling #ifndef _KERNEL 210990b4856Slling const char *colname = prop_entry->pd_colname; 211990b4856Slling int c; 212990b4856Slling #endif 213990b4856Slling 214990b4856Slling if (len == strlen(propname) && 215990b4856Slling strncmp(p, propname, len) == 0) 216990b4856Slling return (B_TRUE); 217990b4856Slling 218990b4856Slling #ifndef _KERNEL 21914843421SMatthew Ahrens if (colname == NULL || len != strlen(colname)) 220990b4856Slling return (B_FALSE); 221990b4856Slling 222990b4856Slling for (c = 0; c < len; c++) 223990b4856Slling if (p[c] != tolower(colname[c])) 224990b4856Slling break; 225990b4856Slling 226990b4856Slling return (colname[c] == '\0'); 227990b4856Slling #else 228990b4856Slling return (B_FALSE); 229990b4856Slling #endif 230990b4856Slling } 231990b4856Slling 232990b4856Slling typedef struct name_to_prop_cb { 233990b4856Slling const char *propname; 234990b4856Slling zprop_desc_t *prop_tbl; 235990b4856Slling } name_to_prop_cb_t; 236990b4856Slling 237990b4856Slling static int 238990b4856Slling zprop_name_to_prop_cb(int prop, void *cb_data) 239990b4856Slling { 240990b4856Slling name_to_prop_cb_t *data = cb_data; 241990b4856Slling 242990b4856Slling if (propname_match(data->propname, strlen(data->propname), 243990b4856Slling &data->prop_tbl[prop])) 244990b4856Slling return (prop); 245990b4856Slling 246990b4856Slling return (ZPROP_CONT); 247990b4856Slling } 248990b4856Slling 249990b4856Slling int 250990b4856Slling zprop_name_to_prop(const char *propname, zfs_type_t type) 251990b4856Slling { 252990b4856Slling int prop; 253990b4856Slling name_to_prop_cb_t cb_data; 254990b4856Slling 255990b4856Slling cb_data.propname = propname; 256990b4856Slling cb_data.prop_tbl = zprop_get_proptable(type); 257990b4856Slling 258990b4856Slling prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 259990b4856Slling B_TRUE, B_FALSE, type); 260990b4856Slling 261990b4856Slling return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 262990b4856Slling } 263990b4856Slling 264990b4856Slling int 265990b4856Slling zprop_string_to_index(int prop, const char *string, uint64_t *index, 266990b4856Slling zfs_type_t type) 267990b4856Slling { 268990b4856Slling zprop_desc_t *prop_tbl; 269990b4856Slling const zprop_index_t *idx_tbl; 270990b4856Slling int i; 271990b4856Slling 27279912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 27379912923Sgw25295 return (-1); 27479912923Sgw25295 27579912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 276990b4856Slling prop_tbl = zprop_get_proptable(type); 277990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 278990b4856Slling return (-1); 279990b4856Slling 280990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 281990b4856Slling if (strcmp(string, idx_tbl[i].pi_name) == 0) { 282990b4856Slling *index = idx_tbl[i].pi_value; 283990b4856Slling return (0); 284990b4856Slling } 285990b4856Slling } 286990b4856Slling 287990b4856Slling return (-1); 288990b4856Slling } 289990b4856Slling 290990b4856Slling int 291990b4856Slling zprop_index_to_string(int prop, uint64_t index, const char **string, 292990b4856Slling zfs_type_t type) 293990b4856Slling { 294990b4856Slling zprop_desc_t *prop_tbl; 295990b4856Slling const zprop_index_t *idx_tbl; 296990b4856Slling int i; 297990b4856Slling 29879912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 29979912923Sgw25295 return (-1); 30079912923Sgw25295 30179912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 302990b4856Slling prop_tbl = zprop_get_proptable(type); 303990b4856Slling if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 304990b4856Slling return (-1); 305990b4856Slling 306990b4856Slling for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 307990b4856Slling if (idx_tbl[i].pi_value == index) { 308990b4856Slling *string = idx_tbl[i].pi_name; 309990b4856Slling return (0); 310990b4856Slling } 311990b4856Slling } 312990b4856Slling 313990b4856Slling return (-1); 314990b4856Slling } 315990b4856Slling 316b24ab676SJeff Bonwick /* 317b24ab676SJeff Bonwick * Return a random valid property value. Used by ztest. 318b24ab676SJeff Bonwick */ 319b24ab676SJeff Bonwick uint64_t 320b24ab676SJeff Bonwick zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 321b24ab676SJeff Bonwick { 322b24ab676SJeff Bonwick zprop_desc_t *prop_tbl; 323b24ab676SJeff Bonwick const zprop_index_t *idx_tbl; 324b24ab676SJeff Bonwick 325b24ab676SJeff Bonwick ASSERT((uint_t)prop < zprop_get_numprops(type)); 326b24ab676SJeff Bonwick prop_tbl = zprop_get_proptable(type); 327b24ab676SJeff Bonwick idx_tbl = prop_tbl[prop].pd_table; 328b24ab676SJeff Bonwick 329b24ab676SJeff Bonwick if (idx_tbl == NULL) 330b24ab676SJeff Bonwick return (seed); 331b24ab676SJeff Bonwick 332b24ab676SJeff Bonwick return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 333b24ab676SJeff Bonwick } 334b24ab676SJeff Bonwick 335990b4856Slling const char * 336990b4856Slling zprop_values(int prop, zfs_type_t type) 337990b4856Slling { 338990b4856Slling zprop_desc_t *prop_tbl; 339990b4856Slling 34079912923Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 34179912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 34279912923Sgw25295 343990b4856Slling prop_tbl = zprop_get_proptable(type); 344990b4856Slling 345990b4856Slling return (prop_tbl[prop].pd_values); 346990b4856Slling } 347990b4856Slling 348990b4856Slling /* 349990b4856Slling * Returns TRUE if the property applies to any of the given dataset types. 350990b4856Slling */ 35179912923Sgw25295 boolean_t 352990b4856Slling zprop_valid_for_type(int prop, zfs_type_t type) 353990b4856Slling { 35479912923Sgw25295 zprop_desc_t *prop_tbl; 355990b4856Slling 35679912923Sgw25295 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 35779912923Sgw25295 return (B_FALSE); 35879912923Sgw25295 35979912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 36079912923Sgw25295 prop_tbl = zprop_get_proptable(type); 361990b4856Slling return ((prop_tbl[prop].pd_types & type) != 0); 362990b4856Slling } 363990b4856Slling 364990b4856Slling #ifndef _KERNEL 365990b4856Slling 366990b4856Slling /* 367990b4856Slling * Determines the minimum width for the column, and indicates whether it's fixed 368990b4856Slling * or not. Only string columns are non-fixed. 369990b4856Slling */ 370990b4856Slling size_t 371990b4856Slling zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 372990b4856Slling { 373990b4856Slling zprop_desc_t *prop_tbl, *pd; 374990b4856Slling const zprop_index_t *idx; 375990b4856Slling size_t ret; 376990b4856Slling int i; 377990b4856Slling 37879912923Sgw25295 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 37979912923Sgw25295 ASSERT(prop < zprop_get_numprops(type)); 38079912923Sgw25295 381990b4856Slling prop_tbl = zprop_get_proptable(type); 382990b4856Slling pd = &prop_tbl[prop]; 383990b4856Slling 384990b4856Slling *fixed = B_TRUE; 385990b4856Slling 386990b4856Slling /* 387990b4856Slling * Start with the width of the column name. 388990b4856Slling */ 389990b4856Slling ret = strlen(pd->pd_colname); 390990b4856Slling 391990b4856Slling /* 392990b4856Slling * For fixed-width values, make sure the width is large enough to hold 393990b4856Slling * any possible value. 394990b4856Slling */ 395990b4856Slling switch (pd->pd_proptype) { 396990b4856Slling case PROP_TYPE_NUMBER: 397990b4856Slling /* 398990b4856Slling * The maximum length of a human-readable number is 5 characters 399990b4856Slling * ("20.4M", for example). 400990b4856Slling */ 401990b4856Slling if (ret < 5) 402990b4856Slling ret = 5; 403990b4856Slling /* 404990b4856Slling * 'creation' is handled specially because it's a number 405990b4856Slling * internally, but displayed as a date string. 406990b4856Slling */ 407990b4856Slling if (prop == ZFS_PROP_CREATION) 408990b4856Slling *fixed = B_FALSE; 409990b4856Slling break; 410990b4856Slling case PROP_TYPE_INDEX: 411990b4856Slling idx = prop_tbl[prop].pd_table; 412990b4856Slling for (i = 0; idx[i].pi_name != NULL; i++) { 413990b4856Slling if (strlen(idx[i].pi_name) > ret) 414990b4856Slling ret = strlen(idx[i].pi_name); 415990b4856Slling } 416990b4856Slling break; 417990b4856Slling 418990b4856Slling case PROP_TYPE_STRING: 419990b4856Slling *fixed = B_FALSE; 420990b4856Slling break; 421990b4856Slling } 422990b4856Slling 423990b4856Slling return (ret); 424990b4856Slling } 425990b4856Slling 426990b4856Slling #endif 427