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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2012 by Delphix. All rights reserved. 27 */ 28 29 /* 30 * Common routines used by zfs and zpool property management. 31 */ 32 33 #include <sys/zio.h> 34 #include <sys/spa.h> 35 #include <sys/zfs_acl.h> 36 #include <sys/zfs_ioctl.h> 37 #include <sys/zfs_znode.h> 38 #include <sys/fs/zfs.h> 39 40 #include "zfs_prop.h" 41 #include "zfs_deleg.h" 42 43 #if defined(_KERNEL) 44 #include <sys/systm.h> 45 #ifdef __FreeBSD__ 46 #include <sys/libkern.h> 47 #else 48 #include <util/qsort.h> 49 #endif 50 #else 51 #include <stdlib.h> 52 #include <string.h> 53 #include <ctype.h> 54 #endif 55 56 static zprop_desc_t * 57 zprop_get_proptable(zfs_type_t type) 58 { 59 if (type == ZFS_TYPE_POOL) 60 return (zpool_prop_get_table()); 61 else 62 return (zfs_prop_get_table()); 63 } 64 65 static int 66 zprop_get_numprops(zfs_type_t type) 67 { 68 if (type == ZFS_TYPE_POOL) 69 return (ZPOOL_NUM_PROPS); 70 else 71 return (ZFS_NUM_PROPS); 72 } 73 74 void 75 zprop_register_impl(int prop, const char *name, zprop_type_t type, 76 uint64_t numdefault, const char *strdefault, zprop_attr_t attr, 77 int objset_types, const char *values, const char *colname, 78 boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl) 79 { 80 zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); 81 zprop_desc_t *pd; 82 83 pd = &prop_tbl[prop]; 84 85 ASSERT(pd->pd_name == NULL || pd->pd_name == name); 86 ASSERT(name != NULL); 87 ASSERT(colname != NULL); 88 89 pd->pd_name = name; 90 pd->pd_propnum = prop; 91 pd->pd_proptype = type; 92 pd->pd_numdefault = numdefault; 93 pd->pd_strdefault = strdefault; 94 pd->pd_attr = attr; 95 pd->pd_types = objset_types; 96 pd->pd_values = values; 97 pd->pd_colname = colname; 98 pd->pd_rightalign = rightalign; 99 pd->pd_visible = visible; 100 pd->pd_table = idx_tbl; 101 pd->pd_table_size = 0; 102 while (idx_tbl && (idx_tbl++)->pi_name != NULL) 103 pd->pd_table_size++; 104 } 105 106 void 107 zprop_register_string(int prop, const char *name, const char *def, 108 zprop_attr_t attr, int objset_types, const char *values, 109 const char *colname) 110 { 111 zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, 112 objset_types, values, colname, B_FALSE, B_TRUE, NULL); 113 114 } 115 116 void 117 zprop_register_number(int prop, const char *name, uint64_t def, 118 zprop_attr_t attr, int objset_types, const char *values, 119 const char *colname) 120 { 121 zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 122 objset_types, values, colname, B_TRUE, B_TRUE, NULL); 123 } 124 125 void 126 zprop_register_index(int prop, const char *name, uint64_t def, 127 zprop_attr_t attr, int objset_types, const char *values, 128 const char *colname, const zprop_index_t *idx_tbl) 129 { 130 zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 131 objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); 132 } 133 134 void 135 zprop_register_hidden(int prop, const char *name, zprop_type_t type, 136 zprop_attr_t attr, int objset_types, const char *colname) 137 { 138 zprop_register_impl(prop, name, type, 0, NULL, attr, 139 objset_types, NULL, colname, 140 type == PROP_TYPE_NUMBER, B_FALSE, NULL); 141 } 142 143 144 /* 145 * A comparison function we can use to order indexes into property tables. 146 */ 147 static int 148 zprop_compare(const void *arg1, const void *arg2) 149 { 150 const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 151 const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 152 boolean_t p1ro, p2ro; 153 154 p1ro = (p1->pd_attr == PROP_READONLY); 155 p2ro = (p2->pd_attr == PROP_READONLY); 156 157 if (p1ro == p2ro) 158 return (strcmp(p1->pd_name, p2->pd_name)); 159 160 return (p1ro ? -1 : 1); 161 } 162 163 /* 164 * Iterate over all properties in the given property table, calling back 165 * into the specified function for each property. We will continue to 166 * iterate until we either reach the end or the callback function returns 167 * something other than ZPROP_CONT. 168 */ 169 int 170 zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 171 boolean_t ordered, zfs_type_t type) 172 { 173 int i, j, num_props, size, prop; 174 zprop_desc_t *prop_tbl; 175 zprop_desc_t **order; 176 177 prop_tbl = zprop_get_proptable(type); 178 num_props = zprop_get_numprops(type); 179 size = num_props * sizeof (zprop_desc_t *); 180 181 #if defined(_KERNEL) 182 order = kmem_alloc(size, KM_SLEEP); 183 #else 184 if ((order = malloc(size)) == NULL) 185 return (ZPROP_CONT); 186 #endif 187 188 for (j = 0; j < num_props; j++) 189 order[j] = &prop_tbl[j]; 190 191 if (ordered) { 192 qsort((void *)order, num_props, sizeof (zprop_desc_t *), 193 zprop_compare); 194 } 195 196 prop = ZPROP_CONT; 197 for (i = 0; i < num_props; i++) { 198 if ((order[i]->pd_visible || show_all) && 199 (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 200 prop = order[i]->pd_propnum; 201 break; 202 } 203 } 204 205 #if defined(_KERNEL) 206 kmem_free(order, size); 207 #else 208 free(order); 209 #endif 210 return (prop); 211 } 212 213 static boolean_t 214 propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 215 { 216 const char *propname = prop_entry->pd_name; 217 #ifndef _KERNEL 218 const char *colname = prop_entry->pd_colname; 219 int c; 220 #endif 221 222 if (len == strlen(propname) && 223 strncmp(p, propname, len) == 0) 224 return (B_TRUE); 225 226 #ifndef _KERNEL 227 if (colname == NULL || len != strlen(colname)) 228 return (B_FALSE); 229 230 for (c = 0; c < len; c++) 231 if (p[c] != tolower(colname[c])) 232 break; 233 234 return (colname[c] == '\0'); 235 #else 236 return (B_FALSE); 237 #endif 238 } 239 240 typedef struct name_to_prop_cb { 241 const char *propname; 242 zprop_desc_t *prop_tbl; 243 } name_to_prop_cb_t; 244 245 static int 246 zprop_name_to_prop_cb(int prop, void *cb_data) 247 { 248 name_to_prop_cb_t *data = cb_data; 249 250 if (propname_match(data->propname, strlen(data->propname), 251 &data->prop_tbl[prop])) 252 return (prop); 253 254 return (ZPROP_CONT); 255 } 256 257 int 258 zprop_name_to_prop(const char *propname, zfs_type_t type) 259 { 260 int prop; 261 name_to_prop_cb_t cb_data; 262 263 cb_data.propname = propname; 264 cb_data.prop_tbl = zprop_get_proptable(type); 265 266 prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 267 B_TRUE, B_FALSE, type); 268 269 return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 270 } 271 272 int 273 zprop_string_to_index(int prop, const char *string, uint64_t *index, 274 zfs_type_t type) 275 { 276 zprop_desc_t *prop_tbl; 277 const zprop_index_t *idx_tbl; 278 int i; 279 280 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 281 return (-1); 282 283 ASSERT(prop < zprop_get_numprops(type)); 284 prop_tbl = zprop_get_proptable(type); 285 if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 286 return (-1); 287 288 for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 289 if (strcmp(string, idx_tbl[i].pi_name) == 0) { 290 *index = idx_tbl[i].pi_value; 291 return (0); 292 } 293 } 294 295 return (-1); 296 } 297 298 int 299 zprop_index_to_string(int prop, uint64_t index, const char **string, 300 zfs_type_t type) 301 { 302 zprop_desc_t *prop_tbl; 303 const zprop_index_t *idx_tbl; 304 int i; 305 306 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 307 return (-1); 308 309 ASSERT(prop < zprop_get_numprops(type)); 310 prop_tbl = zprop_get_proptable(type); 311 if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 312 return (-1); 313 314 for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 315 if (idx_tbl[i].pi_value == index) { 316 *string = idx_tbl[i].pi_name; 317 return (0); 318 } 319 } 320 321 return (-1); 322 } 323 324 /* 325 * Return a random valid property value. Used by ztest. 326 */ 327 uint64_t 328 zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 329 { 330 zprop_desc_t *prop_tbl; 331 const zprop_index_t *idx_tbl; 332 333 ASSERT((uint_t)prop < zprop_get_numprops(type)); 334 prop_tbl = zprop_get_proptable(type); 335 idx_tbl = prop_tbl[prop].pd_table; 336 337 if (idx_tbl == NULL) 338 return (seed); 339 340 return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 341 } 342 343 const char * 344 zprop_values(int prop, zfs_type_t type) 345 { 346 zprop_desc_t *prop_tbl; 347 348 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 349 ASSERT(prop < zprop_get_numprops(type)); 350 351 prop_tbl = zprop_get_proptable(type); 352 353 return (prop_tbl[prop].pd_values); 354 } 355 356 /* 357 * Returns TRUE if the property applies to any of the given dataset types. 358 */ 359 boolean_t 360 zprop_valid_for_type(int prop, zfs_type_t type) 361 { 362 zprop_desc_t *prop_tbl; 363 364 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 365 return (B_FALSE); 366 367 ASSERT(prop < zprop_get_numprops(type)); 368 prop_tbl = zprop_get_proptable(type); 369 return ((prop_tbl[prop].pd_types & type) != 0); 370 } 371 372 #ifndef _KERNEL 373 374 /* 375 * Determines the minimum width for the column, and indicates whether it's fixed 376 * or not. Only string columns are non-fixed. 377 */ 378 size_t 379 zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 380 { 381 zprop_desc_t *prop_tbl, *pd; 382 const zprop_index_t *idx; 383 size_t ret; 384 int i; 385 386 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 387 ASSERT(prop < zprop_get_numprops(type)); 388 389 prop_tbl = zprop_get_proptable(type); 390 pd = &prop_tbl[prop]; 391 392 *fixed = B_TRUE; 393 394 /* 395 * Start with the width of the column name. 396 */ 397 ret = strlen(pd->pd_colname); 398 399 /* 400 * For fixed-width values, make sure the width is large enough to hold 401 * any possible value. 402 */ 403 switch (pd->pd_proptype) { 404 case PROP_TYPE_NUMBER: 405 /* 406 * The maximum length of a human-readable number is 5 characters 407 * ("20.4M", for example). 408 */ 409 if (ret < 5) 410 ret = 5; 411 /* 412 * 'creation' is handled specially because it's a number 413 * internally, but displayed as a date string. 414 */ 415 if (prop == ZFS_PROP_CREATION) 416 *fixed = B_FALSE; 417 break; 418 case PROP_TYPE_INDEX: 419 idx = prop_tbl[prop].pd_table; 420 for (i = 0; idx[i].pi_name != NULL; i++) { 421 if (strlen(idx[i].pi_name) > ret) 422 ret = strlen(idx[i].pi_name); 423 } 424 break; 425 426 case PROP_TYPE_STRING: 427 *fixed = B_FALSE; 428 break; 429 } 430 431 return (ret); 432 } 433 434 #endif 435