]> git.proxmox.com Git - mirror_zfs.git/blame - module/zcommon/zfs_namecheck.c
Undo c89 workarounds to match with upstream
[mirror_zfs.git] / module / zcommon / zfs_namecheck.c
CommitLineData
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/*
9babb374 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
34dc7c2f
BB
23 * Use is subject to license terms.
24 */
da536844
MA
25/*
26 * Copyright (c) 2013 by Delphix. All rights reserved.
27 */
34dc7c2f 28
34dc7c2f
BB
29/*
30 * Common name validation routines for ZFS. These routines are shared by the
31 * userland code as well as the ioctl() layer to ensure that we don't
32 * inadvertently expose a hole through direct ioctl()s that never gets tested.
33 * In userland, however, we want significantly more information about _why_ the
34 * name is invalid. In the kernel, we only care whether it's valid or not.
35 * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
36 * the name failed to validate.
37 *
38 * Each function returns 0 on success, -1 on error.
39 */
40
41#if defined(_KERNEL)
42#include <sys/systm.h>
43#else
44#include <string.h>
45#endif
46
871e0732 47#include <sys/dsl_dir.h>
34dc7c2f
BB
48#include <sys/param.h>
49#include <sys/nvpair.h>
50#include "zfs_namecheck.h"
51#include "zfs_deleg.h"
52
53static int
54valid_char(char c)
55{
56 return ((c >= 'a' && c <= 'z') ||
57 (c >= 'A' && c <= 'Z') ||
58 (c >= '0' && c <= '9') ||
b128c09f 59 c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
34dc7c2f
BB
60}
61
62/*
63 * Snapshot names must be made up of alphanumeric characters plus the following
64 * characters:
65 *
45d1cae3 66 * [-_.: ]
34dc7c2f
BB
67 */
68int
da536844 69zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
34dc7c2f
BB
70{
71 const char *loc;
72
eca7b760 73 if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
34dc7c2f
BB
74 if (why)
75 *why = NAME_ERR_TOOLONG;
76 return (-1);
77 }
78
79 if (path[0] == '\0') {
80 if (why)
81 *why = NAME_ERR_EMPTY_COMPONENT;
82 return (-1);
83 }
84
85 for (loc = path; *loc; loc++) {
86 if (!valid_char(*loc)) {
87 if (why) {
88 *why = NAME_ERR_INVALCHAR;
89 *what = *loc;
90 }
91 return (-1);
92 }
93 }
94 return (0);
95}
96
97
98/*
99 * Permissions set name must start with the letter '@' followed by the
100 * same character restrictions as snapshot names, except that the name
101 * cannot exceed 64 characters.
102 */
103int
104permset_namecheck(const char *path, namecheck_err_t *why, char *what)
105{
106 if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
107 if (why)
108 *why = NAME_ERR_TOOLONG;
109 return (-1);
110 }
111
112 if (path[0] != '@') {
113 if (why) {
114 *why = NAME_ERR_NO_AT;
115 *what = path[0];
116 }
117 return (-1);
118 }
119
da536844 120 return (zfs_component_namecheck(&path[1], why, what));
34dc7c2f
BB
121}
122
123/*
aeacdefe 124 * Entity names must be of the following form:
34dc7c2f 125 *
aeacdefe 126 * [component/]*[component][(@|#)component]?
34dc7c2f
BB
127 *
128 * Where each component is made up of alphanumeric characters plus the following
129 * characters:
130 *
131 * [-_.:%]
132 *
133 * We allow '%' here as we use that character internally to create unique
134 * names for temporary clones (for online recv).
135 */
136int
aeacdefe 137entity_namecheck(const char *path, namecheck_err_t *why, char *what)
34dc7c2f 138{
1c27024e 139 const char *start, *end;
aeacdefe 140 int found_delim;
34dc7c2f
BB
141
142 /*
143 * Make sure the name is not too long.
34dc7c2f 144 */
1c27024e 145
eca7b760 146 if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
34dc7c2f
BB
147 if (why)
148 *why = NAME_ERR_TOOLONG;
149 return (-1);
150 }
151
152 /* Explicitly check for a leading slash. */
153 if (path[0] == '/') {
154 if (why)
155 *why = NAME_ERR_LEADING_SLASH;
156 return (-1);
157 }
158
159 if (path[0] == '\0') {
160 if (why)
161 *why = NAME_ERR_EMPTY_COMPONENT;
162 return (-1);
163 }
164
aeacdefe
GM
165 start = path;
166 found_delim = 0;
34dc7c2f
BB
167 for (;;) {
168 /* Find the end of this component */
aeacdefe
GM
169 end = start;
170 while (*end != '/' && *end != '@' && *end != '#' &&
171 *end != '\0')
34dc7c2f
BB
172 end++;
173
174 if (*end == '\0' && end[-1] == '/') {
175 /* trailing slashes are not allowed */
176 if (why)
177 *why = NAME_ERR_TRAILING_SLASH;
178 return (-1);
179 }
180
34dc7c2f 181 /* Validate the contents of this component */
1c27024e 182 for (const char *loc = start; loc != end; loc++) {
34dc7c2f
BB
183 if (!valid_char(*loc) && *loc != '%') {
184 if (why) {
185 *why = NAME_ERR_INVALCHAR;
186 *what = *loc;
187 }
188 return (-1);
189 }
34dc7c2f
BB
190 }
191
aeacdefe
GM
192 /* Snapshot or bookmark delimiter found */
193 if (*end == '@' || *end == '#') {
194 /* Multiple delimiters are not allowed */
195 if (found_delim != 0) {
34dc7c2f 196 if (why)
aeacdefe 197 *why = NAME_ERR_MULTIPLE_DELIMITERS;
34dc7c2f
BB
198 return (-1);
199 }
200
aeacdefe 201 found_delim = 1;
34dc7c2f
BB
202 }
203
aeacdefe
GM
204 /* Zero-length components are not allowed */
205 if (start == end) {
206 if (why)
207 *why = NAME_ERR_EMPTY_COMPONENT;
208 return (-1);
209 }
210
211 /* If we've reached the end of the string, we're OK */
212 if (*end == '\0')
213 return (0);
214
34dc7c2f 215 /*
aeacdefe 216 * If there is a '/' in a snapshot or bookmark name
34dc7c2f
BB
217 * then report an error
218 */
aeacdefe 219 if (*end == '/' && found_delim != 0) {
34dc7c2f
BB
220 if (why)
221 *why = NAME_ERR_TRAILING_SLASH;
222 return (-1);
223 }
224
225 /* Update to the next component */
aeacdefe 226 start = end + 1;
34dc7c2f
BB
227 }
228}
229
aeacdefe
GM
230/*
231 * Dataset is any entity, except bookmark
232 */
233int
234dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
235{
236 int ret = entity_namecheck(path, why, what);
237
238 if (ret == 0 && strchr(path, '#') != NULL) {
239 if (why != NULL) {
240 *why = NAME_ERR_INVALCHAR;
241 *what = '#';
242 }
243 return (-1);
244 }
245
246 return (ret);
247}
34dc7c2f
BB
248
249/*
250 * mountpoint names must be of the following form:
251 *
252 * /[component][/]*[component][/]
253 */
254int
255mountpoint_namecheck(const char *path, namecheck_err_t *why)
256{
257 const char *start, *end;
258
259 /*
260 * Make sure none of the mountpoint component names are too long.
261 * If a component name is too long then the mkdir of the mountpoint
262 * will fail but then the mountpoint property will be set to a value
263 * that can never be mounted. Better to fail before setting the prop.
264 * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
265 */
266
267 if (path == NULL || *path != '/') {
268 if (why)
269 *why = NAME_ERR_LEADING_SLASH;
270 return (-1);
271 }
272
273 /* Skip leading slash */
274 start = &path[1];
275 do {
276 end = start;
277 while (*end != '/' && *end != '\0')
278 end++;
279
eca7b760 280 if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
34dc7c2f
BB
281 if (why)
282 *why = NAME_ERR_TOOLONG;
283 return (-1);
284 }
285 start = end + 1;
286
287 } while (*end != '\0');
288
289 return (0);
290}
291
292/*
293 * For pool names, we have the same set of valid characters as described in
294 * dataset names, with the additional restriction that the pool name must begin
295 * with a letter. The pool names 'raidz' and 'mirror' are also reserved names
296 * that cannot be used.
297 */
298int
299pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
300{
301 const char *c;
302
303 /*
304 * Make sure the name is not too long.
871e0732 305 * If we're creating a pool with version >= SPA_VERSION_DSL_SCRUB (v11)
306 * we need to account for additional space needed by the origin ds which
307 * will also be snapshotted: "poolname"+"/"+"$ORIGIN"+"@"+"$ORIGIN".
308 * Play it safe and enforce this limit even if the pool version is < 11
309 * so it can be upgraded without issues.
34dc7c2f 310 */
871e0732 311 if (strlen(pool) >= (ZFS_MAX_DATASET_NAME_LEN - 2 -
312 strlen(ORIGIN_DIR_NAME) * 2)) {
34dc7c2f
BB
313 if (why)
314 *why = NAME_ERR_TOOLONG;
315 return (-1);
316 }
317
318 c = pool;
319 while (*c != '\0') {
320 if (!valid_char(*c)) {
321 if (why) {
322 *why = NAME_ERR_INVALCHAR;
323 *what = *c;
324 }
325 return (-1);
326 }
327 c++;
328 }
329
330 if (!(*pool >= 'a' && *pool <= 'z') &&
331 !(*pool >= 'A' && *pool <= 'Z')) {
332 if (why)
333 *why = NAME_ERR_NOLETTER;
334 return (-1);
335 }
336
337 if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
338 if (why)
339 *why = NAME_ERR_RESERVED;
340 return (-1);
341 }
342
343 if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
344 if (why)
345 *why = NAME_ERR_DISKLIKE;
346 return (-1);
347 }
348
349 return (0);
350}
c28b2279
BB
351
352#if defined(_KERNEL) && defined(HAVE_SPL)
c28b2279
BB
353EXPORT_SYMBOL(pool_namecheck);
354EXPORT_SYMBOL(dataset_namecheck);
da536844 355EXPORT_SYMBOL(zfs_component_namecheck);
c28b2279 356#endif