]>
Commit | Line | Data |
---|---|---|
34dc7c2f BB |
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 | /* | |
b128c09f | 22 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
34dc7c2f BB |
23 | * Use is subject to license terms. |
24 | */ | |
25 | ||
b128c09f | 26 | #pragma ident "%Z%%M% %I% %E% SMI" |
34dc7c2f BB |
27 | |
28 | /* | |
29 | * Common routines used by zfs and zpool property management. | |
30 | */ | |
31 | ||
32 | #include <sys/zio.h> | |
33 | #include <sys/spa.h> | |
34 | #include <sys/zfs_acl.h> | |
35 | #include <sys/zfs_ioctl.h> | |
36 | #include <sys/zfs_znode.h> | |
37 | #include <sys/fs/zfs.h> | |
38 | ||
39 | #include "zfs_prop.h" | |
40 | #include "zfs_deleg.h" | |
41 | ||
42 | #if defined(_KERNEL) | |
43 | #include <sys/systm.h> | |
44 | #include <util/qsort.h> | |
45 | #else | |
46 | #include <stdlib.h> | |
47 | #include <string.h> | |
48 | #include <ctype.h> | |
49 | #endif | |
50 | ||
51 | static zprop_desc_t * | |
52 | zprop_get_proptable(zfs_type_t type) | |
53 | { | |
54 | if (type == ZFS_TYPE_POOL) | |
55 | return (zpool_prop_get_table()); | |
56 | else | |
57 | return (zfs_prop_get_table()); | |
58 | } | |
59 | ||
60 | static int | |
61 | zprop_get_numprops(zfs_type_t type) | |
62 | { | |
63 | if (type == ZFS_TYPE_POOL) | |
64 | return (ZPOOL_NUM_PROPS); | |
65 | else | |
66 | return (ZFS_NUM_PROPS); | |
67 | } | |
68 | ||
69 | void | |
70 | register_impl(int prop, const char *name, zprop_type_t type, | |
71 | uint64_t numdefault, const char *strdefault, zprop_attr_t attr, | |
72 | int objset_types, const char *values, const char *colname, | |
73 | boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl) | |
74 | { | |
75 | zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types); | |
76 | zprop_desc_t *pd; | |
77 | ||
78 | pd = &prop_tbl[prop]; | |
79 | ||
80 | ASSERT(pd->pd_name == NULL || pd->pd_name == name); | |
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 | } | |
95 | ||
96 | void | |
97 | register_string(int prop, const char *name, const char *def, | |
98 | zprop_attr_t attr, int objset_types, const char *values, | |
99 | const char *colname) | |
100 | { | |
101 | register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr, | |
102 | objset_types, values, colname, B_FALSE, B_TRUE, NULL); | |
103 | ||
104 | } | |
105 | ||
106 | void | |
107 | register_number(int prop, const char *name, uint64_t def, zprop_attr_t attr, | |
108 | int objset_types, const char *values, const char *colname) | |
109 | { | |
110 | register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr, | |
111 | objset_types, values, colname, B_TRUE, B_TRUE, NULL); | |
112 | } | |
113 | ||
114 | void | |
115 | register_index(int prop, const char *name, uint64_t def, zprop_attr_t attr, | |
116 | int objset_types, const char *values, const char *colname, | |
117 | const zprop_index_t *idx_tbl) | |
118 | { | |
119 | register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr, | |
120 | objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl); | |
121 | } | |
122 | ||
123 | void | |
124 | register_hidden(int prop, const char *name, zprop_type_t type, | |
125 | zprop_attr_t attr, int objset_types, const char *colname) | |
126 | { | |
127 | register_impl(prop, name, type, 0, NULL, attr, | |
128 | objset_types, NULL, colname, B_FALSE, B_FALSE, NULL); | |
129 | } | |
130 | ||
131 | ||
132 | /* | |
133 | * A comparison function we can use to order indexes into property tables. | |
134 | */ | |
135 | static int | |
136 | zprop_compare(const void *arg1, const void *arg2) | |
137 | { | |
138 | const zprop_desc_t *p1 = *((zprop_desc_t **)arg1); | |
139 | const zprop_desc_t *p2 = *((zprop_desc_t **)arg2); | |
140 | boolean_t p1ro, p2ro; | |
141 | ||
142 | p1ro = (p1->pd_attr == PROP_READONLY); | |
143 | p2ro = (p2->pd_attr == PROP_READONLY); | |
144 | ||
145 | if (p1ro == p2ro) | |
146 | return (strcmp(p1->pd_name, p2->pd_name)); | |
147 | ||
148 | return (p1ro ? -1 : 1); | |
149 | } | |
150 | ||
151 | /* | |
152 | * Iterate over all properties in the given property table, calling back | |
153 | * into the specified function for each property. We will continue to | |
154 | * iterate until we either reach the end or the callback function returns | |
155 | * something other than ZPROP_CONT. | |
156 | */ | |
157 | int | |
158 | zprop_iter_common(zprop_func func, void *cb, boolean_t show_all, | |
159 | boolean_t ordered, zfs_type_t type) | |
160 | { | |
161 | int i, num_props, size, prop; | |
162 | zprop_desc_t *prop_tbl; | |
163 | zprop_desc_t **order; | |
164 | ||
165 | prop_tbl = zprop_get_proptable(type); | |
166 | num_props = zprop_get_numprops(type); | |
167 | size = num_props * sizeof (zprop_desc_t *); | |
168 | ||
169 | #if defined(_KERNEL) | |
170 | order = kmem_alloc(size, KM_SLEEP); | |
171 | #else | |
172 | if ((order = malloc(size)) == NULL) | |
173 | return (ZPROP_CONT); | |
174 | #endif | |
175 | ||
176 | for (int j = 0; j < num_props; j++) | |
177 | order[j] = &prop_tbl[j]; | |
178 | ||
179 | if (ordered) { | |
180 | qsort((void *)order, num_props, sizeof (zprop_desc_t *), | |
181 | zprop_compare); | |
182 | } | |
183 | ||
184 | prop = ZPROP_CONT; | |
185 | for (i = 0; i < num_props; i++) { | |
186 | if ((order[i]->pd_visible || show_all) && | |
187 | (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) { | |
188 | prop = order[i]->pd_propnum; | |
189 | break; | |
190 | } | |
191 | } | |
192 | ||
193 | #if defined(_KERNEL) | |
194 | kmem_free(order, size); | |
195 | #else | |
196 | free(order); | |
197 | #endif | |
198 | return (prop); | |
199 | } | |
200 | ||
201 | static boolean_t | |
202 | propname_match(const char *p, size_t len, zprop_desc_t *prop_entry) | |
203 | { | |
204 | const char *propname = prop_entry->pd_name; | |
205 | #ifndef _KERNEL | |
206 | const char *colname = prop_entry->pd_colname; | |
207 | int c; | |
208 | ||
209 | if (colname == NULL) | |
210 | return (B_FALSE); | |
211 | #endif | |
212 | ||
213 | if (len == strlen(propname) && | |
214 | strncmp(p, propname, len) == 0) | |
215 | return (B_TRUE); | |
216 | ||
217 | #ifndef _KERNEL | |
218 | if (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 | ||
b128c09f BB |
271 | if (prop == ZPROP_INVAL || prop == ZPROP_CONT) |
272 | return (-1); | |
273 | ||
274 | ASSERT(prop < zprop_get_numprops(type)); | |
34dc7c2f BB |
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 | ||
b128c09f BB |
297 | if (prop == ZPROP_INVAL || prop == ZPROP_CONT) |
298 | return (-1); | |
299 | ||
300 | ASSERT(prop < zprop_get_numprops(type)); | |
34dc7c2f BB |
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 | const char * | |
316 | zprop_values(int prop, zfs_type_t type) | |
317 | { | |
318 | zprop_desc_t *prop_tbl; | |
319 | ||
b128c09f BB |
320 | ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); |
321 | ASSERT(prop < zprop_get_numprops(type)); | |
322 | ||
34dc7c2f BB |
323 | prop_tbl = zprop_get_proptable(type); |
324 | ||
325 | return (prop_tbl[prop].pd_values); | |
326 | } | |
327 | ||
328 | /* | |
329 | * Returns TRUE if the property applies to any of the given dataset types. | |
330 | */ | |
b128c09f | 331 | boolean_t |
34dc7c2f BB |
332 | zprop_valid_for_type(int prop, zfs_type_t type) |
333 | { | |
b128c09f BB |
334 | zprop_desc_t *prop_tbl; |
335 | ||
336 | if (prop == ZPROP_INVAL || prop == ZPROP_CONT) | |
337 | return (B_FALSE); | |
34dc7c2f | 338 | |
b128c09f BB |
339 | ASSERT(prop < zprop_get_numprops(type)); |
340 | prop_tbl = zprop_get_proptable(type); | |
34dc7c2f BB |
341 | return ((prop_tbl[prop].pd_types & type) != 0); |
342 | } | |
343 | ||
344 | #ifndef _KERNEL | |
345 | ||
346 | /* | |
347 | * Determines the minimum width for the column, and indicates whether it's fixed | |
348 | * or not. Only string columns are non-fixed. | |
349 | */ | |
350 | size_t | |
351 | zprop_width(int prop, boolean_t *fixed, zfs_type_t type) | |
352 | { | |
353 | zprop_desc_t *prop_tbl, *pd; | |
354 | const zprop_index_t *idx; | |
355 | size_t ret; | |
356 | int i; | |
357 | ||
b128c09f BB |
358 | ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT); |
359 | ASSERT(prop < zprop_get_numprops(type)); | |
360 | ||
34dc7c2f BB |
361 | prop_tbl = zprop_get_proptable(type); |
362 | pd = &prop_tbl[prop]; | |
363 | ||
364 | *fixed = B_TRUE; | |
365 | ||
366 | /* | |
367 | * Start with the width of the column name. | |
368 | */ | |
369 | ret = strlen(pd->pd_colname); | |
370 | ||
371 | /* | |
372 | * For fixed-width values, make sure the width is large enough to hold | |
373 | * any possible value. | |
374 | */ | |
375 | switch (pd->pd_proptype) { | |
376 | case PROP_TYPE_NUMBER: | |
377 | /* | |
378 | * The maximum length of a human-readable number is 5 characters | |
379 | * ("20.4M", for example). | |
380 | */ | |
381 | if (ret < 5) | |
382 | ret = 5; | |
383 | /* | |
384 | * 'creation' is handled specially because it's a number | |
385 | * internally, but displayed as a date string. | |
386 | */ | |
387 | if (prop == ZFS_PROP_CREATION) | |
388 | *fixed = B_FALSE; | |
389 | break; | |
390 | case PROP_TYPE_INDEX: | |
391 | idx = prop_tbl[prop].pd_table; | |
392 | for (i = 0; idx[i].pi_name != NULL; i++) { | |
393 | if (strlen(idx[i].pi_name) > ret) | |
394 | ret = strlen(idx[i].pi_name); | |
395 | } | |
396 | break; | |
397 | ||
398 | case PROP_TYPE_STRING: | |
399 | *fixed = B_FALSE; | |
400 | break; | |
401 | } | |
402 | ||
403 | return (ret); | |
404 | } | |
405 | ||
406 | #endif |