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_sysfs.h> 38 #include <sys/zfs_znode.h> 39 #include <sys/fs/zfs.h> 40 41 #include "zfs_prop.h" 42 #include "zfs_deleg.h" 43 44 #if !defined(_KERNEL) 45 #include <stdlib.h> 46 #include <string.h> 47 #include <ctype.h> 48 #include <sys/stat.h> 49 #endif 50 51 static zprop_desc_t * 52 zprop_get_proptable(zfs_type_t type) 53 { 54 if (type == ZFS_TYPE_POOL) 55 return (zpool_prop_get_table()); 56 else if (type == ZFS_TYPE_VDEV) 57 return (vdev_prop_get_table()); 58 else 59 return (zfs_prop_get_table()); 60 } 61 62 static int 63 zprop_get_numprops(zfs_type_t type) 64 { 65 if (type == ZFS_TYPE_POOL) 66 return (ZPOOL_NUM_PROPS); 67 else if (type == ZFS_TYPE_VDEV) 68 return (VDEV_NUM_PROPS); 69 else 70 return (ZFS_NUM_PROPS); 71 } 72 73 static boolean_t 74 zfs_mod_supported_prop(const char *name, zfs_type_t type, 75 const struct zfs_mod_supported_features *sfeatures) 76 { 77 /* 78 * The zfs module spa_feature_table[], whether in-kernel or in libzpool, 79 * always supports all the properties. libzfs needs to query the running 80 * module, via sysfs, to determine which properties are supported. 81 * 82 * The equivalent _can_ be done on FreeBSD by way of the sysctl 83 * tree, but this has not been done yet. 84 */ 85 #if defined(_KERNEL) || defined(LIB_ZPOOL_BUILD) || defined(__FreeBSD__) 86 (void) name, (void) type, (void) sfeatures; 87 return (B_TRUE); 88 #else 89 return (zfs_mod_supported(type == ZFS_TYPE_POOL ? 90 ZFS_SYSFS_POOL_PROPERTIES : (type == ZFS_TYPE_VDEV ? 91 ZFS_SYSFS_VDEV_PROPERTIES : ZFS_SYSFS_DATASET_PROPERTIES), 92 name, sfeatures)); 93 #endif 94 } 95 96 void 97 zprop_register_impl(int prop, const char *name, zprop_type_t type, 98 uint64_t numdefault, const char *strdefault, zprop_attr_t attr, 99 int objset_types, const char *values, const char *colname, 100 boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl, 101 const struct zfs_mod_supported_features *sfeatures) 102 { 103 zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); 104 zprop_desc_t *pd; 105 106 pd = &prop_tbl[prop]; 107 108 ASSERT(pd->pd_name == NULL || pd->pd_name == name); 109 ASSERT(name != NULL); 110 ASSERT(colname != NULL); 111 112 pd->pd_name = name; 113 pd->pd_propnum = prop; 114 pd->pd_proptype = type; 115 pd->pd_numdefault = numdefault; 116 pd->pd_strdefault = strdefault; 117 pd->pd_attr = attr; 118 pd->pd_types = objset_types; 119 pd->pd_values = values; 120 pd->pd_colname = colname; 121 pd->pd_rightalign = rightalign; 122 pd->pd_visible = visible; 123 pd->pd_zfs_mod_supported = 124 zfs_mod_supported_prop(name, objset_types, sfeatures); 125 pd->pd_table = idx_tbl; 126 pd->pd_table_size = 0; 127 while (idx_tbl && (idx_tbl++)->pi_name != NULL) 128 pd->pd_table_size++; 129 } 130 131 void 132 zprop_register_string(int prop, const char *name, const char *def, 133 zprop_attr_t attr, int objset_types, const char *values, 134 const char *colname, const struct zfs_mod_supported_features *sfeatures) 135 { 136 zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, 137 objset_types, values, colname, B_FALSE, B_TRUE, NULL, sfeatures); 138 139 } 140 141 void 142 zprop_register_number(int prop, const char *name, uint64_t def, 143 zprop_attr_t attr, int objset_types, const char *values, 144 const char *colname, const struct zfs_mod_supported_features *sfeatures) 145 { 146 zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, 147 objset_types, values, colname, B_TRUE, B_TRUE, NULL, sfeatures); 148 } 149 150 void 151 zprop_register_index(int prop, const char *name, uint64_t def, 152 zprop_attr_t attr, int objset_types, const char *values, 153 const char *colname, const zprop_index_t *idx_tbl, 154 const struct zfs_mod_supported_features *sfeatures) 155 { 156 zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, 157 objset_types, values, colname, B_FALSE, B_TRUE, idx_tbl, sfeatures); 158 } 159 160 void 161 zprop_register_hidden(int prop, const char *name, zprop_type_t type, 162 zprop_attr_t attr, int objset_types, const char *colname, 163 const struct zfs_mod_supported_features *sfeatures) 164 { 165 zprop_register_impl(prop, name, type, 0, NULL, attr, 166 objset_types, NULL, colname, 167 type == PROP_TYPE_NUMBER, B_FALSE, NULL, sfeatures); 168 } 169 170 171 /* 172 * A comparison function we can use to order indexes into property tables. 173 */ 174 static int 175 zprop_compare(const void *arg1, const void *arg2) 176 { 177 const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); 178 const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); 179 boolean_t p1ro, p2ro; 180 181 p1ro = (p1->pd_attr == PROP_READONLY); 182 p2ro = (p2->pd_attr == PROP_READONLY); 183 184 if (p1ro == p2ro) 185 return (strcmp(p1->pd_name, p2->pd_name)); 186 187 return (p1ro ? -1 : 1); 188 } 189 190 /* 191 * Iterate over all properties in the given property table, calling back 192 * into the specified function for each property. We will continue to 193 * iterate until we either reach the end or the callback function returns 194 * something other than ZPROP_CONT. 195 */ 196 int 197 zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, 198 boolean_t ordered, zfs_type_t type) 199 { 200 int i, num_props, size, prop; 201 zprop_desc_t *prop_tbl; 202 zprop_desc_t **order; 203 204 prop_tbl = zprop_get_proptable(type); 205 num_props = zprop_get_numprops(type); 206 size = num_props * sizeof (zprop_desc_t *); 207 208 #if defined(_KERNEL) 209 order = kmem_alloc(size, KM_SLEEP); 210 #else 211 if ((order = malloc(size)) == NULL) 212 return (ZPROP_CONT); 213 #endif 214 215 for (int j = 0; j < num_props; j++) 216 order[j] = &prop_tbl[j]; 217 218 if (ordered) { 219 qsort((void *)order, num_props, sizeof (zprop_desc_t *), 220 zprop_compare); 221 } 222 223 prop = ZPROP_CONT; 224 for (i = 0; i < num_props; i++) { 225 if ((order[i]->pd_visible || show_all) && 226 order[i]->pd_zfs_mod_supported && 227 (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { 228 prop = order[i]->pd_propnum; 229 break; 230 } 231 } 232 233 #if defined(_KERNEL) 234 kmem_free(order, size); 235 #else 236 free(order); 237 #endif 238 return (prop); 239 } 240 241 static boolean_t 242 propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) 243 { 244 const char *propname = prop_entry->pd_name; 245 #ifndef _KERNEL 246 const char *colname = prop_entry->pd_colname; 247 int c; 248 #endif 249 250 ASSERT(propname != NULL); 251 252 if (len == strlen(propname) && 253 strncmp(p, propname, len) == 0) 254 return (B_TRUE); 255 256 #ifndef _KERNEL 257 if (colname == NULL || len != strlen(colname)) 258 return (B_FALSE); 259 260 for (c = 0; c < len; c++) 261 if (p[c] != tolower(colname[c])) 262 break; 263 264 return (colname[c] == '\0'); 265 #else 266 return (B_FALSE); 267 #endif 268 } 269 270 typedef struct name_to_prop_cb { 271 const char *propname; 272 zprop_desc_t *prop_tbl; 273 } name_to_prop_cb_t; 274 275 static int 276 zprop_name_to_prop_cb(int prop, void *cb_data) 277 { 278 name_to_prop_cb_t *data = cb_data; 279 280 if (propname_match(data->propname, strlen(data->propname), 281 &data->prop_tbl[prop])) 282 return (prop); 283 284 return (ZPROP_CONT); 285 } 286 287 int 288 zprop_name_to_prop(const char *propname, zfs_type_t type) 289 { 290 int prop; 291 name_to_prop_cb_t cb_data; 292 293 cb_data.propname = propname; 294 cb_data.prop_tbl = zprop_get_proptable(type); 295 296 prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data, 297 B_TRUE, B_FALSE, type); 298 299 return (prop == ZPROP_CONT ? ZPROP_INVAL : prop); 300 } 301 302 int 303 zprop_string_to_index(int prop, const char *string, uint64_t *index, 304 zfs_type_t type) 305 { 306 zprop_desc_t *prop_tbl; 307 const zprop_index_t *idx_tbl; 308 int i; 309 310 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 311 return (-1); 312 313 ASSERT(prop < zprop_get_numprops(type)); 314 prop_tbl = zprop_get_proptable(type); 315 if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 316 return (-1); 317 318 for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 319 if (strcmp(string, idx_tbl[i].pi_name) == 0) { 320 *index = idx_tbl[i].pi_value; 321 return (0); 322 } 323 } 324 325 return (-1); 326 } 327 328 int 329 zprop_index_to_string(int prop, uint64_t index, const char **string, 330 zfs_type_t type) 331 { 332 zprop_desc_t *prop_tbl; 333 const zprop_index_t *idx_tbl; 334 int i; 335 336 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 337 return (-1); 338 339 ASSERT(prop < zprop_get_numprops(type)); 340 prop_tbl = zprop_get_proptable(type); 341 if ((idx_tbl = prop_tbl[prop].pd_table) == NULL) 342 return (-1); 343 344 for (i = 0; idx_tbl[i].pi_name != NULL; i++) { 345 if (idx_tbl[i].pi_value == index) { 346 *string = idx_tbl[i].pi_name; 347 return (0); 348 } 349 } 350 351 return (-1); 352 } 353 354 /* 355 * Return a random valid property value. Used by ztest. 356 */ 357 uint64_t 358 zprop_random_value(int prop, uint64_t seed, zfs_type_t type) 359 { 360 zprop_desc_t *prop_tbl; 361 const zprop_index_t *idx_tbl; 362 363 ASSERT((uint_t)prop < zprop_get_numprops(type)); 364 prop_tbl = zprop_get_proptable(type); 365 idx_tbl = prop_tbl[prop].pd_table; 366 367 if (idx_tbl == NULL) 368 return (seed); 369 370 return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value); 371 } 372 373 const char * 374 zprop_values(int prop, zfs_type_t type) 375 { 376 zprop_desc_t *prop_tbl; 377 378 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 379 ASSERT(prop < zprop_get_numprops(type)); 380 381 prop_tbl = zprop_get_proptable(type); 382 383 return (prop_tbl[prop].pd_values); 384 } 385 386 /* 387 * Returns TRUE if the property applies to any of the given dataset types. 388 * 389 * If headcheck is set, the check is being made against the head dataset 390 * type of a snapshot which requires to return B_TRUE when the property 391 * is only valid for snapshots. 392 */ 393 boolean_t 394 zprop_valid_for_type(int prop, zfs_type_t type, boolean_t headcheck) 395 { 396 zprop_desc_t *prop_tbl; 397 398 if (prop == ZPROP_INVAL || prop == ZPROP_CONT) 399 return (B_FALSE); 400 401 ASSERT(prop < zprop_get_numprops(type)); 402 prop_tbl = zprop_get_proptable(type); 403 if (headcheck && prop_tbl[prop].pd_types == ZFS_TYPE_SNAPSHOT) 404 return (B_TRUE); 405 return ((prop_tbl[prop].pd_types & type) != 0); 406 } 407 408 /* 409 * For user property names, we allow all lowercase alphanumeric characters, plus 410 * a few useful punctuation characters. 411 */ 412 int 413 zprop_valid_char(char c) 414 { 415 return ((c >= 'a' && c <= 'z') || 416 (c >= '0' && c <= '9') || 417 c == '-' || c == '_' || c == '.' || c == ':'); 418 } 419 420 #ifndef _KERNEL 421 422 /* 423 * Determines the minimum width for the column, and indicates whether it's fixed 424 * or not. Only string columns are non-fixed. 425 */ 426 size_t 427 zprop_width(int prop, boolean_t *fixed, zfs_type_t type) 428 { 429 zprop_desc_t *prop_tbl, *pd; 430 const zprop_index_t *idx; 431 size_t ret; 432 int i; 433 434 ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); 435 ASSERT(prop < zprop_get_numprops(type)); 436 437 prop_tbl = zprop_get_proptable(type); 438 pd = &prop_tbl[prop]; 439 440 *fixed = B_TRUE; 441 442 /* 443 * Start with the width of the column name. 444 */ 445 ret = strlen(pd->pd_colname); 446 447 /* 448 * For fixed-width values, make sure the width is large enough to hold 449 * any possible value. 450 */ 451 switch (pd->pd_proptype) { 452 case PROP_TYPE_NUMBER: 453 /* 454 * The maximum length of a human-readable number is 5 characters 455 * ("20.4M", for example). 456 */ 457 if (ret < 5) 458 ret = 5; 459 /* 460 * 'creation' is handled specially because it's a number 461 * internally, but displayed as a date string. 462 */ 463 if (prop == ZFS_PROP_CREATION) 464 *fixed = B_FALSE; 465 /* 466 * 'health' is handled specially because it's a number 467 * internally, but displayed as a fixed 8 character string. 468 */ 469 if (prop == ZPOOL_PROP_HEALTH) 470 ret = 8; 471 break; 472 case PROP_TYPE_INDEX: 473 idx = prop_tbl[prop].pd_table; 474 for (i = 0; idx[i].pi_name != NULL; i++) { 475 if (strlen(idx[i].pi_name) > ret) 476 ret = strlen(idx[i].pi_name); 477 } 478 break; 479 480 case PROP_TYPE_STRING: 481 *fixed = B_FALSE; 482 break; 483 } 484 485 return (ret); 486 } 487 488 #endif 489 490 #if defined(_KERNEL) 491 /* Common routines to initialize property tables */ 492 EXPORT_SYMBOL(zprop_register_impl); 493 EXPORT_SYMBOL(zprop_register_string); 494 EXPORT_SYMBOL(zprop_register_number); 495 EXPORT_SYMBOL(zprop_register_index); 496 EXPORT_SYMBOL(zprop_register_hidden); 497 498 /* Common routines for zfs and zpool property management */ 499 EXPORT_SYMBOL(zprop_iter_common); 500 EXPORT_SYMBOL(zprop_name_to_prop); 501 EXPORT_SYMBOL(zprop_string_to_index); 502 EXPORT_SYMBOL(zprop_index_to_string); 503 EXPORT_SYMBOL(zprop_random_value); 504 EXPORT_SYMBOL(zprop_values); 505 EXPORT_SYMBOL(zprop_valid_for_type); 506 EXPORT_SYMBOL(zprop_valid_char); 507 #endif 508