Print this page
5918 Memory leak when zfs_destroy_snaps_nvl fails
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ new/usr/src/lib/libzfs/common/libzfs_dataset.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25 25 * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
26 26 * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
27 27 * Copyright (c) 2013 Martin Matuska. All rights reserved.
28 28 * Copyright (c) 2013 Steven Hartland. All rights reserved.
29 29 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
30 30 */
31 31
32 32 #include <ctype.h>
33 33 #include <errno.h>
34 34 #include <libintl.h>
35 35 #include <math.h>
36 36 #include <stdio.h>
37 37 #include <stdlib.h>
38 38 #include <strings.h>
39 39 #include <unistd.h>
40 40 #include <stddef.h>
41 41 #include <zone.h>
42 42 #include <fcntl.h>
43 43 #include <sys/mntent.h>
44 44 #include <sys/mount.h>
45 45 #include <priv.h>
46 46 #include <pwd.h>
47 47 #include <grp.h>
48 48 #include <stddef.h>
49 49 #include <ucred.h>
50 50 #include <idmap.h>
51 51 #include <aclutils.h>
52 52 #include <directory.h>
53 53
54 54 #include <sys/dnode.h>
55 55 #include <sys/spa.h>
56 56 #include <sys/zap.h>
57 57 #include <libzfs.h>
58 58
59 59 #include "zfs_namecheck.h"
60 60 #include "zfs_prop.h"
61 61 #include "libzfs_impl.h"
62 62 #include "zfs_deleg.h"
63 63
64 64 static int userquota_propname_decode(const char *propname, boolean_t zoned,
65 65 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
66 66
67 67 /*
68 68 * Given a single type (not a mask of types), return the type in a human
69 69 * readable form.
70 70 */
71 71 const char *
72 72 zfs_type_to_name(zfs_type_t type)
73 73 {
74 74 switch (type) {
75 75 case ZFS_TYPE_FILESYSTEM:
76 76 return (dgettext(TEXT_DOMAIN, "filesystem"));
77 77 case ZFS_TYPE_SNAPSHOT:
78 78 return (dgettext(TEXT_DOMAIN, "snapshot"));
79 79 case ZFS_TYPE_VOLUME:
80 80 return (dgettext(TEXT_DOMAIN, "volume"));
81 81 }
82 82
83 83 return (NULL);
84 84 }
85 85
86 86 /*
87 87 * Given a path and mask of ZFS types, return a string describing this dataset.
88 88 * This is used when we fail to open a dataset and we cannot get an exact type.
89 89 * We guess what the type would have been based on the path and the mask of
90 90 * acceptable types.
91 91 */
92 92 static const char *
93 93 path_to_str(const char *path, int types)
94 94 {
95 95 /*
96 96 * When given a single type, always report the exact type.
97 97 */
98 98 if (types == ZFS_TYPE_SNAPSHOT)
99 99 return (dgettext(TEXT_DOMAIN, "snapshot"));
100 100 if (types == ZFS_TYPE_FILESYSTEM)
101 101 return (dgettext(TEXT_DOMAIN, "filesystem"));
102 102 if (types == ZFS_TYPE_VOLUME)
103 103 return (dgettext(TEXT_DOMAIN, "volume"));
104 104
105 105 /*
106 106 * The user is requesting more than one type of dataset. If this is the
107 107 * case, consult the path itself. If we're looking for a snapshot, and
108 108 * a '@' is found, then report it as "snapshot". Otherwise, remove the
109 109 * snapshot attribute and try again.
110 110 */
111 111 if (types & ZFS_TYPE_SNAPSHOT) {
112 112 if (strchr(path, '@') != NULL)
113 113 return (dgettext(TEXT_DOMAIN, "snapshot"));
114 114 return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
115 115 }
116 116
117 117 /*
118 118 * The user has requested either filesystems or volumes.
119 119 * We have no way of knowing a priori what type this would be, so always
120 120 * report it as "filesystem" or "volume", our two primitive types.
121 121 */
122 122 if (types & ZFS_TYPE_FILESYSTEM)
123 123 return (dgettext(TEXT_DOMAIN, "filesystem"));
124 124
125 125 assert(types & ZFS_TYPE_VOLUME);
126 126 return (dgettext(TEXT_DOMAIN, "volume"));
127 127 }
128 128
129 129 /*
130 130 * Validate a ZFS path. This is used even before trying to open the dataset, to
131 131 * provide a more meaningful error message. We call zfs_error_aux() to
132 132 * explain exactly why the name was not valid.
133 133 */
134 134 int
135 135 zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
136 136 boolean_t modifying)
137 137 {
138 138 namecheck_err_t why;
139 139 char what;
140 140
141 141 (void) zfs_prop_get_table();
142 142 if (dataset_namecheck(path, &why, &what) != 0) {
143 143 if (hdl != NULL) {
144 144 switch (why) {
145 145 case NAME_ERR_TOOLONG:
146 146 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
147 147 "name is too long"));
148 148 break;
149 149
150 150 case NAME_ERR_LEADING_SLASH:
151 151 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
152 152 "leading slash in name"));
153 153 break;
154 154
155 155 case NAME_ERR_EMPTY_COMPONENT:
156 156 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
157 157 "empty component in name"));
158 158 break;
159 159
160 160 case NAME_ERR_TRAILING_SLASH:
161 161 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
162 162 "trailing slash in name"));
163 163 break;
164 164
165 165 case NAME_ERR_INVALCHAR:
166 166 zfs_error_aux(hdl,
167 167 dgettext(TEXT_DOMAIN, "invalid character "
168 168 "'%c' in name"), what);
169 169 break;
170 170
171 171 case NAME_ERR_MULTIPLE_AT:
172 172 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
173 173 "multiple '@' delimiters in name"));
174 174 break;
175 175
176 176 case NAME_ERR_NOLETTER:
177 177 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
178 178 "pool doesn't begin with a letter"));
179 179 break;
180 180
181 181 case NAME_ERR_RESERVED:
182 182 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
183 183 "name is reserved"));
184 184 break;
185 185
186 186 case NAME_ERR_DISKLIKE:
187 187 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
188 188 "reserved disk name"));
189 189 break;
190 190 }
191 191 }
192 192
193 193 return (0);
194 194 }
195 195
196 196 if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
197 197 if (hdl != NULL)
198 198 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
199 199 "snapshot delimiter '@' in filesystem name"));
200 200 return (0);
201 201 }
202 202
203 203 if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
204 204 if (hdl != NULL)
205 205 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
206 206 "missing '@' delimiter in snapshot name"));
207 207 return (0);
208 208 }
209 209
210 210 if (modifying && strchr(path, '%') != NULL) {
211 211 if (hdl != NULL)
212 212 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
213 213 "invalid character %c in name"), '%');
214 214 return (0);
215 215 }
216 216
217 217 return (-1);
218 218 }
219 219
220 220 int
221 221 zfs_name_valid(const char *name, zfs_type_t type)
222 222 {
223 223 if (type == ZFS_TYPE_POOL)
224 224 return (zpool_name_valid(NULL, B_FALSE, name));
225 225 return (zfs_validate_name(NULL, name, type, B_FALSE));
226 226 }
227 227
228 228 /*
229 229 * This function takes the raw DSL properties, and filters out the user-defined
230 230 * properties into a separate nvlist.
231 231 */
232 232 static nvlist_t *
233 233 process_user_props(zfs_handle_t *zhp, nvlist_t *props)
234 234 {
235 235 libzfs_handle_t *hdl = zhp->zfs_hdl;
236 236 nvpair_t *elem;
237 237 nvlist_t *propval;
238 238 nvlist_t *nvl;
239 239
240 240 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
241 241 (void) no_memory(hdl);
242 242 return (NULL);
243 243 }
244 244
245 245 elem = NULL;
246 246 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
247 247 if (!zfs_prop_user(nvpair_name(elem)))
248 248 continue;
249 249
250 250 verify(nvpair_value_nvlist(elem, &propval) == 0);
251 251 if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
252 252 nvlist_free(nvl);
253 253 (void) no_memory(hdl);
254 254 return (NULL);
255 255 }
256 256 }
257 257
258 258 return (nvl);
259 259 }
260 260
261 261 static zpool_handle_t *
262 262 zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
263 263 {
264 264 libzfs_handle_t *hdl = zhp->zfs_hdl;
265 265 zpool_handle_t *zph;
266 266
267 267 if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
268 268 if (hdl->libzfs_pool_handles != NULL)
269 269 zph->zpool_next = hdl->libzfs_pool_handles;
270 270 hdl->libzfs_pool_handles = zph;
271 271 }
272 272 return (zph);
273 273 }
274 274
275 275 static zpool_handle_t *
276 276 zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
277 277 {
278 278 libzfs_handle_t *hdl = zhp->zfs_hdl;
279 279 zpool_handle_t *zph = hdl->libzfs_pool_handles;
280 280
281 281 while ((zph != NULL) &&
282 282 (strncmp(pool_name, zpool_get_name(zph), len) != 0))
283 283 zph = zph->zpool_next;
284 284 return (zph);
285 285 }
286 286
287 287 /*
288 288 * Returns a handle to the pool that contains the provided dataset.
289 289 * If a handle to that pool already exists then that handle is returned.
290 290 * Otherwise, a new handle is created and added to the list of handles.
291 291 */
292 292 static zpool_handle_t *
293 293 zpool_handle(zfs_handle_t *zhp)
294 294 {
295 295 char *pool_name;
296 296 int len;
297 297 zpool_handle_t *zph;
298 298
299 299 len = strcspn(zhp->zfs_name, "/@#") + 1;
300 300 pool_name = zfs_alloc(zhp->zfs_hdl, len);
301 301 (void) strlcpy(pool_name, zhp->zfs_name, len);
302 302
303 303 zph = zpool_find_handle(zhp, pool_name, len);
304 304 if (zph == NULL)
305 305 zph = zpool_add_handle(zhp, pool_name);
306 306
307 307 free(pool_name);
308 308 return (zph);
309 309 }
310 310
311 311 void
312 312 zpool_free_handles(libzfs_handle_t *hdl)
313 313 {
314 314 zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
315 315
316 316 while (zph != NULL) {
317 317 next = zph->zpool_next;
318 318 zpool_close(zph);
319 319 zph = next;
320 320 }
321 321 hdl->libzfs_pool_handles = NULL;
322 322 }
323 323
324 324 /*
325 325 * Utility function to gather stats (objset and zpl) for the given object.
326 326 */
327 327 static int
328 328 get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
329 329 {
330 330 libzfs_handle_t *hdl = zhp->zfs_hdl;
331 331
332 332 (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
333 333
334 334 while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
335 335 if (errno == ENOMEM) {
336 336 if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
337 337 return (-1);
338 338 }
339 339 } else {
340 340 return (-1);
341 341 }
342 342 }
343 343 return (0);
344 344 }
345 345
346 346 /*
347 347 * Utility function to get the received properties of the given object.
348 348 */
349 349 static int
350 350 get_recvd_props_ioctl(zfs_handle_t *zhp)
351 351 {
352 352 libzfs_handle_t *hdl = zhp->zfs_hdl;
353 353 nvlist_t *recvdprops;
354 354 zfs_cmd_t zc = { 0 };
355 355 int err;
356 356
357 357 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
358 358 return (-1);
359 359
360 360 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
361 361
362 362 while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
363 363 if (errno == ENOMEM) {
364 364 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
365 365 return (-1);
366 366 }
367 367 } else {
368 368 zcmd_free_nvlists(&zc);
369 369 return (-1);
370 370 }
371 371 }
372 372
373 373 err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
374 374 zcmd_free_nvlists(&zc);
375 375 if (err != 0)
376 376 return (-1);
377 377
378 378 nvlist_free(zhp->zfs_recvd_props);
379 379 zhp->zfs_recvd_props = recvdprops;
380 380
381 381 return (0);
382 382 }
383 383
384 384 static int
385 385 put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
386 386 {
387 387 nvlist_t *allprops, *userprops;
388 388
389 389 zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
390 390
391 391 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
392 392 return (-1);
393 393 }
394 394
395 395 /*
396 396 * XXX Why do we store the user props separately, in addition to
397 397 * storing them in zfs_props?
398 398 */
399 399 if ((userprops = process_user_props(zhp, allprops)) == NULL) {
400 400 nvlist_free(allprops);
401 401 return (-1);
402 402 }
403 403
404 404 nvlist_free(zhp->zfs_props);
405 405 nvlist_free(zhp->zfs_user_props);
406 406
407 407 zhp->zfs_props = allprops;
408 408 zhp->zfs_user_props = userprops;
409 409
410 410 return (0);
411 411 }
412 412
413 413 static int
414 414 get_stats(zfs_handle_t *zhp)
415 415 {
416 416 int rc = 0;
417 417 zfs_cmd_t zc = { 0 };
418 418
419 419 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
420 420 return (-1);
421 421 if (get_stats_ioctl(zhp, &zc) != 0)
422 422 rc = -1;
423 423 else if (put_stats_zhdl(zhp, &zc) != 0)
424 424 rc = -1;
425 425 zcmd_free_nvlists(&zc);
426 426 return (rc);
427 427 }
428 428
429 429 /*
430 430 * Refresh the properties currently stored in the handle.
431 431 */
432 432 void
433 433 zfs_refresh_properties(zfs_handle_t *zhp)
434 434 {
435 435 (void) get_stats(zhp);
436 436 }
437 437
438 438 /*
439 439 * Makes a handle from the given dataset name. Used by zfs_open() and
440 440 * zfs_iter_* to create child handles on the fly.
441 441 */
442 442 static int
443 443 make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
444 444 {
445 445 if (put_stats_zhdl(zhp, zc) != 0)
446 446 return (-1);
447 447
448 448 /*
449 449 * We've managed to open the dataset and gather statistics. Determine
450 450 * the high-level type.
451 451 */
452 452 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
453 453 zhp->zfs_head_type = ZFS_TYPE_VOLUME;
454 454 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
455 455 zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
456 456 else
457 457 abort();
458 458
459 459 if (zhp->zfs_dmustats.dds_is_snapshot)
460 460 zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
461 461 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
462 462 zhp->zfs_type = ZFS_TYPE_VOLUME;
463 463 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
464 464 zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
465 465 else
466 466 abort(); /* we should never see any other types */
467 467
468 468 if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
469 469 return (-1);
470 470
471 471 return (0);
472 472 }
473 473
474 474 zfs_handle_t *
475 475 make_dataset_handle(libzfs_handle_t *hdl, const char *path)
476 476 {
477 477 zfs_cmd_t zc = { 0 };
478 478
479 479 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
480 480
481 481 if (zhp == NULL)
482 482 return (NULL);
483 483
484 484 zhp->zfs_hdl = hdl;
485 485 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
486 486 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
487 487 free(zhp);
488 488 return (NULL);
489 489 }
490 490 if (get_stats_ioctl(zhp, &zc) == -1) {
491 491 zcmd_free_nvlists(&zc);
492 492 free(zhp);
493 493 return (NULL);
494 494 }
495 495 if (make_dataset_handle_common(zhp, &zc) == -1) {
496 496 free(zhp);
497 497 zhp = NULL;
498 498 }
499 499 zcmd_free_nvlists(&zc);
500 500 return (zhp);
501 501 }
502 502
503 503 zfs_handle_t *
504 504 make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
505 505 {
506 506 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
507 507
508 508 if (zhp == NULL)
509 509 return (NULL);
510 510
511 511 zhp->zfs_hdl = hdl;
512 512 (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
513 513 if (make_dataset_handle_common(zhp, zc) == -1) {
514 514 free(zhp);
515 515 return (NULL);
516 516 }
517 517 return (zhp);
518 518 }
519 519
520 520 zfs_handle_t *
521 521 zfs_handle_dup(zfs_handle_t *zhp_orig)
522 522 {
523 523 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
524 524
525 525 if (zhp == NULL)
526 526 return (NULL);
527 527
528 528 zhp->zfs_hdl = zhp_orig->zfs_hdl;
529 529 zhp->zpool_hdl = zhp_orig->zpool_hdl;
530 530 (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
531 531 sizeof (zhp->zfs_name));
532 532 zhp->zfs_type = zhp_orig->zfs_type;
533 533 zhp->zfs_head_type = zhp_orig->zfs_head_type;
534 534 zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
535 535 if (zhp_orig->zfs_props != NULL) {
536 536 if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
537 537 (void) no_memory(zhp->zfs_hdl);
538 538 zfs_close(zhp);
539 539 return (NULL);
540 540 }
541 541 }
542 542 if (zhp_orig->zfs_user_props != NULL) {
543 543 if (nvlist_dup(zhp_orig->zfs_user_props,
544 544 &zhp->zfs_user_props, 0) != 0) {
545 545 (void) no_memory(zhp->zfs_hdl);
546 546 zfs_close(zhp);
547 547 return (NULL);
548 548 }
549 549 }
550 550 if (zhp_orig->zfs_recvd_props != NULL) {
551 551 if (nvlist_dup(zhp_orig->zfs_recvd_props,
552 552 &zhp->zfs_recvd_props, 0)) {
553 553 (void) no_memory(zhp->zfs_hdl);
554 554 zfs_close(zhp);
555 555 return (NULL);
556 556 }
557 557 }
558 558 zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
559 559 if (zhp_orig->zfs_mntopts != NULL) {
560 560 zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
561 561 zhp_orig->zfs_mntopts);
562 562 }
563 563 zhp->zfs_props_table = zhp_orig->zfs_props_table;
564 564 return (zhp);
565 565 }
566 566
567 567 boolean_t
568 568 zfs_bookmark_exists(const char *path)
569 569 {
570 570 nvlist_t *bmarks;
571 571 nvlist_t *props;
572 572 char fsname[ZFS_MAXNAMELEN];
573 573 char *bmark_name;
574 574 char *pound;
575 575 int err;
576 576 boolean_t rv;
577 577
578 578
579 579 (void) strlcpy(fsname, path, sizeof (fsname));
580 580 pound = strchr(fsname, '#');
581 581 if (pound == NULL)
582 582 return (B_FALSE);
583 583
584 584 *pound = '\0';
585 585 bmark_name = pound + 1;
586 586 props = fnvlist_alloc();
587 587 err = lzc_get_bookmarks(fsname, props, &bmarks);
588 588 nvlist_free(props);
589 589 if (err != 0) {
590 590 nvlist_free(bmarks);
591 591 return (B_FALSE);
592 592 }
593 593
594 594 rv = nvlist_exists(bmarks, bmark_name);
595 595 nvlist_free(bmarks);
596 596 return (rv);
597 597 }
598 598
599 599 zfs_handle_t *
600 600 make_bookmark_handle(zfs_handle_t *parent, const char *path,
601 601 nvlist_t *bmark_props)
602 602 {
603 603 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
604 604
605 605 if (zhp == NULL)
606 606 return (NULL);
607 607
608 608 /* Fill in the name. */
609 609 zhp->zfs_hdl = parent->zfs_hdl;
610 610 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
611 611
612 612 /* Set the property lists. */
613 613 if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
614 614 free(zhp);
615 615 return (NULL);
616 616 }
617 617
618 618 /* Set the types. */
619 619 zhp->zfs_head_type = parent->zfs_head_type;
620 620 zhp->zfs_type = ZFS_TYPE_BOOKMARK;
621 621
622 622 if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
623 623 nvlist_free(zhp->zfs_props);
624 624 free(zhp);
625 625 return (NULL);
626 626 }
627 627
628 628 return (zhp);
629 629 }
630 630
631 631 /*
632 632 * Opens the given snapshot, filesystem, or volume. The 'types'
633 633 * argument is a mask of acceptable types. The function will print an
634 634 * appropriate error message and return NULL if it can't be opened.
635 635 */
636 636 zfs_handle_t *
637 637 zfs_open(libzfs_handle_t *hdl, const char *path, int types)
638 638 {
639 639 zfs_handle_t *zhp;
640 640 char errbuf[1024];
641 641
642 642 (void) snprintf(errbuf, sizeof (errbuf),
643 643 dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
644 644
645 645 /*
646 646 * Validate the name before we even try to open it.
647 647 */
648 648 if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
649 649 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
650 650 "invalid dataset name"));
651 651 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
652 652 return (NULL);
653 653 }
654 654
655 655 /*
656 656 * Try to get stats for the dataset, which will tell us if it exists.
657 657 */
658 658 errno = 0;
659 659 if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
660 660 (void) zfs_standard_error(hdl, errno, errbuf);
661 661 return (NULL);
662 662 }
663 663
664 664 if (!(types & zhp->zfs_type)) {
665 665 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
666 666 zfs_close(zhp);
667 667 return (NULL);
668 668 }
669 669
670 670 return (zhp);
671 671 }
672 672
673 673 /*
674 674 * Release a ZFS handle. Nothing to do but free the associated memory.
675 675 */
676 676 void
677 677 zfs_close(zfs_handle_t *zhp)
678 678 {
679 679 if (zhp->zfs_mntopts)
680 680 free(zhp->zfs_mntopts);
681 681 nvlist_free(zhp->zfs_props);
682 682 nvlist_free(zhp->zfs_user_props);
683 683 nvlist_free(zhp->zfs_recvd_props);
684 684 free(zhp);
685 685 }
686 686
687 687 typedef struct mnttab_node {
688 688 struct mnttab mtn_mt;
689 689 avl_node_t mtn_node;
690 690 } mnttab_node_t;
691 691
692 692 static int
693 693 libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
694 694 {
695 695 const mnttab_node_t *mtn1 = arg1;
696 696 const mnttab_node_t *mtn2 = arg2;
697 697 int rv;
698 698
699 699 rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
700 700
701 701 if (rv == 0)
702 702 return (0);
703 703 return (rv > 0 ? 1 : -1);
704 704 }
705 705
706 706 void
707 707 libzfs_mnttab_init(libzfs_handle_t *hdl)
708 708 {
709 709 assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
710 710 avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
711 711 sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
712 712 }
713 713
714 714 void
715 715 libzfs_mnttab_update(libzfs_handle_t *hdl)
716 716 {
717 717 struct mnttab entry;
718 718
719 719 rewind(hdl->libzfs_mnttab);
720 720 while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
721 721 mnttab_node_t *mtn;
722 722
723 723 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
724 724 continue;
725 725 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
726 726 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
727 727 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
728 728 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
729 729 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
730 730 avl_add(&hdl->libzfs_mnttab_cache, mtn);
731 731 }
732 732 }
733 733
734 734 void
735 735 libzfs_mnttab_fini(libzfs_handle_t *hdl)
736 736 {
737 737 void *cookie = NULL;
738 738 mnttab_node_t *mtn;
739 739
740 740 while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) {
741 741 free(mtn->mtn_mt.mnt_special);
742 742 free(mtn->mtn_mt.mnt_mountp);
743 743 free(mtn->mtn_mt.mnt_fstype);
744 744 free(mtn->mtn_mt.mnt_mntopts);
745 745 free(mtn);
746 746 }
747 747 avl_destroy(&hdl->libzfs_mnttab_cache);
748 748 }
749 749
750 750 void
751 751 libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
752 752 {
753 753 hdl->libzfs_mnttab_enable = enable;
754 754 }
755 755
756 756 int
757 757 libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
758 758 struct mnttab *entry)
759 759 {
760 760 mnttab_node_t find;
761 761 mnttab_node_t *mtn;
762 762
763 763 if (!hdl->libzfs_mnttab_enable) {
764 764 struct mnttab srch = { 0 };
765 765
766 766 if (avl_numnodes(&hdl->libzfs_mnttab_cache))
767 767 libzfs_mnttab_fini(hdl);
768 768 rewind(hdl->libzfs_mnttab);
769 769 srch.mnt_special = (char *)fsname;
770 770 srch.mnt_fstype = MNTTYPE_ZFS;
771 771 if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
772 772 return (0);
773 773 else
774 774 return (ENOENT);
775 775 }
776 776
777 777 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
778 778 libzfs_mnttab_update(hdl);
779 779
780 780 find.mtn_mt.mnt_special = (char *)fsname;
781 781 mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
782 782 if (mtn) {
783 783 *entry = mtn->mtn_mt;
784 784 return (0);
785 785 }
786 786 return (ENOENT);
787 787 }
788 788
789 789 void
790 790 libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
791 791 const char *mountp, const char *mntopts)
792 792 {
793 793 mnttab_node_t *mtn;
794 794
795 795 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
796 796 return;
797 797 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
798 798 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
799 799 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
800 800 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
801 801 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
802 802 avl_add(&hdl->libzfs_mnttab_cache, mtn);
803 803 }
804 804
805 805 void
806 806 libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
807 807 {
808 808 mnttab_node_t find;
809 809 mnttab_node_t *ret;
810 810
811 811 find.mtn_mt.mnt_special = (char *)fsname;
812 812 if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) {
813 813 avl_remove(&hdl->libzfs_mnttab_cache, ret);
814 814 free(ret->mtn_mt.mnt_special);
815 815 free(ret->mtn_mt.mnt_mountp);
816 816 free(ret->mtn_mt.mnt_fstype);
817 817 free(ret->mtn_mt.mnt_mntopts);
818 818 free(ret);
819 819 }
820 820 }
821 821
822 822 int
823 823 zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
824 824 {
825 825 zpool_handle_t *zpool_handle = zhp->zpool_hdl;
826 826
827 827 if (zpool_handle == NULL)
828 828 return (-1);
829 829
830 830 *spa_version = zpool_get_prop_int(zpool_handle,
831 831 ZPOOL_PROP_VERSION, NULL);
832 832 return (0);
833 833 }
834 834
835 835 /*
836 836 * The choice of reservation property depends on the SPA version.
837 837 */
838 838 static int
839 839 zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
840 840 {
841 841 int spa_version;
842 842
843 843 if (zfs_spa_version(zhp, &spa_version) < 0)
844 844 return (-1);
845 845
846 846 if (spa_version >= SPA_VERSION_REFRESERVATION)
847 847 *resv_prop = ZFS_PROP_REFRESERVATION;
848 848 else
849 849 *resv_prop = ZFS_PROP_RESERVATION;
850 850
851 851 return (0);
852 852 }
853 853
854 854 /*
855 855 * Given an nvlist of properties to set, validates that they are correct, and
856 856 * parses any numeric properties (index, boolean, etc) if they are specified as
857 857 * strings.
858 858 */
859 859 nvlist_t *
860 860 zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
861 861 uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
862 862 {
863 863 nvpair_t *elem;
864 864 uint64_t intval;
865 865 char *strval;
866 866 zfs_prop_t prop;
867 867 nvlist_t *ret;
868 868 int chosen_normal = -1;
869 869 int chosen_utf = -1;
870 870
871 871 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
872 872 (void) no_memory(hdl);
873 873 return (NULL);
874 874 }
875 875
876 876 /*
877 877 * Make sure this property is valid and applies to this type.
878 878 */
879 879
880 880 elem = NULL;
881 881 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
882 882 const char *propname = nvpair_name(elem);
883 883
884 884 prop = zfs_name_to_prop(propname);
885 885 if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
886 886 /*
887 887 * This is a user property: make sure it's a
888 888 * string, and that it's less than ZAP_MAXNAMELEN.
889 889 */
890 890 if (nvpair_type(elem) != DATA_TYPE_STRING) {
891 891 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
892 892 "'%s' must be a string"), propname);
893 893 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
894 894 goto error;
895 895 }
896 896
897 897 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
898 898 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
899 899 "property name '%s' is too long"),
900 900 propname);
901 901 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
902 902 goto error;
903 903 }
904 904
905 905 (void) nvpair_value_string(elem, &strval);
906 906 if (nvlist_add_string(ret, propname, strval) != 0) {
907 907 (void) no_memory(hdl);
908 908 goto error;
909 909 }
910 910 continue;
911 911 }
912 912
913 913 /*
914 914 * Currently, only user properties can be modified on
915 915 * snapshots.
916 916 */
917 917 if (type == ZFS_TYPE_SNAPSHOT) {
918 918 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
919 919 "this property can not be modified for snapshots"));
920 920 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
921 921 goto error;
922 922 }
923 923
924 924 if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
925 925 zfs_userquota_prop_t uqtype;
926 926 char newpropname[128];
927 927 char domain[128];
928 928 uint64_t rid;
929 929 uint64_t valary[3];
930 930
931 931 if (userquota_propname_decode(propname, zoned,
932 932 &uqtype, domain, sizeof (domain), &rid) != 0) {
933 933 zfs_error_aux(hdl,
934 934 dgettext(TEXT_DOMAIN,
935 935 "'%s' has an invalid user/group name"),
936 936 propname);
937 937 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
938 938 goto error;
939 939 }
940 940
941 941 if (uqtype != ZFS_PROP_USERQUOTA &&
942 942 uqtype != ZFS_PROP_GROUPQUOTA) {
943 943 zfs_error_aux(hdl,
944 944 dgettext(TEXT_DOMAIN, "'%s' is readonly"),
945 945 propname);
946 946 (void) zfs_error(hdl, EZFS_PROPREADONLY,
947 947 errbuf);
948 948 goto error;
949 949 }
950 950
951 951 if (nvpair_type(elem) == DATA_TYPE_STRING) {
952 952 (void) nvpair_value_string(elem, &strval);
953 953 if (strcmp(strval, "none") == 0) {
954 954 intval = 0;
955 955 } else if (zfs_nicestrtonum(hdl,
956 956 strval, &intval) != 0) {
957 957 (void) zfs_error(hdl,
958 958 EZFS_BADPROP, errbuf);
959 959 goto error;
960 960 }
961 961 } else if (nvpair_type(elem) ==
962 962 DATA_TYPE_UINT64) {
963 963 (void) nvpair_value_uint64(elem, &intval);
964 964 if (intval == 0) {
965 965 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
966 966 "use 'none' to disable "
967 967 "userquota/groupquota"));
968 968 goto error;
969 969 }
970 970 } else {
971 971 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
972 972 "'%s' must be a number"), propname);
973 973 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
974 974 goto error;
975 975 }
976 976
977 977 /*
978 978 * Encode the prop name as
979 979 * userquota@<hex-rid>-domain, to make it easy
980 980 * for the kernel to decode.
981 981 */
982 982 (void) snprintf(newpropname, sizeof (newpropname),
983 983 "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
984 984 (longlong_t)rid, domain);
985 985 valary[0] = uqtype;
986 986 valary[1] = rid;
987 987 valary[2] = intval;
988 988 if (nvlist_add_uint64_array(ret, newpropname,
989 989 valary, 3) != 0) {
990 990 (void) no_memory(hdl);
991 991 goto error;
992 992 }
993 993 continue;
994 994 } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
995 995 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
996 996 "'%s' is readonly"),
997 997 propname);
998 998 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
999 999 goto error;
1000 1000 }
1001 1001
1002 1002 if (prop == ZPROP_INVAL) {
1003 1003 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1004 1004 "invalid property '%s'"), propname);
1005 1005 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1006 1006 goto error;
1007 1007 }
1008 1008
1009 1009 if (!zfs_prop_valid_for_type(prop, type)) {
1010 1010 zfs_error_aux(hdl,
1011 1011 dgettext(TEXT_DOMAIN, "'%s' does not "
1012 1012 "apply to datasets of this type"), propname);
1013 1013 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
1014 1014 goto error;
1015 1015 }
1016 1016
1017 1017 if (zfs_prop_readonly(prop) &&
1018 1018 (!zfs_prop_setonce(prop) || zhp != NULL)) {
1019 1019 zfs_error_aux(hdl,
1020 1020 dgettext(TEXT_DOMAIN, "'%s' is readonly"),
1021 1021 propname);
1022 1022 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
1023 1023 goto error;
1024 1024 }
1025 1025
1026 1026 if (zprop_parse_value(hdl, elem, prop, type, ret,
1027 1027 &strval, &intval, errbuf) != 0)
1028 1028 goto error;
1029 1029
1030 1030 /*
1031 1031 * Perform some additional checks for specific properties.
1032 1032 */
1033 1033 switch (prop) {
1034 1034 case ZFS_PROP_VERSION:
1035 1035 {
1036 1036 int version;
1037 1037
1038 1038 if (zhp == NULL)
1039 1039 break;
1040 1040 version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1041 1041 if (intval < version) {
1042 1042 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1043 1043 "Can not downgrade; already at version %u"),
1044 1044 version);
1045 1045 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1046 1046 goto error;
1047 1047 }
1048 1048 break;
1049 1049 }
1050 1050
1051 1051 case ZFS_PROP_VOLBLOCKSIZE:
1052 1052 case ZFS_PROP_RECORDSIZE:
1053 1053 {
1054 1054 int maxbs = SPA_MAXBLOCKSIZE;
1055 1055 if (zhp != NULL) {
1056 1056 maxbs = zpool_get_prop_int(zhp->zpool_hdl,
1057 1057 ZPOOL_PROP_MAXBLOCKSIZE, NULL);
1058 1058 }
1059 1059 /*
1060 1060 * Volumes are limited to a volblocksize of 128KB,
1061 1061 * because they typically service workloads with
1062 1062 * small random writes, which incur a large performance
1063 1063 * penalty with large blocks.
1064 1064 */
1065 1065 if (prop == ZFS_PROP_VOLBLOCKSIZE)
1066 1066 maxbs = SPA_OLD_MAXBLOCKSIZE;
1067 1067 /*
1068 1068 * The value must be a power of two between
1069 1069 * SPA_MINBLOCKSIZE and maxbs.
1070 1070 */
1071 1071 if (intval < SPA_MINBLOCKSIZE ||
1072 1072 intval > maxbs || !ISP2(intval)) {
1073 1073 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1074 1074 "'%s' must be power of 2 from 512B "
1075 1075 "to %uKB"), propname, maxbs >> 10);
1076 1076 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1077 1077 goto error;
1078 1078 }
1079 1079 break;
1080 1080 }
1081 1081 case ZFS_PROP_MLSLABEL:
1082 1082 {
1083 1083 /*
1084 1084 * Verify the mlslabel string and convert to
1085 1085 * internal hex label string.
1086 1086 */
1087 1087
1088 1088 m_label_t *new_sl;
1089 1089 char *hex = NULL; /* internal label string */
1090 1090
1091 1091 /* Default value is already OK. */
1092 1092 if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
1093 1093 break;
1094 1094
1095 1095 /* Verify the label can be converted to binary form */
1096 1096 if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
1097 1097 (str_to_label(strval, &new_sl, MAC_LABEL,
1098 1098 L_NO_CORRECTION, NULL) == -1)) {
1099 1099 goto badlabel;
1100 1100 }
1101 1101
1102 1102 /* Now translate to hex internal label string */
1103 1103 if (label_to_str(new_sl, &hex, M_INTERNAL,
1104 1104 DEF_NAMES) != 0) {
1105 1105 if (hex)
1106 1106 free(hex);
1107 1107 goto badlabel;
1108 1108 }
1109 1109 m_label_free(new_sl);
1110 1110
1111 1111 /* If string is already in internal form, we're done. */
1112 1112 if (strcmp(strval, hex) == 0) {
1113 1113 free(hex);
1114 1114 break;
1115 1115 }
1116 1116
1117 1117 /* Replace the label string with the internal form. */
1118 1118 (void) nvlist_remove(ret, zfs_prop_to_name(prop),
1119 1119 DATA_TYPE_STRING);
1120 1120 verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
1121 1121 hex) == 0);
1122 1122 free(hex);
1123 1123
1124 1124 break;
1125 1125
1126 1126 badlabel:
1127 1127 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1128 1128 "invalid mlslabel '%s'"), strval);
1129 1129 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1130 1130 m_label_free(new_sl); /* OK if null */
1131 1131 goto error;
1132 1132
1133 1133 }
1134 1134
1135 1135 case ZFS_PROP_MOUNTPOINT:
1136 1136 {
1137 1137 namecheck_err_t why;
1138 1138
1139 1139 if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
1140 1140 strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
1141 1141 break;
1142 1142
1143 1143 if (mountpoint_namecheck(strval, &why)) {
1144 1144 switch (why) {
1145 1145 case NAME_ERR_LEADING_SLASH:
1146 1146 zfs_error_aux(hdl,
1147 1147 dgettext(TEXT_DOMAIN,
1148 1148 "'%s' must be an absolute path, "
1149 1149 "'none', or 'legacy'"), propname);
1150 1150 break;
1151 1151 case NAME_ERR_TOOLONG:
1152 1152 zfs_error_aux(hdl,
1153 1153 dgettext(TEXT_DOMAIN,
1154 1154 "component of '%s' is too long"),
1155 1155 propname);
1156 1156 break;
1157 1157 }
1158 1158 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1159 1159 goto error;
1160 1160 }
1161 1161 }
1162 1162
1163 1163 /*FALLTHRU*/
1164 1164
1165 1165 case ZFS_PROP_SHARESMB:
1166 1166 case ZFS_PROP_SHARENFS:
1167 1167 /*
1168 1168 * For the mountpoint and sharenfs or sharesmb
1169 1169 * properties, check if it can be set in a
1170 1170 * global/non-global zone based on
1171 1171 * the zoned property value:
1172 1172 *
1173 1173 * global zone non-global zone
1174 1174 * --------------------------------------------------
1175 1175 * zoned=on mountpoint (no) mountpoint (yes)
1176 1176 * sharenfs (no) sharenfs (no)
1177 1177 * sharesmb (no) sharesmb (no)
1178 1178 *
1179 1179 * zoned=off mountpoint (yes) N/A
1180 1180 * sharenfs (yes)
1181 1181 * sharesmb (yes)
1182 1182 */
1183 1183 if (zoned) {
1184 1184 if (getzoneid() == GLOBAL_ZONEID) {
1185 1185 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1186 1186 "'%s' cannot be set on "
1187 1187 "dataset in a non-global zone"),
1188 1188 propname);
1189 1189 (void) zfs_error(hdl, EZFS_ZONED,
1190 1190 errbuf);
1191 1191 goto error;
1192 1192 } else if (prop == ZFS_PROP_SHARENFS ||
1193 1193 prop == ZFS_PROP_SHARESMB) {
1194 1194 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1195 1195 "'%s' cannot be set in "
1196 1196 "a non-global zone"), propname);
1197 1197 (void) zfs_error(hdl, EZFS_ZONED,
1198 1198 errbuf);
1199 1199 goto error;
1200 1200 }
1201 1201 } else if (getzoneid() != GLOBAL_ZONEID) {
1202 1202 /*
1203 1203 * If zoned property is 'off', this must be in
1204 1204 * a global zone. If not, something is wrong.
1205 1205 */
1206 1206 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1207 1207 "'%s' cannot be set while dataset "
1208 1208 "'zoned' property is set"), propname);
1209 1209 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
1210 1210 goto error;
1211 1211 }
1212 1212
1213 1213 /*
1214 1214 * At this point, it is legitimate to set the
1215 1215 * property. Now we want to make sure that the
1216 1216 * property value is valid if it is sharenfs.
1217 1217 */
1218 1218 if ((prop == ZFS_PROP_SHARENFS ||
1219 1219 prop == ZFS_PROP_SHARESMB) &&
1220 1220 strcmp(strval, "on") != 0 &&
1221 1221 strcmp(strval, "off") != 0) {
1222 1222 zfs_share_proto_t proto;
1223 1223
1224 1224 if (prop == ZFS_PROP_SHARESMB)
1225 1225 proto = PROTO_SMB;
1226 1226 else
1227 1227 proto = PROTO_NFS;
1228 1228
1229 1229 /*
1230 1230 * Must be an valid sharing protocol
1231 1231 * option string so init the libshare
1232 1232 * in order to enable the parser and
1233 1233 * then parse the options. We use the
1234 1234 * control API since we don't care about
1235 1235 * the current configuration and don't
1236 1236 * want the overhead of loading it
1237 1237 * until we actually do something.
1238 1238 */
1239 1239
1240 1240 if (zfs_init_libshare(hdl,
1241 1241 SA_INIT_CONTROL_API) != SA_OK) {
1242 1242 /*
1243 1243 * An error occurred so we can't do
1244 1244 * anything
1245 1245 */
1246 1246 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1247 1247 "'%s' cannot be set: problem "
1248 1248 "in share initialization"),
1249 1249 propname);
1250 1250 (void) zfs_error(hdl, EZFS_BADPROP,
1251 1251 errbuf);
1252 1252 goto error;
1253 1253 }
1254 1254
1255 1255 if (zfs_parse_options(strval, proto) != SA_OK) {
1256 1256 /*
1257 1257 * There was an error in parsing so
1258 1258 * deal with it by issuing an error
1259 1259 * message and leaving after
1260 1260 * uninitializing the the libshare
1261 1261 * interface.
1262 1262 */
1263 1263 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1264 1264 "'%s' cannot be set to invalid "
1265 1265 "options"), propname);
1266 1266 (void) zfs_error(hdl, EZFS_BADPROP,
1267 1267 errbuf);
1268 1268 zfs_uninit_libshare(hdl);
1269 1269 goto error;
1270 1270 }
1271 1271 zfs_uninit_libshare(hdl);
1272 1272 }
1273 1273
1274 1274 break;
1275 1275 case ZFS_PROP_UTF8ONLY:
1276 1276 chosen_utf = (int)intval;
1277 1277 break;
1278 1278 case ZFS_PROP_NORMALIZE:
1279 1279 chosen_normal = (int)intval;
1280 1280 break;
1281 1281 }
1282 1282
1283 1283 /*
1284 1284 * For changes to existing volumes, we have some additional
1285 1285 * checks to enforce.
1286 1286 */
1287 1287 if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1288 1288 uint64_t volsize = zfs_prop_get_int(zhp,
1289 1289 ZFS_PROP_VOLSIZE);
1290 1290 uint64_t blocksize = zfs_prop_get_int(zhp,
1291 1291 ZFS_PROP_VOLBLOCKSIZE);
1292 1292 char buf[64];
1293 1293
1294 1294 switch (prop) {
1295 1295 case ZFS_PROP_RESERVATION:
1296 1296 case ZFS_PROP_REFRESERVATION:
1297 1297 if (intval > volsize) {
1298 1298 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1299 1299 "'%s' is greater than current "
1300 1300 "volume size"), propname);
1301 1301 (void) zfs_error(hdl, EZFS_BADPROP,
1302 1302 errbuf);
1303 1303 goto error;
1304 1304 }
1305 1305 break;
1306 1306
1307 1307 case ZFS_PROP_VOLSIZE:
1308 1308 if (intval % blocksize != 0) {
1309 1309 zfs_nicenum(blocksize, buf,
1310 1310 sizeof (buf));
1311 1311 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1312 1312 "'%s' must be a multiple of "
1313 1313 "volume block size (%s)"),
1314 1314 propname, buf);
1315 1315 (void) zfs_error(hdl, EZFS_BADPROP,
1316 1316 errbuf);
1317 1317 goto error;
1318 1318 }
1319 1319
1320 1320 if (intval == 0) {
1321 1321 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1322 1322 "'%s' cannot be zero"),
1323 1323 propname);
1324 1324 (void) zfs_error(hdl, EZFS_BADPROP,
1325 1325 errbuf);
1326 1326 goto error;
1327 1327 }
1328 1328 break;
1329 1329 }
1330 1330 }
1331 1331 }
1332 1332
1333 1333 /*
1334 1334 * If normalization was chosen, but no UTF8 choice was made,
1335 1335 * enforce rejection of non-UTF8 names.
1336 1336 *
1337 1337 * If normalization was chosen, but rejecting non-UTF8 names
1338 1338 * was explicitly not chosen, it is an error.
1339 1339 */
1340 1340 if (chosen_normal > 0 && chosen_utf < 0) {
1341 1341 if (nvlist_add_uint64(ret,
1342 1342 zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
1343 1343 (void) no_memory(hdl);
1344 1344 goto error;
1345 1345 }
1346 1346 } else if (chosen_normal > 0 && chosen_utf == 0) {
1347 1347 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1348 1348 "'%s' must be set 'on' if normalization chosen"),
1349 1349 zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1350 1350 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1351 1351 goto error;
1352 1352 }
1353 1353 return (ret);
1354 1354
1355 1355 error:
1356 1356 nvlist_free(ret);
1357 1357 return (NULL);
1358 1358 }
1359 1359
1360 1360 int
1361 1361 zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1362 1362 {
1363 1363 uint64_t old_volsize;
1364 1364 uint64_t new_volsize;
1365 1365 uint64_t old_reservation;
1366 1366 uint64_t new_reservation;
1367 1367 zfs_prop_t resv_prop;
1368 1368 nvlist_t *props;
1369 1369
1370 1370 /*
1371 1371 * If this is an existing volume, and someone is setting the volsize,
1372 1372 * make sure that it matches the reservation, or add it if necessary.
1373 1373 */
1374 1374 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1375 1375 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1376 1376 return (-1);
1377 1377 old_reservation = zfs_prop_get_int(zhp, resv_prop);
1378 1378
1379 1379 props = fnvlist_alloc();
1380 1380 fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1381 1381 zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1382 1382
1383 1383 if ((zvol_volsize_to_reservation(old_volsize, props) !=
1384 1384 old_reservation) || nvlist_exists(nvl,
1385 1385 zfs_prop_to_name(resv_prop))) {
1386 1386 fnvlist_free(props);
1387 1387 return (0);
1388 1388 }
1389 1389 if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1390 1390 &new_volsize) != 0) {
1391 1391 fnvlist_free(props);
1392 1392 return (-1);
1393 1393 }
1394 1394 new_reservation = zvol_volsize_to_reservation(new_volsize, props);
1395 1395 fnvlist_free(props);
1396 1396
1397 1397 if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1398 1398 new_reservation) != 0) {
1399 1399 (void) no_memory(zhp->zfs_hdl);
1400 1400 return (-1);
1401 1401 }
1402 1402 return (1);
1403 1403 }
1404 1404
1405 1405 void
1406 1406 zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1407 1407 char *errbuf)
1408 1408 {
1409 1409 switch (err) {
1410 1410
1411 1411 case ENOSPC:
1412 1412 /*
1413 1413 * For quotas and reservations, ENOSPC indicates
1414 1414 * something different; setting a quota or reservation
1415 1415 * doesn't use any disk space.
1416 1416 */
1417 1417 switch (prop) {
1418 1418 case ZFS_PROP_QUOTA:
1419 1419 case ZFS_PROP_REFQUOTA:
1420 1420 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1421 1421 "size is less than current used or "
1422 1422 "reserved space"));
1423 1423 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1424 1424 break;
1425 1425
1426 1426 case ZFS_PROP_RESERVATION:
1427 1427 case ZFS_PROP_REFRESERVATION:
1428 1428 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1429 1429 "size is greater than available space"));
1430 1430 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1431 1431 break;
1432 1432
1433 1433 default:
1434 1434 (void) zfs_standard_error(hdl, err, errbuf);
1435 1435 break;
1436 1436 }
1437 1437 break;
1438 1438
1439 1439 case EBUSY:
1440 1440 (void) zfs_standard_error(hdl, EBUSY, errbuf);
1441 1441 break;
1442 1442
1443 1443 case EROFS:
1444 1444 (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1445 1445 break;
1446 1446
1447 1447 case E2BIG:
1448 1448 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1449 1449 "property value too long"));
1450 1450 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1451 1451 break;
1452 1452
1453 1453 case ENOTSUP:
1454 1454 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1455 1455 "pool and or dataset must be upgraded to set this "
1456 1456 "property or value"));
1457 1457 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1458 1458 break;
1459 1459
1460 1460 case ERANGE:
1461 1461 if (prop == ZFS_PROP_COMPRESSION ||
1462 1462 prop == ZFS_PROP_RECORDSIZE) {
1463 1463 (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1464 1464 "property setting is not allowed on "
1465 1465 "bootable datasets"));
1466 1466 (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1467 1467 } else {
1468 1468 (void) zfs_standard_error(hdl, err, errbuf);
1469 1469 }
1470 1470 break;
1471 1471
1472 1472 case EINVAL:
1473 1473 if (prop == ZPROP_INVAL) {
1474 1474 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1475 1475 } else {
1476 1476 (void) zfs_standard_error(hdl, err, errbuf);
1477 1477 }
1478 1478 break;
1479 1479
1480 1480 case EOVERFLOW:
1481 1481 /*
1482 1482 * This platform can't address a volume this big.
1483 1483 */
1484 1484 #ifdef _ILP32
1485 1485 if (prop == ZFS_PROP_VOLSIZE) {
1486 1486 (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1487 1487 break;
1488 1488 }
1489 1489 #endif
1490 1490 /* FALLTHROUGH */
1491 1491 default:
1492 1492 (void) zfs_standard_error(hdl, err, errbuf);
1493 1493 }
1494 1494 }
1495 1495
1496 1496 /*
1497 1497 * Given a property name and value, set the property for the given dataset.
1498 1498 */
1499 1499 int
1500 1500 zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1501 1501 {
1502 1502 int ret = -1;
1503 1503 char errbuf[1024];
1504 1504 libzfs_handle_t *hdl = zhp->zfs_hdl;
1505 1505 nvlist_t *nvl = NULL;
1506 1506
1507 1507 (void) snprintf(errbuf, sizeof (errbuf),
1508 1508 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1509 1509 zhp->zfs_name);
1510 1510
1511 1511 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1512 1512 nvlist_add_string(nvl, propname, propval) != 0) {
1513 1513 (void) no_memory(hdl);
1514 1514 goto error;
1515 1515 }
1516 1516
1517 1517 ret = zfs_prop_set_list(zhp, nvl);
1518 1518
1519 1519 error:
1520 1520 nvlist_free(nvl);
1521 1521 return (ret);
1522 1522 }
1523 1523
1524 1524
1525 1525
1526 1526 /*
1527 1527 * Given an nvlist of property names and values, set the properties for the
1528 1528 * given dataset.
1529 1529 */
1530 1530 int
1531 1531 zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
1532 1532 {
1533 1533 zfs_cmd_t zc = { 0 };
1534 1534 int ret = -1;
1535 1535 prop_changelist_t **cls = NULL;
1536 1536 int cl_idx;
1537 1537 char errbuf[1024];
1538 1538 libzfs_handle_t *hdl = zhp->zfs_hdl;
1539 1539 nvlist_t *nvl;
1540 1540 int nvl_len;
1541 1541 int added_resv;
1542 1542
1543 1543 (void) snprintf(errbuf, sizeof (errbuf),
1544 1544 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1545 1545 zhp->zfs_name);
1546 1546
1547 1547 if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
1548 1548 zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
1549 1549 goto error;
1550 1550
1551 1551 /*
1552 1552 * We have to check for any extra properties which need to be added
1553 1553 * before computing the length of the nvlist.
1554 1554 */
1555 1555 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1556 1556 elem != NULL;
1557 1557 elem = nvlist_next_nvpair(nvl, elem)) {
1558 1558 if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
1559 1559 (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
1560 1560 goto error;
1561 1561 }
1562 1562 }
1563 1563 /*
1564 1564 * Check how many properties we're setting and allocate an array to
1565 1565 * store changelist pointers for postfix().
1566 1566 */
1567 1567 nvl_len = 0;
1568 1568 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1569 1569 elem != NULL;
1570 1570 elem = nvlist_next_nvpair(nvl, elem))
1571 1571 nvl_len++;
1572 1572 if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
1573 1573 goto error;
1574 1574
1575 1575 cl_idx = 0;
1576 1576 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1577 1577 elem != NULL;
1578 1578 elem = nvlist_next_nvpair(nvl, elem)) {
1579 1579
1580 1580 zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1581 1581
1582 1582 assert(cl_idx < nvl_len);
1583 1583 /*
1584 1584 * We don't want to unmount & remount the dataset when changing
1585 1585 * its canmount property to 'on' or 'noauto'. We only use
1586 1586 * the changelist logic to unmount when setting canmount=off.
1587 1587 */
1588 1588 if (!(prop == ZFS_PROP_CANMOUNT &&
1589 1589 fnvpair_value_uint64(elem) != ZFS_CANMOUNT_OFF)) {
1590 1590 cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
1591 1591 if (cls[cl_idx] == NULL)
1592 1592 goto error;
1593 1593 }
1594 1594
1595 1595 if (prop == ZFS_PROP_MOUNTPOINT &&
1596 1596 changelist_haszonedchild(cls[cl_idx])) {
1597 1597 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1598 1598 "child dataset with inherited mountpoint is used "
1599 1599 "in a non-global zone"));
1600 1600 ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1601 1601 goto error;
1602 1602 }
1603 1603
1604 1604 if (cls[cl_idx] != NULL &&
1605 1605 (ret = changelist_prefix(cls[cl_idx])) != 0)
1606 1606 goto error;
1607 1607
1608 1608 cl_idx++;
1609 1609 }
1610 1610 assert(cl_idx == nvl_len);
1611 1611
1612 1612 /*
1613 1613 * Execute the corresponding ioctl() to set this list of properties.
1614 1614 */
1615 1615 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1616 1616
1617 1617 if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
1618 1618 (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
1619 1619 goto error;
1620 1620
1621 1621 ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1622 1622
1623 1623 if (ret != 0) {
1624 1624 /* Get the list of unset properties back and report them. */
1625 1625 nvlist_t *errorprops = NULL;
1626 1626 if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
1627 1627 goto error;
1628 1628 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1629 1629 elem != NULL;
1630 1630 elem = nvlist_next_nvpair(nvl, elem)) {
1631 1631 zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1632 1632 zfs_setprop_error(hdl, prop, errno, errbuf);
1633 1633 }
1634 1634 nvlist_free(errorprops);
1635 1635
1636 1636 if (added_resv && errno == ENOSPC) {
1637 1637 /* clean up the volsize property we tried to set */
1638 1638 uint64_t old_volsize = zfs_prop_get_int(zhp,
1639 1639 ZFS_PROP_VOLSIZE);
1640 1640 nvlist_free(nvl);
1641 1641 nvl = NULL;
1642 1642 zcmd_free_nvlists(&zc);
1643 1643
1644 1644 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1645 1645 goto error;
1646 1646 if (nvlist_add_uint64(nvl,
1647 1647 zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1648 1648 old_volsize) != 0)
1649 1649 goto error;
1650 1650 if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1651 1651 goto error;
1652 1652 (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1653 1653 }
1654 1654 } else {
1655 1655 for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1656 1656 if (cls[cl_idx] != NULL) {
1657 1657 int clp_err = changelist_postfix(cls[cl_idx]);
1658 1658 if (clp_err != 0)
1659 1659 ret = clp_err;
1660 1660 }
1661 1661 }
1662 1662
1663 1663 /*
1664 1664 * Refresh the statistics so the new property value
1665 1665 * is reflected.
1666 1666 */
1667 1667 if (ret == 0)
1668 1668 (void) get_stats(zhp);
1669 1669 }
1670 1670
1671 1671 error:
1672 1672 nvlist_free(nvl);
1673 1673 zcmd_free_nvlists(&zc);
1674 1674 if (cls != NULL) {
1675 1675 for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1676 1676 if (cls[cl_idx] != NULL)
1677 1677 changelist_free(cls[cl_idx]);
1678 1678 }
1679 1679 free(cls);
1680 1680 }
1681 1681 return (ret);
1682 1682 }
1683 1683
1684 1684 /*
1685 1685 * Given a property, inherit the value from the parent dataset, or if received
1686 1686 * is TRUE, revert to the received value, if any.
1687 1687 */
1688 1688 int
1689 1689 zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
1690 1690 {
1691 1691 zfs_cmd_t zc = { 0 };
1692 1692 int ret;
1693 1693 prop_changelist_t *cl;
1694 1694 libzfs_handle_t *hdl = zhp->zfs_hdl;
1695 1695 char errbuf[1024];
1696 1696 zfs_prop_t prop;
1697 1697
1698 1698 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1699 1699 "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1700 1700
1701 1701 zc.zc_cookie = received;
1702 1702 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
1703 1703 /*
1704 1704 * For user properties, the amount of work we have to do is very
1705 1705 * small, so just do it here.
1706 1706 */
1707 1707 if (!zfs_prop_user(propname)) {
1708 1708 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1709 1709 "invalid property"));
1710 1710 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1711 1711 }
1712 1712
1713 1713 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1714 1714 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1715 1715
1716 1716 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
1717 1717 return (zfs_standard_error(hdl, errno, errbuf));
1718 1718
1719 1719 return (0);
1720 1720 }
1721 1721
1722 1722 /*
1723 1723 * Verify that this property is inheritable.
1724 1724 */
1725 1725 if (zfs_prop_readonly(prop))
1726 1726 return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1727 1727
1728 1728 if (!zfs_prop_inheritable(prop) && !received)
1729 1729 return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1730 1730
1731 1731 /*
1732 1732 * Check to see if the value applies to this type
1733 1733 */
1734 1734 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1735 1735 return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1736 1736
1737 1737 /*
1738 1738 * Normalize the name, to get rid of shorthand abbreviations.
1739 1739 */
1740 1740 propname = zfs_prop_to_name(prop);
1741 1741 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1742 1742 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1743 1743
1744 1744 if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1745 1745 zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
1746 1746 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1747 1747 "dataset is used in a non-global zone"));
1748 1748 return (zfs_error(hdl, EZFS_ZONED, errbuf));
1749 1749 }
1750 1750
1751 1751 /*
1752 1752 * Determine datasets which will be affected by this change, if any.
1753 1753 */
1754 1754 if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1755 1755 return (-1);
1756 1756
1757 1757 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1758 1758 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1759 1759 "child dataset with inherited mountpoint is used "
1760 1760 "in a non-global zone"));
1761 1761 ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1762 1762 goto error;
1763 1763 }
1764 1764
1765 1765 if ((ret = changelist_prefix(cl)) != 0)
1766 1766 goto error;
1767 1767
1768 1768 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
1769 1769 return (zfs_standard_error(hdl, errno, errbuf));
1770 1770 } else {
1771 1771
1772 1772 if ((ret = changelist_postfix(cl)) != 0)
1773 1773 goto error;
1774 1774
1775 1775 /*
1776 1776 * Refresh the statistics so the new property is reflected.
1777 1777 */
1778 1778 (void) get_stats(zhp);
1779 1779 }
1780 1780
1781 1781 error:
1782 1782 changelist_free(cl);
1783 1783 return (ret);
1784 1784 }
1785 1785
1786 1786 /*
1787 1787 * True DSL properties are stored in an nvlist. The following two functions
1788 1788 * extract them appropriately.
1789 1789 */
1790 1790 static uint64_t
1791 1791 getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1792 1792 {
1793 1793 nvlist_t *nv;
1794 1794 uint64_t value;
1795 1795
1796 1796 *source = NULL;
1797 1797 if (nvlist_lookup_nvlist(zhp->zfs_props,
1798 1798 zfs_prop_to_name(prop), &nv) == 0) {
1799 1799 verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
1800 1800 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1801 1801 } else {
1802 1802 verify(!zhp->zfs_props_table ||
1803 1803 zhp->zfs_props_table[prop] == B_TRUE);
1804 1804 value = zfs_prop_default_numeric(prop);
1805 1805 *source = "";
1806 1806 }
1807 1807
1808 1808 return (value);
1809 1809 }
1810 1810
1811 1811 static char *
1812 1812 getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1813 1813 {
1814 1814 nvlist_t *nv;
1815 1815 char *value;
1816 1816
1817 1817 *source = NULL;
1818 1818 if (nvlist_lookup_nvlist(zhp->zfs_props,
1819 1819 zfs_prop_to_name(prop), &nv) == 0) {
1820 1820 verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
1821 1821 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1822 1822 } else {
1823 1823 verify(!zhp->zfs_props_table ||
1824 1824 zhp->zfs_props_table[prop] == B_TRUE);
1825 1825 if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
1826 1826 value = "";
1827 1827 *source = "";
1828 1828 }
1829 1829
1830 1830 return (value);
1831 1831 }
1832 1832
1833 1833 static boolean_t
1834 1834 zfs_is_recvd_props_mode(zfs_handle_t *zhp)
1835 1835 {
1836 1836 return (zhp->zfs_props == zhp->zfs_recvd_props);
1837 1837 }
1838 1838
1839 1839 static void
1840 1840 zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1841 1841 {
1842 1842 *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
1843 1843 zhp->zfs_props = zhp->zfs_recvd_props;
1844 1844 }
1845 1845
1846 1846 static void
1847 1847 zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1848 1848 {
1849 1849 zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
1850 1850 *cookie = 0;
1851 1851 }
1852 1852
1853 1853 /*
1854 1854 * Internal function for getting a numeric property. Both zfs_prop_get() and
1855 1855 * zfs_prop_get_int() are built using this interface.
1856 1856 *
1857 1857 * Certain properties can be overridden using 'mount -o'. In this case, scan
1858 1858 * the contents of the /etc/mnttab entry, searching for the appropriate options.
1859 1859 * If they differ from the on-disk values, report the current values and mark
1860 1860 * the source "temporary".
1861 1861 */
1862 1862 static int
1863 1863 get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
1864 1864 char **source, uint64_t *val)
1865 1865 {
1866 1866 zfs_cmd_t zc = { 0 };
1867 1867 nvlist_t *zplprops = NULL;
1868 1868 struct mnttab mnt;
1869 1869 char *mntopt_on = NULL;
1870 1870 char *mntopt_off = NULL;
1871 1871 boolean_t received = zfs_is_recvd_props_mode(zhp);
1872 1872
1873 1873 *source = NULL;
1874 1874
1875 1875 switch (prop) {
1876 1876 case ZFS_PROP_ATIME:
1877 1877 mntopt_on = MNTOPT_ATIME;
1878 1878 mntopt_off = MNTOPT_NOATIME;
1879 1879 break;
1880 1880
1881 1881 case ZFS_PROP_DEVICES:
1882 1882 mntopt_on = MNTOPT_DEVICES;
1883 1883 mntopt_off = MNTOPT_NODEVICES;
1884 1884 break;
1885 1885
1886 1886 case ZFS_PROP_EXEC:
1887 1887 mntopt_on = MNTOPT_EXEC;
1888 1888 mntopt_off = MNTOPT_NOEXEC;
1889 1889 break;
1890 1890
1891 1891 case ZFS_PROP_READONLY:
1892 1892 mntopt_on = MNTOPT_RO;
1893 1893 mntopt_off = MNTOPT_RW;
1894 1894 break;
1895 1895
1896 1896 case ZFS_PROP_SETUID:
1897 1897 mntopt_on = MNTOPT_SETUID;
1898 1898 mntopt_off = MNTOPT_NOSETUID;
1899 1899 break;
1900 1900
1901 1901 case ZFS_PROP_XATTR:
1902 1902 mntopt_on = MNTOPT_XATTR;
1903 1903 mntopt_off = MNTOPT_NOXATTR;
1904 1904 break;
1905 1905
1906 1906 case ZFS_PROP_NBMAND:
1907 1907 mntopt_on = MNTOPT_NBMAND;
1908 1908 mntopt_off = MNTOPT_NONBMAND;
1909 1909 break;
1910 1910 }
1911 1911
1912 1912 /*
1913 1913 * Because looking up the mount options is potentially expensive
1914 1914 * (iterating over all of /etc/mnttab), we defer its calculation until
1915 1915 * we're looking up a property which requires its presence.
1916 1916 */
1917 1917 if (!zhp->zfs_mntcheck &&
1918 1918 (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
1919 1919 libzfs_handle_t *hdl = zhp->zfs_hdl;
1920 1920 struct mnttab entry;
1921 1921
1922 1922 if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
1923 1923 zhp->zfs_mntopts = zfs_strdup(hdl,
1924 1924 entry.mnt_mntopts);
1925 1925 if (zhp->zfs_mntopts == NULL)
1926 1926 return (-1);
1927 1927 }
1928 1928
1929 1929 zhp->zfs_mntcheck = B_TRUE;
1930 1930 }
1931 1931
1932 1932 if (zhp->zfs_mntopts == NULL)
1933 1933 mnt.mnt_mntopts = "";
1934 1934 else
1935 1935 mnt.mnt_mntopts = zhp->zfs_mntopts;
1936 1936
1937 1937 switch (prop) {
1938 1938 case ZFS_PROP_ATIME:
1939 1939 case ZFS_PROP_DEVICES:
1940 1940 case ZFS_PROP_EXEC:
1941 1941 case ZFS_PROP_READONLY:
1942 1942 case ZFS_PROP_SETUID:
1943 1943 case ZFS_PROP_XATTR:
1944 1944 case ZFS_PROP_NBMAND:
1945 1945 *val = getprop_uint64(zhp, prop, source);
1946 1946
1947 1947 if (received)
1948 1948 break;
1949 1949
1950 1950 if (hasmntopt(&mnt, mntopt_on) && !*val) {
1951 1951 *val = B_TRUE;
1952 1952 if (src)
1953 1953 *src = ZPROP_SRC_TEMPORARY;
1954 1954 } else if (hasmntopt(&mnt, mntopt_off) && *val) {
1955 1955 *val = B_FALSE;
1956 1956 if (src)
1957 1957 *src = ZPROP_SRC_TEMPORARY;
1958 1958 }
1959 1959 break;
1960 1960
1961 1961 case ZFS_PROP_CANMOUNT:
1962 1962 case ZFS_PROP_VOLSIZE:
1963 1963 case ZFS_PROP_QUOTA:
1964 1964 case ZFS_PROP_REFQUOTA:
1965 1965 case ZFS_PROP_RESERVATION:
1966 1966 case ZFS_PROP_REFRESERVATION:
1967 1967 case ZFS_PROP_FILESYSTEM_LIMIT:
1968 1968 case ZFS_PROP_SNAPSHOT_LIMIT:
1969 1969 case ZFS_PROP_FILESYSTEM_COUNT:
1970 1970 case ZFS_PROP_SNAPSHOT_COUNT:
1971 1971 *val = getprop_uint64(zhp, prop, source);
1972 1972
1973 1973 if (*source == NULL) {
1974 1974 /* not default, must be local */
1975 1975 *source = zhp->zfs_name;
1976 1976 }
1977 1977 break;
1978 1978
1979 1979 case ZFS_PROP_MOUNTED:
1980 1980 *val = (zhp->zfs_mntopts != NULL);
1981 1981 break;
1982 1982
1983 1983 case ZFS_PROP_NUMCLONES:
1984 1984 *val = zhp->zfs_dmustats.dds_num_clones;
1985 1985 break;
1986 1986
1987 1987 case ZFS_PROP_VERSION:
1988 1988 case ZFS_PROP_NORMALIZE:
1989 1989 case ZFS_PROP_UTF8ONLY:
1990 1990 case ZFS_PROP_CASE:
1991 1991 if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
1992 1992 zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
1993 1993 return (-1);
1994 1994 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1995 1995 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
1996 1996 zcmd_free_nvlists(&zc);
1997 1997 return (-1);
1998 1998 }
1999 1999 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
2000 2000 nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
2001 2001 val) != 0) {
2002 2002 zcmd_free_nvlists(&zc);
2003 2003 return (-1);
2004 2004 }
2005 2005 if (zplprops)
2006 2006 nvlist_free(zplprops);
2007 2007 zcmd_free_nvlists(&zc);
2008 2008 break;
2009 2009
2010 2010 case ZFS_PROP_INCONSISTENT:
2011 2011 *val = zhp->zfs_dmustats.dds_inconsistent;
2012 2012 break;
2013 2013
2014 2014 default:
2015 2015 switch (zfs_prop_get_type(prop)) {
2016 2016 case PROP_TYPE_NUMBER:
2017 2017 case PROP_TYPE_INDEX:
2018 2018 *val = getprop_uint64(zhp, prop, source);
2019 2019 /*
2020 2020 * If we tried to use a default value for a
2021 2021 * readonly property, it means that it was not
2022 2022 * present.
2023 2023 */
2024 2024 if (zfs_prop_readonly(prop) &&
2025 2025 *source != NULL && (*source)[0] == '\0') {
2026 2026 *source = NULL;
2027 2027 }
2028 2028 break;
2029 2029
2030 2030 case PROP_TYPE_STRING:
2031 2031 default:
2032 2032 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2033 2033 "cannot get non-numeric property"));
2034 2034 return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
2035 2035 dgettext(TEXT_DOMAIN, "internal error")));
2036 2036 }
2037 2037 }
2038 2038
2039 2039 return (0);
2040 2040 }
2041 2041
2042 2042 /*
2043 2043 * Calculate the source type, given the raw source string.
2044 2044 */
2045 2045 static void
2046 2046 get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
2047 2047 char *statbuf, size_t statlen)
2048 2048 {
2049 2049 if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
2050 2050 return;
2051 2051
2052 2052 if (source == NULL) {
2053 2053 *srctype = ZPROP_SRC_NONE;
2054 2054 } else if (source[0] == '\0') {
2055 2055 *srctype = ZPROP_SRC_DEFAULT;
2056 2056 } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
2057 2057 *srctype = ZPROP_SRC_RECEIVED;
2058 2058 } else {
2059 2059 if (strcmp(source, zhp->zfs_name) == 0) {
2060 2060 *srctype = ZPROP_SRC_LOCAL;
2061 2061 } else {
2062 2062 (void) strlcpy(statbuf, source, statlen);
2063 2063 *srctype = ZPROP_SRC_INHERITED;
2064 2064 }
2065 2065 }
2066 2066
2067 2067 }
2068 2068
2069 2069 int
2070 2070 zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
2071 2071 size_t proplen, boolean_t literal)
2072 2072 {
2073 2073 zfs_prop_t prop;
2074 2074 int err = 0;
2075 2075
2076 2076 if (zhp->zfs_recvd_props == NULL)
2077 2077 if (get_recvd_props_ioctl(zhp) != 0)
2078 2078 return (-1);
2079 2079
2080 2080 prop = zfs_name_to_prop(propname);
2081 2081
2082 2082 if (prop != ZPROP_INVAL) {
2083 2083 uint64_t cookie;
2084 2084 if (!nvlist_exists(zhp->zfs_recvd_props, propname))
2085 2085 return (-1);
2086 2086 zfs_set_recvd_props_mode(zhp, &cookie);
2087 2087 err = zfs_prop_get(zhp, prop, propbuf, proplen,
2088 2088 NULL, NULL, 0, literal);
2089 2089 zfs_unset_recvd_props_mode(zhp, &cookie);
2090 2090 } else {
2091 2091 nvlist_t *propval;
2092 2092 char *recvdval;
2093 2093 if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
2094 2094 propname, &propval) != 0)
2095 2095 return (-1);
2096 2096 verify(nvlist_lookup_string(propval, ZPROP_VALUE,
2097 2097 &recvdval) == 0);
2098 2098 (void) strlcpy(propbuf, recvdval, proplen);
2099 2099 }
2100 2100
2101 2101 return (err == 0 ? 0 : -1);
2102 2102 }
2103 2103
2104 2104 static int
2105 2105 get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
2106 2106 {
2107 2107 nvlist_t *value;
2108 2108 nvpair_t *pair;
2109 2109
2110 2110 value = zfs_get_clones_nvl(zhp);
2111 2111 if (value == NULL)
2112 2112 return (-1);
2113 2113
2114 2114 propbuf[0] = '\0';
2115 2115 for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
2116 2116 pair = nvlist_next_nvpair(value, pair)) {
2117 2117 if (propbuf[0] != '\0')
2118 2118 (void) strlcat(propbuf, ",", proplen);
2119 2119 (void) strlcat(propbuf, nvpair_name(pair), proplen);
2120 2120 }
2121 2121
2122 2122 return (0);
2123 2123 }
2124 2124
2125 2125 struct get_clones_arg {
2126 2126 uint64_t numclones;
2127 2127 nvlist_t *value;
2128 2128 const char *origin;
2129 2129 char buf[ZFS_MAXNAMELEN];
2130 2130 };
2131 2131
2132 2132 int
2133 2133 get_clones_cb(zfs_handle_t *zhp, void *arg)
2134 2134 {
2135 2135 struct get_clones_arg *gca = arg;
2136 2136
2137 2137 if (gca->numclones == 0) {
2138 2138 zfs_close(zhp);
2139 2139 return (0);
2140 2140 }
2141 2141
2142 2142 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
2143 2143 NULL, NULL, 0, B_TRUE) != 0)
2144 2144 goto out;
2145 2145 if (strcmp(gca->buf, gca->origin) == 0) {
2146 2146 fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
2147 2147 gca->numclones--;
2148 2148 }
2149 2149
2150 2150 out:
2151 2151 (void) zfs_iter_children(zhp, get_clones_cb, gca);
2152 2152 zfs_close(zhp);
2153 2153 return (0);
2154 2154 }
2155 2155
2156 2156 nvlist_t *
2157 2157 zfs_get_clones_nvl(zfs_handle_t *zhp)
2158 2158 {
2159 2159 nvlist_t *nv, *value;
2160 2160
2161 2161 if (nvlist_lookup_nvlist(zhp->zfs_props,
2162 2162 zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
2163 2163 struct get_clones_arg gca;
2164 2164
2165 2165 /*
2166 2166 * if this is a snapshot, then the kernel wasn't able
2167 2167 * to get the clones. Do it by slowly iterating.
2168 2168 */
2169 2169 if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
2170 2170 return (NULL);
2171 2171 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
2172 2172 return (NULL);
2173 2173 if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
2174 2174 nvlist_free(nv);
2175 2175 return (NULL);
2176 2176 }
2177 2177
2178 2178 gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
2179 2179 gca.value = value;
2180 2180 gca.origin = zhp->zfs_name;
2181 2181
2182 2182 if (gca.numclones != 0) {
2183 2183 zfs_handle_t *root;
2184 2184 char pool[ZFS_MAXNAMELEN];
2185 2185 char *cp = pool;
2186 2186
2187 2187 /* get the pool name */
2188 2188 (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
2189 2189 (void) strsep(&cp, "/@");
2190 2190 root = zfs_open(zhp->zfs_hdl, pool,
2191 2191 ZFS_TYPE_FILESYSTEM);
2192 2192
2193 2193 (void) get_clones_cb(root, &gca);
2194 2194 }
2195 2195
2196 2196 if (gca.numclones != 0 ||
2197 2197 nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
2198 2198 nvlist_add_nvlist(zhp->zfs_props,
2199 2199 zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
2200 2200 nvlist_free(nv);
2201 2201 nvlist_free(value);
2202 2202 return (NULL);
2203 2203 }
2204 2204 nvlist_free(nv);
2205 2205 nvlist_free(value);
2206 2206 verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
2207 2207 zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
2208 2208 }
2209 2209
2210 2210 verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
2211 2211
2212 2212 return (value);
2213 2213 }
2214 2214
2215 2215 /*
2216 2216 * Retrieve a property from the given object. If 'literal' is specified, then
2217 2217 * numbers are left as exact values. Otherwise, numbers are converted to a
2218 2218 * human-readable form.
2219 2219 *
2220 2220 * Returns 0 on success, or -1 on error.
2221 2221 */
2222 2222 int
2223 2223 zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
2224 2224 zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
2225 2225 {
2226 2226 char *source = NULL;
2227 2227 uint64_t val;
2228 2228 char *str;
2229 2229 const char *strval;
2230 2230 boolean_t received = zfs_is_recvd_props_mode(zhp);
2231 2231
2232 2232 /*
2233 2233 * Check to see if this property applies to our object
2234 2234 */
2235 2235 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2236 2236 return (-1);
2237 2237
2238 2238 if (received && zfs_prop_readonly(prop))
2239 2239 return (-1);
2240 2240
2241 2241 if (src)
2242 2242 *src = ZPROP_SRC_NONE;
2243 2243
2244 2244 switch (prop) {
2245 2245 case ZFS_PROP_CREATION:
2246 2246 /*
2247 2247 * 'creation' is a time_t stored in the statistics. We convert
2248 2248 * this into a string unless 'literal' is specified.
2249 2249 */
2250 2250 {
2251 2251 val = getprop_uint64(zhp, prop, &source);
2252 2252 time_t time = (time_t)val;
2253 2253 struct tm t;
2254 2254
2255 2255 if (literal ||
2256 2256 localtime_r(&time, &t) == NULL ||
2257 2257 strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
2258 2258 &t) == 0)
2259 2259 (void) snprintf(propbuf, proplen, "%llu", val);
2260 2260 }
2261 2261 break;
2262 2262
2263 2263 case ZFS_PROP_MOUNTPOINT:
2264 2264 /*
2265 2265 * Getting the precise mountpoint can be tricky.
2266 2266 *
2267 2267 * - for 'none' or 'legacy', return those values.
2268 2268 * - for inherited mountpoints, we want to take everything
2269 2269 * after our ancestor and append it to the inherited value.
2270 2270 *
2271 2271 * If the pool has an alternate root, we want to prepend that
2272 2272 * root to any values we return.
2273 2273 */
2274 2274
2275 2275 str = getprop_string(zhp, prop, &source);
2276 2276
2277 2277 if (str[0] == '/') {
2278 2278 char buf[MAXPATHLEN];
2279 2279 char *root = buf;
2280 2280 const char *relpath;
2281 2281
2282 2282 /*
2283 2283 * If we inherit the mountpoint, even from a dataset
2284 2284 * with a received value, the source will be the path of
2285 2285 * the dataset we inherit from. If source is
2286 2286 * ZPROP_SOURCE_VAL_RECVD, the received value is not
2287 2287 * inherited.
2288 2288 */
2289 2289 if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
2290 2290 relpath = "";
2291 2291 } else {
2292 2292 relpath = zhp->zfs_name + strlen(source);
2293 2293 if (relpath[0] == '/')
2294 2294 relpath++;
2295 2295 }
2296 2296
2297 2297 if ((zpool_get_prop(zhp->zpool_hdl,
2298 2298 ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
2299 2299 B_FALSE)) || (strcmp(root, "-") == 0))
2300 2300 root[0] = '\0';
2301 2301 /*
2302 2302 * Special case an alternate root of '/'. This will
2303 2303 * avoid having multiple leading slashes in the
2304 2304 * mountpoint path.
2305 2305 */
2306 2306 if (strcmp(root, "/") == 0)
2307 2307 root++;
2308 2308
2309 2309 /*
2310 2310 * If the mountpoint is '/' then skip over this
2311 2311 * if we are obtaining either an alternate root or
2312 2312 * an inherited mountpoint.
2313 2313 */
2314 2314 if (str[1] == '\0' && (root[0] != '\0' ||
2315 2315 relpath[0] != '\0'))
2316 2316 str++;
2317 2317
2318 2318 if (relpath[0] == '\0')
2319 2319 (void) snprintf(propbuf, proplen, "%s%s",
2320 2320 root, str);
2321 2321 else
2322 2322 (void) snprintf(propbuf, proplen, "%s%s%s%s",
2323 2323 root, str, relpath[0] == '@' ? "" : "/",
2324 2324 relpath);
2325 2325 } else {
2326 2326 /* 'legacy' or 'none' */
2327 2327 (void) strlcpy(propbuf, str, proplen);
2328 2328 }
2329 2329
2330 2330 break;
2331 2331
2332 2332 case ZFS_PROP_ORIGIN:
2333 2333 (void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
2334 2334 proplen);
2335 2335 /*
2336 2336 * If there is no parent at all, return failure to indicate that
2337 2337 * it doesn't apply to this dataset.
2338 2338 */
2339 2339 if (propbuf[0] == '\0')
2340 2340 return (-1);
2341 2341 break;
2342 2342
2343 2343 case ZFS_PROP_CLONES:
2344 2344 if (get_clones_string(zhp, propbuf, proplen) != 0)
2345 2345 return (-1);
2346 2346 break;
2347 2347
2348 2348 case ZFS_PROP_QUOTA:
2349 2349 case ZFS_PROP_REFQUOTA:
2350 2350 case ZFS_PROP_RESERVATION:
2351 2351 case ZFS_PROP_REFRESERVATION:
2352 2352
2353 2353 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2354 2354 return (-1);
2355 2355
2356 2356 /*
2357 2357 * If quota or reservation is 0, we translate this into 'none'
2358 2358 * (unless literal is set), and indicate that it's the default
2359 2359 * value. Otherwise, we print the number nicely and indicate
2360 2360 * that its set locally.
2361 2361 */
2362 2362 if (val == 0) {
2363 2363 if (literal)
2364 2364 (void) strlcpy(propbuf, "0", proplen);
2365 2365 else
2366 2366 (void) strlcpy(propbuf, "none", proplen);
2367 2367 } else {
2368 2368 if (literal)
2369 2369 (void) snprintf(propbuf, proplen, "%llu",
2370 2370 (u_longlong_t)val);
2371 2371 else
2372 2372 zfs_nicenum(val, propbuf, proplen);
2373 2373 }
2374 2374 break;
2375 2375
2376 2376 case ZFS_PROP_FILESYSTEM_LIMIT:
2377 2377 case ZFS_PROP_SNAPSHOT_LIMIT:
2378 2378 case ZFS_PROP_FILESYSTEM_COUNT:
2379 2379 case ZFS_PROP_SNAPSHOT_COUNT:
2380 2380
2381 2381 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2382 2382 return (-1);
2383 2383
2384 2384 /*
2385 2385 * If limit is UINT64_MAX, we translate this into 'none' (unless
2386 2386 * literal is set), and indicate that it's the default value.
2387 2387 * Otherwise, we print the number nicely and indicate that it's
2388 2388 * set locally.
2389 2389 */
2390 2390 if (literal) {
2391 2391 (void) snprintf(propbuf, proplen, "%llu",
2392 2392 (u_longlong_t)val);
2393 2393 } else if (val == UINT64_MAX) {
2394 2394 (void) strlcpy(propbuf, "none", proplen);
2395 2395 } else {
2396 2396 zfs_nicenum(val, propbuf, proplen);
2397 2397 }
2398 2398 break;
2399 2399
2400 2400 case ZFS_PROP_REFRATIO:
2401 2401 case ZFS_PROP_COMPRESSRATIO:
2402 2402 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2403 2403 return (-1);
2404 2404 (void) snprintf(propbuf, proplen, "%llu.%02llux",
2405 2405 (u_longlong_t)(val / 100),
2406 2406 (u_longlong_t)(val % 100));
2407 2407 break;
2408 2408
2409 2409 case ZFS_PROP_TYPE:
2410 2410 switch (zhp->zfs_type) {
2411 2411 case ZFS_TYPE_FILESYSTEM:
2412 2412 str = "filesystem";
2413 2413 break;
2414 2414 case ZFS_TYPE_VOLUME:
2415 2415 str = "volume";
2416 2416 break;
2417 2417 case ZFS_TYPE_SNAPSHOT:
2418 2418 str = "snapshot";
2419 2419 break;
2420 2420 case ZFS_TYPE_BOOKMARK:
2421 2421 str = "bookmark";
2422 2422 break;
2423 2423 default:
2424 2424 abort();
2425 2425 }
2426 2426 (void) snprintf(propbuf, proplen, "%s", str);
2427 2427 break;
2428 2428
2429 2429 case ZFS_PROP_MOUNTED:
2430 2430 /*
2431 2431 * The 'mounted' property is a pseudo-property that described
2432 2432 * whether the filesystem is currently mounted. Even though
2433 2433 * it's a boolean value, the typical values of "on" and "off"
2434 2434 * don't make sense, so we translate to "yes" and "no".
2435 2435 */
2436 2436 if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
2437 2437 src, &source, &val) != 0)
2438 2438 return (-1);
2439 2439 if (val)
2440 2440 (void) strlcpy(propbuf, "yes", proplen);
2441 2441 else
2442 2442 (void) strlcpy(propbuf, "no", proplen);
2443 2443 break;
2444 2444
2445 2445 case ZFS_PROP_NAME:
2446 2446 /*
2447 2447 * The 'name' property is a pseudo-property derived from the
2448 2448 * dataset name. It is presented as a real property to simplify
2449 2449 * consumers.
2450 2450 */
2451 2451 (void) strlcpy(propbuf, zhp->zfs_name, proplen);
2452 2452 break;
2453 2453
2454 2454 case ZFS_PROP_MLSLABEL:
2455 2455 {
2456 2456 m_label_t *new_sl = NULL;
2457 2457 char *ascii = NULL; /* human readable label */
2458 2458
2459 2459 (void) strlcpy(propbuf,
2460 2460 getprop_string(zhp, prop, &source), proplen);
2461 2461
2462 2462 if (literal || (strcasecmp(propbuf,
2463 2463 ZFS_MLSLABEL_DEFAULT) == 0))
2464 2464 break;
2465 2465
2466 2466 /*
2467 2467 * Try to translate the internal hex string to
2468 2468 * human-readable output. If there are any
2469 2469 * problems just use the hex string.
2470 2470 */
2471 2471
2472 2472 if (str_to_label(propbuf, &new_sl, MAC_LABEL,
2473 2473 L_NO_CORRECTION, NULL) == -1) {
2474 2474 m_label_free(new_sl);
2475 2475 break;
2476 2476 }
2477 2477
2478 2478 if (label_to_str(new_sl, &ascii, M_LABEL,
2479 2479 DEF_NAMES) != 0) {
2480 2480 if (ascii)
2481 2481 free(ascii);
2482 2482 m_label_free(new_sl);
2483 2483 break;
2484 2484 }
2485 2485 m_label_free(new_sl);
2486 2486
2487 2487 (void) strlcpy(propbuf, ascii, proplen);
2488 2488 free(ascii);
2489 2489 }
2490 2490 break;
2491 2491
2492 2492 case ZFS_PROP_GUID:
2493 2493 /*
2494 2494 * GUIDs are stored as numbers, but they are identifiers.
2495 2495 * We don't want them to be pretty printed, because pretty
2496 2496 * printing mangles the ID into a truncated and useless value.
2497 2497 */
2498 2498 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2499 2499 return (-1);
2500 2500 (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
2501 2501 break;
2502 2502
2503 2503 default:
2504 2504 switch (zfs_prop_get_type(prop)) {
2505 2505 case PROP_TYPE_NUMBER:
2506 2506 if (get_numeric_property(zhp, prop, src,
2507 2507 &source, &val) != 0)
2508 2508 return (-1);
2509 2509 if (literal)
2510 2510 (void) snprintf(propbuf, proplen, "%llu",
2511 2511 (u_longlong_t)val);
2512 2512 else
2513 2513 zfs_nicenum(val, propbuf, proplen);
2514 2514 break;
2515 2515
2516 2516 case PROP_TYPE_STRING:
2517 2517 (void) strlcpy(propbuf,
2518 2518 getprop_string(zhp, prop, &source), proplen);
2519 2519 break;
2520 2520
2521 2521 case PROP_TYPE_INDEX:
2522 2522 if (get_numeric_property(zhp, prop, src,
2523 2523 &source, &val) != 0)
2524 2524 return (-1);
2525 2525 if (zfs_prop_index_to_string(prop, val, &strval) != 0)
2526 2526 return (-1);
2527 2527 (void) strlcpy(propbuf, strval, proplen);
2528 2528 break;
2529 2529
2530 2530 default:
2531 2531 abort();
2532 2532 }
2533 2533 }
2534 2534
2535 2535 get_source(zhp, src, source, statbuf, statlen);
2536 2536
2537 2537 return (0);
2538 2538 }
2539 2539
2540 2540 /*
2541 2541 * Utility function to get the given numeric property. Does no validation that
2542 2542 * the given property is the appropriate type; should only be used with
2543 2543 * hard-coded property types.
2544 2544 */
2545 2545 uint64_t
2546 2546 zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
2547 2547 {
2548 2548 char *source;
2549 2549 uint64_t val;
2550 2550
2551 2551 (void) get_numeric_property(zhp, prop, NULL, &source, &val);
2552 2552
2553 2553 return (val);
2554 2554 }
2555 2555
2556 2556 int
2557 2557 zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2558 2558 {
2559 2559 char buf[64];
2560 2560
2561 2561 (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2562 2562 return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2563 2563 }
2564 2564
2565 2565 /*
2566 2566 * Similar to zfs_prop_get(), but returns the value as an integer.
2567 2567 */
2568 2568 int
2569 2569 zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
2570 2570 zprop_source_t *src, char *statbuf, size_t statlen)
2571 2571 {
2572 2572 char *source;
2573 2573
2574 2574 /*
2575 2575 * Check to see if this property applies to our object
2576 2576 */
2577 2577 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
2578 2578 return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
2579 2579 dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
2580 2580 zfs_prop_to_name(prop)));
2581 2581 }
2582 2582
2583 2583 if (src)
2584 2584 *src = ZPROP_SRC_NONE;
2585 2585
2586 2586 if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2587 2587 return (-1);
2588 2588
2589 2589 get_source(zhp, src, source, statbuf, statlen);
2590 2590
2591 2591 return (0);
2592 2592 }
2593 2593
2594 2594 static int
2595 2595 idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2596 2596 char **domainp, idmap_rid_t *ridp)
2597 2597 {
2598 2598 idmap_get_handle_t *get_hdl = NULL;
2599 2599 idmap_stat status;
2600 2600 int err = EINVAL;
2601 2601
2602 2602 if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
2603 2603 goto out;
2604 2604
2605 2605 if (isuser) {
2606 2606 err = idmap_get_sidbyuid(get_hdl, id,
2607 2607 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2608 2608 } else {
2609 2609 err = idmap_get_sidbygid(get_hdl, id,
2610 2610 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2611 2611 }
2612 2612 if (err == IDMAP_SUCCESS &&
2613 2613 idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
2614 2614 status == IDMAP_SUCCESS)
2615 2615 err = 0;
2616 2616 else
2617 2617 err = EINVAL;
2618 2618 out:
2619 2619 if (get_hdl)
2620 2620 idmap_get_destroy(get_hdl);
2621 2621 return (err);
2622 2622 }
2623 2623
2624 2624 /*
2625 2625 * convert the propname into parameters needed by kernel
2626 2626 * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
2627 2627 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
2628 2628 */
2629 2629 static int
2630 2630 userquota_propname_decode(const char *propname, boolean_t zoned,
2631 2631 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
2632 2632 {
2633 2633 zfs_userquota_prop_t type;
2634 2634 char *cp, *end;
2635 2635 char *numericsid = NULL;
2636 2636 boolean_t isuser;
2637 2637
2638 2638 domain[0] = '\0';
2639 2639 *ridp = 0;
2640 2640 /* Figure out the property type ({user|group}{quota|space}) */
2641 2641 for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
2642 2642 if (strncmp(propname, zfs_userquota_prop_prefixes[type],
2643 2643 strlen(zfs_userquota_prop_prefixes[type])) == 0)
2644 2644 break;
2645 2645 }
2646 2646 if (type == ZFS_NUM_USERQUOTA_PROPS)
2647 2647 return (EINVAL);
2648 2648 *typep = type;
2649 2649
2650 2650 isuser = (type == ZFS_PROP_USERQUOTA ||
2651 2651 type == ZFS_PROP_USERUSED);
2652 2652
2653 2653 cp = strchr(propname, '@') + 1;
2654 2654
2655 2655 if (strchr(cp, '@')) {
2656 2656 /*
2657 2657 * It's a SID name (eg "user@domain") that needs to be
2658 2658 * turned into S-1-domainID-RID.
2659 2659 */
2660 2660 int flag = 0;
2661 2661 idmap_stat stat, map_stat;
2662 2662 uid_t pid;
2663 2663 idmap_rid_t rid;
2664 2664 idmap_get_handle_t *gh = NULL;
2665 2665
2666 2666 stat = idmap_get_create(&gh);
2667 2667 if (stat != IDMAP_SUCCESS) {
2668 2668 idmap_get_destroy(gh);
2669 2669 return (ENOMEM);
2670 2670 }
2671 2671 if (zoned && getzoneid() == GLOBAL_ZONEID)
2672 2672 return (ENOENT);
2673 2673 if (isuser) {
2674 2674 stat = idmap_getuidbywinname(cp, NULL, flag, &pid);
2675 2675 if (stat < 0)
2676 2676 return (ENOENT);
2677 2677 stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid,
2678 2678 &rid, &map_stat);
2679 2679 } else {
2680 2680 stat = idmap_getgidbywinname(cp, NULL, flag, &pid);
2681 2681 if (stat < 0)
2682 2682 return (ENOENT);
2683 2683 stat = idmap_get_sidbygid(gh, pid, flag, &numericsid,
2684 2684 &rid, &map_stat);
2685 2685 }
2686 2686 if (stat < 0) {
2687 2687 idmap_get_destroy(gh);
2688 2688 return (ENOENT);
2689 2689 }
2690 2690 stat = idmap_get_mappings(gh);
2691 2691 idmap_get_destroy(gh);
2692 2692
2693 2693 if (stat < 0) {
2694 2694 return (ENOENT);
2695 2695 }
2696 2696 if (numericsid == NULL)
2697 2697 return (ENOENT);
2698 2698 cp = numericsid;
2699 2699 *ridp = rid;
2700 2700 /* will be further decoded below */
2701 2701 }
2702 2702
2703 2703 if (strncmp(cp, "S-1-", 4) == 0) {
2704 2704 /* It's a numeric SID (eg "S-1-234-567-89") */
2705 2705 (void) strlcpy(domain, cp, domainlen);
2706 2706 errno = 0;
2707 2707 if (*ridp == 0) {
2708 2708 cp = strrchr(domain, '-');
2709 2709 *cp = '\0';
2710 2710 cp++;
2711 2711 *ridp = strtoull(cp, &end, 10);
2712 2712 } else {
2713 2713 end = "";
2714 2714 }
2715 2715 if (numericsid) {
2716 2716 free(numericsid);
2717 2717 numericsid = NULL;
2718 2718 }
2719 2719 if (errno != 0 || *end != '\0')
2720 2720 return (EINVAL);
2721 2721 } else if (!isdigit(*cp)) {
2722 2722 /*
2723 2723 * It's a user/group name (eg "user") that needs to be
2724 2724 * turned into a uid/gid
2725 2725 */
2726 2726 if (zoned && getzoneid() == GLOBAL_ZONEID)
2727 2727 return (ENOENT);
2728 2728 if (isuser) {
2729 2729 struct passwd *pw;
2730 2730 pw = getpwnam(cp);
2731 2731 if (pw == NULL)
2732 2732 return (ENOENT);
2733 2733 *ridp = pw->pw_uid;
2734 2734 } else {
2735 2735 struct group *gr;
2736 2736 gr = getgrnam(cp);
2737 2737 if (gr == NULL)
2738 2738 return (ENOENT);
2739 2739 *ridp = gr->gr_gid;
2740 2740 }
2741 2741 } else {
2742 2742 /* It's a user/group ID (eg "12345"). */
2743 2743 uid_t id = strtoul(cp, &end, 10);
2744 2744 idmap_rid_t rid;
2745 2745 char *mapdomain;
2746 2746
2747 2747 if (*end != '\0')
2748 2748 return (EINVAL);
2749 2749 if (id > MAXUID) {
2750 2750 /* It's an ephemeral ID. */
2751 2751 if (idmap_id_to_numeric_domain_rid(id, isuser,
2752 2752 &mapdomain, &rid) != 0)
2753 2753 return (ENOENT);
2754 2754 (void) strlcpy(domain, mapdomain, domainlen);
2755 2755 *ridp = rid;
2756 2756 } else {
2757 2757 *ridp = id;
2758 2758 }
2759 2759 }
2760 2760
2761 2761 ASSERT3P(numericsid, ==, NULL);
2762 2762 return (0);
2763 2763 }
2764 2764
2765 2765 static int
2766 2766 zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
2767 2767 uint64_t *propvalue, zfs_userquota_prop_t *typep)
2768 2768 {
2769 2769 int err;
2770 2770 zfs_cmd_t zc = { 0 };
2771 2771
2772 2772 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2773 2773
2774 2774 err = userquota_propname_decode(propname,
2775 2775 zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
2776 2776 typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
2777 2777 zc.zc_objset_type = *typep;
2778 2778 if (err)
2779 2779 return (err);
2780 2780
2781 2781 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
2782 2782 if (err)
2783 2783 return (err);
2784 2784
2785 2785 *propvalue = zc.zc_cookie;
2786 2786 return (0);
2787 2787 }
2788 2788
2789 2789 int
2790 2790 zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
2791 2791 uint64_t *propvalue)
2792 2792 {
2793 2793 zfs_userquota_prop_t type;
2794 2794
2795 2795 return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
2796 2796 &type));
2797 2797 }
2798 2798
2799 2799 int
2800 2800 zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
2801 2801 char *propbuf, int proplen, boolean_t literal)
2802 2802 {
2803 2803 int err;
2804 2804 uint64_t propvalue;
2805 2805 zfs_userquota_prop_t type;
2806 2806
2807 2807 err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
2808 2808 &type);
2809 2809
2810 2810 if (err)
2811 2811 return (err);
2812 2812
2813 2813 if (literal) {
2814 2814 (void) snprintf(propbuf, proplen, "%llu", propvalue);
2815 2815 } else if (propvalue == 0 &&
2816 2816 (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
2817 2817 (void) strlcpy(propbuf, "none", proplen);
2818 2818 } else {
2819 2819 zfs_nicenum(propvalue, propbuf, proplen);
2820 2820 }
2821 2821 return (0);
2822 2822 }
2823 2823
2824 2824 int
2825 2825 zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
2826 2826 uint64_t *propvalue)
2827 2827 {
2828 2828 int err;
2829 2829 zfs_cmd_t zc = { 0 };
2830 2830 const char *snapname;
2831 2831
2832 2832 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2833 2833
2834 2834 snapname = strchr(propname, '@') + 1;
2835 2835 if (strchr(snapname, '@')) {
2836 2836 (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
2837 2837 } else {
2838 2838 /* snapname is the short name, append it to zhp's fsname */
2839 2839 char *cp;
2840 2840
2841 2841 (void) strlcpy(zc.zc_value, zhp->zfs_name,
2842 2842 sizeof (zc.zc_value));
2843 2843 cp = strchr(zc.zc_value, '@');
2844 2844 if (cp != NULL)
2845 2845 *cp = '\0';
2846 2846 (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
2847 2847 (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
2848 2848 }
2849 2849
2850 2850 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
2851 2851 if (err)
2852 2852 return (err);
2853 2853
2854 2854 *propvalue = zc.zc_cookie;
2855 2855 return (0);
2856 2856 }
2857 2857
2858 2858 int
2859 2859 zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
2860 2860 char *propbuf, int proplen, boolean_t literal)
2861 2861 {
2862 2862 int err;
2863 2863 uint64_t propvalue;
2864 2864
2865 2865 err = zfs_prop_get_written_int(zhp, propname, &propvalue);
2866 2866
2867 2867 if (err)
2868 2868 return (err);
2869 2869
2870 2870 if (literal) {
2871 2871 (void) snprintf(propbuf, proplen, "%llu", propvalue);
2872 2872 } else {
2873 2873 zfs_nicenum(propvalue, propbuf, proplen);
2874 2874 }
2875 2875 return (0);
2876 2876 }
2877 2877
2878 2878 /*
2879 2879 * Returns the name of the given zfs handle.
2880 2880 */
2881 2881 const char *
2882 2882 zfs_get_name(const zfs_handle_t *zhp)
2883 2883 {
2884 2884 return (zhp->zfs_name);
2885 2885 }
2886 2886
2887 2887 /*
2888 2888 * Returns the type of the given zfs handle.
2889 2889 */
2890 2890 zfs_type_t
2891 2891 zfs_get_type(const zfs_handle_t *zhp)
2892 2892 {
2893 2893 return (zhp->zfs_type);
2894 2894 }
2895 2895
2896 2896 /*
2897 2897 * Is one dataset name a child dataset of another?
2898 2898 *
2899 2899 * Needs to handle these cases:
2900 2900 * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo"
2901 2901 * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar"
2902 2902 * Descendant? No. No. No. Yes.
2903 2903 */
2904 2904 static boolean_t
2905 2905 is_descendant(const char *ds1, const char *ds2)
2906 2906 {
2907 2907 size_t d1len = strlen(ds1);
2908 2908
2909 2909 /* ds2 can't be a descendant if it's smaller */
2910 2910 if (strlen(ds2) < d1len)
2911 2911 return (B_FALSE);
2912 2912
2913 2913 /* otherwise, compare strings and verify that there's a '/' char */
2914 2914 return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
2915 2915 }
2916 2916
2917 2917 /*
2918 2918 * Given a complete name, return just the portion that refers to the parent.
2919 2919 * Will return -1 if there is no parent (path is just the name of the
2920 2920 * pool).
2921 2921 */
2922 2922 static int
2923 2923 parent_name(const char *path, char *buf, size_t buflen)
2924 2924 {
2925 2925 char *slashp;
2926 2926
2927 2927 (void) strlcpy(buf, path, buflen);
2928 2928
2929 2929 if ((slashp = strrchr(buf, '/')) == NULL)
2930 2930 return (-1);
2931 2931 *slashp = '\0';
2932 2932
2933 2933 return (0);
2934 2934 }
2935 2935
2936 2936 /*
2937 2937 * If accept_ancestor is false, then check to make sure that the given path has
2938 2938 * a parent, and that it exists. If accept_ancestor is true, then find the
2939 2939 * closest existing ancestor for the given path. In prefixlen return the
2940 2940 * length of already existing prefix of the given path. We also fetch the
2941 2941 * 'zoned' property, which is used to validate property settings when creating
2942 2942 * new datasets.
2943 2943 */
2944 2944 static int
2945 2945 check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
2946 2946 boolean_t accept_ancestor, int *prefixlen)
2947 2947 {
2948 2948 zfs_cmd_t zc = { 0 };
2949 2949 char parent[ZFS_MAXNAMELEN];
2950 2950 char *slash;
2951 2951 zfs_handle_t *zhp;
2952 2952 char errbuf[1024];
2953 2953 uint64_t is_zoned;
2954 2954
2955 2955 (void) snprintf(errbuf, sizeof (errbuf),
2956 2956 dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
2957 2957
2958 2958 /* get parent, and check to see if this is just a pool */
2959 2959 if (parent_name(path, parent, sizeof (parent)) != 0) {
2960 2960 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2961 2961 "missing dataset name"));
2962 2962 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2963 2963 }
2964 2964
2965 2965 /* check to see if the pool exists */
2966 2966 if ((slash = strchr(parent, '/')) == NULL)
2967 2967 slash = parent + strlen(parent);
2968 2968 (void) strncpy(zc.zc_name, parent, slash - parent);
2969 2969 zc.zc_name[slash - parent] = '\0';
2970 2970 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
2971 2971 errno == ENOENT) {
2972 2972 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2973 2973 "no such pool '%s'"), zc.zc_name);
2974 2974 return (zfs_error(hdl, EZFS_NOENT, errbuf));
2975 2975 }
2976 2976
2977 2977 /* check to see if the parent dataset exists */
2978 2978 while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
2979 2979 if (errno == ENOENT && accept_ancestor) {
2980 2980 /*
2981 2981 * Go deeper to find an ancestor, give up on top level.
2982 2982 */
2983 2983 if (parent_name(parent, parent, sizeof (parent)) != 0) {
2984 2984 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2985 2985 "no such pool '%s'"), zc.zc_name);
2986 2986 return (zfs_error(hdl, EZFS_NOENT, errbuf));
2987 2987 }
2988 2988 } else if (errno == ENOENT) {
2989 2989 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2990 2990 "parent does not exist"));
2991 2991 return (zfs_error(hdl, EZFS_NOENT, errbuf));
2992 2992 } else
2993 2993 return (zfs_standard_error(hdl, errno, errbuf));
2994 2994 }
2995 2995
2996 2996 is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
2997 2997 if (zoned != NULL)
2998 2998 *zoned = is_zoned;
2999 2999
3000 3000 /* we are in a non-global zone, but parent is in the global zone */
3001 3001 if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
3002 3002 (void) zfs_standard_error(hdl, EPERM, errbuf);
3003 3003 zfs_close(zhp);
3004 3004 return (-1);
3005 3005 }
3006 3006
3007 3007 /* make sure parent is a filesystem */
3008 3008 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
3009 3009 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3010 3010 "parent is not a filesystem"));
3011 3011 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
3012 3012 zfs_close(zhp);
3013 3013 return (-1);
3014 3014 }
3015 3015
3016 3016 zfs_close(zhp);
3017 3017 if (prefixlen != NULL)
3018 3018 *prefixlen = strlen(parent);
3019 3019 return (0);
3020 3020 }
3021 3021
3022 3022 /*
3023 3023 * Finds whether the dataset of the given type(s) exists.
3024 3024 */
3025 3025 boolean_t
3026 3026 zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
3027 3027 {
3028 3028 zfs_handle_t *zhp;
3029 3029
3030 3030 if (!zfs_validate_name(hdl, path, types, B_FALSE))
3031 3031 return (B_FALSE);
3032 3032
3033 3033 /*
3034 3034 * Try to get stats for the dataset, which will tell us if it exists.
3035 3035 */
3036 3036 if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
3037 3037 int ds_type = zhp->zfs_type;
3038 3038
3039 3039 zfs_close(zhp);
3040 3040 if (types & ds_type)
3041 3041 return (B_TRUE);
3042 3042 }
3043 3043 return (B_FALSE);
3044 3044 }
3045 3045
3046 3046 /*
3047 3047 * Given a path to 'target', create all the ancestors between
3048 3048 * the prefixlen portion of the path, and the target itself.
3049 3049 * Fail if the initial prefixlen-ancestor does not already exist.
3050 3050 */
3051 3051 int
3052 3052 create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
3053 3053 {
3054 3054 zfs_handle_t *h;
3055 3055 char *cp;
3056 3056 const char *opname;
3057 3057
3058 3058 /* make sure prefix exists */
3059 3059 cp = target + prefixlen;
3060 3060 if (*cp != '/') {
3061 3061 assert(strchr(cp, '/') == NULL);
3062 3062 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3063 3063 } else {
3064 3064 *cp = '\0';
3065 3065 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3066 3066 *cp = '/';
3067 3067 }
3068 3068 if (h == NULL)
3069 3069 return (-1);
3070 3070 zfs_close(h);
3071 3071
3072 3072 /*
3073 3073 * Attempt to create, mount, and share any ancestor filesystems,
3074 3074 * up to the prefixlen-long one.
3075 3075 */
3076 3076 for (cp = target + prefixlen + 1;
3077 3077 cp = strchr(cp, '/'); *cp = '/', cp++) {
3078 3078
3079 3079 *cp = '\0';
3080 3080
3081 3081 h = make_dataset_handle(hdl, target);
3082 3082 if (h) {
3083 3083 /* it already exists, nothing to do here */
3084 3084 zfs_close(h);
3085 3085 continue;
3086 3086 }
3087 3087
3088 3088 if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
3089 3089 NULL) != 0) {
3090 3090 opname = dgettext(TEXT_DOMAIN, "create");
3091 3091 goto ancestorerr;
3092 3092 }
3093 3093
3094 3094 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3095 3095 if (h == NULL) {
3096 3096 opname = dgettext(TEXT_DOMAIN, "open");
3097 3097 goto ancestorerr;
3098 3098 }
3099 3099
3100 3100 if (zfs_mount(h, NULL, 0) != 0) {
3101 3101 opname = dgettext(TEXT_DOMAIN, "mount");
3102 3102 goto ancestorerr;
3103 3103 }
3104 3104
3105 3105 if (zfs_share(h) != 0) {
3106 3106 opname = dgettext(TEXT_DOMAIN, "share");
3107 3107 goto ancestorerr;
3108 3108 }
3109 3109
3110 3110 zfs_close(h);
3111 3111 }
3112 3112
3113 3113 return (0);
3114 3114
3115 3115 ancestorerr:
3116 3116 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3117 3117 "failed to %s ancestor '%s'"), opname, target);
3118 3118 return (-1);
3119 3119 }
3120 3120
3121 3121 /*
3122 3122 * Creates non-existing ancestors of the given path.
3123 3123 */
3124 3124 int
3125 3125 zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
3126 3126 {
3127 3127 int prefix;
3128 3128 char *path_copy;
3129 3129 int rc;
3130 3130
3131 3131 if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
3132 3132 return (-1);
3133 3133
3134 3134 if ((path_copy = strdup(path)) != NULL) {
3135 3135 rc = create_parents(hdl, path_copy, prefix);
3136 3136 free(path_copy);
3137 3137 }
3138 3138 if (path_copy == NULL || rc != 0)
3139 3139 return (-1);
3140 3140
3141 3141 return (0);
3142 3142 }
3143 3143
3144 3144 /*
3145 3145 * Create a new filesystem or volume.
3146 3146 */
3147 3147 int
3148 3148 zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
3149 3149 nvlist_t *props)
3150 3150 {
3151 3151 int ret;
3152 3152 uint64_t size = 0;
3153 3153 uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
3154 3154 char errbuf[1024];
3155 3155 uint64_t zoned;
3156 3156 dmu_objset_type_t ost;
3157 3157
3158 3158 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3159 3159 "cannot create '%s'"), path);
3160 3160
3161 3161 /* validate the path, taking care to note the extended error message */
3162 3162 if (!zfs_validate_name(hdl, path, type, B_TRUE))
3163 3163 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3164 3164
3165 3165 /* validate parents exist */
3166 3166 if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
3167 3167 return (-1);
3168 3168
3169 3169 /*
3170 3170 * The failure modes when creating a dataset of a different type over
3171 3171 * one that already exists is a little strange. In particular, if you
3172 3172 * try to create a dataset on top of an existing dataset, the ioctl()
3173 3173 * will return ENOENT, not EEXIST. To prevent this from happening, we
3174 3174 * first try to see if the dataset exists.
3175 3175 */
3176 3176 if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
3177 3177 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3178 3178 "dataset already exists"));
3179 3179 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3180 3180 }
3181 3181
3182 3182 if (type == ZFS_TYPE_VOLUME)
3183 3183 ost = DMU_OST_ZVOL;
3184 3184 else
3185 3185 ost = DMU_OST_ZFS;
3186 3186
3187 3187 if (props && (props = zfs_valid_proplist(hdl, type, props,
3188 3188 zoned, NULL, errbuf)) == 0)
3189 3189 return (-1);
3190 3190
3191 3191 if (type == ZFS_TYPE_VOLUME) {
3192 3192 /*
3193 3193 * If we are creating a volume, the size and block size must
3194 3194 * satisfy a few restraints. First, the blocksize must be a
3195 3195 * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the
3196 3196 * volsize must be a multiple of the block size, and cannot be
3197 3197 * zero.
3198 3198 */
3199 3199 if (props == NULL || nvlist_lookup_uint64(props,
3200 3200 zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
3201 3201 nvlist_free(props);
3202 3202 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3203 3203 "missing volume size"));
3204 3204 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3205 3205 }
3206 3206
3207 3207 if ((ret = nvlist_lookup_uint64(props,
3208 3208 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
3209 3209 &blocksize)) != 0) {
3210 3210 if (ret == ENOENT) {
3211 3211 blocksize = zfs_prop_default_numeric(
3212 3212 ZFS_PROP_VOLBLOCKSIZE);
3213 3213 } else {
3214 3214 nvlist_free(props);
3215 3215 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3216 3216 "missing volume block size"));
3217 3217 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3218 3218 }
3219 3219 }
3220 3220
3221 3221 if (size == 0) {
3222 3222 nvlist_free(props);
3223 3223 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3224 3224 "volume size cannot be zero"));
3225 3225 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3226 3226 }
3227 3227
3228 3228 if (size % blocksize != 0) {
3229 3229 nvlist_free(props);
3230 3230 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3231 3231 "volume size must be a multiple of volume block "
3232 3232 "size"));
3233 3233 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3234 3234 }
3235 3235 }
3236 3236
3237 3237 /* create the dataset */
3238 3238 ret = lzc_create(path, ost, props);
3239 3239 nvlist_free(props);
3240 3240
3241 3241 /* check for failure */
3242 3242 if (ret != 0) {
3243 3243 char parent[ZFS_MAXNAMELEN];
3244 3244 (void) parent_name(path, parent, sizeof (parent));
3245 3245
3246 3246 switch (errno) {
3247 3247 case ENOENT:
3248 3248 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3249 3249 "no such parent '%s'"), parent);
3250 3250 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3251 3251
3252 3252 case EINVAL:
3253 3253 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3254 3254 "parent '%s' is not a filesystem"), parent);
3255 3255 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3256 3256
3257 3257 case EDOM:
3258 3258 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3259 3259 "volume block size must be power of 2 from "
3260 3260 "512B to 128KB"));
3261 3261
3262 3262 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3263 3263
3264 3264 case ENOTSUP:
3265 3265 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3266 3266 "pool must be upgraded to set this "
3267 3267 "property or value"));
3268 3268 return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
3269 3269 #ifdef _ILP32
3270 3270 case EOVERFLOW:
3271 3271 /*
3272 3272 * This platform can't address a volume this big.
3273 3273 */
3274 3274 if (type == ZFS_TYPE_VOLUME)
3275 3275 return (zfs_error(hdl, EZFS_VOLTOOBIG,
3276 3276 errbuf));
3277 3277 #endif
3278 3278 /* FALLTHROUGH */
3279 3279 default:
3280 3280 return (zfs_standard_error(hdl, errno, errbuf));
3281 3281 }
3282 3282 }
3283 3283
3284 3284 return (0);
3285 3285 }
3286 3286
3287 3287 /*
3288 3288 * Destroys the given dataset. The caller must make sure that the filesystem
3289 3289 * isn't mounted, and that there are no active dependents. If the file system
3290 3290 * does not exist this function does nothing.
3291 3291 */
3292 3292 int
3293 3293 zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
3294 3294 {
3295 3295 zfs_cmd_t zc = { 0 };
3296 3296
3297 3297 if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
3298 3298 nvlist_t *nv = fnvlist_alloc();
3299 3299 fnvlist_add_boolean(nv, zhp->zfs_name);
3300 3300 int error = lzc_destroy_bookmarks(nv, NULL);
3301 3301 fnvlist_free(nv);
3302 3302 if (error != 0) {
3303 3303 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3304 3304 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3305 3305 zhp->zfs_name));
3306 3306 }
3307 3307 return (0);
3308 3308 }
3309 3309
3310 3310 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3311 3311
3312 3312 if (ZFS_IS_VOLUME(zhp)) {
3313 3313 zc.zc_objset_type = DMU_OST_ZVOL;
3314 3314 } else {
3315 3315 zc.zc_objset_type = DMU_OST_ZFS;
3316 3316 }
3317 3317
3318 3318 zc.zc_defer_destroy = defer;
3319 3319 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
3320 3320 errno != ENOENT) {
3321 3321 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3322 3322 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3323 3323 zhp->zfs_name));
3324 3324 }
3325 3325
3326 3326 remove_mountpoint(zhp);
3327 3327
3328 3328 return (0);
3329 3329 }
3330 3330
3331 3331 struct destroydata {
3332 3332 nvlist_t *nvl;
3333 3333 const char *snapname;
3334 3334 };
3335 3335
3336 3336 static int
3337 3337 zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
3338 3338 {
3339 3339 struct destroydata *dd = arg;
3340 3340 char name[ZFS_MAXNAMELEN];
3341 3341 int rv = 0;
3342 3342
3343 3343 (void) snprintf(name, sizeof (name),
3344 3344 "%s@%s", zhp->zfs_name, dd->snapname);
3345 3345
3346 3346 if (lzc_exists(name))
3347 3347 verify(nvlist_add_boolean(dd->nvl, name) == 0);
3348 3348
3349 3349 rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
3350 3350 zfs_close(zhp);
3351 3351 return (rv);
3352 3352 }
3353 3353
3354 3354 /*
3355 3355 * Destroys all snapshots with the given name in zhp & descendants.
3356 3356 */
3357 3357 int
3358 3358 zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
3359 3359 {
3360 3360 int ret;
3361 3361 struct destroydata dd = { 0 };
3362 3362
3363 3363 dd.snapname = snapname;
3364 3364 verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
3365 3365 (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
3366 3366
3367 3367 if (nvlist_empty(dd.nvl)) {
3368 3368 ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
3369 3369 dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
3370 3370 zhp->zfs_name, snapname);
3371 3371 } else {
3372 3372 ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
3373 3373 }
3374 3374 nvlist_free(dd.nvl);
3375 3375 return (ret);
3376 3376 }
3377 3377
3378 3378 /*
3379 3379 * Destroys all the snapshots named in the nvlist.
3380 3380 */
3381 3381 int
3382 3382 zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
3383 3383 {
3384 3384 int ret;
3385 3385 nvlist_t *errlist;
3386 3386
3387 3387 ret = lzc_destroy_snaps(snaps, defer, &errlist);
3388 3388
3389 3389 if (ret == 0)
3390 3390 return (0);
3391 3391
3392 3392 if (nvlist_empty(errlist)) {
3393 3393 char errbuf[1024];
3394 3394 (void) snprintf(errbuf, sizeof (errbuf),
3395 3395 dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
3396 3396
3397 3397 ret = zfs_standard_error(hdl, ret, errbuf);
3398 3398 }
3399 3399 for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
3400 3400 pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
3401 3401 char errbuf[1024];
3402 3402 (void) snprintf(errbuf, sizeof (errbuf),
3403 3403 dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
3404 3404 nvpair_name(pair));
3405 3405
3406 3406 switch (fnvpair_value_int32(pair)) {
3407 3407 case EEXIST:
↓ open down ↓ |
3407 lines elided |
↑ open up ↑ |
3408 3408 zfs_error_aux(hdl,
3409 3409 dgettext(TEXT_DOMAIN, "snapshot is cloned"));
3410 3410 ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
3411 3411 break;
3412 3412 default:
3413 3413 ret = zfs_standard_error(hdl, errno, errbuf);
3414 3414 break;
3415 3415 }
3416 3416 }
3417 3417
3418 + nvlist_free(errlist);
3418 3419 return (ret);
3419 3420 }
3420 3421
3421 3422 /*
3422 3423 * Clones the given dataset. The target must be of the same type as the source.
3423 3424 */
3424 3425 int
3425 3426 zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
3426 3427 {
3427 3428 char parent[ZFS_MAXNAMELEN];
3428 3429 int ret;
3429 3430 char errbuf[1024];
3430 3431 libzfs_handle_t *hdl = zhp->zfs_hdl;
3431 3432 uint64_t zoned;
3432 3433
3433 3434 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
3434 3435
3435 3436 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3436 3437 "cannot create '%s'"), target);
3437 3438
3438 3439 /* validate the target/clone name */
3439 3440 if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
3440 3441 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3441 3442
3442 3443 /* validate parents exist */
3443 3444 if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
3444 3445 return (-1);
3445 3446
3446 3447 (void) parent_name(target, parent, sizeof (parent));
3447 3448
3448 3449 /* do the clone */
3449 3450
3450 3451 if (props) {
3451 3452 zfs_type_t type;
3452 3453 if (ZFS_IS_VOLUME(zhp)) {
3453 3454 type = ZFS_TYPE_VOLUME;
3454 3455 } else {
3455 3456 type = ZFS_TYPE_FILESYSTEM;
3456 3457 }
3457 3458 if ((props = zfs_valid_proplist(hdl, type, props, zoned,
3458 3459 zhp, errbuf)) == NULL)
3459 3460 return (-1);
3460 3461 }
3461 3462
3462 3463 ret = lzc_clone(target, zhp->zfs_name, props);
3463 3464 nvlist_free(props);
3464 3465
3465 3466 if (ret != 0) {
3466 3467 switch (errno) {
3467 3468
3468 3469 case ENOENT:
3469 3470 /*
3470 3471 * The parent doesn't exist. We should have caught this
3471 3472 * above, but there may a race condition that has since
3472 3473 * destroyed the parent.
3473 3474 *
3474 3475 * At this point, we don't know whether it's the source
3475 3476 * that doesn't exist anymore, or whether the target
3476 3477 * dataset doesn't exist.
3477 3478 */
3478 3479 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3479 3480 "no such parent '%s'"), parent);
3480 3481 return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
3481 3482
3482 3483 case EXDEV:
3483 3484 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3484 3485 "source and target pools differ"));
3485 3486 return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
3486 3487 errbuf));
3487 3488
3488 3489 default:
3489 3490 return (zfs_standard_error(zhp->zfs_hdl, errno,
3490 3491 errbuf));
3491 3492 }
3492 3493 }
3493 3494
3494 3495 return (ret);
3495 3496 }
3496 3497
3497 3498 /*
3498 3499 * Promotes the given clone fs to be the clone parent.
3499 3500 */
3500 3501 int
3501 3502 zfs_promote(zfs_handle_t *zhp)
3502 3503 {
3503 3504 libzfs_handle_t *hdl = zhp->zfs_hdl;
3504 3505 zfs_cmd_t zc = { 0 };
3505 3506 char parent[MAXPATHLEN];
3506 3507 int ret;
3507 3508 char errbuf[1024];
3508 3509
3509 3510 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3510 3511 "cannot promote '%s'"), zhp->zfs_name);
3511 3512
3512 3513 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3513 3514 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3514 3515 "snapshots can not be promoted"));
3515 3516 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3516 3517 }
3517 3518
3518 3519 (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent));
3519 3520 if (parent[0] == '\0') {
3520 3521 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3521 3522 "not a cloned filesystem"));
3522 3523 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3523 3524 }
3524 3525
3525 3526 (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin,
3526 3527 sizeof (zc.zc_value));
3527 3528 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3528 3529 ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
3529 3530
3530 3531 if (ret != 0) {
3531 3532 int save_errno = errno;
3532 3533
3533 3534 switch (save_errno) {
3534 3535 case EEXIST:
3535 3536 /* There is a conflicting snapshot name. */
3536 3537 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3537 3538 "conflicting snapshot '%s' from parent '%s'"),
3538 3539 zc.zc_string, parent);
3539 3540 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3540 3541
3541 3542 default:
3542 3543 return (zfs_standard_error(hdl, save_errno, errbuf));
3543 3544 }
3544 3545 }
3545 3546 return (ret);
3546 3547 }
3547 3548
3548 3549 typedef struct snapdata {
3549 3550 nvlist_t *sd_nvl;
3550 3551 const char *sd_snapname;
3551 3552 } snapdata_t;
3552 3553
3553 3554 static int
3554 3555 zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
3555 3556 {
3556 3557 snapdata_t *sd = arg;
3557 3558 char name[ZFS_MAXNAMELEN];
3558 3559 int rv = 0;
3559 3560
3560 3561 if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
3561 3562 (void) snprintf(name, sizeof (name),
3562 3563 "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
3563 3564
3564 3565 fnvlist_add_boolean(sd->sd_nvl, name);
3565 3566
3566 3567 rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
3567 3568 }
3568 3569 zfs_close(zhp);
3569 3570
3570 3571 return (rv);
3571 3572 }
3572 3573
3573 3574 /*
3574 3575 * Creates snapshots. The keys in the snaps nvlist are the snapshots to be
3575 3576 * created.
3576 3577 */
3577 3578 int
3578 3579 zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
3579 3580 {
3580 3581 int ret;
3581 3582 char errbuf[1024];
3582 3583 nvpair_t *elem;
3583 3584 nvlist_t *errors;
3584 3585
3585 3586 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3586 3587 "cannot create snapshots "));
3587 3588
3588 3589 elem = NULL;
3589 3590 while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
3590 3591 const char *snapname = nvpair_name(elem);
3591 3592
3592 3593 /* validate the target name */
3593 3594 if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
3594 3595 B_TRUE)) {
3595 3596 (void) snprintf(errbuf, sizeof (errbuf),
3596 3597 dgettext(TEXT_DOMAIN,
3597 3598 "cannot create snapshot '%s'"), snapname);
3598 3599 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3599 3600 }
3600 3601 }
3601 3602
3602 3603 if (props != NULL &&
3603 3604 (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
3604 3605 props, B_FALSE, NULL, errbuf)) == NULL) {
3605 3606 return (-1);
3606 3607 }
3607 3608
3608 3609 ret = lzc_snapshot(snaps, props, &errors);
3609 3610
3610 3611 if (ret != 0) {
3611 3612 boolean_t printed = B_FALSE;
3612 3613 for (elem = nvlist_next_nvpair(errors, NULL);
3613 3614 elem != NULL;
3614 3615 elem = nvlist_next_nvpair(errors, elem)) {
3615 3616 (void) snprintf(errbuf, sizeof (errbuf),
3616 3617 dgettext(TEXT_DOMAIN,
3617 3618 "cannot create snapshot '%s'"), nvpair_name(elem));
3618 3619 (void) zfs_standard_error(hdl,
3619 3620 fnvpair_value_int32(elem), errbuf);
3620 3621 printed = B_TRUE;
3621 3622 }
3622 3623 if (!printed) {
3623 3624 switch (ret) {
3624 3625 case EXDEV:
3625 3626 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3626 3627 "multiple snapshots of same "
3627 3628 "fs not allowed"));
3628 3629 (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3629 3630
3630 3631 break;
3631 3632 default:
3632 3633 (void) zfs_standard_error(hdl, ret, errbuf);
3633 3634 }
3634 3635 }
3635 3636 }
3636 3637
3637 3638 nvlist_free(props);
3638 3639 nvlist_free(errors);
3639 3640 return (ret);
3640 3641 }
3641 3642
3642 3643 int
3643 3644 zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
3644 3645 nvlist_t *props)
3645 3646 {
3646 3647 int ret;
3647 3648 snapdata_t sd = { 0 };
3648 3649 char fsname[ZFS_MAXNAMELEN];
3649 3650 char *cp;
3650 3651 zfs_handle_t *zhp;
3651 3652 char errbuf[1024];
3652 3653
3653 3654 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3654 3655 "cannot snapshot %s"), path);
3655 3656
3656 3657 if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
3657 3658 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3658 3659
3659 3660 (void) strlcpy(fsname, path, sizeof (fsname));
3660 3661 cp = strchr(fsname, '@');
3661 3662 *cp = '\0';
3662 3663 sd.sd_snapname = cp + 1;
3663 3664
3664 3665 if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
3665 3666 ZFS_TYPE_VOLUME)) == NULL) {
3666 3667 return (-1);
3667 3668 }
3668 3669
3669 3670 verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
3670 3671 if (recursive) {
3671 3672 (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
3672 3673 } else {
3673 3674 fnvlist_add_boolean(sd.sd_nvl, path);
3674 3675 }
3675 3676
3676 3677 ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
3677 3678 nvlist_free(sd.sd_nvl);
3678 3679 zfs_close(zhp);
3679 3680 return (ret);
3680 3681 }
3681 3682
3682 3683 /*
3683 3684 * Destroy any more recent snapshots. We invoke this callback on any dependents
3684 3685 * of the snapshot first. If the 'cb_dependent' member is non-zero, then this
3685 3686 * is a dependent and we should just destroy it without checking the transaction
3686 3687 * group.
3687 3688 */
3688 3689 typedef struct rollback_data {
3689 3690 const char *cb_target; /* the snapshot */
3690 3691 uint64_t cb_create; /* creation time reference */
3691 3692 boolean_t cb_error;
3692 3693 boolean_t cb_force;
3693 3694 } rollback_data_t;
3694 3695
3695 3696 static int
3696 3697 rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
3697 3698 {
3698 3699 rollback_data_t *cbp = data;
3699 3700 prop_changelist_t *clp;
3700 3701
3701 3702 /* We must destroy this clone; first unmount it */
3702 3703 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3703 3704 cbp->cb_force ? MS_FORCE: 0);
3704 3705 if (clp == NULL || changelist_prefix(clp) != 0) {
3705 3706 cbp->cb_error = B_TRUE;
3706 3707 zfs_close(zhp);
3707 3708 return (0);
3708 3709 }
3709 3710 if (zfs_destroy(zhp, B_FALSE) != 0)
3710 3711 cbp->cb_error = B_TRUE;
3711 3712 else
3712 3713 changelist_remove(clp, zhp->zfs_name);
3713 3714 (void) changelist_postfix(clp);
3714 3715 changelist_free(clp);
3715 3716
3716 3717 zfs_close(zhp);
3717 3718 return (0);
3718 3719 }
3719 3720
3720 3721 static int
3721 3722 rollback_destroy(zfs_handle_t *zhp, void *data)
3722 3723 {
3723 3724 rollback_data_t *cbp = data;
3724 3725
3725 3726 if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
3726 3727 cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
3727 3728 rollback_destroy_dependent, cbp);
3728 3729
3729 3730 cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
3730 3731 }
3731 3732
3732 3733 zfs_close(zhp);
3733 3734 return (0);
3734 3735 }
3735 3736
3736 3737 /*
3737 3738 * Given a dataset, rollback to a specific snapshot, discarding any
3738 3739 * data changes since then and making it the active dataset.
3739 3740 *
3740 3741 * Any snapshots and bookmarks more recent than the target are
3741 3742 * destroyed, along with their dependents (i.e. clones).
3742 3743 */
3743 3744 int
3744 3745 zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3745 3746 {
3746 3747 rollback_data_t cb = { 0 };
3747 3748 int err;
3748 3749 boolean_t restore_resv = 0;
3749 3750 uint64_t old_volsize, new_volsize;
3750 3751 zfs_prop_t resv_prop;
3751 3752
3752 3753 assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3753 3754 zhp->zfs_type == ZFS_TYPE_VOLUME);
3754 3755
3755 3756 /*
3756 3757 * Destroy all recent snapshots and their dependents.
3757 3758 */
3758 3759 cb.cb_force = force;
3759 3760 cb.cb_target = snap->zfs_name;
3760 3761 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3761 3762 (void) zfs_iter_snapshots(zhp, rollback_destroy, &cb);
3762 3763 (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
3763 3764
3764 3765 if (cb.cb_error)
3765 3766 return (-1);
3766 3767
3767 3768 /*
3768 3769 * Now that we have verified that the snapshot is the latest,
3769 3770 * rollback to the given snapshot.
3770 3771 */
3771 3772
3772 3773 if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3773 3774 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
3774 3775 return (-1);
3775 3776 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3776 3777 restore_resv =
3777 3778 (old_volsize == zfs_prop_get_int(zhp, resv_prop));
3778 3779 }
3779 3780
3780 3781 /*
3781 3782 * We rely on zfs_iter_children() to verify that there are no
3782 3783 * newer snapshots for the given dataset. Therefore, we can
3783 3784 * simply pass the name on to the ioctl() call. There is still
3784 3785 * an unlikely race condition where the user has taken a
3785 3786 * snapshot since we verified that this was the most recent.
3786 3787 */
3787 3788 err = lzc_rollback(zhp->zfs_name, NULL, 0);
3788 3789 if (err != 0) {
3789 3790 (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3790 3791 dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3791 3792 zhp->zfs_name);
3792 3793 return (err);
3793 3794 }
3794 3795
3795 3796 /*
3796 3797 * For volumes, if the pre-rollback volsize matched the pre-
3797 3798 * rollback reservation and the volsize has changed then set
3798 3799 * the reservation property to the post-rollback volsize.
3799 3800 * Make a new handle since the rollback closed the dataset.
3800 3801 */
3801 3802 if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
3802 3803 (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
3803 3804 if (restore_resv) {
3804 3805 new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3805 3806 if (old_volsize != new_volsize)
3806 3807 err = zfs_prop_set_int(zhp, resv_prop,
3807 3808 new_volsize);
3808 3809 }
3809 3810 zfs_close(zhp);
3810 3811 }
3811 3812 return (err);
3812 3813 }
3813 3814
3814 3815 /*
3815 3816 * Renames the given dataset.
3816 3817 */
3817 3818 int
3818 3819 zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
3819 3820 boolean_t force_unmount)
3820 3821 {
3821 3822 int ret;
3822 3823 zfs_cmd_t zc = { 0 };
3823 3824 char *delim;
3824 3825 prop_changelist_t *cl = NULL;
3825 3826 zfs_handle_t *zhrp = NULL;
3826 3827 char *parentname = NULL;
3827 3828 char parent[ZFS_MAXNAMELEN];
3828 3829 libzfs_handle_t *hdl = zhp->zfs_hdl;
3829 3830 char errbuf[1024];
3830 3831
3831 3832 /* if we have the same exact name, just return success */
3832 3833 if (strcmp(zhp->zfs_name, target) == 0)
3833 3834 return (0);
3834 3835
3835 3836 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3836 3837 "cannot rename to '%s'"), target);
3837 3838
3838 3839 /*
3839 3840 * Make sure the target name is valid
3840 3841 */
3841 3842 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3842 3843 if ((strchr(target, '@') == NULL) ||
3843 3844 *target == '@') {
3844 3845 /*
3845 3846 * Snapshot target name is abbreviated,
3846 3847 * reconstruct full dataset name
3847 3848 */
3848 3849 (void) strlcpy(parent, zhp->zfs_name,
3849 3850 sizeof (parent));
3850 3851 delim = strchr(parent, '@');
3851 3852 if (strchr(target, '@') == NULL)
3852 3853 *(++delim) = '\0';
3853 3854 else
3854 3855 *delim = '\0';
3855 3856 (void) strlcat(parent, target, sizeof (parent));
3856 3857 target = parent;
3857 3858 } else {
3858 3859 /*
3859 3860 * Make sure we're renaming within the same dataset.
3860 3861 */
3861 3862 delim = strchr(target, '@');
3862 3863 if (strncmp(zhp->zfs_name, target, delim - target)
3863 3864 != 0 || zhp->zfs_name[delim - target] != '@') {
3864 3865 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3865 3866 "snapshots must be part of same "
3866 3867 "dataset"));
3867 3868 return (zfs_error(hdl, EZFS_CROSSTARGET,
3868 3869 errbuf));
3869 3870 }
3870 3871 }
3871 3872 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3872 3873 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3873 3874 } else {
3874 3875 if (recursive) {
3875 3876 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3876 3877 "recursive rename must be a snapshot"));
3877 3878 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3878 3879 }
3879 3880
3880 3881 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3881 3882 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3882 3883
3883 3884 /* validate parents */
3884 3885 if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
3885 3886 return (-1);
3886 3887
3887 3888 /* make sure we're in the same pool */
3888 3889 verify((delim = strchr(target, '/')) != NULL);
3889 3890 if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
3890 3891 zhp->zfs_name[delim - target] != '/') {
3891 3892 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3892 3893 "datasets must be within same pool"));
3893 3894 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
3894 3895 }
3895 3896
3896 3897 /* new name cannot be a child of the current dataset name */
3897 3898 if (is_descendant(zhp->zfs_name, target)) {
3898 3899 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3899 3900 "New dataset name cannot be a descendant of "
3900 3901 "current dataset name"));
3901 3902 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3902 3903 }
3903 3904 }
3904 3905
3905 3906 (void) snprintf(errbuf, sizeof (errbuf),
3906 3907 dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
3907 3908
3908 3909 if (getzoneid() == GLOBAL_ZONEID &&
3909 3910 zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
3910 3911 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3911 3912 "dataset is used in a non-global zone"));
3912 3913 return (zfs_error(hdl, EZFS_ZONED, errbuf));
3913 3914 }
3914 3915
3915 3916 if (recursive) {
3916 3917 parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
3917 3918 if (parentname == NULL) {
3918 3919 ret = -1;
3919 3920 goto error;
3920 3921 }
3921 3922 delim = strchr(parentname, '@');
3922 3923 *delim = '\0';
3923 3924 zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
3924 3925 if (zhrp == NULL) {
3925 3926 ret = -1;
3926 3927 goto error;
3927 3928 }
3928 3929 } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
3929 3930 if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3930 3931 force_unmount ? MS_FORCE : 0)) == NULL)
3931 3932 return (-1);
3932 3933
3933 3934 if (changelist_haszonedchild(cl)) {
3934 3935 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3935 3936 "child dataset with inherited mountpoint is used "
3936 3937 "in a non-global zone"));
3937 3938 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
3938 3939 goto error;
3939 3940 }
3940 3941
3941 3942 if ((ret = changelist_prefix(cl)) != 0)
3942 3943 goto error;
3943 3944 }
3944 3945
3945 3946 if (ZFS_IS_VOLUME(zhp))
3946 3947 zc.zc_objset_type = DMU_OST_ZVOL;
3947 3948 else
3948 3949 zc.zc_objset_type = DMU_OST_ZFS;
3949 3950
3950 3951 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3951 3952 (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
3952 3953
3953 3954 zc.zc_cookie = recursive;
3954 3955
3955 3956 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
3956 3957 /*
3957 3958 * if it was recursive, the one that actually failed will
3958 3959 * be in zc.zc_name
3959 3960 */
3960 3961 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3961 3962 "cannot rename '%s'"), zc.zc_name);
3962 3963
3963 3964 if (recursive && errno == EEXIST) {
3964 3965 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3965 3966 "a child dataset already has a snapshot "
3966 3967 "with the new name"));
3967 3968 (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3968 3969 } else {
3969 3970 (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
3970 3971 }
3971 3972
3972 3973 /*
3973 3974 * On failure, we still want to remount any filesystems that
3974 3975 * were previously mounted, so we don't alter the system state.
3975 3976 */
3976 3977 if (cl != NULL)
3977 3978 (void) changelist_postfix(cl);
3978 3979 } else {
3979 3980 if (cl != NULL) {
3980 3981 changelist_rename(cl, zfs_get_name(zhp), target);
3981 3982 ret = changelist_postfix(cl);
3982 3983 }
3983 3984 }
3984 3985
3985 3986 error:
3986 3987 if (parentname != NULL) {
3987 3988 free(parentname);
3988 3989 }
3989 3990 if (zhrp != NULL) {
3990 3991 zfs_close(zhrp);
3991 3992 }
3992 3993 if (cl != NULL) {
3993 3994 changelist_free(cl);
3994 3995 }
3995 3996 return (ret);
3996 3997 }
3997 3998
3998 3999 nvlist_t *
3999 4000 zfs_get_user_props(zfs_handle_t *zhp)
4000 4001 {
4001 4002 return (zhp->zfs_user_props);
4002 4003 }
4003 4004
4004 4005 nvlist_t *
4005 4006 zfs_get_recvd_props(zfs_handle_t *zhp)
4006 4007 {
4007 4008 if (zhp->zfs_recvd_props == NULL)
4008 4009 if (get_recvd_props_ioctl(zhp) != 0)
4009 4010 return (NULL);
4010 4011 return (zhp->zfs_recvd_props);
4011 4012 }
4012 4013
4013 4014 /*
4014 4015 * This function is used by 'zfs list' to determine the exact set of columns to
4015 4016 * display, and their maximum widths. This does two main things:
4016 4017 *
4017 4018 * - If this is a list of all properties, then expand the list to include
4018 4019 * all native properties, and set a flag so that for each dataset we look
4019 4020 * for new unique user properties and add them to the list.
4020 4021 *
4021 4022 * - For non fixed-width properties, keep track of the maximum width seen
4022 4023 * so that we can size the column appropriately. If the user has
4023 4024 * requested received property values, we also need to compute the width
4024 4025 * of the RECEIVED column.
4025 4026 */
4026 4027 int
4027 4028 zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
4028 4029 boolean_t literal)
4029 4030 {
4030 4031 libzfs_handle_t *hdl = zhp->zfs_hdl;
4031 4032 zprop_list_t *entry;
4032 4033 zprop_list_t **last, **start;
4033 4034 nvlist_t *userprops, *propval;
4034 4035 nvpair_t *elem;
4035 4036 char *strval;
4036 4037 char buf[ZFS_MAXPROPLEN];
4037 4038
4038 4039 if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
4039 4040 return (-1);
4040 4041
4041 4042 userprops = zfs_get_user_props(zhp);
4042 4043
4043 4044 entry = *plp;
4044 4045 if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
4045 4046 /*
4046 4047 * Go through and add any user properties as necessary. We
4047 4048 * start by incrementing our list pointer to the first
4048 4049 * non-native property.
4049 4050 */
4050 4051 start = plp;
4051 4052 while (*start != NULL) {
4052 4053 if ((*start)->pl_prop == ZPROP_INVAL)
4053 4054 break;
4054 4055 start = &(*start)->pl_next;
4055 4056 }
4056 4057
4057 4058 elem = NULL;
4058 4059 while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
4059 4060 /*
4060 4061 * See if we've already found this property in our list.
4061 4062 */
4062 4063 for (last = start; *last != NULL;
4063 4064 last = &(*last)->pl_next) {
4064 4065 if (strcmp((*last)->pl_user_prop,
4065 4066 nvpair_name(elem)) == 0)
4066 4067 break;
4067 4068 }
4068 4069
4069 4070 if (*last == NULL) {
4070 4071 if ((entry = zfs_alloc(hdl,
4071 4072 sizeof (zprop_list_t))) == NULL ||
4072 4073 ((entry->pl_user_prop = zfs_strdup(hdl,
4073 4074 nvpair_name(elem)))) == NULL) {
4074 4075 free(entry);
4075 4076 return (-1);
4076 4077 }
4077 4078
4078 4079 entry->pl_prop = ZPROP_INVAL;
4079 4080 entry->pl_width = strlen(nvpair_name(elem));
4080 4081 entry->pl_all = B_TRUE;
4081 4082 *last = entry;
4082 4083 }
4083 4084 }
4084 4085 }
4085 4086
4086 4087 /*
4087 4088 * Now go through and check the width of any non-fixed columns
4088 4089 */
4089 4090 for (entry = *plp; entry != NULL; entry = entry->pl_next) {
4090 4091 if (entry->pl_fixed && !literal)
4091 4092 continue;
4092 4093
4093 4094 if (entry->pl_prop != ZPROP_INVAL) {
4094 4095 if (zfs_prop_get(zhp, entry->pl_prop,
4095 4096 buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
4096 4097 if (strlen(buf) > entry->pl_width)
4097 4098 entry->pl_width = strlen(buf);
4098 4099 }
4099 4100 if (received && zfs_prop_get_recvd(zhp,
4100 4101 zfs_prop_to_name(entry->pl_prop),
4101 4102 buf, sizeof (buf), literal) == 0)
4102 4103 if (strlen(buf) > entry->pl_recvd_width)
4103 4104 entry->pl_recvd_width = strlen(buf);
4104 4105 } else {
4105 4106 if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
4106 4107 &propval) == 0) {
4107 4108 verify(nvlist_lookup_string(propval,
4108 4109 ZPROP_VALUE, &strval) == 0);
4109 4110 if (strlen(strval) > entry->pl_width)
4110 4111 entry->pl_width = strlen(strval);
4111 4112 }
4112 4113 if (received && zfs_prop_get_recvd(zhp,
4113 4114 entry->pl_user_prop,
4114 4115 buf, sizeof (buf), literal) == 0)
4115 4116 if (strlen(buf) > entry->pl_recvd_width)
4116 4117 entry->pl_recvd_width = strlen(buf);
4117 4118 }
4118 4119 }
4119 4120
4120 4121 return (0);
4121 4122 }
4122 4123
4123 4124 int
4124 4125 zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
4125 4126 char *resource, void *export, void *sharetab,
4126 4127 int sharemax, zfs_share_op_t operation)
4127 4128 {
4128 4129 zfs_cmd_t zc = { 0 };
4129 4130 int error;
4130 4131
4131 4132 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4132 4133 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4133 4134 if (resource)
4134 4135 (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
4135 4136 zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
4136 4137 zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
4137 4138 zc.zc_share.z_sharetype = operation;
4138 4139 zc.zc_share.z_sharemax = sharemax;
4139 4140 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
4140 4141 return (error);
4141 4142 }
4142 4143
4143 4144 void
4144 4145 zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
4145 4146 {
4146 4147 nvpair_t *curr;
4147 4148
4148 4149 /*
4149 4150 * Keep a reference to the props-table against which we prune the
4150 4151 * properties.
4151 4152 */
4152 4153 zhp->zfs_props_table = props;
4153 4154
4154 4155 curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
4155 4156
4156 4157 while (curr) {
4157 4158 zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
4158 4159 nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
4159 4160
4160 4161 /*
4161 4162 * User properties will result in ZPROP_INVAL, and since we
4162 4163 * only know how to prune standard ZFS properties, we always
4163 4164 * leave these in the list. This can also happen if we
4164 4165 * encounter an unknown DSL property (when running older
4165 4166 * software, for example).
4166 4167 */
4167 4168 if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
4168 4169 (void) nvlist_remove(zhp->zfs_props,
4169 4170 nvpair_name(curr), nvpair_type(curr));
4170 4171 curr = next;
4171 4172 }
4172 4173 }
4173 4174
4174 4175 static int
4175 4176 zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
4176 4177 zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
4177 4178 {
4178 4179 zfs_cmd_t zc = { 0 };
4179 4180 nvlist_t *nvlist = NULL;
4180 4181 int error;
4181 4182
4182 4183 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4183 4184 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4184 4185 zc.zc_cookie = (uint64_t)cmd;
4185 4186
4186 4187 if (cmd == ZFS_SMB_ACL_RENAME) {
4187 4188 if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
4188 4189 (void) no_memory(hdl);
4189 4190 return (0);
4190 4191 }
4191 4192 }
4192 4193
4193 4194 switch (cmd) {
4194 4195 case ZFS_SMB_ACL_ADD:
4195 4196 case ZFS_SMB_ACL_REMOVE:
4196 4197 (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
4197 4198 break;
4198 4199 case ZFS_SMB_ACL_RENAME:
4199 4200 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
4200 4201 resource1) != 0) {
4201 4202 (void) no_memory(hdl);
4202 4203 return (-1);
4203 4204 }
4204 4205 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
4205 4206 resource2) != 0) {
4206 4207 (void) no_memory(hdl);
4207 4208 return (-1);
4208 4209 }
4209 4210 if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
4210 4211 nvlist_free(nvlist);
4211 4212 return (-1);
4212 4213 }
4213 4214 break;
4214 4215 case ZFS_SMB_ACL_PURGE:
4215 4216 break;
4216 4217 default:
4217 4218 return (-1);
4218 4219 }
4219 4220 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
4220 4221 if (nvlist)
4221 4222 nvlist_free(nvlist);
4222 4223 return (error);
4223 4224 }
4224 4225
4225 4226 int
4226 4227 zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4227 4228 char *path, char *resource)
4228 4229 {
4229 4230 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4230 4231 resource, NULL));
4231 4232 }
4232 4233
4233 4234 int
4234 4235 zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4235 4236 char *path, char *resource)
4236 4237 {
4237 4238 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4238 4239 resource, NULL));
4239 4240 }
4240 4241
4241 4242 int
4242 4243 zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4243 4244 {
4244 4245 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4245 4246 NULL, NULL));
4246 4247 }
4247 4248
4248 4249 int
4249 4250 zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4250 4251 char *oldname, char *newname)
4251 4252 {
4252 4253 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4253 4254 oldname, newname));
4254 4255 }
4255 4256
4256 4257 int
4257 4258 zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4258 4259 zfs_userspace_cb_t func, void *arg)
4259 4260 {
4260 4261 zfs_cmd_t zc = { 0 };
4261 4262 zfs_useracct_t buf[100];
4262 4263 libzfs_handle_t *hdl = zhp->zfs_hdl;
4263 4264 int ret;
4264 4265
4265 4266 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4266 4267
4267 4268 zc.zc_objset_type = type;
4268 4269 zc.zc_nvlist_dst = (uintptr_t)buf;
4269 4270
4270 4271 for (;;) {
4271 4272 zfs_useracct_t *zua = buf;
4272 4273
4273 4274 zc.zc_nvlist_dst_size = sizeof (buf);
4274 4275 if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
4275 4276 char errbuf[1024];
4276 4277
4277 4278 (void) snprintf(errbuf, sizeof (errbuf),
4278 4279 dgettext(TEXT_DOMAIN,
4279 4280 "cannot get used/quota for %s"), zc.zc_name);
4280 4281 return (zfs_standard_error_fmt(hdl, errno, errbuf));
4281 4282 }
4282 4283 if (zc.zc_nvlist_dst_size == 0)
4283 4284 break;
4284 4285
4285 4286 while (zc.zc_nvlist_dst_size > 0) {
4286 4287 if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
4287 4288 zua->zu_space)) != 0)
4288 4289 return (ret);
4289 4290 zua++;
4290 4291 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4291 4292 }
4292 4293 }
4293 4294
4294 4295 return (0);
4295 4296 }
4296 4297
4297 4298 struct holdarg {
4298 4299 nvlist_t *nvl;
4299 4300 const char *snapname;
4300 4301 const char *tag;
4301 4302 boolean_t recursive;
4302 4303 int error;
4303 4304 };
4304 4305
4305 4306 static int
4306 4307 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4307 4308 {
4308 4309 struct holdarg *ha = arg;
4309 4310 char name[ZFS_MAXNAMELEN];
4310 4311 int rv = 0;
4311 4312
4312 4313 (void) snprintf(name, sizeof (name),
4313 4314 "%s@%s", zhp->zfs_name, ha->snapname);
4314 4315
4315 4316 if (lzc_exists(name))
4316 4317 fnvlist_add_string(ha->nvl, name, ha->tag);
4317 4318
4318 4319 if (ha->recursive)
4319 4320 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4320 4321 zfs_close(zhp);
4321 4322 return (rv);
4322 4323 }
4323 4324
4324 4325 int
4325 4326 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4326 4327 boolean_t recursive, int cleanup_fd)
4327 4328 {
4328 4329 int ret;
4329 4330 struct holdarg ha;
4330 4331
4331 4332 ha.nvl = fnvlist_alloc();
4332 4333 ha.snapname = snapname;
4333 4334 ha.tag = tag;
4334 4335 ha.recursive = recursive;
4335 4336 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4336 4337
4337 4338 if (nvlist_empty(ha.nvl)) {
4338 4339 char errbuf[1024];
4339 4340
4340 4341 fnvlist_free(ha.nvl);
4341 4342 ret = ENOENT;
4342 4343 (void) snprintf(errbuf, sizeof (errbuf),
4343 4344 dgettext(TEXT_DOMAIN,
4344 4345 "cannot hold snapshot '%s@%s'"),
4345 4346 zhp->zfs_name, snapname);
4346 4347 (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4347 4348 return (ret);
4348 4349 }
4349 4350
4350 4351 ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4351 4352 fnvlist_free(ha.nvl);
4352 4353
4353 4354 return (ret);
4354 4355 }
4355 4356
4356 4357 int
4357 4358 zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
4358 4359 {
4359 4360 int ret;
4360 4361 nvlist_t *errors;
4361 4362 libzfs_handle_t *hdl = zhp->zfs_hdl;
4362 4363 char errbuf[1024];
4363 4364 nvpair_t *elem;
4364 4365
4365 4366 errors = NULL;
4366 4367 ret = lzc_hold(holds, cleanup_fd, &errors);
4367 4368
4368 4369 if (ret == 0) {
4369 4370 /* There may be errors even in the success case. */
4370 4371 fnvlist_free(errors);
4371 4372 return (0);
4372 4373 }
4373 4374
4374 4375 if (nvlist_empty(errors)) {
4375 4376 /* no hold-specific errors */
4376 4377 (void) snprintf(errbuf, sizeof (errbuf),
4377 4378 dgettext(TEXT_DOMAIN, "cannot hold"));
4378 4379 switch (ret) {
4379 4380 case ENOTSUP:
4380 4381 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4381 4382 "pool must be upgraded"));
4382 4383 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4383 4384 break;
4384 4385 case EINVAL:
4385 4386 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4386 4387 break;
4387 4388 default:
4388 4389 (void) zfs_standard_error(hdl, ret, errbuf);
4389 4390 }
4390 4391 }
4391 4392
4392 4393 for (elem = nvlist_next_nvpair(errors, NULL);
4393 4394 elem != NULL;
4394 4395 elem = nvlist_next_nvpair(errors, elem)) {
4395 4396 (void) snprintf(errbuf, sizeof (errbuf),
4396 4397 dgettext(TEXT_DOMAIN,
4397 4398 "cannot hold snapshot '%s'"), nvpair_name(elem));
4398 4399 switch (fnvpair_value_int32(elem)) {
4399 4400 case E2BIG:
4400 4401 /*
4401 4402 * Temporary tags wind up having the ds object id
4402 4403 * prepended. So even if we passed the length check
4403 4404 * above, it's still possible for the tag to wind
4404 4405 * up being slightly too long.
4405 4406 */
4406 4407 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4407 4408 break;
4408 4409 case EINVAL:
4409 4410 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4410 4411 break;
4411 4412 case EEXIST:
4412 4413 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4413 4414 break;
4414 4415 default:
4415 4416 (void) zfs_standard_error(hdl,
4416 4417 fnvpair_value_int32(elem), errbuf);
4417 4418 }
4418 4419 }
4419 4420
4420 4421 fnvlist_free(errors);
4421 4422 return (ret);
4422 4423 }
4423 4424
4424 4425 static int
4425 4426 zfs_release_one(zfs_handle_t *zhp, void *arg)
4426 4427 {
4427 4428 struct holdarg *ha = arg;
4428 4429 char name[ZFS_MAXNAMELEN];
4429 4430 int rv = 0;
4430 4431 nvlist_t *existing_holds;
4431 4432
4432 4433 (void) snprintf(name, sizeof (name),
4433 4434 "%s@%s", zhp->zfs_name, ha->snapname);
4434 4435
4435 4436 if (lzc_get_holds(name, &existing_holds) != 0) {
4436 4437 ha->error = ENOENT;
4437 4438 } else if (!nvlist_exists(existing_holds, ha->tag)) {
4438 4439 ha->error = ESRCH;
4439 4440 } else {
4440 4441 nvlist_t *torelease = fnvlist_alloc();
4441 4442 fnvlist_add_boolean(torelease, ha->tag);
4442 4443 fnvlist_add_nvlist(ha->nvl, name, torelease);
4443 4444 fnvlist_free(torelease);
4444 4445 }
4445 4446
4446 4447 if (ha->recursive)
4447 4448 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4448 4449 zfs_close(zhp);
4449 4450 return (rv);
4450 4451 }
4451 4452
4452 4453 int
4453 4454 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4454 4455 boolean_t recursive)
4455 4456 {
4456 4457 int ret;
4457 4458 struct holdarg ha;
4458 4459 nvlist_t *errors = NULL;
4459 4460 nvpair_t *elem;
4460 4461 libzfs_handle_t *hdl = zhp->zfs_hdl;
4461 4462 char errbuf[1024];
4462 4463
4463 4464 ha.nvl = fnvlist_alloc();
4464 4465 ha.snapname = snapname;
4465 4466 ha.tag = tag;
4466 4467 ha.recursive = recursive;
4467 4468 ha.error = 0;
4468 4469 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4469 4470
4470 4471 if (nvlist_empty(ha.nvl)) {
4471 4472 fnvlist_free(ha.nvl);
4472 4473 ret = ha.error;
4473 4474 (void) snprintf(errbuf, sizeof (errbuf),
4474 4475 dgettext(TEXT_DOMAIN,
4475 4476 "cannot release hold from snapshot '%s@%s'"),
4476 4477 zhp->zfs_name, snapname);
4477 4478 if (ret == ESRCH) {
4478 4479 (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
4479 4480 } else {
4480 4481 (void) zfs_standard_error(hdl, ret, errbuf);
4481 4482 }
4482 4483 return (ret);
4483 4484 }
4484 4485
4485 4486 ret = lzc_release(ha.nvl, &errors);
4486 4487 fnvlist_free(ha.nvl);
4487 4488
4488 4489 if (ret == 0) {
4489 4490 /* There may be errors even in the success case. */
4490 4491 fnvlist_free(errors);
4491 4492 return (0);
4492 4493 }
4493 4494
4494 4495 if (nvlist_empty(errors)) {
4495 4496 /* no hold-specific errors */
4496 4497 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4497 4498 "cannot release"));
4498 4499 switch (errno) {
4499 4500 case ENOTSUP:
4500 4501 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4501 4502 "pool must be upgraded"));
4502 4503 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4503 4504 break;
4504 4505 default:
4505 4506 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4506 4507 }
4507 4508 }
4508 4509
4509 4510 for (elem = nvlist_next_nvpair(errors, NULL);
4510 4511 elem != NULL;
4511 4512 elem = nvlist_next_nvpair(errors, elem)) {
4512 4513 (void) snprintf(errbuf, sizeof (errbuf),
4513 4514 dgettext(TEXT_DOMAIN,
4514 4515 "cannot release hold from snapshot '%s'"),
4515 4516 nvpair_name(elem));
4516 4517 switch (fnvpair_value_int32(elem)) {
4517 4518 case ESRCH:
4518 4519 (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
4519 4520 break;
4520 4521 case EINVAL:
4521 4522 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4522 4523 break;
4523 4524 default:
4524 4525 (void) zfs_standard_error_fmt(hdl,
4525 4526 fnvpair_value_int32(elem), errbuf);
4526 4527 }
4527 4528 }
4528 4529
4529 4530 fnvlist_free(errors);
4530 4531 return (ret);
4531 4532 }
4532 4533
4533 4534 int
4534 4535 zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
4535 4536 {
4536 4537 zfs_cmd_t zc = { 0 };
4537 4538 libzfs_handle_t *hdl = zhp->zfs_hdl;
4538 4539 int nvsz = 2048;
4539 4540 void *nvbuf;
4540 4541 int err = 0;
4541 4542 char errbuf[1024];
4542 4543
4543 4544 assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4544 4545 zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4545 4546
4546 4547 tryagain:
4547 4548
4548 4549 nvbuf = malloc(nvsz);
4549 4550 if (nvbuf == NULL) {
4550 4551 err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
4551 4552 goto out;
4552 4553 }
4553 4554
4554 4555 zc.zc_nvlist_dst_size = nvsz;
4555 4556 zc.zc_nvlist_dst = (uintptr_t)nvbuf;
4556 4557
4557 4558 (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
4558 4559
4559 4560 if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
4560 4561 (void) snprintf(errbuf, sizeof (errbuf),
4561 4562 dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
4562 4563 zc.zc_name);
4563 4564 switch (errno) {
4564 4565 case ENOMEM:
4565 4566 free(nvbuf);
4566 4567 nvsz = zc.zc_nvlist_dst_size;
4567 4568 goto tryagain;
4568 4569
4569 4570 case ENOTSUP:
4570 4571 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4571 4572 "pool must be upgraded"));
4572 4573 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4573 4574 break;
4574 4575 case EINVAL:
4575 4576 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4576 4577 break;
4577 4578 case ENOENT:
4578 4579 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4579 4580 break;
4580 4581 default:
4581 4582 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4582 4583 break;
4583 4584 }
4584 4585 } else {
4585 4586 /* success */
4586 4587 int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
4587 4588 if (rc) {
4588 4589 (void) snprintf(errbuf, sizeof (errbuf), dgettext(
4589 4590 TEXT_DOMAIN, "cannot get permissions on '%s'"),
4590 4591 zc.zc_name);
4591 4592 err = zfs_standard_error_fmt(hdl, rc, errbuf);
4592 4593 }
4593 4594 }
4594 4595
4595 4596 free(nvbuf);
4596 4597 out:
4597 4598 return (err);
4598 4599 }
4599 4600
4600 4601 int
4601 4602 zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
4602 4603 {
4603 4604 zfs_cmd_t zc = { 0 };
4604 4605 libzfs_handle_t *hdl = zhp->zfs_hdl;
4605 4606 char *nvbuf;
4606 4607 char errbuf[1024];
4607 4608 size_t nvsz;
4608 4609 int err;
4609 4610
4610 4611 assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4611 4612 zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4612 4613
4613 4614 err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
4614 4615 assert(err == 0);
4615 4616
4616 4617 nvbuf = malloc(nvsz);
4617 4618
4618 4619 err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
4619 4620 assert(err == 0);
4620 4621
4621 4622 zc.zc_nvlist_src_size = nvsz;
4622 4623 zc.zc_nvlist_src = (uintptr_t)nvbuf;
4623 4624 zc.zc_perm_action = un;
4624 4625
4625 4626 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4626 4627
4627 4628 if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
4628 4629 (void) snprintf(errbuf, sizeof (errbuf),
4629 4630 dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
4630 4631 zc.zc_name);
4631 4632 switch (errno) {
4632 4633 case ENOTSUP:
4633 4634 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4634 4635 "pool must be upgraded"));
4635 4636 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4636 4637 break;
4637 4638 case EINVAL:
4638 4639 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4639 4640 break;
4640 4641 case ENOENT:
4641 4642 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4642 4643 break;
4643 4644 default:
4644 4645 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4645 4646 break;
4646 4647 }
4647 4648 }
4648 4649
4649 4650 free(nvbuf);
4650 4651
4651 4652 return (err);
4652 4653 }
4653 4654
4654 4655 int
4655 4656 zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
4656 4657 {
4657 4658 int err;
4658 4659 char errbuf[1024];
4659 4660
4660 4661 err = lzc_get_holds(zhp->zfs_name, nvl);
4661 4662
4662 4663 if (err != 0) {
4663 4664 libzfs_handle_t *hdl = zhp->zfs_hdl;
4664 4665
4665 4666 (void) snprintf(errbuf, sizeof (errbuf),
4666 4667 dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
4667 4668 zhp->zfs_name);
4668 4669 switch (err) {
4669 4670 case ENOTSUP:
4670 4671 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4671 4672 "pool must be upgraded"));
4672 4673 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4673 4674 break;
4674 4675 case EINVAL:
4675 4676 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4676 4677 break;
4677 4678 case ENOENT:
4678 4679 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4679 4680 break;
4680 4681 default:
4681 4682 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4682 4683 break;
4683 4684 }
4684 4685 }
4685 4686
4686 4687 return (err);
4687 4688 }
4688 4689
4689 4690 /*
4690 4691 * Convert the zvol's volume size to an appropriate reservation.
4691 4692 * Note: If this routine is updated, it is necessary to update the ZFS test
4692 4693 * suite's shell version in reservation.kshlib.
4693 4694 */
4694 4695 uint64_t
4695 4696 zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
4696 4697 {
4697 4698 uint64_t numdb;
4698 4699 uint64_t nblocks, volblocksize;
4699 4700 int ncopies;
4700 4701 char *strval;
4701 4702
4702 4703 if (nvlist_lookup_string(props,
4703 4704 zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
4704 4705 ncopies = atoi(strval);
4705 4706 else
4706 4707 ncopies = 1;
4707 4708 if (nvlist_lookup_uint64(props,
4708 4709 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
4709 4710 &volblocksize) != 0)
4710 4711 volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
4711 4712 nblocks = volsize/volblocksize;
4712 4713 /* start with metadnode L0-L6 */
4713 4714 numdb = 7;
4714 4715 /* calculate number of indirects */
4715 4716 while (nblocks > 1) {
4716 4717 nblocks += DNODES_PER_LEVEL - 1;
4717 4718 nblocks /= DNODES_PER_LEVEL;
4718 4719 numdb += nblocks;
4719 4720 }
4720 4721 numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4721 4722 volsize *= ncopies;
4722 4723 /*
4723 4724 * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4724 4725 * compressed, but in practice they compress down to about
4725 4726 * 1100 bytes
4726 4727 */
4727 4728 numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4728 4729 volsize += numdb;
4729 4730 return (volsize);
4730 4731 }
↓ open down ↓ |
1303 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX