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