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