Deleted Added
full compact
libzfs_dataset.c (208684) libzfs_dataset.c (209962)
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

--- 23 unchanged lines hidden (view full) ---

32#include <stdio.h>
33#include <stdlib.h>
34#include <strings.h>
35#include <unistd.h>
36#include <stddef.h>
37#include <zone.h>
38#include <fcntl.h>
39#include <sys/mntent.h>
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

--- 23 unchanged lines hidden (view full) ---

32#include <stdio.h>
33#include <stdlib.h>
34#include <strings.h>
35#include <unistd.h>
36#include <stddef.h>
37#include <zone.h>
38#include <fcntl.h>
39#include <sys/mntent.h>
40#include <sys/mnttab.h>
41#include <sys/mount.h>
42#include <sys/avl.h>
43#include <priv.h>
44#include <pwd.h>
45#include <grp.h>
46#include <stddef.h>
40#include <sys/mount.h>
41#include <sys/avl.h>
42#include <priv.h>
43#include <pwd.h>
44#include <grp.h>
45#include <stddef.h>
46#include <idmap.h>
47
48#include <sys/spa.h>
49#include <sys/zap.h>
47
48#include <sys/spa.h>
49#include <sys/zap.h>
50#include <sys/misc.h>
50#include <libzfs.h>
51
52#include "zfs_namecheck.h"
53#include "zfs_prop.h"
54#include "libzfs_impl.h"
55#include "zfs_deleg.h"
56
57static int zvol_create_link_common(libzfs_handle_t *, const char *, int);
51#include <libzfs.h>
52
53#include "zfs_namecheck.h"
54#include "zfs_prop.h"
55#include "libzfs_impl.h"
56#include "zfs_deleg.h"
57
58static int zvol_create_link_common(libzfs_handle_t *, const char *, int);
59static int userquota_propname_decode(const char *propname, boolean_t zoned,
60 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
58
59/*
60 * Given a single type (not a mask of types), return the type in a human
61 * readable form.
62 */
63const char *
64zfs_type_to_name(zfs_type_t type)
65{

--- 35 unchanged lines hidden (view full) ---

101 * snapshot attribute and try again.
102 */
103 if (types & ZFS_TYPE_SNAPSHOT) {
104 if (strchr(path, '@') != NULL)
105 return (dgettext(TEXT_DOMAIN, "snapshot"));
106 return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
107 }
108
61
62/*
63 * Given a single type (not a mask of types), return the type in a human
64 * readable form.
65 */
66const char *
67zfs_type_to_name(zfs_type_t type)
68{

--- 35 unchanged lines hidden (view full) ---

104 * snapshot attribute and try again.
105 */
106 if (types & ZFS_TYPE_SNAPSHOT) {
107 if (strchr(path, '@') != NULL)
108 return (dgettext(TEXT_DOMAIN, "snapshot"));
109 return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
110 }
111
109
110 /*
111 * The user has requested either filesystems or volumes.
112 * We have no way of knowing a priori what type this would be, so always
113 * report it as "filesystem" or "volume", our two primitive types.
114 */
115 if (types & ZFS_TYPE_FILESYSTEM)
116 return (dgettext(TEXT_DOMAIN, "filesystem"));
117
118 assert(types & ZFS_TYPE_VOLUME);
119 return (dgettext(TEXT_DOMAIN, "volume"));
120}
121
122/*
123 * Validate a ZFS path. This is used even before trying to open the dataset, to
112 /*
113 * The user has requested either filesystems or volumes.
114 * We have no way of knowing a priori what type this would be, so always
115 * report it as "filesystem" or "volume", our two primitive types.
116 */
117 if (types & ZFS_TYPE_FILESYSTEM)
118 return (dgettext(TEXT_DOMAIN, "filesystem"));
119
120 assert(types & ZFS_TYPE_VOLUME);
121 return (dgettext(TEXT_DOMAIN, "volume"));
122}
123
124/*
125 * Validate a ZFS path. This is used even before trying to open the dataset, to
124 * provide a more meaningful error message. We place a more useful message in
125 * 'buf' detailing exactly why the name was not valid.
126 * provide a more meaningful error message. We call zfs_error_aux() to
127 * explain exactly why the name was not valid.
126 */
127static int
128zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
129 boolean_t modifying)
130{
131 namecheck_err_t why;
132 char what;
133

--- 177 unchanged lines hidden (view full) ---

311 zph = next;
312 }
313 hdl->libzfs_pool_handles = NULL;
314}
315
316/*
317 * Utility function to gather stats (objset and zpl) for the given object.
318 */
128 */
129static int
130zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
131 boolean_t modifying)
132{
133 namecheck_err_t why;
134 char what;
135

--- 177 unchanged lines hidden (view full) ---

313 zph = next;
314 }
315 hdl->libzfs_pool_handles = NULL;
316}
317
318/*
319 * Utility function to gather stats (objset and zpl) for the given object.
320 */
319static int
320get_stats(zfs_handle_t *zhp)
321get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
321{
322{
322 zfs_cmd_t zc = { 0 };
323 libzfs_handle_t *hdl = zhp->zfs_hdl;
323 libzfs_handle_t *hdl = zhp->zfs_hdl;
324 nvlist_t *allprops, *userprops;
325
324
326 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
325 (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
327
326
328 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
329 return (-1);
330
331 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
327 while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
332 if (errno == ENOMEM) {
328 if (errno == ENOMEM) {
333 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
334 zcmd_free_nvlists(&zc);
329 if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
335 return (-1);
336 }
337 } else {
330 return (-1);
331 }
332 } else {
338 zcmd_free_nvlists(&zc);
339 return (-1);
340 }
341 }
333 return (-1);
334 }
335 }
336 return (0);
337}
342
338
343 zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */
339static int
340put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
341{
342 nvlist_t *allprops, *userprops;
344
343
345 if (zcmd_read_dst_nvlist(hdl, &zc, &allprops) != 0) {
346 zcmd_free_nvlists(&zc);
344 zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
345
346 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
347 return (-1);
348 }
349
347 return (-1);
348 }
349
350 zcmd_free_nvlists(&zc);
351
350 /*
351 * XXX Why do we store the user props separately, in addition to
352 * storing them in zfs_props?
353 */
352 if ((userprops = process_user_props(zhp, allprops)) == NULL) {
353 nvlist_free(allprops);
354 return (-1);
355 }
356
357 nvlist_free(zhp->zfs_props);
358 nvlist_free(zhp->zfs_user_props);
359
360 zhp->zfs_props = allprops;
361 zhp->zfs_user_props = userprops;
362
363 return (0);
364}
365
354 if ((userprops = process_user_props(zhp, allprops)) == NULL) {
355 nvlist_free(allprops);
356 return (-1);
357 }
358
359 nvlist_free(zhp->zfs_props);
360 nvlist_free(zhp->zfs_user_props);
361
362 zhp->zfs_props = allprops;
363 zhp->zfs_user_props = userprops;
364
365 return (0);
366}
367
368static int
369get_stats(zfs_handle_t *zhp)
370{
371 int rc = 0;
372 zfs_cmd_t zc = { 0 };
373
374 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
375 return (-1);
376 if (get_stats_ioctl(zhp, &zc) != 0)
377 rc = -1;
378 else if (put_stats_zhdl(zhp, &zc) != 0)
379 rc = -1;
380 zcmd_free_nvlists(&zc);
381 return (rc);
382}
383
366/*
367 * Refresh the properties currently stored in the handle.
368 */
369void
370zfs_refresh_properties(zfs_handle_t *zhp)
371{
372 (void) get_stats(zhp);
373}
374
375/*
376 * Makes a handle from the given dataset name. Used by zfs_open() and
377 * zfs_iter_* to create child handles on the fly.
378 */
384/*
385 * Refresh the properties currently stored in the handle.
386 */
387void
388zfs_refresh_properties(zfs_handle_t *zhp)
389{
390 (void) get_stats(zhp);
391}
392
393/*
394 * Makes a handle from the given dataset name. Used by zfs_open() and
395 * zfs_iter_* to create child handles on the fly.
396 */
379zfs_handle_t *
380make_dataset_handle(libzfs_handle_t *hdl, const char *path)
397static int
398make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
381{
399{
382 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
383 char *logstr;
400 char *logstr;
401 libzfs_handle_t *hdl = zhp->zfs_hdl;
384
402
385 if (zhp == NULL)
386 return (NULL);
387
388 zhp->zfs_hdl = hdl;
389
390 /*
391 * Preserve history log string.
392 * any changes performed here will be
393 * logged as an internal event.
394 */
395 logstr = zhp->zfs_hdl->libzfs_log_str;
396 zhp->zfs_hdl->libzfs_log_str = NULL;
403 /*
404 * Preserve history log string.
405 * any changes performed here will be
406 * logged as an internal event.
407 */
408 logstr = zhp->zfs_hdl->libzfs_log_str;
409 zhp->zfs_hdl->libzfs_log_str = NULL;
397top:
398 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
399
410
400 if (get_stats(zhp) != 0) {
411top:
412 if (put_stats_zhdl(zhp, zc) != 0) {
401 zhp->zfs_hdl->libzfs_log_str = logstr;
413 zhp->zfs_hdl->libzfs_log_str = logstr;
402 free(zhp);
403 return (NULL);
414 return (-1);
404 }
405
415 }
416
417
406 if (zhp->zfs_dmustats.dds_inconsistent) {
418 if (zhp->zfs_dmustats.dds_inconsistent) {
407 zfs_cmd_t zc = { 0 };
419 zfs_cmd_t zc2 = { 0 };
408
409 /*
410 * If it is dds_inconsistent, then we've caught it in
411 * the middle of a 'zfs receive' or 'zfs destroy', and
412 * it is inconsistent from the ZPL's point of view, so
413 * can't be mounted. However, it could also be that we
414 * have crashed in the middle of one of those
415 * operations, in which case we need to get rid of the
416 * inconsistent state. We do that by either rolling
417 * back to the previous snapshot (which will fail if
418 * there is none), or destroying the filesystem. Note
419 * that if we are still in the middle of an active
420 * 'receive' or 'destroy', then the rollback and destroy
421 * will fail with EBUSY and we will drive on as usual.
422 */
423
420
421 /*
422 * If it is dds_inconsistent, then we've caught it in
423 * the middle of a 'zfs receive' or 'zfs destroy', and
424 * it is inconsistent from the ZPL's point of view, so
425 * can't be mounted. However, it could also be that we
426 * have crashed in the middle of one of those
427 * operations, in which case we need to get rid of the
428 * inconsistent state. We do that by either rolling
429 * back to the previous snapshot (which will fail if
430 * there is none), or destroying the filesystem. Note
431 * that if we are still in the middle of an active
432 * 'receive' or 'destroy', then the rollback and destroy
433 * will fail with EBUSY and we will drive on as usual.
434 */
435
424 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
436 (void) strlcpy(zc2.zc_name, zhp->zfs_name,
437 sizeof (zc2.zc_name));
425
426 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) {
427 (void) zvol_remove_link(hdl, zhp->zfs_name);
438
439 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) {
440 (void) zvol_remove_link(hdl, zhp->zfs_name);
428 zc.zc_objset_type = DMU_OST_ZVOL;
441 zc2.zc_objset_type = DMU_OST_ZVOL;
429 } else {
442 } else {
430 zc.zc_objset_type = DMU_OST_ZFS;
443 zc2.zc_objset_type = DMU_OST_ZFS;
431 }
432
433 /*
434 * If we can successfully destroy it, pretend that it
435 * never existed.
436 */
444 }
445
446 /*
447 * If we can successfully destroy it, pretend that it
448 * never existed.
449 */
437 if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
450 if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc2) == 0) {
438 zhp->zfs_hdl->libzfs_log_str = logstr;
451 zhp->zfs_hdl->libzfs_log_str = logstr;
439 free(zhp);
440 errno = ENOENT;
452 errno = ENOENT;
441 return (NULL);
453 return (-1);
442 }
454 }
443 /* If we can successfully roll it back, reget the stats */
444 if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
455 /* If we can successfully roll it back, reset the stats */
456 if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc2) == 0) {
457 if (get_stats_ioctl(zhp, zc) != 0) {
458 zhp->zfs_hdl->libzfs_log_str = logstr;
459 return (-1);
460 }
445 goto top;
461 goto top;
462 }
446 }
447
448 /*
449 * We've managed to open the dataset and gather statistics. Determine
450 * the high-level type.
451 */
452 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
453 zhp->zfs_head_type = ZFS_TYPE_VOLUME;

