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