]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/cddl/contrib/opensolaris/common/zfs/zprop_common.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / cddl / contrib / opensolaris / common / zfs / zprop_common.c
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 <sys/libkern.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, j, 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 (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