--- 8 unchanged lines hidden (view full) ---

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
468 zhp->zfs_hdl->libzfs_log_str = logstr;
469 zhp->zpool_hdl = zpool_handle(zhp);
463 }
464
465 /*
466 * We've managed to open the dataset and gather statistics. Determine
467 * the high-level type.
468 */
469 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
470 zhp->zfs_head_type = ZFS_TYPE_VOLUME;

--- 8 unchanged lines hidden (view full) ---

479 zhp->zfs_type = ZFS_TYPE_VOLUME;
480 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
481 zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
482 else
483 abort(); /* we should never see any other types */
484
485 zhp->zfs_hdl->libzfs_log_str = logstr;
486 zhp->zpool_hdl = zpool_handle(zhp);
487 return (0);
488}
489
490zfs_handle_t *
491make_dataset_handle(libzfs_handle_t *hdl, const char *path)
492{
493 zfs_cmd_t zc = { 0 };
494
495 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
496
497 if (zhp == NULL)
498 return (NULL);
499
500 zhp->zfs_hdl = hdl;
501 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
502 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
503 free(zhp);
504 return (NULL);
505 }
506 if (get_stats_ioctl(zhp, &zc) == -1) {
507 zcmd_free_nvlists(&zc);
508 free(zhp);
509 return (NULL);
510 }
511 if (make_dataset_handle_common(zhp, &zc) == -1) {
512 free(zhp);
513 zhp = NULL;
514 }
515 zcmd_free_nvlists(&zc);
470 return (zhp);
471}
472
516 return (zhp);
517}
518
519static zfs_handle_t *
520make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
521{
522 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
523
524 if (zhp == NULL)
525 return (NULL);
526
527 zhp->zfs_hdl = hdl;
528 (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
529 if (make_dataset_handle_common(zhp, zc) == -1) {
530 free(zhp);
531 return (NULL);
532 }
533 return (zhp);
534}
535
473/*
474 * Opens the given snapshot, filesystem, or volume. The 'types'
475 * argument is a mask of acceptable types. The function will print an
476 * appropriate error message and return NULL if it can't be opened.
477 */
478zfs_handle_t *
479zfs_open(libzfs_handle_t *hdl, const char *path, int types)
480{

--- 39 unchanged lines hidden (view full) ---

520{
521 if (zhp->zfs_mntopts)
522 free(zhp->zfs_mntopts);
523 nvlist_free(zhp->zfs_props);
524 nvlist_free(zhp->zfs_user_props);
525 free(zhp);
526}
527
536/*
537 * Opens the given snapshot, filesystem, or volume. The 'types'
538 * argument is a mask of acceptable types. The function will print an
539 * appropriate error message and return NULL if it can't be opened.
540 */
541zfs_handle_t *
542zfs_open(libzfs_handle_t *hdl, const char *path, int types)
543{

--- 39 unchanged lines hidden (view full) ---

583{
584 if (zhp->zfs_mntopts)
585 free(zhp->zfs_mntopts);
586 nvlist_free(zhp->zfs_props);
587 nvlist_free(zhp->zfs_user_props);
588 free(zhp);
589}
590
591typedef struct mnttab_node {
592 struct mnttab mtn_mt;
593 avl_node_t mtn_node;
594} mnttab_node_t;
595
596static int
597libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
598{
599 const mnttab_node_t *mtn1 = arg1;
600 const mnttab_node_t *mtn2 = arg2;
601 int rv;
602
603 rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
604
605 if (rv == 0)
606 return (0);
607 return (rv > 0 ? 1 : -1);
608}
609
610void
611libzfs_mnttab_init(libzfs_handle_t *hdl)
612{
613 assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
614 avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
615 sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
616}
617
618void
619libzfs_mnttab_update(libzfs_handle_t *hdl)
620{
621 struct mnttab entry;
622
623 rewind(hdl->libzfs_mnttab);
624 while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
625 mnttab_node_t *mtn;
626
627 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
628 continue;
629 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
630 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
631 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
632 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
633 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
634 avl_add(&hdl->libzfs_mnttab_cache, mtn);
635 }
636}
637
638void
639libzfs_mnttab_fini(libzfs_handle_t *hdl)
640{
641 void *cookie = NULL;
642 mnttab_node_t *mtn;
643
644 while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) {
645 free(mtn->mtn_mt.mnt_special);
646 free(mtn->mtn_mt.mnt_mountp);
647 free(mtn->mtn_mt.mnt_fstype);
648 free(mtn->mtn_mt.mnt_mntopts);
649 free(mtn);
650 }
651 avl_destroy(&hdl->libzfs_mnttab_cache);
652}
653
654void
655libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
656{
657 hdl->libzfs_mnttab_enable = enable;
658}
659
528int
660int
661libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
662 struct mnttab *entry)
663{
664 mnttab_node_t find;
665 mnttab_node_t *mtn;
666
667 if (!hdl->libzfs_mnttab_enable) {
668 struct mnttab srch = { 0 };
669
670 if (avl_numnodes(&hdl->libzfs_mnttab_cache))
671 libzfs_mnttab_fini(hdl);
672 rewind(hdl->libzfs_mnttab);
673 srch.mnt_special = (char *)fsname;
674 srch.mnt_fstype = MNTTYPE_ZFS;
675 if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
676 return (0);
677 else
678 return (ENOENT);
679 }
680
681 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
682 libzfs_mnttab_update(hdl);
683
684 find.mtn_mt.mnt_special = (char *)fsname;
685 mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
686 if (mtn) {
687 *entry = mtn->mtn_mt;
688 return (0);
689 }
690 return (ENOENT);
691}
692
693void
694libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
695 const char *mountp, const char *mntopts)
696{
697 mnttab_node_t *mtn;
698
699 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
700 return;
701 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
702 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
703 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
704 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
705 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
706 avl_add(&hdl->libzfs_mnttab_cache, mtn);
707}
708
709void
710libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
711{
712 mnttab_node_t find;
713 mnttab_node_t *ret;
714
715 find.mtn_mt.mnt_special = (char *)fsname;
716 if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) {
717 avl_remove(&hdl->libzfs_mnttab_cache, ret);
718 free(ret->mtn_mt.mnt_special);
719 free(ret->mtn_mt.mnt_mountp);
720 free(ret->mtn_mt.mnt_fstype);
721 free(ret->mtn_mt.mnt_mntopts);
722 free(ret);
723 }
724}
725
726int
529zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
530{
531 zpool_handle_t *zpool_handle = zhp->zpool_hdl;
532
533 if (zpool_handle == NULL)
534 return (-1);
535
536 *spa_version = zpool_get_prop_int(zpool_handle,

--- 37 unchanged lines hidden (view full) ---

574 int chosen_normal = -1;
575 int chosen_utf = -1;
576
577 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
578 (void) no_memory(hdl);
579 return (NULL);
580 }
581
727zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
728{
729 zpool_handle_t *zpool_handle = zhp->zpool_hdl;
730
731 if (zpool_handle == NULL)
732 return (-1);
733
734 *spa_version = zpool_get_prop_int(zpool_handle,

--- 37 unchanged lines hidden (view full) ---

772 int chosen_normal = -1;
773 int chosen_utf = -1;
774
775 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
776 (void) no_memory(hdl);
777 return (NULL);
778 }
779
780 /*
781 * Make sure this property is valid and applies to this type.
782 */
783
582 elem = NULL;
583 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
584 const char *propname = nvpair_name(elem);
585
784 elem = NULL;
785 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
786 const char *propname = nvpair_name(elem);
787
586 /*
587 * Make sure this property is valid and applies to this type.
588 */
589 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
590 if (!zfs_prop_user(propname)) {
591 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
592 "invalid property '%s'"), propname);
593 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
594 goto error;
595 }
596
788 prop = zfs_name_to_prop(propname);
789 if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
597 /*
790 /*
598 * If this is a user property, make sure it's a
791 * This is a user property: make sure it's a
599 * string, and that it's less than ZAP_MAXNAMELEN.
600 */
601 if (nvpair_type(elem) != DATA_TYPE_STRING) {
602 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
603 "'%s' must be a string"), propname);
604 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
605 goto error;
606 }

