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