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