--- 9 unchanged lines hidden (view full) ---

616 (void) nvpair_value_string(elem, &strval);
617 if (nvlist_add_string(ret, propname, strval) != 0) {
618 (void) no_memory(hdl);
619 goto error;
620 }
621 continue;
622 }
623
792 * string, and that it's less than ZAP_MAXNAMELEN.
793 */
794 if (nvpair_type(elem) != DATA_TYPE_STRING) {
795 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
796 "'%s' must be a string"), propname);
797 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
798 goto error;
799 }

--- 9 unchanged lines hidden (view full) ---

809 (void) nvpair_value_string(elem, &strval);
810 if (nvlist_add_string(ret, propname, strval) != 0) {
811 (void) no_memory(hdl);
812 goto error;
813 }
814 continue;
815 }
816
817 /*
818 * Currently, only user properties can be modified on
819 * snapshots.
820 */
624 if (type == ZFS_TYPE_SNAPSHOT) {
625 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
626 "this property can not be modified for snapshots"));
627 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
628 goto error;
629 }
630
821 if (type == ZFS_TYPE_SNAPSHOT) {
822 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
823 "this property can not be modified for snapshots"));
824 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
825 goto error;
826 }
827
828 if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
829 zfs_userquota_prop_t uqtype;
830 char newpropname[128];
831 char domain[128];
832 uint64_t rid;
833 uint64_t valary[3];
834
835 if (userquota_propname_decode(propname, zoned,
836 &uqtype, domain, sizeof (domain), &rid) != 0) {
837 zfs_error_aux(hdl,
838 dgettext(TEXT_DOMAIN,
839 "'%s' has an invalid user/group name"),
840 propname);
841 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
842 goto error;
843 }
844
845 if (uqtype != ZFS_PROP_USERQUOTA &&
846 uqtype != ZFS_PROP_GROUPQUOTA) {
847 zfs_error_aux(hdl,
848 dgettext(TEXT_DOMAIN, "'%s' is readonly"),
849 propname);
850 (void) zfs_error(hdl, EZFS_PROPREADONLY,
851 errbuf);
852 goto error;
853 }
854
855 if (nvpair_type(elem) == DATA_TYPE_STRING) {
856 (void) nvpair_value_string(elem, &strval);
857 if (strcmp(strval, "none") == 0) {
858 intval = 0;
859 } else if (zfs_nicestrtonum(hdl,
860 strval, &intval) != 0) {
861 (void) zfs_error(hdl,
862 EZFS_BADPROP, errbuf);
863 goto error;
864 }
865 } else if (nvpair_type(elem) ==
866 DATA_TYPE_UINT64) {
867 (void) nvpair_value_uint64(elem, &intval);
868 if (intval == 0) {
869 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
870 "use 'none' to disable "
871 "userquota/groupquota"));
872 goto error;
873 }
874 } else {
875 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
876 "'%s' must be a number"), propname);
877 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
878 goto error;
879 }
880
881 (void) snprintf(newpropname, sizeof (newpropname),
882 "%s%s", zfs_userquota_prop_prefixes[uqtype],
883 domain);
884 valary[0] = uqtype;
885 valary[1] = rid;
886 valary[2] = intval;
887 if (nvlist_add_uint64_array(ret, newpropname,
888 valary, 3) != 0) {
889 (void) no_memory(hdl);
890 goto error;
891 }
892 continue;
893 }
894
895 if (prop == ZPROP_INVAL) {
896 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
897 "invalid property '%s'"), propname);
898 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
899 goto error;
900 }
901
631 if (!zfs_prop_valid_for_type(prop, type)) {
632 zfs_error_aux(hdl,
633 dgettext(TEXT_DOMAIN, "'%s' does not "
634 "apply to datasets of this type"), propname);
635 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
636 goto error;
637 }
638

--- 123 unchanged lines hidden (view full) ---

762 "a non-global zone"), propname);
763 (void) zfs_error(hdl, EZFS_ZONED,
764 errbuf);
765 goto error;
766 }
767 } else if (getzoneid() != GLOBAL_ZONEID) {
768 /*
769 * If zoned property is 'off', this must be in
902 if (!zfs_prop_valid_for_type(prop, type)) {
903 zfs_error_aux(hdl,
904 dgettext(TEXT_DOMAIN, "'%s' does not "
905 "apply to datasets of this type"), propname);
906 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
907 goto error;
908 }
909

--- 123 unchanged lines hidden (view full) ---

1033 "a non-global zone"), propname);
1034 (void) zfs_error(hdl, EZFS_ZONED,
1035 errbuf);
1036 goto error;
1037 }
1038 } else if (getzoneid() != GLOBAL_ZONEID) {
1039 /*
1040 * If zoned property is 'off', this must be in
770 * a globle zone. If not, something is wrong.
1041 * a global zone. If not, something is wrong.
771 */
772 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
773 "'%s' cannot be set while dataset "
774 "'zoned' property is set"), propname);
775 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
776 goto error;
777 }
778

--- 167 unchanged lines hidden (view full) ---

946 }
947 return (ret);
948
949error:
950 nvlist_free(ret);
951 return (NULL);
952}
953
1042 */
1043 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1044 "'%s' cannot be set while dataset "
1045 "'zoned' property is set"), propname);
1046 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
1047 goto error;
1048 }
1049

--- 167 unchanged lines hidden (view full) ---

