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