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