1217 }
1218 return (ret);
1219
1220error:
1221 nvlist_free(ret);
1222 return (NULL);
1223}
1224
954static int
955zfs_get_perm_who(const char *who, zfs_deleg_who_type_t *who_type,
956 uint64_t *ret_who)
957{
958 struct passwd *pwd;
959 struct group *grp;
960 uid_t id;
961
962 if (*who_type == ZFS_DELEG_EVERYONE || *who_type == ZFS_DELEG_CREATE ||
963 *who_type == ZFS_DELEG_NAMED_SET) {
964 *ret_who = -1;
965 return (0);
966 }
967 if (who == NULL && !(*who_type == ZFS_DELEG_EVERYONE))
968 return (EZFS_BADWHO);
969
970 if (*who_type == ZFS_DELEG_WHO_UNKNOWN &&
971 strcmp(who, "everyone") == 0) {
972 *ret_who = -1;
973 *who_type = ZFS_DELEG_EVERYONE;
974 return (0);
975 }
976
977 pwd = getpwnam(who);
978 grp = getgrnam(who);
979
980 if ((*who_type == ZFS_DELEG_USER) && pwd) {
981 *ret_who = pwd->pw_uid;
982 } else if ((*who_type == ZFS_DELEG_GROUP) && grp) {
983 *ret_who = grp->gr_gid;
984 } else if (pwd) {
985 *ret_who = pwd->pw_uid;
986 *who_type = ZFS_DELEG_USER;
987 } else if (grp) {
988 *ret_who = grp->gr_gid;
989 *who_type = ZFS_DELEG_GROUP;
990 } else {
991 char *end;
992
993 id = strtol(who, &end, 10);
994 if (errno != 0 || *end != '\0') {
995 return (EZFS_BADWHO);
996 } else {
997 *ret_who = id;
998 if (*who_type == ZFS_DELEG_WHO_UNKNOWN)
999 *who_type = ZFS_DELEG_USER;
1000 }
1001 }
1002
1003 return (0);
1004}
1005
1006static void
1007zfs_perms_add_to_nvlist(nvlist_t *who_nvp, char *name, nvlist_t *perms_nvp)
1008{
1009 if (perms_nvp != NULL) {
1010 verify(nvlist_add_nvlist(who_nvp,
1011 name, perms_nvp) == 0);
1012 } else {
1013 verify(nvlist_add_boolean(who_nvp, name) == 0);
1014 }
1015}
1016
1017static void
1018helper(zfs_deleg_who_type_t who_type, uint64_t whoid, char *whostr,
1019 zfs_deleg_inherit_t inherit, nvlist_t *who_nvp, nvlist_t *perms_nvp,
1020 nvlist_t *sets_nvp)
1021{
1022 boolean_t do_perms, do_sets;
1023 char name[ZFS_MAX_DELEG_NAME];
1024
1025 do_perms = (nvlist_next_nvpair(perms_nvp, NULL) != NULL);
1026 do_sets = (nvlist_next_nvpair(sets_nvp, NULL) != NULL);
1027
1028 if (!do_perms && !do_sets)
1029 do_perms = do_sets = B_TRUE;
1030
1031 if (do_perms) {
1032 zfs_deleg_whokey(name, who_type, inherit,
1033 (who_type == ZFS_DELEG_NAMED_SET) ?
1034 whostr : (void *)&whoid);
1035 zfs_perms_add_to_nvlist(who_nvp, name, perms_nvp);
1036 }
1037 if (do_sets) {
1038 zfs_deleg_whokey(name, toupper(who_type), inherit,
1039 (who_type == ZFS_DELEG_NAMED_SET) ?
1040 whostr : (void *)&whoid);
1041 zfs_perms_add_to_nvlist(who_nvp, name, sets_nvp);
1042 }
1043}
1044
1045static void
1046zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr,
1047 nvlist_t *perms_nvp, nvlist_t *sets_nvp,
1048 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit)
1049{
1050 if (who_type == ZFS_DELEG_NAMED_SET || who_type == ZFS_DELEG_CREATE) {
1051 helper(who_type, whoid, whostr, 0,
1052 who_nvp, perms_nvp, sets_nvp);
1053 } else {
1054 if (inherit & ZFS_DELEG_PERM_LOCAL) {
1055 helper(who_type, whoid, whostr, ZFS_DELEG_LOCAL,
1056 who_nvp, perms_nvp, sets_nvp);
1057 }
1058 if (inherit & ZFS_DELEG_PERM_DESCENDENT) {
1059 helper(who_type, whoid, whostr, ZFS_DELEG_DESCENDENT,
1060 who_nvp, perms_nvp, sets_nvp);
1061 }
1062 }
1063}
1064
1065/*
1225/*
1066 * Construct nvlist to pass down to kernel for setting/removing permissions.
1067 *
1068 * The nvlist is constructed as a series of nvpairs with an optional embedded
1069 * nvlist of permissions to remove or set. The topmost nvpairs are the actual
1070 * base attribute named stored in the dsl.
1071 * Arguments:
1072 *
1073 * whostr: is a comma separated list of users, groups, or a single set name.
1074 * whostr may be null for everyone or create perms.
1075 * who_type: is the type of entry in whostr. Typically this will be
1076 * ZFS_DELEG_WHO_UNKNOWN.
1077 * perms: common separated list of permissions. May be null if user
1078 * is requested to remove permissions by who.
1079 * inherit: Specifies the inheritance of the permissions. Will be either
1080 * ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT.
1081 * nvp The constructed nvlist to pass to zfs_perm_set().
1082 * The output nvp will look something like this.
1083 * ul$1234 -> {create ; destroy }
1084 * Ul$1234 -> { @myset }
1085 * s-$@myset - { snapshot; checksum; compression }
1086 */
1087int
1088zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
1089 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit, nvlist_t **nvp)
1090{
1091 nvlist_t *who_nvp;
1092 nvlist_t *perms_nvp = NULL;
1093 nvlist_t *sets_nvp = NULL;
1094 char errbuf[1024];
1095 char *who_tok, *perm;
1096 int error;
1097
1098 *nvp = NULL;
1099
1100 if (perms) {
1101 if ((error = nvlist_alloc(&perms_nvp,
1102 NV_UNIQUE_NAME, 0)) != 0) {
1103 return (1);
1104 }
1105 if ((error = nvlist_alloc(&sets_nvp,
1106 NV_UNIQUE_NAME, 0)) != 0) {
1107 nvlist_free(perms_nvp);
1108 return (1);
1109 }
1110 }
1111
1112 if ((error = nvlist_alloc(&who_nvp, NV_UNIQUE_NAME, 0)) != 0) {
1113 if (perms_nvp)
1114 nvlist_free(perms_nvp);
1115 if (sets_nvp)
1116 nvlist_free(sets_nvp);
1117 return (1);
1118 }
1119
1120 if (who_type == ZFS_DELEG_NAMED_SET) {
1121 namecheck_err_t why;
1122 char what;
1123
1124 if ((error = permset_namecheck(whostr, &why, &what)) != 0) {
1125 nvlist_free(who_nvp);
1126 if (perms_nvp)
1127 nvlist_free(perms_nvp);
1128 if (sets_nvp)
1129 nvlist_free(sets_nvp);
1130
1131 switch (why) {
1132 case NAME_ERR_NO_AT:
1133 zfs_error_aux(zhp->zfs_hdl,
1134 dgettext(TEXT_DOMAIN,
1135 "set definition must begin with an '@' "
1136 "character"));
1137 }
1138 return (zfs_error(zhp->zfs_hdl,
1139 EZFS_BADPERMSET, whostr));
1140 }
1141 }
1142
1143 /*
1144 * Build up nvlist(s) of permissions. Two nvlists are maintained.
1145 * The first nvlist perms_nvp will have normal permissions and the
1146 * other sets_nvp will have only permssion set names in it.
1147 */
1148 for (perm = strtok(perms, ","); perm; perm = strtok(NULL, ",")) {
1149 const char *perm_canonical = zfs_deleg_canonicalize_perm(perm);
1150
1151 if (perm_canonical) {
1152 verify(nvlist_add_boolean(perms_nvp,
1153 perm_canonical) == 0);
1154 } else if (perm[0] == '@') {
1155 verify(nvlist_add_boolean(sets_nvp, perm) == 0);
1156 } else {
1157 nvlist_free(who_nvp);
1158 nvlist_free(perms_nvp);
1159 nvlist_free(sets_nvp);
1160 return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, perm));
1161 }
1162 }
1163
1164 if (whostr && who_type != ZFS_DELEG_CREATE) {
1165 who_tok = strtok(whostr, ",");
1166 if (who_tok == NULL) {
1167 nvlist_free(who_nvp);
1168 if (perms_nvp)
1169 nvlist_free(perms_nvp);
1170 if (sets_nvp)
1171 nvlist_free(sets_nvp);
1172 (void) snprintf(errbuf, sizeof (errbuf),
1173 dgettext(TEXT_DOMAIN, "Who string is NULL"),
1174 whostr);
1175 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf));
1176 }
1177 }
1178
1179 /*
1180 * Now create the nvlist(s)
1181 */
1182 do {
1183 uint64_t who_id;
1184
1185 error = zfs_get_perm_who(who_tok, &who_type,
1186 &who_id);
1187 if (error) {
1188 nvlist_free(who_nvp);
1189 if (perms_nvp)
1190 nvlist_free(perms_nvp);
1191 if (sets_nvp)
1192 nvlist_free(sets_nvp);
1193 (void) snprintf(errbuf, sizeof (errbuf),
1194 dgettext(TEXT_DOMAIN,
1195 "Unable to determine uid/gid for "
1196 "%s "), who_tok);
1197 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf));
1198 }
1199
1200 /*
1201 * add entries for both local and descendent when required
1202 */
1203 zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok,
1204 perms_nvp, sets_nvp, who_type, inherit);
1205
1206 } while (who_tok = strtok(NULL, ","));
1207 *nvp = who_nvp;
1208 return (0);
1209}
1210
1211static int
1212zfs_perm_set_common(zfs_handle_t *zhp, nvlist_t *nvp, boolean_t unset)
1213{
1214 zfs_cmd_t zc = { 0 };
1215 int error;
1216 char errbuf[1024];
1217
1218 (void) snprintf(errbuf, sizeof (errbuf),
1219 dgettext(TEXT_DOMAIN, "Cannot update 'allows' for '%s'"),
1220 zhp->zfs_name);
1221
1222 if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, nvp))
1223 return (-1);
1224
1225 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1226 zc.zc_perm_action = unset;
1227
1228 error = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_FSACL, &zc);
1229 if (error && errno == ENOTSUP) {
1230 (void) snprintf(errbuf, sizeof (errbuf),
1231 gettext("Pool must be upgraded to use 'allow/unallow'"));
1232 zcmd_free_nvlists(&zc);
1233 return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, errbuf));
1234 } else if (error) {
1235 return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf));
1236 }
1237 zcmd_free_nvlists(&zc);
1238
1239 return (error);
1240}
1241
1242int
1243zfs_perm_set(zfs_handle_t *zhp, nvlist_t *nvp)
1244{
1245 return (zfs_perm_set_common(zhp, nvp, B_FALSE));
1246}
1247
1248int
1249zfs_perm_remove(zfs_handle_t *zhp, nvlist_t *perms)
1250{
1251 return (zfs_perm_set_common(zhp, perms, B_TRUE));
1252}
1253
1254static int
1255perm_compare(const void *arg1, const void *arg2)
1256{
1257 const zfs_perm_node_t *node1 = arg1;
1258 const zfs_perm_node_t *node2 = arg2;
1259 int ret;
1260
1261 ret = strcmp(node1->z_pname, node2->z_pname);
1262
1263 if (ret > 0)
1264 return (1);
1265 if (ret < 0)
1266 return (-1);
1267 else
1268 return (0);
1269}
1270
1271static void
1272zfs_destroy_perm_tree(avl_tree_t *tree)
1273{
1274 zfs_perm_node_t *permnode;
1275 void *cookie = NULL;
1276
1277 while ((permnode = avl_destroy_nodes(tree, &cookie)) != NULL)
1278 free(permnode);
1279 avl_destroy(tree);
1280}
1281
1282static void
1283zfs_destroy_tree(avl_tree_t *tree)
1284{
1285 zfs_allow_node_t *allownode;
1286 void *cookie = NULL;
1287
1288 while ((allownode = avl_destroy_nodes(tree, &cookie)) != NULL) {
1289 zfs_destroy_perm_tree(&allownode->z_localdescend);
1290 zfs_destroy_perm_tree(&allownode->z_local);
1291 zfs_destroy_perm_tree(&allownode->z_descend);
1292 free(allownode);
1293 }
1294 avl_destroy(tree);
1295}
1296
1297void
1298zfs_free_allows(zfs_allow_t *allow)
1299{
1300 zfs_allow_t *allownext;
1301 zfs_allow_t *freeallow;
1302
1303 allownext = allow;
1304 while (allownext) {
1305 zfs_destroy_tree(&allownext->z_sets);
1306 zfs_destroy_tree(&allownext->z_crperms);
1307 zfs_destroy_tree(&allownext->z_user);
1308 zfs_destroy_tree(&allownext->z_group);
1309 zfs_destroy_tree(&allownext->z_everyone);
1310 freeallow = allownext;
1311 allownext = allownext->z_next;
1312 free(freeallow);
1313 }
1314}
1315
1316static zfs_allow_t *
1317zfs_alloc_perm_tree(zfs_handle_t *zhp, zfs_allow_t *prev, char *setpoint)
1318{
1319 zfs_allow_t *ptree;
1320
1321 if ((ptree = zfs_alloc(zhp->zfs_hdl,
1322 sizeof (zfs_allow_t))) == NULL) {
1323 return (NULL);
1324 }
1325
1326 (void) strlcpy(ptree->z_setpoint, setpoint, sizeof (ptree->z_setpoint));
1327 avl_create(&ptree->z_sets,
1328 perm_compare, sizeof (zfs_allow_node_t),
1329 offsetof(zfs_allow_node_t, z_node));
1330 avl_create(&ptree->z_crperms,
1331 perm_compare, sizeof (zfs_allow_node_t),
1332 offsetof(zfs_allow_node_t, z_node));
1333 avl_create(&ptree->z_user,
1334 perm_compare, sizeof (zfs_allow_node_t),
1335 offsetof(zfs_allow_node_t, z_node));
1336 avl_create(&ptree->z_group,
1337 perm_compare, sizeof (zfs_allow_node_t),
1338 offsetof(zfs_allow_node_t, z_node));
1339 avl_create(&ptree->z_everyone,
1340 perm_compare, sizeof (zfs_allow_node_t),
1341 offsetof(zfs_allow_node_t, z_node));
1342
1343 if (prev)
1344 prev->z_next = ptree;
1345 ptree->z_next = NULL;
1346 return (ptree);
1347}
1348
1349/*
1350 * Add permissions to the appropriate AVL permission tree.
1351 * The appropriate tree may not be the requested tree.
1352 * For example if ld indicates a local permission, but
1353 * same permission also exists as a descendent permission
1354 * then the permission will be removed from the descendent
1355 * tree and add the the local+descendent tree.
1356 */
1357static int
1358zfs_coalesce_perm(zfs_handle_t *zhp, zfs_allow_node_t *allownode,
1359 char *perm, char ld)
1360{
1361 zfs_perm_node_t pnode, *permnode, *permnode2;
1362 zfs_perm_node_t *newnode;
1363 avl_index_t where, where2;
1364 avl_tree_t *tree, *altree;
1365
1366 (void) strlcpy(pnode.z_pname, perm, sizeof (pnode.z_pname));
1367
1368 if (ld == ZFS_DELEG_NA) {
1369 tree = &allownode->z_localdescend;
1370 altree = &allownode->z_descend;
1371 } else if (ld == ZFS_DELEG_LOCAL) {
1372 tree = &allownode->z_local;
1373 altree = &allownode->z_descend;
1374 } else {
1375 tree = &allownode->z_descend;
1376 altree = &allownode->z_local;
1377 }
1378 permnode = avl_find(tree, &pnode, &where);
1379 permnode2 = avl_find(altree, &pnode, &where2);
1380
1381 if (permnode2) {
1382 avl_remove(altree, permnode2);
1383 free(permnode2);
1384 if (permnode == NULL) {
1385 tree = &allownode->z_localdescend;
1386 }
1387 }
1388
1389 /*
1390 * Now insert new permission in either requested location
1391 * local/descendent or into ld when perm will exist in both.
1392 */
1393 if (permnode == NULL) {
1394 if ((newnode = zfs_alloc(zhp->zfs_hdl,
1395 sizeof (zfs_perm_node_t))) == NULL) {
1396 return (-1);
1397 }
1398 *newnode = pnode;
1399 avl_add(tree, newnode);
1400 }
1401 return (0);
1402}
1403
1404/*
1405 * Uggh, this is going to be a bit complicated.
1406 * we have an nvlist coming out of the kernel that
1407 * will indicate where the permission is set and then
1408 * it will contain allow of the various "who's", and what
1409 * their permissions are. To further complicate this
1410 * we will then have to coalesce the local,descendent
1411 * and local+descendent permissions where appropriate.
1412 * The kernel only knows about a permission as being local
1413 * or descendent, but not both.
1414 *
1415 * In order to make this easier for zfs_main to deal with
1416 * a series of AVL trees will be used to maintain
1417 * all of this, primarily for sorting purposes as well
1418 * as the ability to quickly locate a specific entry.
1419 *
1420 * What we end up with are tree's for sets, create perms,
1421 * user, groups and everyone. With each of those trees
1422 * we have subtrees for local, descendent and local+descendent
1423 * permissions.
1424 */
1425int
1426zfs_perm_get(zfs_handle_t *zhp, zfs_allow_t **zfs_perms)
1427{
1428 zfs_cmd_t zc = { 0 };
1429 int error;
1430 nvlist_t *nvlist;
1431 nvlist_t *permnv, *sourcenv;
1432 nvpair_t *who_pair, *source_pair;
1433 nvpair_t *perm_pair;
1434 char errbuf[1024];
1435 zfs_allow_t *zallowp, *newallowp;
1436 char ld;
1437 char *nvpname;
1438 uid_t uid;
1439 gid_t gid;
1440 avl_tree_t *tree;
1441 avl_index_t where;
1442
1443 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1444
1445 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
1446 return (-1);
1447
1448 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
1449 if (errno == ENOMEM) {
1450 if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, &zc) != 0) {
1451 zcmd_free_nvlists(&zc);
1452 return (-1);
1453 }
1454 } else if (errno == ENOTSUP) {
1455 zcmd_free_nvlists(&zc);
1456 (void) snprintf(errbuf, sizeof (errbuf),
1457 gettext("Pool must be upgraded to use 'allow'"));
1458 return (zfs_error(zhp->zfs_hdl,
1459 EZFS_BADVERSION, errbuf));
1460 } else {
1461 zcmd_free_nvlists(&zc);
1462 return (-1);
1463 }
1464 }
1465
1466 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &nvlist) != 0) {
1467 zcmd_free_nvlists(&zc);
1468 return (-1);
1469 }
1470
1471 zcmd_free_nvlists(&zc);
1472
1473 source_pair = nvlist_next_nvpair(nvlist, NULL);
1474
1475 if (source_pair == NULL) {
1476 *zfs_perms = NULL;
1477 return (0);
1478 }
1479
1480 *zfs_perms = zfs_alloc_perm_tree(zhp, NULL, nvpair_name(source_pair));
1481 if (*zfs_perms == NULL) {
1482 return (0);
1483 }
1484
1485 zallowp = *zfs_perms;
1486
1487 for (;;) {
1488 struct passwd *pwd;
1489 struct group *grp;
1490 zfs_allow_node_t *allownode;
1491 zfs_allow_node_t findallownode;
1492 zfs_allow_node_t *newallownode;
1493
1494 (void) strlcpy(zallowp->z_setpoint,
1495 nvpair_name(source_pair),
1496 sizeof (zallowp->z_setpoint));
1497
1498 if ((error = nvpair_value_nvlist(source_pair, &sourcenv)) != 0)
1499 goto abort;
1500
1501 /*
1502 * Make sure nvlist is composed correctly
1503 */
1504 if (zfs_deleg_verify_nvlist(sourcenv)) {
1505 goto abort;
1506 }
1507
1508 who_pair = nvlist_next_nvpair(sourcenv, NULL);
1509 if (who_pair == NULL) {
1510 goto abort;
1511 }
1512
1513 do {
1514 error = nvpair_value_nvlist(who_pair, &permnv);
1515 if (error) {
1516 goto abort;
1517 }
1518
1519 /*
1520 * First build up the key to use
1521 * for looking up in the various
1522 * who trees.
1523 */
1524 ld = nvpair_name(who_pair)[1];
1525 nvpname = nvpair_name(who_pair);
1526 switch (nvpair_name(who_pair)[0]) {
1527 case ZFS_DELEG_USER:
1528 case ZFS_DELEG_USER_SETS:
1529 tree = &zallowp->z_user;
1530 uid = atol(&nvpname[3]);
1531 pwd = getpwuid(uid);
1532 (void) snprintf(findallownode.z_key,
1533 sizeof (findallownode.z_key), "user %s",
1534 (pwd) ? pwd->pw_name :
1535 &nvpair_name(who_pair)[3]);
1536 break;
1537 case ZFS_DELEG_GROUP:
1538 case ZFS_DELEG_GROUP_SETS:
1539 tree = &zallowp->z_group;
1540 gid = atol(&nvpname[3]);
1541 grp = getgrgid(gid);
1542 (void) snprintf(findallownode.z_key,
1543 sizeof (findallownode.z_key), "group %s",
1544 (grp) ? grp->gr_name :
1545 &nvpair_name(who_pair)[3]);
1546 break;
1547 case ZFS_DELEG_CREATE:
1548 case ZFS_DELEG_CREATE_SETS:
1549 tree = &zallowp->z_crperms;
1550 (void) strlcpy(findallownode.z_key, "",
1551 sizeof (findallownode.z_key));
1552 break;
1553 case ZFS_DELEG_EVERYONE:
1554 case ZFS_DELEG_EVERYONE_SETS:
1555 (void) snprintf(findallownode.z_key,
1556 sizeof (findallownode.z_key), "everyone");
1557 tree = &zallowp->z_everyone;
1558 break;
1559 case ZFS_DELEG_NAMED_SET:
1560 case ZFS_DELEG_NAMED_SET_SETS:
1561 (void) snprintf(findallownode.z_key,
1562 sizeof (findallownode.z_key), "%s",
1563 &nvpair_name(who_pair)[3]);
1564 tree = &zallowp->z_sets;
1565 break;
1566 }
1567
1568 /*
1569 * Place who in tree
1570 */
1571 allownode = avl_find(tree, &findallownode, &where);
1572 if (allownode == NULL) {
1573 if ((newallownode = zfs_alloc(zhp->zfs_hdl,
1574 sizeof (zfs_allow_node_t))) == NULL) {
1575 goto abort;
1576 }
1577 avl_create(&newallownode->z_localdescend,
1578 perm_compare,
1579 sizeof (zfs_perm_node_t),
1580 offsetof(zfs_perm_node_t, z_node));
1581 avl_create(&newallownode->z_local,
1582 perm_compare,
1583 sizeof (zfs_perm_node_t),
1584 offsetof(zfs_perm_node_t, z_node));
1585 avl_create(&newallownode->z_descend,
1586 perm_compare,
1587 sizeof (zfs_perm_node_t),
1588 offsetof(zfs_perm_node_t, z_node));
1589 (void) strlcpy(newallownode->z_key,
1590 findallownode.z_key,
1591 sizeof (findallownode.z_key));
1592 avl_insert(tree, newallownode, where);
1593 allownode = newallownode;
1594 }
1595
1596 /*
1597 * Now iterate over the permissions and
1598 * place them in the appropriate local,
1599 * descendent or local+descendent tree.
1600 *
1601 * The permissions are added to the tree
1602 * via zfs_coalesce_perm().
1603 */
1604 perm_pair = nvlist_next_nvpair(permnv, NULL);
1605 if (perm_pair == NULL)
1606 goto abort;
1607 do {
1608 if (zfs_coalesce_perm(zhp, allownode,
1609 nvpair_name(perm_pair), ld) != 0)
1610 goto abort;
1611 } while (perm_pair = nvlist_next_nvpair(permnv,
1612 perm_pair));
1613 } while (who_pair = nvlist_next_nvpair(sourcenv, who_pair));
1614
1615 source_pair = nvlist_next_nvpair(nvlist, source_pair);
1616 if (source_pair == NULL)
1617 break;
1618
1619 /*
1620 * allocate another node from the link list of
1621 * zfs_allow_t structures
1622 */
1623 newallowp = zfs_alloc_perm_tree(zhp, zallowp,
1624 nvpair_name(source_pair));
1625 if (newallowp == NULL) {
1626 goto abort;
1627 }
1628 zallowp = newallowp;
1629 }
1630 nvlist_free(nvlist);
1631 return (0);
1632abort:
1633 zfs_free_allows(*zfs_perms);
1634 nvlist_free(nvlist);
1635 return (-1);
1636}
1637
1638static char *
1639zfs_deleg_perm_note(zfs_deleg_note_t note)
1640{
1641 /*
1642 * Don't put newlines on end of lines
1643 */
1644 switch (note) {
1645 case ZFS_DELEG_NOTE_CREATE:
1646 return (dgettext(TEXT_DOMAIN,
1647 "Must also have the 'mount' ability"));
1648 case ZFS_DELEG_NOTE_DESTROY:
1649 return (dgettext(TEXT_DOMAIN,
1650 "Must also have the 'mount' ability"));
1651 case ZFS_DELEG_NOTE_SNAPSHOT:
1652 return (dgettext(TEXT_DOMAIN,
1653 "Must also have the 'mount' ability"));
1654 case ZFS_DELEG_NOTE_ROLLBACK:
1655 return (dgettext(TEXT_DOMAIN,
1656 "Must also have the 'mount' ability"));
1657 case ZFS_DELEG_NOTE_CLONE:
1658 return (dgettext(TEXT_DOMAIN, "Must also have the 'create' "
1659 "ability and 'mount'\n"
1660 "\t\t\t\tability in the origin file system"));
1661 case ZFS_DELEG_NOTE_PROMOTE:
1662 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'\n"
1663 "\t\t\t\tand 'promote' ability in the origin file system"));
1664 case ZFS_DELEG_NOTE_RENAME:
1665 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount' "
1666 "and 'create' \n\t\t\t\tability in the new parent"));
1667 case ZFS_DELEG_NOTE_RECEIVE:
1668 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'"
1669 " and 'create' ability"));
1670 case ZFS_DELEG_NOTE_USERPROP:
1671 return (dgettext(TEXT_DOMAIN,
1672 "Allows changing any user property"));
1673 case ZFS_DELEG_NOTE_ALLOW:
1674 return (dgettext(TEXT_DOMAIN,
1675 "Must also have the permission that is being\n"
1676 "\t\t\t\tallowed"));
1677 case ZFS_DELEG_NOTE_MOUNT:
1678 return (dgettext(TEXT_DOMAIN,
1679 "Allows mount/umount of ZFS datasets"));
1680 case ZFS_DELEG_NOTE_SHARE:
1681 return (dgettext(TEXT_DOMAIN,
1682 "Allows sharing file systems over NFS or SMB\n"
1683 "\t\t\t\tprotocols"));
1684 case ZFS_DELEG_NOTE_NONE:
1685 default:
1686 return (dgettext(TEXT_DOMAIN, ""));
1687 }
1688}
1689
1690typedef enum {
1691 ZFS_DELEG_SUBCOMMAND,
1692 ZFS_DELEG_PROP,
1693 ZFS_DELEG_OTHER
1694} zfs_deleg_perm_type_t;
1695
1696/*
1697 * is the permission a subcommand or other?
1698 */
1699zfs_deleg_perm_type_t
1700zfs_deleg_perm_type(const char *perm)
1701{
1702 if (strcmp(perm, "userprop") == 0)
1703 return (ZFS_DELEG_OTHER);
1704 else
1705 return (ZFS_DELEG_SUBCOMMAND);
1706}
1707
1708static char *
1709zfs_deleg_perm_type_str(zfs_deleg_perm_type_t type)
1710{
1711 switch (type) {
1712 case ZFS_DELEG_SUBCOMMAND:
1713 return (dgettext(TEXT_DOMAIN, "subcommand"));
1714 case ZFS_DELEG_PROP:
1715 return (dgettext(TEXT_DOMAIN, "property"));
1716 case ZFS_DELEG_OTHER:
1717 return (dgettext(TEXT_DOMAIN, "other"));
1718 }
1719 return ("");
1720}
1721
1722/*ARGSUSED*/
1723static int
1724zfs_deleg_prop_cb(int prop, void *cb)
1725{
1726 if (zfs_prop_delegatable(prop))
1727 (void) fprintf(stderr, "%-15s %-15s\n", zfs_prop_to_name(prop),
1728 zfs_deleg_perm_type_str(ZFS_DELEG_PROP));
1729
1730 return (ZPROP_CONT);
1731}
1732
1733void
1734zfs_deleg_permissions(void)
1735{
1736 int i;
1737
1738 (void) fprintf(stderr, "\n%-15s %-15s\t%s\n\n", "NAME",
1739 "TYPE", "NOTES");
1740
1741 /*
1742 * First print out the subcommands
1743 */
1744 for (i = 0; zfs_deleg_perm_tab[i].z_perm != NULL; i++) {
1745 (void) fprintf(stderr, "%-15s %-15s\t%s\n",
1746 zfs_deleg_perm_tab[i].z_perm,
1747 zfs_deleg_perm_type_str(
1748 zfs_deleg_perm_type(zfs_deleg_perm_tab[i].z_perm)),
1749 zfs_deleg_perm_note(zfs_deleg_perm_tab[i].z_note));
1750 }
1751
1752 (void) zprop_iter(zfs_deleg_prop_cb, NULL, B_FALSE, B_TRUE,
1753 ZFS_TYPE_DATASET|ZFS_TYPE_VOLUME);
1754}
1755
1756/*
1757 * Given a property name and value, set the property for the given dataset.
1758 */
1759int
1760zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1761{
1762 zfs_cmd_t zc = { 0 };
1763 int ret = -1;
1764 prop_changelist_t *cl = NULL;

--- 64 unchanged lines hidden (view full) ---

1829 * Execute the corresponding ioctl() to set this property.
1830 */
1831 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1832
1833 if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1834 goto error;
1835
1836 ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1226 * Given a property name and value, set the property for the given dataset.
1227 */
1228int
1229zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1230{
1231 zfs_cmd_t zc = { 0 };
1232 int ret = -1;
1233 prop_changelist_t *cl = NULL;

--- 64 unchanged lines hidden (view full) ---

1298 * Execute the corresponding ioctl() to set this property.
1299 */
1300 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1301
1302 if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1303 goto error;
1304
1305 ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1306
1837 if (ret != 0) {
1838 switch (errno) {
1839
1840 case ENOSPC:
1841 /*
1842 * For quotas and reservations, ENOSPC indicates
1843 * something different; setting a quota or reservation
1844 * doesn't use any disk space.

--- 290 unchanged lines hidden (view full) ---

2135
2136 /*
2137 * Because looking up the mount options is potentially expensive
2138 * (iterating over all of /etc/mnttab), we defer its calculation until
2139 * we're looking up a property which requires its presence.
2140 */
2141 if (!zhp->zfs_mntcheck &&
2142 (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
1307 if (ret != 0) {
1308 switch (errno) {
1309
1310 case ENOSPC:
1311 /*
1312 * For quotas and reservations, ENOSPC indicates
1313 * something different; setting a quota or reservation
1314 * doesn't use any disk space.

--- 290 unchanged lines hidden (view full) ---

1605
1606 /*
1607 * Because looking up the mount options is potentially expensive
1608 * (iterating over all of /etc/mnttab), we defer its calculation until
1609 * we're looking up a property which requires its presence.
1610 */
1611 if (!zhp->zfs_mntcheck &&
1612 (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
2143 struct mnttab entry, search = { 0 };
2144 FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab;
1613 libzfs_handle_t *hdl = zhp->zfs_hdl;
1614 struct mnttab entry;
2145
1615
2146 search.mnt_special = (char *)zhp->zfs_name;
2147 search.mnt_fstype = MNTTYPE_ZFS;
2148 rewind(mnttab);
2149
2150 if (getmntany(mnttab, &entry, &search) == 0) {
2151 zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl,
1616 if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
1617 zhp->zfs_mntopts = zfs_strdup(hdl,
2152 entry.mnt_mntopts);
2153 if (zhp->zfs_mntopts == NULL)
2154 return (-1);
2155 }
2156
2157 zhp->zfs_mntcheck = B_TRUE;
2158 }
2159

--- 82 unchanged lines hidden (view full) ---

2242 break;
2243
2244 default:
2245 switch (zfs_prop_get_type(prop)) {
2246 case PROP_TYPE_NUMBER:
2247 case PROP_TYPE_INDEX:
2248 *val = getprop_uint64(zhp, prop, source);
2249 /*
1618 entry.mnt_mntopts);
1619 if (zhp->zfs_mntopts == NULL)
1620 return (-1);
1621 }
1622
1623 zhp->zfs_mntcheck = B_TRUE;
1624 }
1625

--- 82 unchanged lines hidden (view full) ---

1708 break;
1709
1710 default:
1711 switch (zfs_prop_get_type(prop)) {
1712 case PROP_TYPE_NUMBER:
1713 case PROP_TYPE_INDEX:
1714 *val = getprop_uint64(zhp, prop, source);
1715 /*
2250 * If we tried to use a defalut value for a
1716 * If we tried to use a default value for a
2251 * readonly property, it means that it was not
2252 * present; return an error.
2253 */
2254 if (zfs_prop_readonly(prop) &&
2255 *source && (*source)[0] == '\0') {
2256 return (-1);
2257 }
2258 break;

--- 277 unchanged lines hidden (view full) ---

2536 return (val);
2537}
2538
2539int
2540zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2541{
2542 char buf[64];
2543
1717 * readonly property, it means that it was not
1718 * present; return an error.
1719 */
1720 if (zfs_prop_readonly(prop) &&
1721 *source && (*source)[0] == '\0') {
1722 return (-1);
1723 }
1724 break;

--- 277 unchanged lines hidden (view full) ---

2002 return (val);
2003}
2004
2005int
2006zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2007{
2008 char buf[64];
2009
2544 zfs_nicenum(val, buf, sizeof (buf));
2010 (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2545 return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2546}
2547
2548/*
2549 * Similar to zfs_prop_get(), but returns the value as an integer.
2550 */
2551int
2552zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,

--- 16 unchanged lines hidden (view full) ---

2569 if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2570 return (-1);
2571
2572 get_source(zhp, src, source, statbuf, statlen);
2573
2574 return (0);
2575}
2576
2011 return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2012}
2013
2014/*
2015 * Similar to zfs_prop_get(), but returns the value as an integer.
2016 */
2017int
2018zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,

--- 16 unchanged lines hidden (view full) ---

2035 if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2036 return (-1);
2037
2038 get_source(zhp, src, source, statbuf, statlen);
2039
2040 return (0);
2041}
2042
2043static int
2044idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2045 char **domainp, idmap_rid_t *ridp)
2046{
2047#ifdef sun
2048 idmap_handle_t *idmap_hdl = NULL;
2049 idmap_get_handle_t *get_hdl = NULL;
2050 idmap_stat status;
2051 int err = EINVAL;
2052
2053 if (idmap_init(&idmap_hdl) != IDMAP_SUCCESS)
2054 goto out;
2055 if (idmap_get_create(idmap_hdl, &get_hdl) != IDMAP_SUCCESS)
2056 goto out;
2057
2058 if (isuser) {
2059 err = idmap_get_sidbyuid(get_hdl, id,
2060 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2061 } else {
2062 err = idmap_get_sidbygid(get_hdl, id,
2063 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2064 }
2065 if (err == IDMAP_SUCCESS &&
2066 idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
2067 status == IDMAP_SUCCESS)
2068 err = 0;
2069 else
2070 err = EINVAL;
2071out:
2072 if (get_hdl)
2073 idmap_get_destroy(get_hdl);
2074 if (idmap_hdl)
2075 (void) idmap_fini(idmap_hdl);
2076 return (err);
2077#else /* !sun */
2078 assert(!"invalid code path");
2079#endif /* !sun */
2080}
2081
2082#ifndef sun
2083/* Check if a string contains only digits */
2084static int
2085string_is_digits(char *cp)
2086{
2087 int i;
2088
2089 for(i = 0; i < strlen(cp); i++)
2090 if(!isdigit(cp[i]))
2091 return (0);
2092 return (1);
2093}
2094
2095#endif /* !sun */
2096
2577/*
2097/*
2098 * convert the propname into parameters needed by kernel
2099 * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
2100 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
2101 */
2102static int
2103userquota_propname_decode(const char *propname, boolean_t zoned,
2104 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
2105{
2106 zfs_userquota_prop_t type;
2107 char *cp, *end;
2108 char *numericsid = NULL;
2109 boolean_t isuser;
2110
2111 domain[0] = '\0';
2112
2113 /* Figure out the property type ({user|group}{quota|space}) */
2114 for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
2115 if (strncmp(propname, zfs_userquota_prop_prefixes[type],
2116 strlen(zfs_userquota_prop_prefixes[type])) == 0)
2117 break;
2118 }
2119 if (type == ZFS_NUM_USERQUOTA_PROPS)
2120 return (EINVAL);
2121 *typep = type;
2122
2123 isuser = (type == ZFS_PROP_USERQUOTA ||
2124 type == ZFS_PROP_USERUSED);
2125
2126 cp = strchr(propname, '@') + 1;
2127
2128 if (strchr(cp, '@')) {
2129#ifdef sun
2130 /*
2131 * It's a SID name (eg "user@domain") that needs to be
2132 * turned into S-1-domainID-RID.
2133 */
2134 directory_error_t e;
2135
2136 if (zoned && getzoneid() == GLOBAL_ZONEID)
2137 return (ENOENT);
2138 if (isuser) {
2139 e = directory_sid_from_user_name(NULL,
2140 cp, &numericsid);
2141 } else {
2142 e = directory_sid_from_group_name(NULL,
2143 cp, &numericsid);
2144 }
2145 if (e != NULL) {
2146 directory_error_free(e);
2147 return (ENOENT);
2148 }
2149 if (numericsid == NULL)
2150 return (ENOENT);
2151 cp = numericsid;
2152 /* will be further decoded below */
2153#else /* !sun */
2154 return (ENOENT);
2155#endif /* !sun */
2156 }
2157
2158 if (strncmp(cp, "S-1-", 4) == 0) {
2159 /* It's a numeric SID (eg "S-1-234-567-89") */
2160 (void) strlcpy(domain, cp, domainlen);
2161 cp = strrchr(domain, '-');
2162 *cp = '\0';
2163 cp++;
2164
2165 errno = 0;
2166 *ridp = strtoull(cp, &end, 10);
2167 if (numericsid) {
2168 free(numericsid);
2169 numericsid = NULL;
2170 }
2171 if (errno != 0 || *end != '\0')
2172 return (EINVAL);
2173#ifdef sun
2174 } else if (!isdigit(*cp)) {
2175#else /* sun */
2176 /*
2177 * In FreeBSD user and group names can begin with a digit so treat
2178 * as a uid/gid if string contains digits only
2179 */
2180 } else if (!string_is_digits(cp)) {
2181#endif /* sun */
2182 /*
2183 * It's a user/group name (eg "user") that needs to be
2184 * turned into a uid/gid
2185 */
2186 if (zoned && getzoneid() == GLOBAL_ZONEID)
2187 return (ENOENT);
2188 if (isuser) {
2189 struct passwd *pw;
2190 pw = getpwnam(cp);
2191 if (pw == NULL)
2192 return (ENOENT);
2193 *ridp = pw->pw_uid;
2194 } else {
2195 struct group *gr;
2196 gr = getgrnam(cp);
2197 if (gr == NULL)
2198 return (ENOENT);
2199 *ridp = gr->gr_gid;
2200 }
2201 } else {
2202 /* It's a user/group ID (eg "12345"). */
2203 uid_t id = strtoul(cp, &end, 10);
2204 idmap_rid_t rid;
2205 char *mapdomain;
2206
2207 if (*end != '\0')
2208 return (EINVAL);
2209 if (id > MAXUID) {
2210 /* It's an ephemeral ID. */
2211 if (idmap_id_to_numeric_domain_rid(id, isuser,
2212 &mapdomain, &rid) != 0)
2213 return (ENOENT);
2214 (void) strlcpy(domain, mapdomain, domainlen);
2215 *ridp = rid;
2216 } else {
2217 *ridp = id;
2218 }
2219 }
2220
2221 ASSERT3P(numericsid, ==, NULL);
2222 return (0);
2223}
2224
2225static int
2226zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
2227 uint64_t *propvalue, zfs_userquota_prop_t *typep)
2228{
2229 int err;
2230 zfs_cmd_t zc = { 0 };
2231
2232 (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2233
2234 err = userquota_propname_decode(propname,
2235 zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
2236 typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
2237 zc.zc_objset_type = *typep;
2238 if (err)
2239 return (err);
2240
2241 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
2242 if (err)
2243 return (err);
2244
2245 *propvalue = zc.zc_cookie;
2246 return (0);
2247}
2248
2249int
2250zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
2251 uint64_t *propvalue)
2252{
2253 zfs_userquota_prop_t type;
2254
2255 return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
2256 &type));
2257}
2258
2259int
2260zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
2261 char *propbuf, int proplen, boolean_t literal)
2262{
2263 int err;
2264 uint64_t propvalue;
2265 zfs_userquota_prop_t type;
2266
2267 err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
2268 &type);
2269
2270 if (err)
2271 return (err);
2272
2273 if (literal) {
2274 (void) snprintf(propbuf, proplen, "%llu", propvalue);
2275 } else if (propvalue == 0 &&
2276 (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
2277 (void) strlcpy(propbuf, "none", proplen);
2278 } else {
2279 zfs_nicenum(propvalue, propbuf, proplen);
2280 }
2281 return (0);
2282}
2283
2284/*
2578 * Returns the name of the given zfs handle.
2579 */
2580const char *
2581zfs_get_name(const zfs_handle_t *zhp)
2582{
2583 return (zhp->zfs_name);
2584}
2585
2586/*
2587 * Returns the type of the given zfs handle.
2588 */
2589zfs_type_t
2590zfs_get_type(const zfs_handle_t *zhp)
2591{
2592 return (zhp->zfs_type);
2593}
2594
2285 * Returns the name of the given zfs handle.
2286 */
2287const char *
2288zfs_get_name(const zfs_handle_t *zhp)
2289{
2290 return (zhp->zfs_name);
2291}
2292
2293/*
2294 * Returns the type of the given zfs handle.
2295 */
2296zfs_type_t
2297zfs_get_type(const zfs_handle_t *zhp)
2298{
2299 return (zhp->zfs_type);
2300}
2301
2302static int
2303zfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc)
2304{
2305 int rc;
2306 uint64_t orig_cookie;
2307
2308 orig_cookie = zc->zc_cookie;
2309top:
2310 (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
2311 rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
2312
2313 /*
2314 * FreeBSD compatibility with pre-v15 kernel module.
2315 * Ignore private dataset names.
2316 */
2317 if (strchr(zc->zc_name, '$') != NULL)
2318 rc = 0;
2319
2320 if (rc == -1) {
2321 switch (errno) {
2322 case ENOMEM:
2323 /* expand nvlist memory and try again */
2324 if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
2325 zcmd_free_nvlists(zc);
2326 return (-1);
2327 }
2328 zc->zc_cookie = orig_cookie;
2329 goto top;
2330 /*
2331 * An errno value of ESRCH indicates normal completion.
2332 * If ENOENT is returned, then the underlying dataset
2333 * has been removed since we obtained the handle.
2334 */
2335 case ESRCH:
2336 case ENOENT:
2337 rc = 1;
2338 break;
2339 default:
2340 rc = zfs_standard_error(zhp->zfs_hdl, errno,
2341 dgettext(TEXT_DOMAIN,
2342 "cannot iterate filesystems"));
2343 break;
2344 }
2345 }
2346 return (rc);
2347}
2348
2595/*
2596 * Iterate over all child filesystems
2597 */
2598int
2599zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2600{
2601 zfs_cmd_t zc = { 0 };
2602 zfs_handle_t *nzhp;
2603 int ret;
2604
2605 if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
2606 return (0);
2607
2349/*
2350 * Iterate over all child filesystems
2351 */
2352int
2353zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2354{
2355 zfs_cmd_t zc = { 0 };
2356 zfs_handle_t *nzhp;
2357 int ret;
2358
2359 if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
2360 return (0);
2361
2608 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2609 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
2610 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
2362 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
2363 return (-1);
2364
2365 while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
2366 &zc)) == 0) {
2367
2611 /*
2368 /*
2369 * FreeBSD compatibility with pre-v15 kernel module.
2612 * Ignore private dataset names.
2613 */
2370 * Ignore private dataset names.
2371 */
2614 if (dataset_name_hidden(zc.zc_name))
2372 if (strchr(zc.zc_name, '$') != NULL)
2615 continue;
2616
2617 /*
2618 * Silently ignore errors, as the only plausible explanation is
2619 * that the pool has since been removed.
2620 */
2373 continue;
2374
2375 /*
2376 * Silently ignore errors, as the only plausible explanation is
2377 * that the pool has since been removed.
2378 */
2621 if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
2622 zc.zc_name)) == NULL)
2379 if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
2380 &zc)) == NULL) {
2623 continue;
2381 continue;
2382 }
2624
2383
2625 if ((ret = func(nzhp, data)) != 0)
2384 if ((ret = func(nzhp, data)) != 0) {
2385 zcmd_free_nvlists(&zc);
2626 return (ret);
2386 return (ret);
2387 }
2627 }
2388 }
2628
2629 /*
2630 * An errno value of ESRCH indicates normal completion. If ENOENT is
2631 * returned, then the underlying dataset has been removed since we
2632 * obtained the handle.
2633 */
2634 if (errno != ESRCH && errno != ENOENT)
2635 return (zfs_standard_error(zhp->zfs_hdl, errno,
2636 dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
2637
2638 return (0);
2389 zcmd_free_nvlists(&zc);
2390 return ((ret < 0) ? ret : 0);
2639}
2640
2641/*
2642 * Iterate over all snapshots
2643 */
2644int
2645zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2646{
2647 zfs_cmd_t zc = { 0 };
2648 zfs_handle_t *nzhp;
2649 int ret;
2650
2651 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
2652 return (0);
2653
2391}
2392
2393/*
2394 * Iterate over all snapshots
2395 */
2396int
2397zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2398{
2399 zfs_cmd_t zc = { 0 };
2400 zfs_handle_t *nzhp;
2401 int ret;
2402
2403 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
2404 return (0);
2405
2654 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2655 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
2656 &zc) == 0;
2657 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
2406 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
2407 return (-1);
2408 while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
2409 &zc)) == 0) {
2658
2410
2659 if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
2660 zc.zc_name)) == NULL)
2411 /*
2412 * FreeBSD compatibility with pre-v15 kernel module.
2413 * Ignore private dataset names.
2414 */
2415 if (strchr(zc.zc_name, '$') != NULL)
2661 continue;
2662
2416 continue;
2417
2663 if ((ret = func(nzhp, data)) != 0)
2418 if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
2419 &zc)) == NULL) {
2420 continue;
2421 }
2422
2423 if ((ret = func(nzhp, data)) != 0) {
2424 zcmd_free_nvlists(&zc);
2664 return (ret);
2425 return (ret);
2426 }
2665 }
2427 }
2666
2667 /*
2668 * An errno value of ESRCH indicates normal completion. If ENOENT is
2669 * returned, then the underlying dataset has been removed since we
2670 * obtained the handle. Silently ignore this case, and return success.
2671 */
2672 if (errno != ESRCH && errno != ENOENT)
2673 return (zfs_standard_error(zhp->zfs_hdl, errno,
2674 dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
2675
2676 return (0);
2428 zcmd_free_nvlists(&zc);
2429 return ((ret < 0) ? ret : 0);
2677}
2678
2679/*
2680 * Iterate over all children, snapshots and filesystems
2681 */
2682int
2683zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2684{

--- 36 unchanged lines hidden (view full) ---

2721 boolean_t accept_ancestor, int *prefixlen)
2722{
2723 zfs_cmd_t zc = { 0 };
2724 char parent[ZFS_MAXNAMELEN];
2725 char *slash;
2726 zfs_handle_t *zhp;
2727 char errbuf[1024];
2728
2430}
2431
2432/*
2433 * Iterate over all children, snapshots and filesystems
2434 */
2435int
2436zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
2437{

--- 36 unchanged lines hidden (view full) ---

2474 boolean_t accept_ancestor, int *prefixlen)
2475{
2476 zfs_cmd_t zc = { 0 };
2477 char parent[ZFS_MAXNAMELEN];
2478 char *slash;
2479 zfs_handle_t *zhp;
2480 char errbuf[1024];
2481
2729 (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'",
2730 path);
2482 (void) snprintf(errbuf, sizeof (errbuf),
2483 dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
2731
2732 /* get parent, and check to see if this is just a pool */
2733 if (parent_name(path, parent, sizeof (parent)) != 0) {
2734 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2735 "missing dataset name"));
2736 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2737 }
2738

--- 1510 unchanged lines hidden (view full) ---

4249 error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc);
4250 nvlist_free(nvp);
4251 return (error);
4252}
4253#endif
4254
4255int
4256zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
2484
2485 /* get parent, and check to see if this is just a pool */
2486 if (parent_name(path, parent, sizeof (parent)) != 0) {
2487 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2488 "missing dataset name"));
2489 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2490 }
2491

