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