--- 1510 unchanged lines hidden (view full) ---

4002 error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc);
4003 nvlist_free(nvp);
4004 return (error);
4005}
4006#endif
4007
4008int
4009zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
4257 void *export, void *sharetab, int sharemax, zfs_share_op_t operation)
4010 char *resource, void *export, void *sharetab,
4011 int sharemax, zfs_share_op_t operation)
4258{
4259 zfs_cmd_t zc = { 0 };
4260 int error;
4261
4262 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4263 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4012{
4013 zfs_cmd_t zc = { 0 };
4014 int error;
4015
4016 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4017 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4018 if (resource)
4019 (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
4264 zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
4265 zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
4266 zc.zc_share.z_sharetype = operation;
4267 zc.zc_share.z_sharemax = sharemax;
4020 zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
4021 zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
4022 zc.zc_share.z_sharetype = operation;
4023 zc.zc_share.z_sharemax = sharemax;
4268
4269 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
4270 return (error);
4271}
4272
4273void
4274zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
4275{
4276 nvpair_t *curr;

--- 17 unchanged lines hidden (view full) ---

4294 */
4295 if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
4296 (void) nvlist_remove(zhp->zfs_props,
4297 nvpair_name(curr), nvpair_type(curr));
4298 curr = next;
4299 }
4300}
4301
4024 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
4025 return (error);
4026}
4027
4028void
4029zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
4030{
4031 nvpair_t *curr;

--- 17 unchanged lines hidden (view full) ---

4049 */
4050 if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
4051 (void) nvlist_remove(zhp->zfs_props,
4052 nvpair_name(curr), nvpair_type(curr));
4053 curr = next;
4054 }
4055}
4056
4057#ifdef sun
4058static int
4059zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
4060 zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
4061{
4062 zfs_cmd_t zc = { 0 };
4063 nvlist_t *nvlist = NULL;
4064 int error;
4065
4066 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4067 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4068 zc.zc_cookie = (uint64_t)cmd;
4069
4070 if (cmd == ZFS_SMB_ACL_RENAME) {
4071 if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
4072 (void) no_memory(hdl);
4073 return (NULL);
4074 }
4075 }
4076
4077 switch (cmd) {
4078 case ZFS_SMB_ACL_ADD:
4079 case ZFS_SMB_ACL_REMOVE:
4080 (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
4081 break;
4082 case ZFS_SMB_ACL_RENAME:
4083 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
4084 resource1) != 0) {
4085 (void) no_memory(hdl);
4086 return (-1);
4087 }
4088 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
4089 resource2) != 0) {
4090 (void) no_memory(hdl);
4091 return (-1);
4092 }
4093 if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
4094 nvlist_free(nvlist);
4095 return (-1);
4096 }
4097 break;
4098 case ZFS_SMB_ACL_PURGE:
4099 break;
4100 default:
4101 return (-1);
4102 }
4103 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
4104 if (nvlist)
4105 nvlist_free(nvlist);
4106 return (error);
4107}
4108
4109int
4110zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4111 char *path, char *resource)
4112{
4113 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4114 resource, NULL));
4115}
4116
4117int
4118zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4119 char *path, char *resource)
4120{
4121 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4122 resource, NULL));
4123}
4124
4125int
4126zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4127{
4128 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4129 NULL, NULL));
4130}
4131
4132int
4133zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4134 char *oldname, char *newname)
4135{
4136 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4137 oldname, newname));
4138}
4139#endif /* sun */
4140
4141int
4142zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4143 zfs_userspace_cb_t func, void *arg)
4144{
4145 zfs_cmd_t zc = { 0 };
4146 int error;
4147 zfs_useracct_t buf[100];
4148
4149 (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4150
4151 zc.zc_objset_type = type;
4152 zc.zc_nvlist_dst = (uintptr_t)buf;
4153
4154 /* CONSTCOND */
4155 while (1) {
4156 zfs_useracct_t *zua = buf;
4157
4158 zc.zc_nvlist_dst_size = sizeof (buf);
4159 error = ioctl(zhp->zfs_hdl->libzfs_fd,
4160 ZFS_IOC_USERSPACE_MANY, &zc);
4161 if (error || zc.zc_nvlist_dst_size == 0)
4162 break;
4163
4164 while (zc.zc_nvlist_dst_size > 0) {
4165 error = func(arg, zua->zu_domain, zua->zu_rid,
4166 zua->zu_space);
4167 if (error != 0)
4168 return (error);
4169 zua++;
4170 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4171 }
4172 }
4173
4174 return (error);
4175}
4176
4302/*
4303 * Attach/detach the given filesystem to/from the given jail.
4304 */
4305int
4306zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
4307{
4308 libzfs_handle_t *hdl = zhp->zfs_hdl;
4309 zfs_cmd_t zc = { 0 };

--- 33 unchanged lines hidden ---
4177/*
4178 * Attach/detach the given filesystem to/from the given jail.
4179 */
4180int
4181zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
4182{
4183 libzfs_handle_t *hdl = zhp->zfs_hdl;
4184 zfs_cmd_t zc = { 0 };

--- 33 unchanged lines hidden ---