libzfs_dataset.c revision 332525
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24264835Sdelphij * Copyright (c) 2013, Joyent, Inc. All rights reserved. 25325139Savg * Copyright (c) 2011, 2016 by Delphix. All rights reserved. 26252219Sdelphij * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 27307046Smav * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. 28307046Smav * Copyright (c) 2013 Martin Matuska. All rights reserved. 29251646Sdelphij * Copyright (c) 2013 Steven Hartland. All rights reserved. 30296519Smav * Copyright (c) 2014 Integros [integros.com] 31307050Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> 32329489Smav * Copyright 2017 Nexenta Systems, Inc. 33321577Smav * Copyright 2017 RackTop Systems. 34168404Spjd */ 35168404Spjd 36168404Spjd#include <ctype.h> 37168404Spjd#include <errno.h> 38168404Spjd#include <libintl.h> 39168404Spjd#include <math.h> 40168404Spjd#include <stdio.h> 41168404Spjd#include <stdlib.h> 42168404Spjd#include <strings.h> 43168404Spjd#include <unistd.h> 44185029Spjd#include <stddef.h> 45168404Spjd#include <zone.h> 46168404Spjd#include <fcntl.h> 47168404Spjd#include <sys/mntent.h> 48168404Spjd#include <sys/mount.h> 49185029Spjd#include <priv.h> 50185029Spjd#include <pwd.h> 51185029Spjd#include <grp.h> 52185029Spjd#include <stddef.h> 53209962Smm#include <idmap.h> 54168404Spjd 55219089Spjd#include <sys/dnode.h> 56168404Spjd#include <sys/spa.h> 57168404Spjd#include <sys/zap.h> 58209962Smm#include <sys/misc.h> 59168404Spjd#include <libzfs.h> 60168404Spjd 61168404Spjd#include "zfs_namecheck.h" 62168404Spjd#include "zfs_prop.h" 63168404Spjd#include "libzfs_impl.h" 64185029Spjd#include "zfs_deleg.h" 65168404Spjd 66209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 67209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 68168676Spjd 69168404Spjd/* 70168404Spjd * Given a single type (not a mask of types), return the type in a human 71168404Spjd * readable form. 72168404Spjd */ 73168404Spjdconst char * 74168404Spjdzfs_type_to_name(zfs_type_t type) 75168404Spjd{ 76168404Spjd switch (type) { 77168404Spjd case ZFS_TYPE_FILESYSTEM: 78168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 79168404Spjd case ZFS_TYPE_SNAPSHOT: 80168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 81168404Spjd case ZFS_TYPE_VOLUME: 82168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 83307050Smav case ZFS_TYPE_POOL: 84307050Smav return (dgettext(TEXT_DOMAIN, "pool")); 85307050Smav case ZFS_TYPE_BOOKMARK: 86307050Smav return (dgettext(TEXT_DOMAIN, "bookmark")); 87307050Smav default: 88307050Smav assert(!"unhandled zfs_type_t"); 89168404Spjd } 90168404Spjd 91168404Spjd return (NULL); 92168404Spjd} 93168404Spjd 94168404Spjd/* 95168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 96209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 97209962Smm * explain exactly why the name was not valid. 98168404Spjd */ 99219089Spjdint 100185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 101185029Spjd boolean_t modifying) 102168404Spjd{ 103168404Spjd namecheck_err_t why; 104168404Spjd char what; 105168404Spjd 106321534Smav if (entity_namecheck(path, &why, &what) != 0) { 107168404Spjd if (hdl != NULL) { 108168404Spjd switch (why) { 109168404Spjd case NAME_ERR_TOOLONG: 110168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 111168404Spjd "name is too long")); 112168404Spjd break; 113168404Spjd 114168404Spjd case NAME_ERR_LEADING_SLASH: 115168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116168404Spjd "leading slash in name")); 117168404Spjd break; 118168404Spjd 119168404Spjd case NAME_ERR_EMPTY_COMPONENT: 120168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 121168404Spjd "empty component in name")); 122168404Spjd break; 123168404Spjd 124168404Spjd case NAME_ERR_TRAILING_SLASH: 125168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 126168404Spjd "trailing slash in name")); 127168404Spjd break; 128168404Spjd 129168404Spjd case NAME_ERR_INVALCHAR: 130168404Spjd zfs_error_aux(hdl, 131168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 132168404Spjd "'%c' in name"), what); 133168404Spjd break; 134168404Spjd 135321534Smav case NAME_ERR_MULTIPLE_DELIMITERS: 136168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 137321534Smav "multiple '@' and/or '#' delimiters in " 138321534Smav "name")); 139168404Spjd break; 140168404Spjd 141168404Spjd case NAME_ERR_NOLETTER: 142168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 143168404Spjd "pool doesn't begin with a letter")); 144168404Spjd break; 145168404Spjd 146168404Spjd case NAME_ERR_RESERVED: 147168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 148168404Spjd "name is reserved")); 149168404Spjd break; 150168404Spjd 151168404Spjd case NAME_ERR_DISKLIKE: 152168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 153168404Spjd "reserved disk name")); 154168404Spjd break; 155307050Smav 156307050Smav default: 157307050Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 158307050Smav "(%d) not defined"), why); 159307050Smav break; 160168404Spjd } 161168404Spjd } 162168404Spjd 163168404Spjd return (0); 164168404Spjd } 165168404Spjd 166168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 167168404Spjd if (hdl != NULL) 168168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 169321534Smav "snapshot delimiter '@' is not expected here")); 170168404Spjd return (0); 171168404Spjd } 172168404Spjd 173168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 174168404Spjd if (hdl != NULL) 175168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 176168404Spjd "missing '@' delimiter in snapshot name")); 177168404Spjd return (0); 178168404Spjd } 179168404Spjd 180321534Smav if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) { 181321534Smav if (hdl != NULL) 182321534Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 183321534Smav "bookmark delimiter '#' is not expected here")); 184321534Smav return (0); 185321534Smav } 186321534Smav 187321534Smav if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) { 188321534Smav if (hdl != NULL) 189321534Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 190321534Smav "missing '#' delimiter in bookmark name")); 191321534Smav return (0); 192321534Smav } 193321534Smav 194185029Spjd if (modifying && strchr(path, '%') != NULL) { 195185029Spjd if (hdl != NULL) 196185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 197185029Spjd "invalid character %c in name"), '%'); 198185029Spjd return (0); 199185029Spjd } 200185029Spjd 201168404Spjd return (-1); 202168404Spjd} 203168404Spjd 204168404Spjdint 205168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 206168404Spjd{ 207185029Spjd if (type == ZFS_TYPE_POOL) 208185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 209185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 210168404Spjd} 211168404Spjd 212168404Spjd/* 213168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 214168404Spjd * properties into a separate nvlist. 215168404Spjd */ 216185029Spjdstatic nvlist_t * 217185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 218168404Spjd{ 219168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 220168404Spjd nvpair_t *elem; 221168404Spjd nvlist_t *propval; 222185029Spjd nvlist_t *nvl; 223168404Spjd 224185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 225185029Spjd (void) no_memory(hdl); 226185029Spjd return (NULL); 227185029Spjd } 228168404Spjd 229168404Spjd elem = NULL; 230185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 231168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 232168404Spjd continue; 233168404Spjd 234168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 235185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 236185029Spjd nvlist_free(nvl); 237185029Spjd (void) no_memory(hdl); 238185029Spjd return (NULL); 239185029Spjd } 240168404Spjd } 241168404Spjd 242185029Spjd return (nvl); 243168404Spjd} 244168404Spjd 245185029Spjdstatic zpool_handle_t * 246185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 247185029Spjd{ 248185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 249185029Spjd zpool_handle_t *zph; 250185029Spjd 251185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 252185029Spjd if (hdl->libzfs_pool_handles != NULL) 253185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 254185029Spjd hdl->libzfs_pool_handles = zph; 255185029Spjd } 256185029Spjd return (zph); 257185029Spjd} 258185029Spjd 259185029Spjdstatic zpool_handle_t * 260185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 261185029Spjd{ 262185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 263185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 264185029Spjd 265185029Spjd while ((zph != NULL) && 266185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 267185029Spjd zph = zph->zpool_next; 268185029Spjd return (zph); 269185029Spjd} 270185029Spjd 271168404Spjd/* 272185029Spjd * Returns a handle to the pool that contains the provided dataset. 273185029Spjd * If a handle to that pool already exists then that handle is returned. 274185029Spjd * Otherwise, a new handle is created and added to the list of handles. 275185029Spjd */ 276185029Spjdstatic zpool_handle_t * 277185029Spjdzpool_handle(zfs_handle_t *zhp) 278185029Spjd{ 279185029Spjd char *pool_name; 280185029Spjd int len; 281185029Spjd zpool_handle_t *zph; 282185029Spjd 283260183Sdelphij len = strcspn(zhp->zfs_name, "/@#") + 1; 284185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 285185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 286185029Spjd 287185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 288185029Spjd if (zph == NULL) 289185029Spjd zph = zpool_add_handle(zhp, pool_name); 290185029Spjd 291185029Spjd free(pool_name); 292185029Spjd return (zph); 293185029Spjd} 294185029Spjd 295185029Spjdvoid 296185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 297185029Spjd{ 298185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 299185029Spjd 300185029Spjd while (zph != NULL) { 301185029Spjd next = zph->zpool_next; 302185029Spjd zpool_close(zph); 303185029Spjd zph = next; 304185029Spjd } 305185029Spjd hdl->libzfs_pool_handles = NULL; 306185029Spjd} 307185029Spjd 308185029Spjd/* 309168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 310168404Spjd */ 311219089Spjdstatic int 312209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 313168404Spjd{ 314168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 315168404Spjd 316209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 317168404Spjd 318209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 319168404Spjd if (errno == ENOMEM) { 320209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 321168404Spjd return (-1); 322168404Spjd } 323168404Spjd } else { 324168404Spjd return (-1); 325168404Spjd } 326168404Spjd } 327209962Smm return (0); 328209962Smm} 329168404Spjd 330219089Spjd/* 331219089Spjd * Utility function to get the received properties of the given object. 332219089Spjd */ 333209962Smmstatic int 334219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 335219089Spjd{ 336219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 337219089Spjd nvlist_t *recvdprops; 338219089Spjd zfs_cmd_t zc = { 0 }; 339219089Spjd int err; 340219089Spjd 341219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 342219089Spjd return (-1); 343219089Spjd 344219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 345219089Spjd 346219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 347219089Spjd if (errno == ENOMEM) { 348219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 349219089Spjd return (-1); 350219089Spjd } 351219089Spjd } else { 352219089Spjd zcmd_free_nvlists(&zc); 353219089Spjd return (-1); 354219089Spjd } 355219089Spjd } 356219089Spjd 357219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 358219089Spjd zcmd_free_nvlists(&zc); 359219089Spjd if (err != 0) 360219089Spjd return (-1); 361219089Spjd 362219089Spjd nvlist_free(zhp->zfs_recvd_props); 363219089Spjd zhp->zfs_recvd_props = recvdprops; 364219089Spjd 365219089Spjd return (0); 366219089Spjd} 367219089Spjd 368219089Spjdstatic int 369209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 370209962Smm{ 371209962Smm nvlist_t *allprops, *userprops; 372168404Spjd 373209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 374209962Smm 375209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 376168404Spjd return (-1); 377168404Spjd } 378168404Spjd 379209962Smm /* 380209962Smm * XXX Why do we store the user props separately, in addition to 381209962Smm * storing them in zfs_props? 382209962Smm */ 383185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 384185029Spjd nvlist_free(allprops); 385168404Spjd return (-1); 386185029Spjd } 387168404Spjd 388185029Spjd nvlist_free(zhp->zfs_props); 389185029Spjd nvlist_free(zhp->zfs_user_props); 390185029Spjd 391185029Spjd zhp->zfs_props = allprops; 392185029Spjd zhp->zfs_user_props = userprops; 393185029Spjd 394168404Spjd return (0); 395168404Spjd} 396168404Spjd 397209962Smmstatic int 398209962Smmget_stats(zfs_handle_t *zhp) 399209962Smm{ 400209962Smm int rc = 0; 401209962Smm zfs_cmd_t zc = { 0 }; 402209962Smm 403209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 404209962Smm return (-1); 405209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 406209962Smm rc = -1; 407209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 408209962Smm rc = -1; 409209962Smm zcmd_free_nvlists(&zc); 410209962Smm return (rc); 411209962Smm} 412209962Smm 413168404Spjd/* 414168404Spjd * Refresh the properties currently stored in the handle. 415168404Spjd */ 416168404Spjdvoid 417168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 418168404Spjd{ 419168404Spjd (void) get_stats(zhp); 420168404Spjd} 421168404Spjd 422168404Spjd/* 423168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 424168404Spjd * zfs_iter_* to create child handles on the fly. 425168404Spjd */ 426209962Smmstatic int 427209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 428168404Spjd{ 429219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 430209962Smm return (-1); 431168404Spjd 432168404Spjd /* 433168404Spjd * We've managed to open the dataset and gather statistics. Determine 434168404Spjd * the high-level type. 435168404Spjd */ 436168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 437168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 438168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 439168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 440168404Spjd else 441168404Spjd abort(); 442168404Spjd 443168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 444168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 445168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 446168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 447168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 448168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 449168404Spjd else 450168404Spjd abort(); /* we should never see any other types */ 451168404Spjd 452219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 453219089Spjd return (-1); 454219089Spjd 455209962Smm return (0); 456209962Smm} 457209962Smm 458209962Smmzfs_handle_t * 459209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 460209962Smm{ 461209962Smm zfs_cmd_t zc = { 0 }; 462209962Smm 463209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 464209962Smm 465209962Smm if (zhp == NULL) 466209962Smm return (NULL); 467209962Smm 468209962Smm zhp->zfs_hdl = hdl; 469209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 470209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 471209962Smm free(zhp); 472209962Smm return (NULL); 473209962Smm } 474209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 475209962Smm zcmd_free_nvlists(&zc); 476209962Smm free(zhp); 477209962Smm return (NULL); 478209962Smm } 479209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 480209962Smm free(zhp); 481209962Smm zhp = NULL; 482209962Smm } 483209962Smm zcmd_free_nvlists(&zc); 484168404Spjd return (zhp); 485168404Spjd} 486168404Spjd 487228103Smmzfs_handle_t * 488209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 489209962Smm{ 490209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 491209962Smm 492209962Smm if (zhp == NULL) 493209962Smm return (NULL); 494209962Smm 495209962Smm zhp->zfs_hdl = hdl; 496209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 497209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 498209962Smm free(zhp); 499209962Smm return (NULL); 500209962Smm } 501209962Smm return (zhp); 502209962Smm} 503209962Smm 504228103Smmzfs_handle_t * 505230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 506230438Spjd{ 507230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 508230438Spjd 509230438Spjd if (zhp == NULL) 510230438Spjd return (NULL); 511230438Spjd 512230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 513230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 514230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 515230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 516230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 517230438Spjd return (zhp); 518230438Spjd} 519230438Spjd 520230438Spjdzfs_handle_t * 521228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 522228103Smm{ 523228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 524228103Smm 525228103Smm if (zhp == NULL) 526228103Smm return (NULL); 527228103Smm 528228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 529228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 530228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 531228103Smm sizeof (zhp->zfs_name)); 532228103Smm zhp->zfs_type = zhp_orig->zfs_type; 533228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 534228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 535228103Smm if (zhp_orig->zfs_props != NULL) { 536228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 537228103Smm (void) no_memory(zhp->zfs_hdl); 538228103Smm zfs_close(zhp); 539228103Smm return (NULL); 540228103Smm } 541228103Smm } 542228103Smm if (zhp_orig->zfs_user_props != NULL) { 543228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 544228103Smm &zhp->zfs_user_props, 0) != 0) { 545228103Smm (void) no_memory(zhp->zfs_hdl); 546228103Smm zfs_close(zhp); 547228103Smm return (NULL); 548228103Smm } 549228103Smm } 550228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 551228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 552228103Smm &zhp->zfs_recvd_props, 0)) { 553228103Smm (void) no_memory(zhp->zfs_hdl); 554228103Smm zfs_close(zhp); 555228103Smm return (NULL); 556228103Smm } 557228103Smm } 558228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 559228103Smm if (zhp_orig->zfs_mntopts != NULL) { 560228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 561228103Smm zhp_orig->zfs_mntopts); 562228103Smm } 563228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 564228103Smm return (zhp); 565228103Smm} 566228103Smm 567260183Sdelphijboolean_t 568260183Sdelphijzfs_bookmark_exists(const char *path) 569260183Sdelphij{ 570260183Sdelphij nvlist_t *bmarks; 571260183Sdelphij nvlist_t *props; 572307108Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 573260183Sdelphij char *bmark_name; 574260183Sdelphij char *pound; 575260183Sdelphij int err; 576260183Sdelphij boolean_t rv; 577260183Sdelphij 578260183Sdelphij 579260183Sdelphij (void) strlcpy(fsname, path, sizeof (fsname)); 580260183Sdelphij pound = strchr(fsname, '#'); 581260183Sdelphij if (pound == NULL) 582260183Sdelphij return (B_FALSE); 583260183Sdelphij 584260183Sdelphij *pound = '\0'; 585260183Sdelphij bmark_name = pound + 1; 586260183Sdelphij props = fnvlist_alloc(); 587260183Sdelphij err = lzc_get_bookmarks(fsname, props, &bmarks); 588260183Sdelphij nvlist_free(props); 589260183Sdelphij if (err != 0) { 590260183Sdelphij nvlist_free(bmarks); 591260183Sdelphij return (B_FALSE); 592260183Sdelphij } 593260183Sdelphij 594260183Sdelphij rv = nvlist_exists(bmarks, bmark_name); 595260183Sdelphij nvlist_free(bmarks); 596260183Sdelphij return (rv); 597260183Sdelphij} 598260183Sdelphij 599260183Sdelphijzfs_handle_t * 600260183Sdelphijmake_bookmark_handle(zfs_handle_t *parent, const char *path, 601260183Sdelphij nvlist_t *bmark_props) 602260183Sdelphij{ 603260183Sdelphij zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 604260183Sdelphij 605260183Sdelphij if (zhp == NULL) 606260183Sdelphij return (NULL); 607260183Sdelphij 608260183Sdelphij /* Fill in the name. */ 609260183Sdelphij zhp->zfs_hdl = parent->zfs_hdl; 610260183Sdelphij (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 611260183Sdelphij 612260183Sdelphij /* Set the property lists. */ 613260183Sdelphij if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 614260183Sdelphij free(zhp); 615260183Sdelphij return (NULL); 616260183Sdelphij } 617260183Sdelphij 618260183Sdelphij /* Set the types. */ 619260183Sdelphij zhp->zfs_head_type = parent->zfs_head_type; 620260183Sdelphij zhp->zfs_type = ZFS_TYPE_BOOKMARK; 621260183Sdelphij 622260183Sdelphij if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 623260183Sdelphij nvlist_free(zhp->zfs_props); 624260183Sdelphij free(zhp); 625260183Sdelphij return (NULL); 626260183Sdelphij } 627260183Sdelphij 628260183Sdelphij return (zhp); 629260183Sdelphij} 630260183Sdelphij 631321534Smavstruct zfs_open_bookmarks_cb_data { 632321534Smav const char *path; 633321534Smav zfs_handle_t *zhp; 634321534Smav}; 635321534Smav 636321534Smavstatic int 637321534Smavzfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data) 638321534Smav{ 639321534Smav struct zfs_open_bookmarks_cb_data *dp = data; 640321534Smav 641321534Smav /* 642321534Smav * Is it the one we are looking for? 643321534Smav */ 644321534Smav if (strcmp(dp->path, zfs_get_name(zhp)) == 0) { 645321534Smav /* 646321534Smav * We found it. Save it and let the caller know we are done. 647321534Smav */ 648321534Smav dp->zhp = zhp; 649321534Smav return (EEXIST); 650321534Smav } 651321534Smav 652321534Smav /* 653321534Smav * Not found. Close the handle and ask for another one. 654321534Smav */ 655321534Smav zfs_close(zhp); 656321534Smav return (0); 657321534Smav} 658321534Smav 659168404Spjd/* 660321534Smav * Opens the given snapshot, bookmark, filesystem, or volume. The 'types' 661168404Spjd * argument is a mask of acceptable types. The function will print an 662168404Spjd * appropriate error message and return NULL if it can't be opened. 663168404Spjd */ 664168404Spjdzfs_handle_t * 665168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 666168404Spjd{ 667168404Spjd zfs_handle_t *zhp; 668168404Spjd char errbuf[1024]; 669321534Smav char *bookp; 670168404Spjd 671168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 672168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 673168404Spjd 674168404Spjd /* 675168404Spjd * Validate the name before we even try to open it. 676168404Spjd */ 677321534Smav if (!zfs_validate_name(hdl, path, types, B_FALSE)) { 678168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 679168404Spjd return (NULL); 680168404Spjd } 681168404Spjd 682168404Spjd /* 683321534Smav * Bookmarks needs to be handled separately. 684168404Spjd */ 685321534Smav bookp = strchr(path, '#'); 686321534Smav if (bookp == NULL) { 687321534Smav /* 688321534Smav * Try to get stats for the dataset, which will tell us if it 689321534Smav * exists. 690321534Smav */ 691321534Smav errno = 0; 692321534Smav if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 693321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 694321534Smav return (NULL); 695321534Smav } 696321534Smav } else { 697321534Smav char dsname[ZFS_MAX_DATASET_NAME_LEN]; 698321534Smav zfs_handle_t *pzhp; 699321534Smav struct zfs_open_bookmarks_cb_data cb_data = {path, NULL}; 700321534Smav 701321534Smav /* 702321534Smav * We need to cut out '#' and everything after '#' 703321534Smav * to get the parent dataset name only. 704321534Smav */ 705321534Smav assert(bookp - path < sizeof (dsname)); 706321534Smav (void) strncpy(dsname, path, bookp - path); 707321534Smav dsname[bookp - path] = '\0'; 708321534Smav 709321534Smav /* 710321534Smav * Create handle for the parent dataset. 711321534Smav */ 712321534Smav errno = 0; 713321534Smav if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) { 714321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 715321534Smav return (NULL); 716321534Smav } 717321534Smav 718321534Smav /* 719321534Smav * Iterate bookmarks to find the right one. 720321534Smav */ 721321534Smav errno = 0; 722321534Smav if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb, 723321534Smav &cb_data) == 0) && (cb_data.zhp == NULL)) { 724321534Smav (void) zfs_error(hdl, EZFS_NOENT, errbuf); 725321534Smav zfs_close(pzhp); 726321534Smav return (NULL); 727321534Smav } 728321534Smav if (cb_data.zhp == NULL) { 729321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 730321534Smav zfs_close(pzhp); 731321534Smav return (NULL); 732321534Smav } 733321534Smav zhp = cb_data.zhp; 734321534Smav 735321534Smav /* 736321534Smav * Cleanup. 737321534Smav */ 738321534Smav zfs_close(pzhp); 739168404Spjd } 740168404Spjd 741240870Spjd if (zhp == NULL) { 742240870Spjd char *at = strchr(path, '@'); 743240870Spjd 744240870Spjd if (at != NULL) 745240870Spjd *at = '\0'; 746240870Spjd errno = 0; 747240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 748240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 749240870Spjd return (NULL); 750240870Spjd } 751240870Spjd if (at != NULL) 752240870Spjd *at = '@'; 753240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 754240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 755240870Spjd } 756240870Spjd 757168404Spjd if (!(types & zhp->zfs_type)) { 758168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 759168404Spjd zfs_close(zhp); 760168404Spjd return (NULL); 761168404Spjd } 762168404Spjd 763168404Spjd return (zhp); 764168404Spjd} 765168404Spjd 766168404Spjd/* 767168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 768168404Spjd */ 769168404Spjdvoid 770168404Spjdzfs_close(zfs_handle_t *zhp) 771168404Spjd{ 772168404Spjd if (zhp->zfs_mntopts) 773168404Spjd free(zhp->zfs_mntopts); 774168404Spjd nvlist_free(zhp->zfs_props); 775168404Spjd nvlist_free(zhp->zfs_user_props); 776219089Spjd nvlist_free(zhp->zfs_recvd_props); 777168404Spjd free(zhp); 778168404Spjd} 779168404Spjd 780209962Smmtypedef struct mnttab_node { 781209962Smm struct mnttab mtn_mt; 782209962Smm avl_node_t mtn_node; 783209962Smm} mnttab_node_t; 784209962Smm 785209962Smmstatic int 786209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 787209962Smm{ 788209962Smm const mnttab_node_t *mtn1 = arg1; 789209962Smm const mnttab_node_t *mtn2 = arg2; 790209962Smm int rv; 791209962Smm 792209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 793209962Smm 794209962Smm if (rv == 0) 795209962Smm return (0); 796209962Smm return (rv > 0 ? 1 : -1); 797209962Smm} 798209962Smm 799209962Smmvoid 800209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 801209962Smm{ 802209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 803209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 804209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 805209962Smm} 806209962Smm 807209962Smmvoid 808209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 809209962Smm{ 810209962Smm struct mnttab entry; 811209962Smm 812209962Smm rewind(hdl->libzfs_mnttab); 813209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 814209962Smm mnttab_node_t *mtn; 815209962Smm 816209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 817209962Smm continue; 818209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 819209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 820209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 821209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 822209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 823209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 824209962Smm } 825209962Smm} 826209962Smm 827209962Smmvoid 828209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 829209962Smm{ 830209962Smm void *cookie = NULL; 831209962Smm mnttab_node_t *mtn; 832209962Smm 833307050Smav while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) 834307050Smav != NULL) { 835209962Smm free(mtn->mtn_mt.mnt_special); 836209962Smm free(mtn->mtn_mt.mnt_mountp); 837209962Smm free(mtn->mtn_mt.mnt_fstype); 838209962Smm free(mtn->mtn_mt.mnt_mntopts); 839209962Smm free(mtn); 840209962Smm } 841209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 842209962Smm} 843209962Smm 844209962Smmvoid 845209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 846209962Smm{ 847209962Smm hdl->libzfs_mnttab_enable = enable; 848209962Smm} 849209962Smm 850185029Spjdint 851209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 852209962Smm struct mnttab *entry) 853209962Smm{ 854209962Smm mnttab_node_t find; 855209962Smm mnttab_node_t *mtn; 856209962Smm 857209962Smm if (!hdl->libzfs_mnttab_enable) { 858209962Smm struct mnttab srch = { 0 }; 859209962Smm 860209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 861209962Smm libzfs_mnttab_fini(hdl); 862209962Smm rewind(hdl->libzfs_mnttab); 863209962Smm srch.mnt_special = (char *)fsname; 864209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 865209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 866209962Smm return (0); 867209962Smm else 868209962Smm return (ENOENT); 869209962Smm } 870209962Smm 871209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 872209962Smm libzfs_mnttab_update(hdl); 873209962Smm 874209962Smm find.mtn_mt.mnt_special = (char *)fsname; 875209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 876209962Smm if (mtn) { 877209962Smm *entry = mtn->mtn_mt; 878209962Smm return (0); 879209962Smm } 880209962Smm return (ENOENT); 881209962Smm} 882209962Smm 883209962Smmvoid 884209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 885209962Smm const char *mountp, const char *mntopts) 886209962Smm{ 887209962Smm mnttab_node_t *mtn; 888209962Smm 889209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 890209962Smm return; 891209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 892209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 893209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 894209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 895209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 896209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 897209962Smm} 898209962Smm 899209962Smmvoid 900209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 901209962Smm{ 902209962Smm mnttab_node_t find; 903209962Smm mnttab_node_t *ret; 904209962Smm 905209962Smm find.mtn_mt.mnt_special = (char *)fsname; 906307050Smav if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) 907307050Smav != NULL) { 908209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 909209962Smm free(ret->mtn_mt.mnt_special); 910209962Smm free(ret->mtn_mt.mnt_mountp); 911209962Smm free(ret->mtn_mt.mnt_fstype); 912209962Smm free(ret->mtn_mt.mnt_mntopts); 913209962Smm free(ret); 914209962Smm } 915209962Smm} 916209962Smm 917209962Smmint 918185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 919168404Spjd{ 920185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 921168404Spjd 922185029Spjd if (zpool_handle == NULL) 923168404Spjd return (-1); 924168404Spjd 925185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 926185029Spjd ZPOOL_PROP_VERSION, NULL); 927168404Spjd return (0); 928168404Spjd} 929168404Spjd 930168404Spjd/* 931185029Spjd * The choice of reservation property depends on the SPA version. 932168404Spjd */ 933168404Spjdstatic int 934185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 935168404Spjd{ 936185029Spjd int spa_version; 937168404Spjd 938185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 939168404Spjd return (-1); 940168404Spjd 941185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 942185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 943185029Spjd else 944185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 945168404Spjd 946168404Spjd return (0); 947168404Spjd} 948168404Spjd 949168404Spjd/* 950168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 951168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 952168404Spjd * strings. 953168404Spjd */ 954168404Spjdnvlist_t * 955185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 956289500Smav uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl, 957289500Smav const char *errbuf) 958168404Spjd{ 959168404Spjd nvpair_t *elem; 960168404Spjd uint64_t intval; 961168404Spjd char *strval; 962185029Spjd zfs_prop_t prop; 963168404Spjd nvlist_t *ret; 964185029Spjd int chosen_normal = -1; 965185029Spjd int chosen_utf = -1; 966168404Spjd 967168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 968168404Spjd (void) no_memory(hdl); 969168404Spjd return (NULL); 970168404Spjd } 971168404Spjd 972209962Smm /* 973209962Smm * Make sure this property is valid and applies to this type. 974209962Smm */ 975209962Smm 976168404Spjd elem = NULL; 977168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 978185029Spjd const char *propname = nvpair_name(elem); 979168404Spjd 980209962Smm prop = zfs_name_to_prop(propname); 981209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 982185029Spjd /* 983209962Smm * This is a user property: make sure it's a 984185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 985185029Spjd */ 986185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 987185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 988185029Spjd "'%s' must be a string"), propname); 989185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 990185029Spjd goto error; 991168404Spjd } 992168404Spjd 993185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 994185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 995185029Spjd "property name '%s' is too long"), 996185029Spjd propname); 997185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 998185029Spjd goto error; 999185029Spjd } 1000185029Spjd 1001168404Spjd (void) nvpair_value_string(elem, &strval); 1002168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 1003168404Spjd (void) no_memory(hdl); 1004168404Spjd goto error; 1005168404Spjd } 1006168404Spjd continue; 1007168404Spjd } 1008168404Spjd 1009209962Smm /* 1010209962Smm * Currently, only user properties can be modified on 1011209962Smm * snapshots. 1012209962Smm */ 1013185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 1014185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1015185029Spjd "this property can not be modified for snapshots")); 1016185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1017185029Spjd goto error; 1018185029Spjd } 1019168404Spjd 1020209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 1021209962Smm zfs_userquota_prop_t uqtype; 1022209962Smm char newpropname[128]; 1023209962Smm char domain[128]; 1024209962Smm uint64_t rid; 1025209962Smm uint64_t valary[3]; 1026209962Smm 1027209962Smm if (userquota_propname_decode(propname, zoned, 1028209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 1029209962Smm zfs_error_aux(hdl, 1030209962Smm dgettext(TEXT_DOMAIN, 1031209962Smm "'%s' has an invalid user/group name"), 1032209962Smm propname); 1033209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1034209962Smm goto error; 1035209962Smm } 1036209962Smm 1037209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 1038209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 1039209962Smm zfs_error_aux(hdl, 1040209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1041209962Smm propname); 1042209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 1043209962Smm errbuf); 1044209962Smm goto error; 1045209962Smm } 1046209962Smm 1047209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 1048209962Smm (void) nvpair_value_string(elem, &strval); 1049209962Smm if (strcmp(strval, "none") == 0) { 1050209962Smm intval = 0; 1051209962Smm } else if (zfs_nicestrtonum(hdl, 1052209962Smm strval, &intval) != 0) { 1053209962Smm (void) zfs_error(hdl, 1054209962Smm EZFS_BADPROP, errbuf); 1055209962Smm goto error; 1056209962Smm } 1057209962Smm } else if (nvpair_type(elem) == 1058209962Smm DATA_TYPE_UINT64) { 1059209962Smm (void) nvpair_value_uint64(elem, &intval); 1060209962Smm if (intval == 0) { 1061209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1062209962Smm "use 'none' to disable " 1063209962Smm "userquota/groupquota")); 1064209962Smm goto error; 1065209962Smm } 1066209962Smm } else { 1067209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1068209962Smm "'%s' must be a number"), propname); 1069209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1070209962Smm goto error; 1071209962Smm } 1072209962Smm 1073219089Spjd /* 1074219089Spjd * Encode the prop name as 1075219089Spjd * userquota@<hex-rid>-domain, to make it easy 1076219089Spjd * for the kernel to decode. 1077219089Spjd */ 1078209962Smm (void) snprintf(newpropname, sizeof (newpropname), 1079219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 1080219089Spjd (longlong_t)rid, domain); 1081209962Smm valary[0] = uqtype; 1082209962Smm valary[1] = rid; 1083209962Smm valary[2] = intval; 1084209962Smm if (nvlist_add_uint64_array(ret, newpropname, 1085209962Smm valary, 3) != 0) { 1086209962Smm (void) no_memory(hdl); 1087209962Smm goto error; 1088209962Smm } 1089209962Smm continue; 1090228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 1091228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1092228103Smm "'%s' is readonly"), 1093228103Smm propname); 1094228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1095228103Smm goto error; 1096209962Smm } 1097209962Smm 1098209962Smm if (prop == ZPROP_INVAL) { 1099209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1100209962Smm "invalid property '%s'"), propname); 1101209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1102209962Smm goto error; 1103209962Smm } 1104209962Smm 1105168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 1106168404Spjd zfs_error_aux(hdl, 1107168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 1108168404Spjd "apply to datasets of this type"), propname); 1109168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1110168404Spjd goto error; 1111168404Spjd } 1112168404Spjd 1113168404Spjd if (zfs_prop_readonly(prop) && 1114185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 1115168404Spjd zfs_error_aux(hdl, 1116168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1117168404Spjd propname); 1118168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1119168404Spjd goto error; 1120168404Spjd } 1121168404Spjd 1122185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 1123185029Spjd &strval, &intval, errbuf) != 0) 1124185029Spjd goto error; 1125185029Spjd 1126168404Spjd /* 1127185029Spjd * Perform some additional checks for specific properties. 1128168404Spjd */ 1129185029Spjd switch (prop) { 1130185029Spjd case ZFS_PROP_VERSION: 1131185029Spjd { 1132185029Spjd int version; 1133168404Spjd 1134185029Spjd if (zhp == NULL) 1135185029Spjd break; 1136185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1137185029Spjd if (intval < version) { 1138168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1139185029Spjd "Can not downgrade; already at version %u"), 1140185029Spjd version); 1141168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1142168404Spjd goto error; 1143168404Spjd } 1144168404Spjd break; 1145168404Spjd } 1146168404Spjd 1147274337Sdelphij case ZFS_PROP_VOLBLOCKSIZE: 1148168404Spjd case ZFS_PROP_RECORDSIZE: 1149274337Sdelphij { 1150274337Sdelphij int maxbs = SPA_MAXBLOCKSIZE; 1151289500Smav if (zpool_hdl != NULL) { 1152289500Smav maxbs = zpool_get_prop_int(zpool_hdl, 1153274337Sdelphij ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1154274337Sdelphij } 1155274337Sdelphij /* 1156274337Sdelphij * Volumes are limited to a volblocksize of 128KB, 1157274337Sdelphij * because they typically service workloads with 1158274337Sdelphij * small random writes, which incur a large performance 1159274337Sdelphij * penalty with large blocks. 1160274337Sdelphij */ 1161274337Sdelphij if (prop == ZFS_PROP_VOLBLOCKSIZE) 1162274337Sdelphij maxbs = SPA_OLD_MAXBLOCKSIZE; 1163274337Sdelphij /* 1164274337Sdelphij * The value must be a power of two between 1165274337Sdelphij * SPA_MINBLOCKSIZE and maxbs. 1166274337Sdelphij */ 1167168404Spjd if (intval < SPA_MINBLOCKSIZE || 1168274337Sdelphij intval > maxbs || !ISP2(intval)) { 1169168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1170274337Sdelphij "'%s' must be power of 2 from 512B " 1171274337Sdelphij "to %uKB"), propname, maxbs >> 10); 1172168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1173168404Spjd goto error; 1174168404Spjd } 1175168404Spjd break; 1176274337Sdelphij } 1177219089Spjd case ZFS_PROP_MLSLABEL: 1178219089Spjd { 1179277300Ssmh#ifdef illumos 1180219089Spjd /* 1181219089Spjd * Verify the mlslabel string and convert to 1182219089Spjd * internal hex label string. 1183219089Spjd */ 1184219089Spjd 1185219089Spjd m_label_t *new_sl; 1186219089Spjd char *hex = NULL; /* internal label string */ 1187219089Spjd 1188219089Spjd /* Default value is already OK. */ 1189219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1190219089Spjd break; 1191219089Spjd 1192219089Spjd /* Verify the label can be converted to binary form */ 1193219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1194219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1195219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1196219089Spjd goto badlabel; 1197168404Spjd } 1198168404Spjd 1199219089Spjd /* Now translate to hex internal label string */ 1200219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1201219089Spjd DEF_NAMES) != 0) { 1202219089Spjd if (hex) 1203219089Spjd free(hex); 1204219089Spjd goto badlabel; 1205219089Spjd } 1206219089Spjd m_label_free(new_sl); 1207219089Spjd 1208219089Spjd /* If string is already in internal form, we're done. */ 1209219089Spjd if (strcmp(strval, hex) == 0) { 1210219089Spjd free(hex); 1211219089Spjd break; 1212219089Spjd } 1213219089Spjd 1214219089Spjd /* Replace the label string with the internal form. */ 1215219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1216219089Spjd DATA_TYPE_STRING); 1217219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1218219089Spjd hex) == 0); 1219219089Spjd free(hex); 1220219089Spjd 1221168404Spjd break; 1222168404Spjd 1223219089Spjdbadlabel: 1224219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1225219089Spjd "invalid mlslabel '%s'"), strval); 1226219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1227219089Spjd m_label_free(new_sl); /* OK if null */ 1228277300Ssmh#else /* !illumos */ 1229219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1230219089Spjd "mlslabel is not supported on FreeBSD")); 1231219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1232277300Ssmh#endif /* illumos */ 1233219089Spjd goto error; 1234219089Spjd 1235219089Spjd } 1236219089Spjd 1237168404Spjd case ZFS_PROP_MOUNTPOINT: 1238185029Spjd { 1239185029Spjd namecheck_err_t why; 1240185029Spjd 1241168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1242168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1243168404Spjd break; 1244168404Spjd 1245185029Spjd if (mountpoint_namecheck(strval, &why)) { 1246185029Spjd switch (why) { 1247185029Spjd case NAME_ERR_LEADING_SLASH: 1248185029Spjd zfs_error_aux(hdl, 1249185029Spjd dgettext(TEXT_DOMAIN, 1250185029Spjd "'%s' must be an absolute path, " 1251185029Spjd "'none', or 'legacy'"), propname); 1252185029Spjd break; 1253185029Spjd case NAME_ERR_TOOLONG: 1254185029Spjd zfs_error_aux(hdl, 1255185029Spjd dgettext(TEXT_DOMAIN, 1256185029Spjd "component of '%s' is too long"), 1257185029Spjd propname); 1258185029Spjd break; 1259307050Smav 1260307050Smav default: 1261307050Smav zfs_error_aux(hdl, 1262307050Smav dgettext(TEXT_DOMAIN, 1263307050Smav "(%d) not defined"), 1264307050Smav why); 1265307050Smav break; 1266185029Spjd } 1267168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1268168404Spjd goto error; 1269168404Spjd } 1270185029Spjd } 1271185029Spjd 1272168404Spjd /*FALLTHRU*/ 1273168404Spjd 1274185029Spjd case ZFS_PROP_SHARESMB: 1275168404Spjd case ZFS_PROP_SHARENFS: 1276168404Spjd /* 1277185029Spjd * For the mountpoint and sharenfs or sharesmb 1278185029Spjd * properties, check if it can be set in a 1279185029Spjd * global/non-global zone based on 1280168404Spjd * the zoned property value: 1281168404Spjd * 1282168404Spjd * global zone non-global zone 1283168404Spjd * -------------------------------------------------- 1284168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1285168404Spjd * sharenfs (no) sharenfs (no) 1286185029Spjd * sharesmb (no) sharesmb (no) 1287168404Spjd * 1288168404Spjd * zoned=off mountpoint (yes) N/A 1289168404Spjd * sharenfs (yes) 1290185029Spjd * sharesmb (yes) 1291168404Spjd */ 1292168404Spjd if (zoned) { 1293168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1294168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1295168404Spjd "'%s' cannot be set on " 1296168404Spjd "dataset in a non-global zone"), 1297168404Spjd propname); 1298168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1299168404Spjd errbuf); 1300168404Spjd goto error; 1301185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1302185029Spjd prop == ZFS_PROP_SHARESMB) { 1303168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1304168404Spjd "'%s' cannot be set in " 1305168404Spjd "a non-global zone"), propname); 1306168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1307168404Spjd errbuf); 1308168404Spjd goto error; 1309168404Spjd } 1310168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1311168404Spjd /* 1312168404Spjd * If zoned property is 'off', this must be in 1313209962Smm * a global zone. If not, something is wrong. 1314168404Spjd */ 1315168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1316168404Spjd "'%s' cannot be set while dataset " 1317168404Spjd "'zoned' property is set"), propname); 1318168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1319168404Spjd goto error; 1320168404Spjd } 1321168404Spjd 1322168404Spjd /* 1323185029Spjd * At this point, it is legitimate to set the 1324185029Spjd * property. Now we want to make sure that the 1325185029Spjd * property value is valid if it is sharenfs. 1326168404Spjd */ 1327185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1328185029Spjd prop == ZFS_PROP_SHARESMB) && 1329185029Spjd strcmp(strval, "on") != 0 && 1330185029Spjd strcmp(strval, "off") != 0) { 1331185029Spjd zfs_share_proto_t proto; 1332168404Spjd 1333185029Spjd if (prop == ZFS_PROP_SHARESMB) 1334185029Spjd proto = PROTO_SMB; 1335185029Spjd else 1336185029Spjd proto = PROTO_NFS; 1337185029Spjd 1338185029Spjd /* 1339185029Spjd * Must be an valid sharing protocol 1340185029Spjd * option string so init the libshare 1341185029Spjd * in order to enable the parser and 1342185029Spjd * then parse the options. We use the 1343185029Spjd * control API since we don't care about 1344185029Spjd * the current configuration and don't 1345185029Spjd * want the overhead of loading it 1346185029Spjd * until we actually do something. 1347185029Spjd */ 1348185029Spjd 1349185029Spjd if (zfs_init_libshare(hdl, 1350185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1351185029Spjd /* 1352185029Spjd * An error occurred so we can't do 1353185029Spjd * anything 1354185029Spjd */ 1355185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1356185029Spjd "'%s' cannot be set: problem " 1357185029Spjd "in share initialization"), 1358185029Spjd propname); 1359185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1360185029Spjd errbuf); 1361185029Spjd goto error; 1362185029Spjd } 1363185029Spjd 1364185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1365185029Spjd /* 1366185029Spjd * There was an error in parsing so 1367185029Spjd * deal with it by issuing an error 1368185029Spjd * message and leaving after 1369185029Spjd * uninitializing the the libshare 1370185029Spjd * interface. 1371185029Spjd */ 1372185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1373185029Spjd "'%s' cannot be set to invalid " 1374185029Spjd "options"), propname); 1375185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1376185029Spjd errbuf); 1377185029Spjd zfs_uninit_libshare(hdl); 1378185029Spjd goto error; 1379185029Spjd } 1380185029Spjd zfs_uninit_libshare(hdl); 1381168404Spjd } 1382185029Spjd 1383168404Spjd break; 1384307050Smav 1385185029Spjd case ZFS_PROP_UTF8ONLY: 1386185029Spjd chosen_utf = (int)intval; 1387185029Spjd break; 1388307050Smav 1389185029Spjd case ZFS_PROP_NORMALIZE: 1390185029Spjd chosen_normal = (int)intval; 1391185029Spjd break; 1392307050Smav 1393307050Smav default: 1394307050Smav break; 1395168404Spjd } 1396168404Spjd 1397168404Spjd /* 1398168404Spjd * For changes to existing volumes, we have some additional 1399168404Spjd * checks to enforce. 1400168404Spjd */ 1401168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1402168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1403168404Spjd ZFS_PROP_VOLSIZE); 1404168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1405168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1406168404Spjd char buf[64]; 1407168404Spjd 1408168404Spjd switch (prop) { 1409168404Spjd case ZFS_PROP_RESERVATION: 1410185029Spjd case ZFS_PROP_REFRESERVATION: 1411168404Spjd if (intval > volsize) { 1412168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1413168404Spjd "'%s' is greater than current " 1414168404Spjd "volume size"), propname); 1415168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1416168404Spjd errbuf); 1417168404Spjd goto error; 1418168404Spjd } 1419168404Spjd break; 1420168404Spjd 1421168404Spjd case ZFS_PROP_VOLSIZE: 1422168404Spjd if (intval % blocksize != 0) { 1423168404Spjd zfs_nicenum(blocksize, buf, 1424168404Spjd sizeof (buf)); 1425168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1426168404Spjd "'%s' must be a multiple of " 1427168404Spjd "volume block size (%s)"), 1428168404Spjd propname, buf); 1429168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1430168404Spjd errbuf); 1431168404Spjd goto error; 1432168404Spjd } 1433168404Spjd 1434168404Spjd if (intval == 0) { 1435168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1436168404Spjd "'%s' cannot be zero"), 1437168404Spjd propname); 1438168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1439168404Spjd errbuf); 1440168404Spjd goto error; 1441168404Spjd } 1442168404Spjd break; 1443307050Smav 1444307050Smav default: 1445307050Smav break; 1446168404Spjd } 1447168404Spjd } 1448168404Spjd } 1449168404Spjd 1450168404Spjd /* 1451185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1452185029Spjd * enforce rejection of non-UTF8 names. 1453185029Spjd * 1454185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1455185029Spjd * was explicitly not chosen, it is an error. 1456185029Spjd */ 1457185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1458185029Spjd if (nvlist_add_uint64(ret, 1459185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1460185029Spjd (void) no_memory(hdl); 1461185029Spjd goto error; 1462185029Spjd } 1463185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1464185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1465185029Spjd "'%s' must be set 'on' if normalization chosen"), 1466185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1467185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1468185029Spjd goto error; 1469185029Spjd } 1470219089Spjd return (ret); 1471185029Spjd 1472219089Spjderror: 1473219089Spjd nvlist_free(ret); 1474219089Spjd return (NULL); 1475219089Spjd} 1476219089Spjd 1477219089Spjdint 1478219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1479219089Spjd{ 1480219089Spjd uint64_t old_volsize; 1481219089Spjd uint64_t new_volsize; 1482219089Spjd uint64_t old_reservation; 1483219089Spjd uint64_t new_reservation; 1484219089Spjd zfs_prop_t resv_prop; 1485289499Smav nvlist_t *props; 1486219089Spjd 1487185029Spjd /* 1488168404Spjd * If this is an existing volume, and someone is setting the volsize, 1489168404Spjd * make sure that it matches the reservation, or add it if necessary. 1490168404Spjd */ 1491219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1492219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1493219089Spjd return (-1); 1494219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1495289499Smav 1496289499Smav props = fnvlist_alloc(); 1497289499Smav fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1498289499Smav zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1499289499Smav 1500289499Smav if ((zvol_volsize_to_reservation(old_volsize, props) != 1501289499Smav old_reservation) || nvlist_exists(nvl, 1502289499Smav zfs_prop_to_name(resv_prop))) { 1503289499Smav fnvlist_free(props); 1504219089Spjd return (0); 1505219089Spjd } 1506219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1507289499Smav &new_volsize) != 0) { 1508289499Smav fnvlist_free(props); 1509219089Spjd return (-1); 1510289499Smav } 1511289499Smav new_reservation = zvol_volsize_to_reservation(new_volsize, props); 1512289499Smav fnvlist_free(props); 1513289499Smav 1514219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1515219089Spjd new_reservation) != 0) { 1516219089Spjd (void) no_memory(zhp->zfs_hdl); 1517219089Spjd return (-1); 1518219089Spjd } 1519219089Spjd return (1); 1520219089Spjd} 1521168404Spjd 1522219089Spjdvoid 1523219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1524219089Spjd char *errbuf) 1525219089Spjd{ 1526219089Spjd switch (err) { 1527185029Spjd 1528219089Spjd case ENOSPC: 1529219089Spjd /* 1530219089Spjd * For quotas and reservations, ENOSPC indicates 1531219089Spjd * something different; setting a quota or reservation 1532219089Spjd * doesn't use any disk space. 1533219089Spjd */ 1534219089Spjd switch (prop) { 1535219089Spjd case ZFS_PROP_QUOTA: 1536219089Spjd case ZFS_PROP_REFQUOTA: 1537219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1538219089Spjd "size is less than current used or " 1539219089Spjd "reserved space")); 1540219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1541219089Spjd break; 1542219089Spjd 1543219089Spjd case ZFS_PROP_RESERVATION: 1544219089Spjd case ZFS_PROP_REFRESERVATION: 1545219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1546219089Spjd "size is greater than available space")); 1547219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1548219089Spjd break; 1549219089Spjd 1550219089Spjd default: 1551219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1552219089Spjd break; 1553168404Spjd } 1554219089Spjd break; 1555219089Spjd 1556219089Spjd case EBUSY: 1557219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1558219089Spjd break; 1559219089Spjd 1560219089Spjd case EROFS: 1561219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1562219089Spjd break; 1563219089Spjd 1564271764Swill case E2BIG: 1565271764Swill zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1566271764Swill "property value too long")); 1567271764Swill (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1568271764Swill break; 1569271764Swill 1570219089Spjd case ENOTSUP: 1571219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1572219089Spjd "pool and or dataset must be upgraded to set this " 1573219089Spjd "property or value")); 1574219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1575219089Spjd break; 1576219089Spjd 1577219089Spjd case ERANGE: 1578274337Sdelphij case EDOM: 1579274337Sdelphij if (prop == ZFS_PROP_COMPRESSION || 1580274337Sdelphij prop == ZFS_PROP_RECORDSIZE) { 1581219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1582219089Spjd "property setting is not allowed on " 1583219089Spjd "bootable datasets")); 1584219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1585289422Smav } else if (prop == ZFS_PROP_CHECKSUM || 1586289422Smav prop == ZFS_PROP_DEDUP) { 1587289422Smav (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1588289422Smav "property setting is not allowed on " 1589289422Smav "root pools")); 1590289422Smav (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1591219089Spjd } else { 1592219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1593219089Spjd } 1594219089Spjd break; 1595219089Spjd 1596219089Spjd case EINVAL: 1597219089Spjd if (prop == ZPROP_INVAL) { 1598219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1599219089Spjd } else { 1600219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1601219089Spjd } 1602219089Spjd break; 1603219089Spjd 1604219089Spjd case EOVERFLOW: 1605219089Spjd /* 1606219089Spjd * This platform can't address a volume this big. 1607219089Spjd */ 1608219089Spjd#ifdef _ILP32 1609219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1610219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1611219089Spjd break; 1612219089Spjd } 1613219089Spjd#endif 1614219089Spjd /* FALLTHROUGH */ 1615219089Spjd default: 1616219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1617168404Spjd } 1618168404Spjd} 1619168404Spjd 1620168404Spjd/* 1621168404Spjd * Given a property name and value, set the property for the given dataset. 1622168404Spjd */ 1623168404Spjdint 1624168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1625168404Spjd{ 1626168404Spjd int ret = -1; 1627168404Spjd char errbuf[1024]; 1628168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1629289497Smav nvlist_t *nvl = NULL; 1630168404Spjd 1631168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1632168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1633168404Spjd zhp->zfs_name); 1634168404Spjd 1635168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1636168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1637168404Spjd (void) no_memory(hdl); 1638168404Spjd goto error; 1639168404Spjd } 1640168404Spjd 1641289497Smav ret = zfs_prop_set_list(zhp, nvl); 1642185029Spjd 1643289497Smaverror: 1644168404Spjd nvlist_free(nvl); 1645289497Smav return (ret); 1646289497Smav} 1647168404Spjd 1648168404Spjd 1649168404Spjd 1650289497Smav/* 1651289497Smav * Given an nvlist of property names and values, set the properties for the 1652289497Smav * given dataset. 1653289497Smav */ 1654289497Smavint 1655289497Smavzfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) 1656289497Smav{ 1657289497Smav zfs_cmd_t zc = { 0 }; 1658289497Smav int ret = -1; 1659289497Smav prop_changelist_t **cls = NULL; 1660289497Smav int cl_idx; 1661289497Smav char errbuf[1024]; 1662289497Smav libzfs_handle_t *hdl = zhp->zfs_hdl; 1663289497Smav nvlist_t *nvl; 1664289497Smav int nvl_len; 1665307107Smav int added_resv = 0; 1666219089Spjd 1667289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1668289497Smav dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1669289497Smav zhp->zfs_name); 1670168404Spjd 1671289497Smav if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, 1672289500Smav zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl, 1673289500Smav errbuf)) == NULL) 1674168404Spjd goto error; 1675168404Spjd 1676185029Spjd /* 1677289497Smav * We have to check for any extra properties which need to be added 1678289497Smav * before computing the length of the nvlist. 1679185029Spjd */ 1680289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1681289497Smav elem != NULL; 1682289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1683289497Smav if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && 1684289497Smav (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { 1685289497Smav goto error; 1686289497Smav } 1687238391Smm } 1688289497Smav /* 1689289497Smav * Check how many properties we're setting and allocate an array to 1690289497Smav * store changelist pointers for postfix(). 1691289497Smav */ 1692289497Smav nvl_len = 0; 1693289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1694289497Smav elem != NULL; 1695289497Smav elem = nvlist_next_nvpair(nvl, elem)) 1696289497Smav nvl_len++; 1697289497Smav if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) 1698168404Spjd goto error; 1699168404Spjd 1700289497Smav cl_idx = 0; 1701289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1702289497Smav elem != NULL; 1703289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1704289497Smav 1705289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1706289497Smav 1707289497Smav assert(cl_idx < nvl_len); 1708289497Smav /* 1709289497Smav * We don't want to unmount & remount the dataset when changing 1710310068Savg * its canmount property to 'on' or 'noauto'. We only use 1711310068Savg * the changelist logic to unmount when setting canmount=off. 1712289497Smav */ 1713297521Savg if (prop != ZFS_PROP_CANMOUNT || 1714297521Savg (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF && 1715321522Smav zfs_is_mounted(zhp, NULL))) { 1716289497Smav cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); 1717289497Smav if (cls[cl_idx] == NULL) 1718289497Smav goto error; 1719289497Smav } 1720289497Smav 1721289497Smav if (prop == ZFS_PROP_MOUNTPOINT && 1722289497Smav changelist_haszonedchild(cls[cl_idx])) { 1723289497Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1724289497Smav "child dataset with inherited mountpoint is used " 1725289497Smav "in a non-global zone")); 1726289497Smav ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1727289497Smav goto error; 1728289497Smav } 1729289497Smav 1730289497Smav /* We don't support those properties on FreeBSD. */ 1731289497Smav switch (prop) { 1732289497Smav case ZFS_PROP_DEVICES: 1733289497Smav case ZFS_PROP_ISCSIOPTIONS: 1734289497Smav case ZFS_PROP_XATTR: 1735289497Smav case ZFS_PROP_VSCAN: 1736289497Smav case ZFS_PROP_NBMAND: 1737289497Smav case ZFS_PROP_MLSLABEL: 1738289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1739289497Smav "property '%s' not supported on FreeBSD", 1740289497Smav nvpair_name(elem)); 1741289497Smav ret = zfs_error(hdl, EZFS_PERM, errbuf); 1742289497Smav goto error; 1743289497Smav } 1744289497Smav 1745289497Smav if (cls[cl_idx] != NULL && 1746289497Smav (ret = changelist_prefix(cls[cl_idx])) != 0) 1747289497Smav goto error; 1748289497Smav 1749289497Smav cl_idx++; 1750289497Smav } 1751289497Smav assert(cl_idx == nvl_len); 1752289497Smav 1753168404Spjd /* 1754289497Smav * Execute the corresponding ioctl() to set this list of properties. 1755168404Spjd */ 1756168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1757168404Spjd 1758289497Smav if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 || 1759289497Smav (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0) 1760168404Spjd goto error; 1761168404Spjd 1762185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1763209962Smm 1764168404Spjd if (ret != 0) { 1765289497Smav /* Get the list of unset properties back and report them. */ 1766289497Smav nvlist_t *errorprops = NULL; 1767289497Smav if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) 1768289497Smav goto error; 1769289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1770289497Smav elem != NULL; 1771289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1772289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1773289497Smav zfs_setprop_error(hdl, prop, errno, errbuf); 1774289497Smav } 1775289497Smav nvlist_free(errorprops); 1776289497Smav 1777219089Spjd if (added_resv && errno == ENOSPC) { 1778219089Spjd /* clean up the volsize property we tried to set */ 1779219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1780219089Spjd ZFS_PROP_VOLSIZE); 1781219089Spjd nvlist_free(nvl); 1782289497Smav nvl = NULL; 1783219089Spjd zcmd_free_nvlists(&zc); 1784289497Smav 1785219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1786219089Spjd goto error; 1787219089Spjd if (nvlist_add_uint64(nvl, 1788219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1789219089Spjd old_volsize) != 0) 1790219089Spjd goto error; 1791219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1792219089Spjd goto error; 1793219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1794168404Spjd } 1795168404Spjd } else { 1796289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1797289497Smav if (cls[cl_idx] != NULL) { 1798289497Smav int clp_err = changelist_postfix(cls[cl_idx]); 1799289497Smav if (clp_err != 0) 1800289497Smav ret = clp_err; 1801289497Smav } 1802289497Smav } 1803185029Spjd 1804168404Spjd /* 1805168404Spjd * Refresh the statistics so the new property value 1806168404Spjd * is reflected. 1807168404Spjd */ 1808185029Spjd if (ret == 0) 1809168404Spjd (void) get_stats(zhp); 1810168404Spjd } 1811168404Spjd 1812168404Spjderror: 1813168404Spjd nvlist_free(nvl); 1814168404Spjd zcmd_free_nvlists(&zc); 1815289497Smav if (cls != NULL) { 1816289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1817289497Smav if (cls[cl_idx] != NULL) 1818289497Smav changelist_free(cls[cl_idx]); 1819289497Smav } 1820289497Smav free(cls); 1821289497Smav } 1822168404Spjd return (ret); 1823168404Spjd} 1824168404Spjd 1825168404Spjd/* 1826219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1827219089Spjd * is TRUE, revert to the received value, if any. 1828168404Spjd */ 1829168404Spjdint 1830219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1831168404Spjd{ 1832168404Spjd zfs_cmd_t zc = { 0 }; 1833168404Spjd int ret; 1834168404Spjd prop_changelist_t *cl; 1835168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1836168404Spjd char errbuf[1024]; 1837168404Spjd zfs_prop_t prop; 1838168404Spjd 1839168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1840168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1841168404Spjd 1842219089Spjd zc.zc_cookie = received; 1843185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1844168404Spjd /* 1845168404Spjd * For user properties, the amount of work we have to do is very 1846168404Spjd * small, so just do it here. 1847168404Spjd */ 1848168404Spjd if (!zfs_prop_user(propname)) { 1849168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1850168404Spjd "invalid property")); 1851168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1852168404Spjd } 1853168404Spjd 1854168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1855168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1856168404Spjd 1857185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1858168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1859168404Spjd 1860168404Spjd return (0); 1861168404Spjd } 1862168404Spjd 1863168404Spjd /* 1864168404Spjd * Verify that this property is inheritable. 1865168404Spjd */ 1866168404Spjd if (zfs_prop_readonly(prop)) 1867168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1868168404Spjd 1869219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1870168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1871168404Spjd 1872168404Spjd /* 1873168404Spjd * Check to see if the value applies to this type 1874168404Spjd */ 1875168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1876168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1877168404Spjd 1878168404Spjd /* 1879219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1880168404Spjd */ 1881168404Spjd propname = zfs_prop_to_name(prop); 1882168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1883168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1884168404Spjd 1885168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1886168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1887168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1888168404Spjd "dataset is used in a non-global zone")); 1889168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1890168404Spjd } 1891168404Spjd 1892168404Spjd /* 1893168404Spjd * Determine datasets which will be affected by this change, if any. 1894168404Spjd */ 1895185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1896168404Spjd return (-1); 1897168404Spjd 1898168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1899168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1900168404Spjd "child dataset with inherited mountpoint is used " 1901168404Spjd "in a non-global zone")); 1902168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1903168404Spjd goto error; 1904168404Spjd } 1905168404Spjd 1906168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1907168404Spjd goto error; 1908168404Spjd 1909185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1910168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1911168404Spjd } else { 1912168404Spjd 1913168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1914168404Spjd goto error; 1915168404Spjd 1916168404Spjd /* 1917168404Spjd * Refresh the statistics so the new property is reflected. 1918168404Spjd */ 1919168404Spjd (void) get_stats(zhp); 1920168404Spjd } 1921168404Spjd 1922168404Spjderror: 1923168404Spjd changelist_free(cl); 1924168404Spjd return (ret); 1925168404Spjd} 1926168404Spjd 1927168404Spjd/* 1928168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1929168404Spjd * extract them appropriately. 1930168404Spjd */ 1931168404Spjdstatic uint64_t 1932168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1933168404Spjd{ 1934168404Spjd nvlist_t *nv; 1935168404Spjd uint64_t value; 1936168404Spjd 1937168404Spjd *source = NULL; 1938168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1939168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1940185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1941185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1942168404Spjd } else { 1943205198Sdelphij verify(!zhp->zfs_props_table || 1944205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1945168404Spjd value = zfs_prop_default_numeric(prop); 1946168404Spjd *source = ""; 1947168404Spjd } 1948168404Spjd 1949168404Spjd return (value); 1950168404Spjd} 1951168404Spjd 1952289362Smavstatic const char * 1953168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1954168404Spjd{ 1955168404Spjd nvlist_t *nv; 1956289362Smav const char *value; 1957168404Spjd 1958168404Spjd *source = NULL; 1959168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1960168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1961289362Smav value = fnvlist_lookup_string(nv, ZPROP_VALUE); 1962185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1963168404Spjd } else { 1964205198Sdelphij verify(!zhp->zfs_props_table || 1965205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1966289362Smav value = zfs_prop_default_string(prop); 1967168404Spjd *source = ""; 1968168404Spjd } 1969168404Spjd 1970168404Spjd return (value); 1971168404Spjd} 1972168404Spjd 1973219089Spjdstatic boolean_t 1974219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1975219089Spjd{ 1976219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1977219089Spjd} 1978219089Spjd 1979219089Spjdstatic void 1980219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1981219089Spjd{ 1982219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1983219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1984219089Spjd} 1985219089Spjd 1986219089Spjdstatic void 1987219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1988219089Spjd{ 1989219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1990219089Spjd *cookie = 0; 1991219089Spjd} 1992219089Spjd 1993168404Spjd/* 1994168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1995168404Spjd * zfs_prop_get_int() are built using this interface. 1996168404Spjd * 1997168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1998168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1999168404Spjd * If they differ from the on-disk values, report the current values and mark 2000168404Spjd * the source "temporary". 2001168404Spjd */ 2002168404Spjdstatic int 2003185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 2004168404Spjd char **source, uint64_t *val) 2005168404Spjd{ 2006185029Spjd zfs_cmd_t zc = { 0 }; 2007185029Spjd nvlist_t *zplprops = NULL; 2008168404Spjd struct mnttab mnt; 2009168404Spjd char *mntopt_on = NULL; 2010168404Spjd char *mntopt_off = NULL; 2011219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2012168404Spjd 2013168404Spjd *source = NULL; 2014168404Spjd 2015168404Spjd switch (prop) { 2016168404Spjd case ZFS_PROP_ATIME: 2017168404Spjd mntopt_on = MNTOPT_ATIME; 2018168404Spjd mntopt_off = MNTOPT_NOATIME; 2019168404Spjd break; 2020168404Spjd 2021168404Spjd case ZFS_PROP_DEVICES: 2022168404Spjd mntopt_on = MNTOPT_DEVICES; 2023168404Spjd mntopt_off = MNTOPT_NODEVICES; 2024168404Spjd break; 2025168404Spjd 2026168404Spjd case ZFS_PROP_EXEC: 2027168404Spjd mntopt_on = MNTOPT_EXEC; 2028168404Spjd mntopt_off = MNTOPT_NOEXEC; 2029168404Spjd break; 2030168404Spjd 2031168404Spjd case ZFS_PROP_READONLY: 2032168404Spjd mntopt_on = MNTOPT_RO; 2033168404Spjd mntopt_off = MNTOPT_RW; 2034168404Spjd break; 2035168404Spjd 2036168404Spjd case ZFS_PROP_SETUID: 2037168404Spjd mntopt_on = MNTOPT_SETUID; 2038168404Spjd mntopt_off = MNTOPT_NOSETUID; 2039168404Spjd break; 2040168404Spjd 2041168404Spjd case ZFS_PROP_XATTR: 2042168404Spjd mntopt_on = MNTOPT_XATTR; 2043168404Spjd mntopt_off = MNTOPT_NOXATTR; 2044168404Spjd break; 2045185029Spjd 2046185029Spjd case ZFS_PROP_NBMAND: 2047185029Spjd mntopt_on = MNTOPT_NBMAND; 2048185029Spjd mntopt_off = MNTOPT_NONBMAND; 2049185029Spjd break; 2050307050Smav 2051307050Smav default: 2052307050Smav break; 2053168404Spjd } 2054168404Spjd 2055168404Spjd /* 2056168404Spjd * Because looking up the mount options is potentially expensive 2057168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 2058168404Spjd * we're looking up a property which requires its presence. 2059168404Spjd */ 2060168404Spjd if (!zhp->zfs_mntcheck && 2061168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 2062209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 2063209962Smm struct mnttab entry; 2064168404Spjd 2065209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 2066209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 2067168404Spjd entry.mnt_mntopts); 2068168404Spjd if (zhp->zfs_mntopts == NULL) 2069168404Spjd return (-1); 2070168404Spjd } 2071168404Spjd 2072168404Spjd zhp->zfs_mntcheck = B_TRUE; 2073168404Spjd } 2074168404Spjd 2075168404Spjd if (zhp->zfs_mntopts == NULL) 2076168404Spjd mnt.mnt_mntopts = ""; 2077168404Spjd else 2078168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 2079168404Spjd 2080168404Spjd switch (prop) { 2081168404Spjd case ZFS_PROP_ATIME: 2082168404Spjd case ZFS_PROP_DEVICES: 2083168404Spjd case ZFS_PROP_EXEC: 2084168404Spjd case ZFS_PROP_READONLY: 2085168404Spjd case ZFS_PROP_SETUID: 2086168404Spjd case ZFS_PROP_XATTR: 2087185029Spjd case ZFS_PROP_NBMAND: 2088168404Spjd *val = getprop_uint64(zhp, prop, source); 2089168404Spjd 2090219089Spjd if (received) 2091219089Spjd break; 2092219089Spjd 2093168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 2094168404Spjd *val = B_TRUE; 2095168404Spjd if (src) 2096185029Spjd *src = ZPROP_SRC_TEMPORARY; 2097168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2098168404Spjd *val = B_FALSE; 2099168404Spjd if (src) 2100185029Spjd *src = ZPROP_SRC_TEMPORARY; 2101168404Spjd } 2102168404Spjd break; 2103168404Spjd 2104168404Spjd case ZFS_PROP_CANMOUNT: 2105219089Spjd case ZFS_PROP_VOLSIZE: 2106168404Spjd case ZFS_PROP_QUOTA: 2107185029Spjd case ZFS_PROP_REFQUOTA: 2108168404Spjd case ZFS_PROP_RESERVATION: 2109185029Spjd case ZFS_PROP_REFRESERVATION: 2110264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2111264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2112264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2113264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2114168404Spjd *val = getprop_uint64(zhp, prop, source); 2115219089Spjd 2116219089Spjd if (*source == NULL) { 2117219089Spjd /* not default, must be local */ 2118168404Spjd *source = zhp->zfs_name; 2119219089Spjd } 2120168404Spjd break; 2121168404Spjd 2122168404Spjd case ZFS_PROP_MOUNTED: 2123168404Spjd *val = (zhp->zfs_mntopts != NULL); 2124168404Spjd break; 2125168404Spjd 2126168404Spjd case ZFS_PROP_NUMCLONES: 2127168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 2128168404Spjd break; 2129168404Spjd 2130185029Spjd case ZFS_PROP_VERSION: 2131185029Spjd case ZFS_PROP_NORMALIZE: 2132185029Spjd case ZFS_PROP_UTF8ONLY: 2133185029Spjd case ZFS_PROP_CASE: 2134185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 2135185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2136185029Spjd return (-1); 2137185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2138185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2139185029Spjd zcmd_free_nvlists(&zc); 2140219089Spjd return (-1); 2141185029Spjd } 2142185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2143185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2144185029Spjd val) != 0) { 2145185029Spjd zcmd_free_nvlists(&zc); 2146219089Spjd return (-1); 2147185029Spjd } 2148296528Smav nvlist_free(zplprops); 2149185029Spjd zcmd_free_nvlists(&zc); 2150185029Spjd break; 2151185029Spjd 2152253819Sdelphij case ZFS_PROP_INCONSISTENT: 2153253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 2154253819Sdelphij break; 2155253819Sdelphij 2156168404Spjd default: 2157185029Spjd switch (zfs_prop_get_type(prop)) { 2158185029Spjd case PROP_TYPE_NUMBER: 2159185029Spjd case PROP_TYPE_INDEX: 2160185029Spjd *val = getprop_uint64(zhp, prop, source); 2161185029Spjd /* 2162209962Smm * If we tried to use a default value for a 2163185029Spjd * readonly property, it means that it was not 2164331391Smav * present. Note this only applies to "truly" 2165331391Smav * readonly properties, not set-once properties 2166331391Smav * like volblocksize. 2167185029Spjd */ 2168185029Spjd if (zfs_prop_readonly(prop) && 2169331391Smav !zfs_prop_setonce(prop) && 2170219089Spjd *source != NULL && (*source)[0] == '\0') { 2171219089Spjd *source = NULL; 2172325139Savg return (-1); 2173185029Spjd } 2174185029Spjd break; 2175185029Spjd 2176185029Spjd case PROP_TYPE_STRING: 2177185029Spjd default: 2178185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2179185029Spjd "cannot get non-numeric property")); 2180185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2181185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 2182185029Spjd } 2183168404Spjd } 2184168404Spjd 2185168404Spjd return (0); 2186168404Spjd} 2187168404Spjd 2188168404Spjd/* 2189168404Spjd * Calculate the source type, given the raw source string. 2190168404Spjd */ 2191168404Spjdstatic void 2192185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 2193168404Spjd char *statbuf, size_t statlen) 2194168404Spjd{ 2195185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 2196168404Spjd return; 2197168404Spjd 2198168404Spjd if (source == NULL) { 2199185029Spjd *srctype = ZPROP_SRC_NONE; 2200168404Spjd } else if (source[0] == '\0') { 2201185029Spjd *srctype = ZPROP_SRC_DEFAULT; 2202219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 2203219089Spjd *srctype = ZPROP_SRC_RECEIVED; 2204168404Spjd } else { 2205168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 2206185029Spjd *srctype = ZPROP_SRC_LOCAL; 2207168404Spjd } else { 2208168404Spjd (void) strlcpy(statbuf, source, statlen); 2209185029Spjd *srctype = ZPROP_SRC_INHERITED; 2210168404Spjd } 2211168404Spjd } 2212168404Spjd 2213168404Spjd} 2214168404Spjd 2215219089Spjdint 2216219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2217219089Spjd size_t proplen, boolean_t literal) 2218219089Spjd{ 2219219089Spjd zfs_prop_t prop; 2220219089Spjd int err = 0; 2221219089Spjd 2222219089Spjd if (zhp->zfs_recvd_props == NULL) 2223219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 2224219089Spjd return (-1); 2225219089Spjd 2226219089Spjd prop = zfs_name_to_prop(propname); 2227219089Spjd 2228219089Spjd if (prop != ZPROP_INVAL) { 2229219089Spjd uint64_t cookie; 2230219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2231219089Spjd return (-1); 2232219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 2233219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 2234219089Spjd NULL, NULL, 0, literal); 2235219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 2236219089Spjd } else { 2237219089Spjd nvlist_t *propval; 2238219089Spjd char *recvdval; 2239219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2240219089Spjd propname, &propval) != 0) 2241219089Spjd return (-1); 2242219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 2243219089Spjd &recvdval) == 0); 2244219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 2245219089Spjd } 2246219089Spjd 2247219089Spjd return (err == 0 ? 0 : -1); 2248219089Spjd} 2249219089Spjd 2250228103Smmstatic int 2251228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2252228103Smm{ 2253228103Smm nvlist_t *value; 2254228103Smm nvpair_t *pair; 2255228103Smm 2256228103Smm value = zfs_get_clones_nvl(zhp); 2257228103Smm if (value == NULL) 2258228103Smm return (-1); 2259228103Smm 2260228103Smm propbuf[0] = '\0'; 2261228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2262228103Smm pair = nvlist_next_nvpair(value, pair)) { 2263228103Smm if (propbuf[0] != '\0') 2264228103Smm (void) strlcat(propbuf, ",", proplen); 2265228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 2266228103Smm } 2267228103Smm 2268228103Smm return (0); 2269228103Smm} 2270228103Smm 2271228103Smmstruct get_clones_arg { 2272228103Smm uint64_t numclones; 2273228103Smm nvlist_t *value; 2274228103Smm const char *origin; 2275307108Smav char buf[ZFS_MAX_DATASET_NAME_LEN]; 2276228103Smm}; 2277228103Smm 2278228103Smmint 2279228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2280228103Smm{ 2281228103Smm struct get_clones_arg *gca = arg; 2282228103Smm 2283228103Smm if (gca->numclones == 0) { 2284228103Smm zfs_close(zhp); 2285228103Smm return (0); 2286228103Smm } 2287228103Smm 2288228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2289228103Smm NULL, NULL, 0, B_TRUE) != 0) 2290228103Smm goto out; 2291228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2292248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2293228103Smm gca->numclones--; 2294228103Smm } 2295228103Smm 2296228103Smmout: 2297228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2298228103Smm zfs_close(zhp); 2299228103Smm return (0); 2300228103Smm} 2301228103Smm 2302228103Smmnvlist_t * 2303228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2304228103Smm{ 2305228103Smm nvlist_t *nv, *value; 2306228103Smm 2307228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2308228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2309228103Smm struct get_clones_arg gca; 2310228103Smm 2311228103Smm /* 2312228103Smm * if this is a snapshot, then the kernel wasn't able 2313228103Smm * to get the clones. Do it by slowly iterating. 2314228103Smm */ 2315228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2316228103Smm return (NULL); 2317228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2318228103Smm return (NULL); 2319228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2320228103Smm nvlist_free(nv); 2321228103Smm return (NULL); 2322228103Smm } 2323228103Smm 2324228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2325228103Smm gca.value = value; 2326228103Smm gca.origin = zhp->zfs_name; 2327228103Smm 2328228103Smm if (gca.numclones != 0) { 2329228103Smm zfs_handle_t *root; 2330307108Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 2331228103Smm char *cp = pool; 2332228103Smm 2333228103Smm /* get the pool name */ 2334228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2335228103Smm (void) strsep(&cp, "/@"); 2336228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2337228103Smm ZFS_TYPE_FILESYSTEM); 2338228103Smm 2339228103Smm (void) get_clones_cb(root, &gca); 2340228103Smm } 2341228103Smm 2342228103Smm if (gca.numclones != 0 || 2343228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2344228103Smm nvlist_add_nvlist(zhp->zfs_props, 2345228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2346228103Smm nvlist_free(nv); 2347228103Smm nvlist_free(value); 2348228103Smm return (NULL); 2349228103Smm } 2350228103Smm nvlist_free(nv); 2351228103Smm nvlist_free(value); 2352228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2353228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2354228103Smm } 2355228103Smm 2356228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2357228103Smm 2358228103Smm return (value); 2359228103Smm} 2360228103Smm 2361168404Spjd/* 2362325534Savg * Accepts a property and value and checks that the value 2363325534Savg * matches the one found by the channel program. If they are 2364325534Savg * not equal, print both of them. 2365325534Savg */ 2366325534Savgvoid 2367325534Savgzcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval, 2368325534Savg const char *strval) 2369325534Savg{ 2370325534Savg if (!zhp->zfs_hdl->libzfs_prop_debug) 2371325534Savg return; 2372325534Savg int error; 2373325534Savg char *poolname = zhp->zpool_hdl->zpool_name; 2374325534Savg const char *program = 2375325534Savg "args = ...\n" 2376325534Savg "ds = args['dataset']\n" 2377325534Savg "prop = args['property']\n" 2378325534Savg "value, setpoint = zfs.get_prop(ds, prop)\n" 2379325534Savg "return {value=value, setpoint=setpoint}\n"; 2380325534Savg nvlist_t *outnvl; 2381325534Savg nvlist_t *retnvl; 2382325534Savg nvlist_t *argnvl = fnvlist_alloc(); 2383325534Savg 2384325534Savg fnvlist_add_string(argnvl, "dataset", zhp->zfs_name); 2385325534Savg fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop)); 2386325534Savg 2387329484Smav error = lzc_channel_program_nosync(poolname, program, 2388325534Savg 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl); 2389325534Savg 2390325534Savg if (error == 0) { 2391325534Savg retnvl = fnvlist_lookup_nvlist(outnvl, "return"); 2392325534Savg if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) { 2393325534Savg int64_t ans; 2394325534Savg error = nvlist_lookup_int64(retnvl, "value", &ans); 2395325534Savg if (error != 0) { 2396325534Savg (void) fprintf(stderr, "zcp check error: %u\n", 2397325534Savg error); 2398325534Savg return; 2399325534Savg } 2400325534Savg if (ans != intval) { 2401325534Savg (void) fprintf(stderr, 2402325534Savg "%s: zfs found %lld, but zcp found %lld\n", 2403325534Savg zfs_prop_to_name(prop), 2404325534Savg (longlong_t)intval, (longlong_t)ans); 2405325534Savg } 2406325534Savg } else { 2407325534Savg char *str_ans; 2408325534Savg error = nvlist_lookup_string(retnvl, "value", &str_ans); 2409325534Savg if (error != 0) { 2410325534Savg (void) fprintf(stderr, "zcp check error: %u\n", 2411325534Savg error); 2412325534Savg return; 2413325534Savg } 2414325534Savg if (strcmp(strval, str_ans) != 0) { 2415325534Savg (void) fprintf(stderr, 2416325534Savg "%s: zfs found %s, but zcp found %s\n", 2417325534Savg zfs_prop_to_name(prop), 2418325534Savg strval, str_ans); 2419325534Savg } 2420325534Savg } 2421325534Savg } else { 2422325534Savg (void) fprintf(stderr, 2423325534Savg "zcp check failed, channel program error: %u\n", error); 2424325534Savg } 2425325534Savg nvlist_free(argnvl); 2426325534Savg nvlist_free(outnvl); 2427325534Savg} 2428325534Savg 2429325534Savg/* 2430168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2431168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2432168404Spjd * human-readable form. 2433168404Spjd * 2434168404Spjd * Returns 0 on success, or -1 on error. 2435168404Spjd */ 2436168404Spjdint 2437168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2438185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2439168404Spjd{ 2440168404Spjd char *source = NULL; 2441168404Spjd uint64_t val; 2442289362Smav const char *str; 2443168404Spjd const char *strval; 2444219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2445168404Spjd 2446168404Spjd /* 2447168404Spjd * Check to see if this property applies to our object 2448168404Spjd */ 2449168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2450168404Spjd return (-1); 2451168404Spjd 2452219089Spjd if (received && zfs_prop_readonly(prop)) 2453219089Spjd return (-1); 2454219089Spjd 2455168404Spjd if (src) 2456185029Spjd *src = ZPROP_SRC_NONE; 2457168404Spjd 2458168404Spjd switch (prop) { 2459168404Spjd case ZFS_PROP_CREATION: 2460168404Spjd /* 2461168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2462168404Spjd * this into a string unless 'literal' is specified. 2463168404Spjd */ 2464168404Spjd { 2465168404Spjd val = getprop_uint64(zhp, prop, &source); 2466168404Spjd time_t time = (time_t)val; 2467168404Spjd struct tm t; 2468168404Spjd 2469168404Spjd if (literal || 2470168404Spjd localtime_r(&time, &t) == NULL || 2471168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2472168404Spjd &t) == 0) 2473168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2474168404Spjd } 2475325534Savg zcp_check(zhp, prop, val, NULL); 2476168404Spjd break; 2477168404Spjd 2478168404Spjd case ZFS_PROP_MOUNTPOINT: 2479168404Spjd /* 2480168404Spjd * Getting the precise mountpoint can be tricky. 2481168404Spjd * 2482168404Spjd * - for 'none' or 'legacy', return those values. 2483168404Spjd * - for inherited mountpoints, we want to take everything 2484168404Spjd * after our ancestor and append it to the inherited value. 2485168404Spjd * 2486168404Spjd * If the pool has an alternate root, we want to prepend that 2487168404Spjd * root to any values we return. 2488168404Spjd */ 2489185029Spjd 2490168404Spjd str = getprop_string(zhp, prop, &source); 2491168404Spjd 2492185029Spjd if (str[0] == '/') { 2493185029Spjd char buf[MAXPATHLEN]; 2494185029Spjd char *root = buf; 2495219089Spjd const char *relpath; 2496168404Spjd 2497219089Spjd /* 2498219089Spjd * If we inherit the mountpoint, even from a dataset 2499219089Spjd * with a received value, the source will be the path of 2500219089Spjd * the dataset we inherit from. If source is 2501219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2502219089Spjd * inherited. 2503219089Spjd */ 2504219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2505219089Spjd relpath = ""; 2506219089Spjd } else { 2507219089Spjd relpath = zhp->zfs_name + strlen(source); 2508219089Spjd if (relpath[0] == '/') 2509219089Spjd relpath++; 2510219089Spjd } 2511185029Spjd 2512185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2513263889Sdelphij ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, 2514263889Sdelphij B_FALSE)) || (strcmp(root, "-") == 0)) 2515185029Spjd root[0] = '\0'; 2516185029Spjd /* 2517185029Spjd * Special case an alternate root of '/'. This will 2518185029Spjd * avoid having multiple leading slashes in the 2519185029Spjd * mountpoint path. 2520185029Spjd */ 2521185029Spjd if (strcmp(root, "/") == 0) 2522185029Spjd root++; 2523185029Spjd 2524185029Spjd /* 2525185029Spjd * If the mountpoint is '/' then skip over this 2526185029Spjd * if we are obtaining either an alternate root or 2527185029Spjd * an inherited mountpoint. 2528185029Spjd */ 2529185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2530185029Spjd relpath[0] != '\0')) 2531168404Spjd str++; 2532168404Spjd 2533168404Spjd if (relpath[0] == '\0') 2534168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2535168404Spjd root, str); 2536168404Spjd else 2537168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2538168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2539168404Spjd relpath); 2540168404Spjd } else { 2541168404Spjd /* 'legacy' or 'none' */ 2542168404Spjd (void) strlcpy(propbuf, str, proplen); 2543168404Spjd } 2544325534Savg zcp_check(zhp, prop, NULL, propbuf); 2545168404Spjd break; 2546168404Spjd 2547168404Spjd case ZFS_PROP_ORIGIN: 2548289362Smav str = getprop_string(zhp, prop, &source); 2549289362Smav if (str == NULL) 2550168404Spjd return (-1); 2551289362Smav (void) strlcpy(propbuf, str, proplen); 2552325534Savg zcp_check(zhp, prop, NULL, str); 2553168404Spjd break; 2554168404Spjd 2555228103Smm case ZFS_PROP_CLONES: 2556228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2557228103Smm return (-1); 2558228103Smm break; 2559228103Smm 2560168404Spjd case ZFS_PROP_QUOTA: 2561185029Spjd case ZFS_PROP_REFQUOTA: 2562168404Spjd case ZFS_PROP_RESERVATION: 2563185029Spjd case ZFS_PROP_REFRESERVATION: 2564185029Spjd 2565168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2566168404Spjd return (-1); 2567168404Spjd /* 2568168404Spjd * If quota or reservation is 0, we translate this into 'none' 2569168404Spjd * (unless literal is set), and indicate that it's the default 2570168404Spjd * value. Otherwise, we print the number nicely and indicate 2571168404Spjd * that its set locally. 2572168404Spjd */ 2573168404Spjd if (val == 0) { 2574168404Spjd if (literal) 2575168404Spjd (void) strlcpy(propbuf, "0", proplen); 2576168404Spjd else 2577168404Spjd (void) strlcpy(propbuf, "none", proplen); 2578168404Spjd } else { 2579168404Spjd if (literal) 2580168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2581168404Spjd (u_longlong_t)val); 2582168404Spjd else 2583168404Spjd zfs_nicenum(val, propbuf, proplen); 2584168404Spjd } 2585325534Savg zcp_check(zhp, prop, val, NULL); 2586168404Spjd break; 2587168404Spjd 2588264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2589264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2590264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2591264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2592264835Sdelphij 2593264835Sdelphij if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2594264835Sdelphij return (-1); 2595264835Sdelphij 2596264835Sdelphij /* 2597264835Sdelphij * If limit is UINT64_MAX, we translate this into 'none' (unless 2598264835Sdelphij * literal is set), and indicate that it's the default value. 2599264835Sdelphij * Otherwise, we print the number nicely and indicate that it's 2600264835Sdelphij * set locally. 2601264835Sdelphij */ 2602264835Sdelphij if (literal) { 2603264835Sdelphij (void) snprintf(propbuf, proplen, "%llu", 2604264835Sdelphij (u_longlong_t)val); 2605264835Sdelphij } else if (val == UINT64_MAX) { 2606264835Sdelphij (void) strlcpy(propbuf, "none", proplen); 2607264835Sdelphij } else { 2608264835Sdelphij zfs_nicenum(val, propbuf, proplen); 2609264835Sdelphij } 2610325534Savg 2611325534Savg zcp_check(zhp, prop, val, NULL); 2612264835Sdelphij break; 2613264835Sdelphij 2614223623Smm case ZFS_PROP_REFRATIO: 2615168404Spjd case ZFS_PROP_COMPRESSRATIO: 2616168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2617168404Spjd return (-1); 2618219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2619219089Spjd (u_longlong_t)(val / 100), 2620219089Spjd (u_longlong_t)(val % 100)); 2621325534Savg zcp_check(zhp, prop, val, NULL); 2622168404Spjd break; 2623168404Spjd 2624168404Spjd case ZFS_PROP_TYPE: 2625168404Spjd switch (zhp->zfs_type) { 2626168404Spjd case ZFS_TYPE_FILESYSTEM: 2627168404Spjd str = "filesystem"; 2628168404Spjd break; 2629168404Spjd case ZFS_TYPE_VOLUME: 2630168404Spjd str = "volume"; 2631168404Spjd break; 2632168404Spjd case ZFS_TYPE_SNAPSHOT: 2633168404Spjd str = "snapshot"; 2634168404Spjd break; 2635260183Sdelphij case ZFS_TYPE_BOOKMARK: 2636260183Sdelphij str = "bookmark"; 2637260183Sdelphij break; 2638168404Spjd default: 2639168404Spjd abort(); 2640168404Spjd } 2641168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2642325534Savg zcp_check(zhp, prop, NULL, propbuf); 2643168404Spjd break; 2644168404Spjd 2645168404Spjd case ZFS_PROP_MOUNTED: 2646168404Spjd /* 2647168404Spjd * The 'mounted' property is a pseudo-property that described 2648168404Spjd * whether the filesystem is currently mounted. Even though 2649168404Spjd * it's a boolean value, the typical values of "on" and "off" 2650168404Spjd * don't make sense, so we translate to "yes" and "no". 2651168404Spjd */ 2652168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2653168404Spjd src, &source, &val) != 0) 2654168404Spjd return (-1); 2655168404Spjd if (val) 2656168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2657168404Spjd else 2658168404Spjd (void) strlcpy(propbuf, "no", proplen); 2659168404Spjd break; 2660168404Spjd 2661168404Spjd case ZFS_PROP_NAME: 2662168404Spjd /* 2663168404Spjd * The 'name' property is a pseudo-property derived from the 2664168404Spjd * dataset name. It is presented as a real property to simplify 2665168404Spjd * consumers. 2666168404Spjd */ 2667168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2668325534Savg zcp_check(zhp, prop, NULL, propbuf); 2669168404Spjd break; 2670168404Spjd 2671219089Spjd case ZFS_PROP_MLSLABEL: 2672219089Spjd { 2673277300Ssmh#ifdef illumos 2674219089Spjd m_label_t *new_sl = NULL; 2675219089Spjd char *ascii = NULL; /* human readable label */ 2676219089Spjd 2677219089Spjd (void) strlcpy(propbuf, 2678219089Spjd getprop_string(zhp, prop, &source), proplen); 2679219089Spjd 2680219089Spjd if (literal || (strcasecmp(propbuf, 2681219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2682219089Spjd break; 2683219089Spjd 2684219089Spjd /* 2685219089Spjd * Try to translate the internal hex string to 2686219089Spjd * human-readable output. If there are any 2687219089Spjd * problems just use the hex string. 2688219089Spjd */ 2689219089Spjd 2690219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2691219089Spjd L_NO_CORRECTION, NULL) == -1) { 2692219089Spjd m_label_free(new_sl); 2693219089Spjd break; 2694219089Spjd } 2695219089Spjd 2696219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2697219089Spjd DEF_NAMES) != 0) { 2698219089Spjd if (ascii) 2699219089Spjd free(ascii); 2700219089Spjd m_label_free(new_sl); 2701219089Spjd break; 2702219089Spjd } 2703219089Spjd m_label_free(new_sl); 2704219089Spjd 2705219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2706219089Spjd free(ascii); 2707277300Ssmh#else /* !illumos */ 2708219089Spjd propbuf[0] = '\0'; 2709277300Ssmh#endif /* illumos */ 2710219089Spjd } 2711219089Spjd break; 2712219089Spjd 2713236705Smm case ZFS_PROP_GUID: 2714236705Smm /* 2715236705Smm * GUIDs are stored as numbers, but they are identifiers. 2716236705Smm * We don't want them to be pretty printed, because pretty 2717236705Smm * printing mangles the ID into a truncated and useless value. 2718236705Smm */ 2719236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2720236705Smm return (-1); 2721236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2722325534Savg zcp_check(zhp, prop, val, NULL); 2723236705Smm break; 2724236705Smm 2725168404Spjd default: 2726185029Spjd switch (zfs_prop_get_type(prop)) { 2727185029Spjd case PROP_TYPE_NUMBER: 2728185029Spjd if (get_numeric_property(zhp, prop, src, 2729325534Savg &source, &val) != 0) { 2730185029Spjd return (-1); 2731325534Savg } 2732325534Savg 2733325534Savg if (literal) { 2734185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2735185029Spjd (u_longlong_t)val); 2736325534Savg } else { 2737185029Spjd zfs_nicenum(val, propbuf, proplen); 2738325534Savg } 2739325534Savg zcp_check(zhp, prop, val, NULL); 2740185029Spjd break; 2741185029Spjd 2742185029Spjd case PROP_TYPE_STRING: 2743289362Smav str = getprop_string(zhp, prop, &source); 2744289362Smav if (str == NULL) 2745289362Smav return (-1); 2746325534Savg 2747289362Smav (void) strlcpy(propbuf, str, proplen); 2748325534Savg zcp_check(zhp, prop, NULL, str); 2749185029Spjd break; 2750185029Spjd 2751185029Spjd case PROP_TYPE_INDEX: 2752185029Spjd if (get_numeric_property(zhp, prop, src, 2753185029Spjd &source, &val) != 0) 2754185029Spjd return (-1); 2755185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2756185029Spjd return (-1); 2757325534Savg 2758185029Spjd (void) strlcpy(propbuf, strval, proplen); 2759325534Savg zcp_check(zhp, prop, NULL, strval); 2760185029Spjd break; 2761185029Spjd 2762185029Spjd default: 2763185029Spjd abort(); 2764185029Spjd } 2765168404Spjd } 2766168404Spjd 2767168404Spjd get_source(zhp, src, source, statbuf, statlen); 2768168404Spjd 2769168404Spjd return (0); 2770168404Spjd} 2771168404Spjd 2772168404Spjd/* 2773168404Spjd * Utility function to get the given numeric property. Does no validation that 2774168404Spjd * the given property is the appropriate type; should only be used with 2775168404Spjd * hard-coded property types. 2776168404Spjd */ 2777168404Spjduint64_t 2778168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2779168404Spjd{ 2780168404Spjd char *source; 2781168404Spjd uint64_t val; 2782168404Spjd 2783185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2784168404Spjd 2785168404Spjd return (val); 2786168404Spjd} 2787168404Spjd 2788185029Spjdint 2789185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2790185029Spjd{ 2791185029Spjd char buf[64]; 2792185029Spjd 2793209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2794185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2795185029Spjd} 2796185029Spjd 2797168404Spjd/* 2798168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2799168404Spjd */ 2800168404Spjdint 2801168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2802185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2803168404Spjd{ 2804168404Spjd char *source; 2805168404Spjd 2806168404Spjd /* 2807168404Spjd * Check to see if this property applies to our object 2808168404Spjd */ 2809185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2810168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2811168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2812168404Spjd zfs_prop_to_name(prop))); 2813185029Spjd } 2814168404Spjd 2815168404Spjd if (src) 2816185029Spjd *src = ZPROP_SRC_NONE; 2817168404Spjd 2818168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2819168404Spjd return (-1); 2820168404Spjd 2821168404Spjd get_source(zhp, src, source, statbuf, statlen); 2822168404Spjd 2823168404Spjd return (0); 2824168404Spjd} 2825168404Spjd 2826209962Smmstatic int 2827209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2828209962Smm char **domainp, idmap_rid_t *ridp) 2829209962Smm{ 2830277300Ssmh#ifdef illumos 2831209962Smm idmap_get_handle_t *get_hdl = NULL; 2832209962Smm idmap_stat status; 2833209962Smm int err = EINVAL; 2834209962Smm 2835219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2836209962Smm goto out; 2837209962Smm 2838209962Smm if (isuser) { 2839209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2840209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2841209962Smm } else { 2842209962Smm err = idmap_get_sidbygid(get_hdl, id, 2843209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2844209962Smm } 2845209962Smm if (err == IDMAP_SUCCESS && 2846209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2847209962Smm status == IDMAP_SUCCESS) 2848209962Smm err = 0; 2849209962Smm else 2850209962Smm err = EINVAL; 2851209962Smmout: 2852209962Smm if (get_hdl) 2853209962Smm idmap_get_destroy(get_hdl); 2854209962Smm return (err); 2855277300Ssmh#else /* !illumos */ 2856209962Smm assert(!"invalid code path"); 2857264852Ssmh return (EINVAL); // silence compiler warning 2858277300Ssmh#endif /* illumos */ 2859209962Smm} 2860209962Smm 2861168404Spjd/* 2862209962Smm * convert the propname into parameters needed by kernel 2863209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2864209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2865209962Smm */ 2866209962Smmstatic int 2867209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2868209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2869209962Smm{ 2870209962Smm zfs_userquota_prop_t type; 2871209962Smm char *cp, *end; 2872209962Smm char *numericsid = NULL; 2873209962Smm boolean_t isuser; 2874209962Smm 2875209962Smm domain[0] = '\0'; 2876275579Sdelphij *ridp = 0; 2877209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2878209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2879209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2880209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2881209962Smm break; 2882209962Smm } 2883209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2884209962Smm return (EINVAL); 2885209962Smm *typep = type; 2886209962Smm 2887209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2888209962Smm type == ZFS_PROP_USERUSED); 2889209962Smm 2890209962Smm cp = strchr(propname, '@') + 1; 2891209962Smm 2892209962Smm if (strchr(cp, '@')) { 2893277300Ssmh#ifdef illumos 2894209962Smm /* 2895209962Smm * It's a SID name (eg "user@domain") that needs to be 2896209962Smm * turned into S-1-domainID-RID. 2897209962Smm */ 2898275579Sdelphij int flag = 0; 2899275579Sdelphij idmap_stat stat, map_stat; 2900275579Sdelphij uid_t pid; 2901275579Sdelphij idmap_rid_t rid; 2902275579Sdelphij idmap_get_handle_t *gh = NULL; 2903275579Sdelphij 2904275579Sdelphij stat = idmap_get_create(&gh); 2905275579Sdelphij if (stat != IDMAP_SUCCESS) { 2906275579Sdelphij idmap_get_destroy(gh); 2907275579Sdelphij return (ENOMEM); 2908275579Sdelphij } 2909209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2910209962Smm return (ENOENT); 2911209962Smm if (isuser) { 2912275579Sdelphij stat = idmap_getuidbywinname(cp, NULL, flag, &pid); 2913275579Sdelphij if (stat < 0) 2914275579Sdelphij return (ENOENT); 2915275579Sdelphij stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid, 2916275579Sdelphij &rid, &map_stat); 2917209962Smm } else { 2918275579Sdelphij stat = idmap_getgidbywinname(cp, NULL, flag, &pid); 2919275579Sdelphij if (stat < 0) 2920275579Sdelphij return (ENOENT); 2921275579Sdelphij stat = idmap_get_sidbygid(gh, pid, flag, &numericsid, 2922275579Sdelphij &rid, &map_stat); 2923209962Smm } 2924275579Sdelphij if (stat < 0) { 2925275579Sdelphij idmap_get_destroy(gh); 2926209962Smm return (ENOENT); 2927209962Smm } 2928275579Sdelphij stat = idmap_get_mappings(gh); 2929275579Sdelphij idmap_get_destroy(gh); 2930275579Sdelphij 2931275579Sdelphij if (stat < 0) { 2932275579Sdelphij return (ENOENT); 2933275579Sdelphij } 2934209962Smm if (numericsid == NULL) 2935209962Smm return (ENOENT); 2936209962Smm cp = numericsid; 2937275579Sdelphij *ridp = rid; 2938209962Smm /* will be further decoded below */ 2939277300Ssmh#else /* !illumos */ 2940219089Spjd return (ENOENT); 2941277300Ssmh#endif /* illumos */ 2942209962Smm } 2943209962Smm 2944209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2945209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2946209962Smm (void) strlcpy(domain, cp, domainlen); 2947209962Smm errno = 0; 2948275579Sdelphij if (*ridp == 0) { 2949275579Sdelphij cp = strrchr(domain, '-'); 2950275579Sdelphij *cp = '\0'; 2951275579Sdelphij cp++; 2952275579Sdelphij *ridp = strtoull(cp, &end, 10); 2953275579Sdelphij } else { 2954275579Sdelphij end = ""; 2955275579Sdelphij } 2956209962Smm if (numericsid) { 2957209962Smm free(numericsid); 2958209962Smm numericsid = NULL; 2959209962Smm } 2960209962Smm if (errno != 0 || *end != '\0') 2961209962Smm return (EINVAL); 2962209962Smm } else if (!isdigit(*cp)) { 2963209962Smm /* 2964209962Smm * It's a user/group name (eg "user") that needs to be 2965209962Smm * turned into a uid/gid 2966209962Smm */ 2967209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2968209962Smm return (ENOENT); 2969209962Smm if (isuser) { 2970209962Smm struct passwd *pw; 2971209962Smm pw = getpwnam(cp); 2972209962Smm if (pw == NULL) 2973209962Smm return (ENOENT); 2974209962Smm *ridp = pw->pw_uid; 2975209962Smm } else { 2976209962Smm struct group *gr; 2977209962Smm gr = getgrnam(cp); 2978209962Smm if (gr == NULL) 2979209962Smm return (ENOENT); 2980209962Smm *ridp = gr->gr_gid; 2981209962Smm } 2982209962Smm } else { 2983209962Smm /* It's a user/group ID (eg "12345"). */ 2984209962Smm uid_t id = strtoul(cp, &end, 10); 2985209962Smm idmap_rid_t rid; 2986209962Smm char *mapdomain; 2987209962Smm 2988209962Smm if (*end != '\0') 2989209962Smm return (EINVAL); 2990209962Smm if (id > MAXUID) { 2991209962Smm /* It's an ephemeral ID. */ 2992209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2993209962Smm &mapdomain, &rid) != 0) 2994209962Smm return (ENOENT); 2995209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2996209962Smm *ridp = rid; 2997209962Smm } else { 2998209962Smm *ridp = id; 2999209962Smm } 3000209962Smm } 3001209962Smm 3002209962Smm ASSERT3P(numericsid, ==, NULL); 3003209962Smm return (0); 3004209962Smm} 3005209962Smm 3006209962Smmstatic int 3007209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 3008209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 3009209962Smm{ 3010209962Smm int err; 3011209962Smm zfs_cmd_t zc = { 0 }; 3012209962Smm 3013228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3014209962Smm 3015209962Smm err = userquota_propname_decode(propname, 3016209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 3017209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 3018209962Smm zc.zc_objset_type = *typep; 3019209962Smm if (err) 3020209962Smm return (err); 3021209962Smm 3022209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 3023209962Smm if (err) 3024209962Smm return (err); 3025209962Smm 3026209962Smm *propvalue = zc.zc_cookie; 3027209962Smm return (0); 3028209962Smm} 3029209962Smm 3030209962Smmint 3031209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 3032209962Smm uint64_t *propvalue) 3033209962Smm{ 3034209962Smm zfs_userquota_prop_t type; 3035209962Smm 3036209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 3037209962Smm &type)); 3038209962Smm} 3039209962Smm 3040209962Smmint 3041209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 3042209962Smm char *propbuf, int proplen, boolean_t literal) 3043209962Smm{ 3044209962Smm int err; 3045209962Smm uint64_t propvalue; 3046209962Smm zfs_userquota_prop_t type; 3047209962Smm 3048209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 3049209962Smm &type); 3050209962Smm 3051209962Smm if (err) 3052209962Smm return (err); 3053209962Smm 3054209962Smm if (literal) { 3055209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 3056209962Smm } else if (propvalue == 0 && 3057209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 3058209962Smm (void) strlcpy(propbuf, "none", proplen); 3059209962Smm } else { 3060209962Smm zfs_nicenum(propvalue, propbuf, proplen); 3061209962Smm } 3062209962Smm return (0); 3063209962Smm} 3064209962Smm 3065228103Smmint 3066228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 3067228103Smm uint64_t *propvalue) 3068168404Spjd{ 3069228103Smm int err; 3070228103Smm zfs_cmd_t zc = { 0 }; 3071228103Smm const char *snapname; 3072168404Spjd 3073228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3074168404Spjd 3075228103Smm snapname = strchr(propname, '@') + 1; 3076228103Smm if (strchr(snapname, '@')) { 3077228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3078228103Smm } else { 3079228103Smm /* snapname is the short name, append it to zhp's fsname */ 3080228103Smm char *cp; 3081209962Smm 3082228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 3083228103Smm sizeof (zc.zc_value)); 3084228103Smm cp = strchr(zc.zc_value, '@'); 3085228103Smm if (cp != NULL) 3086228103Smm *cp = '\0'; 3087228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 3088228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 3089228103Smm } 3090209962Smm 3091228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 3092228103Smm if (err) 3093228103Smm return (err); 3094228103Smm 3095228103Smm *propvalue = zc.zc_cookie; 3096228103Smm return (0); 3097209962Smm} 3098209962Smm 3099168404Spjdint 3100228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 3101228103Smm char *propbuf, int proplen, boolean_t literal) 3102168404Spjd{ 3103228103Smm int err; 3104228103Smm uint64_t propvalue; 3105168404Spjd 3106228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 3107185029Spjd 3108228103Smm if (err) 3109228103Smm return (err); 3110209962Smm 3111228103Smm if (literal) { 3112228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 3113228103Smm } else { 3114228103Smm zfs_nicenum(propvalue, propbuf, proplen); 3115168404Spjd } 3116228103Smm return (0); 3117168404Spjd} 3118168404Spjd 3119168404Spjd/* 3120228103Smm * Returns the name of the given zfs handle. 3121168404Spjd */ 3122228103Smmconst char * 3123228103Smmzfs_get_name(const zfs_handle_t *zhp) 3124168404Spjd{ 3125228103Smm return (zhp->zfs_name); 3126228103Smm} 3127168404Spjd 3128228103Smm/* 3129307106Smav * Returns the name of the parent pool for the given zfs handle. 3130307106Smav */ 3131307106Smavconst char * 3132307106Smavzfs_get_pool_name(const zfs_handle_t *zhp) 3133307106Smav{ 3134307106Smav return (zhp->zpool_hdl->zpool_name); 3135307106Smav} 3136307106Smav 3137307106Smav/* 3138228103Smm * Returns the type of the given zfs handle. 3139228103Smm */ 3140228103Smmzfs_type_t 3141228103Smmzfs_get_type(const zfs_handle_t *zhp) 3142228103Smm{ 3143228103Smm return (zhp->zfs_type); 3144168404Spjd} 3145168404Spjd 3146168404Spjd/* 3147219089Spjd * Is one dataset name a child dataset of another? 3148219089Spjd * 3149219089Spjd * Needs to handle these cases: 3150219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 3151219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 3152219089Spjd * Descendant? No. No. No. Yes. 3153219089Spjd */ 3154219089Spjdstatic boolean_t 3155219089Spjdis_descendant(const char *ds1, const char *ds2) 3156219089Spjd{ 3157219089Spjd size_t d1len = strlen(ds1); 3158219089Spjd 3159219089Spjd /* ds2 can't be a descendant if it's smaller */ 3160219089Spjd if (strlen(ds2) < d1len) 3161219089Spjd return (B_FALSE); 3162219089Spjd 3163219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 3164219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 3165219089Spjd} 3166219089Spjd 3167219089Spjd/* 3168168404Spjd * Given a complete name, return just the portion that refers to the parent. 3169228103Smm * Will return -1 if there is no parent (path is just the name of the 3170228103Smm * pool). 3171168404Spjd */ 3172168404Spjdstatic int 3173168404Spjdparent_name(const char *path, char *buf, size_t buflen) 3174168404Spjd{ 3175228103Smm char *slashp; 3176168404Spjd 3177228103Smm (void) strlcpy(buf, path, buflen); 3178228103Smm 3179228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 3180168404Spjd return (-1); 3181228103Smm *slashp = '\0'; 3182168404Spjd 3183168404Spjd return (0); 3184168404Spjd} 3185168404Spjd 3186168404Spjd/* 3187185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 3188185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 3189185029Spjd * closest existing ancestor for the given path. In prefixlen return the 3190185029Spjd * length of already existing prefix of the given path. We also fetch the 3191185029Spjd * 'zoned' property, which is used to validate property settings when creating 3192185029Spjd * new datasets. 3193168404Spjd */ 3194168404Spjdstatic int 3195185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 3196185029Spjd boolean_t accept_ancestor, int *prefixlen) 3197168404Spjd{ 3198168404Spjd zfs_cmd_t zc = { 0 }; 3199307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3200168404Spjd char *slash; 3201168404Spjd zfs_handle_t *zhp; 3202168404Spjd char errbuf[1024]; 3203219089Spjd uint64_t is_zoned; 3204168404Spjd 3205209962Smm (void) snprintf(errbuf, sizeof (errbuf), 3206209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 3207168404Spjd 3208168404Spjd /* get parent, and check to see if this is just a pool */ 3209168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 3210168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3211168404Spjd "missing dataset name")); 3212168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3213168404Spjd } 3214168404Spjd 3215168404Spjd /* check to see if the pool exists */ 3216168404Spjd if ((slash = strchr(parent, '/')) == NULL) 3217168404Spjd slash = parent + strlen(parent); 3218168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 3219168404Spjd zc.zc_name[slash - parent] = '\0'; 3220168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 3221168404Spjd errno == ENOENT) { 3222168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3223168404Spjd "no such pool '%s'"), zc.zc_name); 3224168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3225168404Spjd } 3226168404Spjd 3227168404Spjd /* check to see if the parent dataset exists */ 3228185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 3229185029Spjd if (errno == ENOENT && accept_ancestor) { 3230185029Spjd /* 3231185029Spjd * Go deeper to find an ancestor, give up on top level. 3232185029Spjd */ 3233185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 3234185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3235185029Spjd "no such pool '%s'"), zc.zc_name); 3236185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3237185029Spjd } 3238185029Spjd } else if (errno == ENOENT) { 3239168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3240168404Spjd "parent does not exist")); 3241168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3242185029Spjd } else 3243168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3244168404Spjd } 3245168404Spjd 3246219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 3247219089Spjd if (zoned != NULL) 3248219089Spjd *zoned = is_zoned; 3249219089Spjd 3250168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 3251219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 3252168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 3253168404Spjd zfs_close(zhp); 3254168404Spjd return (-1); 3255168404Spjd } 3256168404Spjd 3257168404Spjd /* make sure parent is a filesystem */ 3258168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 3259168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3260168404Spjd "parent is not a filesystem")); 3261168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3262168404Spjd zfs_close(zhp); 3263168404Spjd return (-1); 3264168404Spjd } 3265168404Spjd 3266168404Spjd zfs_close(zhp); 3267185029Spjd if (prefixlen != NULL) 3268185029Spjd *prefixlen = strlen(parent); 3269168404Spjd return (0); 3270168404Spjd} 3271168404Spjd 3272168404Spjd/* 3273185029Spjd * Finds whether the dataset of the given type(s) exists. 3274185029Spjd */ 3275185029Spjdboolean_t 3276185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 3277185029Spjd{ 3278185029Spjd zfs_handle_t *zhp; 3279185029Spjd 3280185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 3281185029Spjd return (B_FALSE); 3282185029Spjd 3283185029Spjd /* 3284185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 3285185029Spjd */ 3286185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 3287185029Spjd int ds_type = zhp->zfs_type; 3288185029Spjd 3289185029Spjd zfs_close(zhp); 3290185029Spjd if (types & ds_type) 3291185029Spjd return (B_TRUE); 3292185029Spjd } 3293185029Spjd return (B_FALSE); 3294185029Spjd} 3295185029Spjd 3296185029Spjd/* 3297185029Spjd * Given a path to 'target', create all the ancestors between 3298185029Spjd * the prefixlen portion of the path, and the target itself. 3299185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 3300185029Spjd */ 3301185029Spjdint 3302185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 3303185029Spjd{ 3304185029Spjd zfs_handle_t *h; 3305185029Spjd char *cp; 3306185029Spjd const char *opname; 3307185029Spjd 3308185029Spjd /* make sure prefix exists */ 3309185029Spjd cp = target + prefixlen; 3310185029Spjd if (*cp != '/') { 3311185029Spjd assert(strchr(cp, '/') == NULL); 3312185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3313185029Spjd } else { 3314185029Spjd *cp = '\0'; 3315185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3316185029Spjd *cp = '/'; 3317185029Spjd } 3318185029Spjd if (h == NULL) 3319185029Spjd return (-1); 3320185029Spjd zfs_close(h); 3321185029Spjd 3322185029Spjd /* 3323185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 3324185029Spjd * up to the prefixlen-long one. 3325185029Spjd */ 3326185029Spjd for (cp = target + prefixlen + 1; 3327307050Smav (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) { 3328185029Spjd 3329185029Spjd *cp = '\0'; 3330185029Spjd 3331185029Spjd h = make_dataset_handle(hdl, target); 3332185029Spjd if (h) { 3333185029Spjd /* it already exists, nothing to do here */ 3334185029Spjd zfs_close(h); 3335185029Spjd continue; 3336185029Spjd } 3337185029Spjd 3338185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 3339185029Spjd NULL) != 0) { 3340185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 3341185029Spjd goto ancestorerr; 3342185029Spjd } 3343185029Spjd 3344185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3345185029Spjd if (h == NULL) { 3346185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 3347185029Spjd goto ancestorerr; 3348185029Spjd } 3349185029Spjd 3350185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 3351185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 3352185029Spjd goto ancestorerr; 3353185029Spjd } 3354185029Spjd 3355185029Spjd if (zfs_share(h) != 0) { 3356185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 3357185029Spjd goto ancestorerr; 3358185029Spjd } 3359185029Spjd 3360185029Spjd zfs_close(h); 3361185029Spjd } 3362185029Spjd 3363185029Spjd return (0); 3364185029Spjd 3365185029Spjdancestorerr: 3366185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3367185029Spjd "failed to %s ancestor '%s'"), opname, target); 3368185029Spjd return (-1); 3369185029Spjd} 3370185029Spjd 3371185029Spjd/* 3372185029Spjd * Creates non-existing ancestors of the given path. 3373185029Spjd */ 3374185029Spjdint 3375185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3376185029Spjd{ 3377185029Spjd int prefix; 3378185029Spjd char *path_copy; 3379307107Smav int rc = 0; 3380185029Spjd 3381219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3382185029Spjd return (-1); 3383185029Spjd 3384185029Spjd if ((path_copy = strdup(path)) != NULL) { 3385185029Spjd rc = create_parents(hdl, path_copy, prefix); 3386185029Spjd free(path_copy); 3387185029Spjd } 3388185029Spjd if (path_copy == NULL || rc != 0) 3389185029Spjd return (-1); 3390185029Spjd 3391185029Spjd return (0); 3392185029Spjd} 3393185029Spjd 3394185029Spjd/* 3395168404Spjd * Create a new filesystem or volume. 3396168404Spjd */ 3397168404Spjdint 3398168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3399168404Spjd nvlist_t *props) 3400168404Spjd{ 3401168404Spjd int ret; 3402168404Spjd uint64_t size = 0; 3403168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3404168404Spjd char errbuf[1024]; 3405168404Spjd uint64_t zoned; 3406298472Savg enum lzc_dataset_type ost; 3407321576Smav zpool_handle_t *zpool_handle; 3408168404Spjd 3409168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3410168404Spjd "cannot create '%s'"), path); 3411168404Spjd 3412168404Spjd /* validate the path, taking care to note the extended error message */ 3413185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3414168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3415168404Spjd 3416168404Spjd /* validate parents exist */ 3417185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3418168404Spjd return (-1); 3419168404Spjd 3420168404Spjd /* 3421168404Spjd * The failure modes when creating a dataset of a different type over 3422168404Spjd * one that already exists is a little strange. In particular, if you 3423168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3424168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3425168404Spjd * first try to see if the dataset exists. 3426168404Spjd */ 3427248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3428168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3429168404Spjd "dataset already exists")); 3430168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3431168404Spjd } 3432168404Spjd 3433168404Spjd if (type == ZFS_TYPE_VOLUME) 3434298472Savg ost = LZC_DATSET_TYPE_ZVOL; 3435168404Spjd else 3436298472Savg ost = LZC_DATSET_TYPE_ZFS; 3437168404Spjd 3438289500Smav /* open zpool handle for prop validation */ 3439307108Smav char pool_path[ZFS_MAX_DATASET_NAME_LEN]; 3440289500Smav (void) strlcpy(pool_path, path, sizeof (pool_path)); 3441289500Smav 3442289500Smav /* truncate pool_path at first slash */ 3443289500Smav char *p = strchr(pool_path, '/'); 3444289500Smav if (p != NULL) 3445289500Smav *p = '\0'; 3446289500Smav 3447321576Smav if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL) 3448321576Smav return (-1); 3449289500Smav 3450185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3451289500Smav zoned, NULL, zpool_handle, errbuf)) == 0) { 3452289500Smav zpool_close(zpool_handle); 3453168404Spjd return (-1); 3454289500Smav } 3455289500Smav zpool_close(zpool_handle); 3456168404Spjd 3457168404Spjd if (type == ZFS_TYPE_VOLUME) { 3458168404Spjd /* 3459168404Spjd * If we are creating a volume, the size and block size must 3460168404Spjd * satisfy a few restraints. First, the blocksize must be a 3461168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3462168404Spjd * volsize must be a multiple of the block size, and cannot be 3463168404Spjd * zero. 3464168404Spjd */ 3465168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3466168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3467168404Spjd nvlist_free(props); 3468168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3469168404Spjd "missing volume size")); 3470168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3471168404Spjd } 3472168404Spjd 3473168404Spjd if ((ret = nvlist_lookup_uint64(props, 3474168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3475168404Spjd &blocksize)) != 0) { 3476168404Spjd if (ret == ENOENT) { 3477168404Spjd blocksize = zfs_prop_default_numeric( 3478168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3479168404Spjd } else { 3480168404Spjd nvlist_free(props); 3481168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3482168404Spjd "missing volume block size")); 3483168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3484168404Spjd } 3485168404Spjd } 3486168404Spjd 3487168404Spjd if (size == 0) { 3488168404Spjd nvlist_free(props); 3489168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3490168404Spjd "volume size cannot be zero")); 3491168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3492168404Spjd } 3493168404Spjd 3494168404Spjd if (size % blocksize != 0) { 3495168404Spjd nvlist_free(props); 3496168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3497168404Spjd "volume size must be a multiple of volume block " 3498168404Spjd "size")); 3499168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3500168404Spjd } 3501168404Spjd } 3502168404Spjd 3503248571Smm /* create the dataset */ 3504248571Smm ret = lzc_create(path, ost, props); 3505168404Spjd nvlist_free(props); 3506168404Spjd 3507168404Spjd /* check for failure */ 3508168404Spjd if (ret != 0) { 3509307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3510168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3511168404Spjd 3512168404Spjd switch (errno) { 3513168404Spjd case ENOENT: 3514168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3515168404Spjd "no such parent '%s'"), parent); 3516168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3517168404Spjd 3518168404Spjd case EINVAL: 3519168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3520168404Spjd "parent '%s' is not a filesystem"), parent); 3521168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3522168404Spjd 3523185029Spjd case ENOTSUP: 3524185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3525185029Spjd "pool must be upgraded to set this " 3526185029Spjd "property or value")); 3527185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3528329489Smav case ERANGE: 3529329489Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3530329489Smav "invalid property value(s) specified")); 3531329489Smav return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3532168404Spjd#ifdef _ILP32 3533168404Spjd case EOVERFLOW: 3534168404Spjd /* 3535168404Spjd * This platform can't address a volume this big. 3536168404Spjd */ 3537168404Spjd if (type == ZFS_TYPE_VOLUME) 3538168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3539168404Spjd errbuf)); 3540168404Spjd#endif 3541168404Spjd /* FALLTHROUGH */ 3542168404Spjd default: 3543168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3544168404Spjd } 3545168404Spjd } 3546168404Spjd 3547168404Spjd return (0); 3548168404Spjd} 3549168404Spjd 3550168404Spjd/* 3551168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3552238422Smm * isn't mounted, and that there are no active dependents. If the file system 3553238422Smm * does not exist this function does nothing. 3554168404Spjd */ 3555168404Spjdint 3556219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3557168404Spjd{ 3558168404Spjd zfs_cmd_t zc = { 0 }; 3559168404Spjd 3560260183Sdelphij if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3561260183Sdelphij nvlist_t *nv = fnvlist_alloc(); 3562260183Sdelphij fnvlist_add_boolean(nv, zhp->zfs_name); 3563260183Sdelphij int error = lzc_destroy_bookmarks(nv, NULL); 3564260183Sdelphij fnvlist_free(nv); 3565260183Sdelphij if (error != 0) { 3566260183Sdelphij return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3567260183Sdelphij dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3568260183Sdelphij zhp->zfs_name)); 3569260183Sdelphij } 3570260183Sdelphij return (0); 3571260183Sdelphij } 3572260183Sdelphij 3573168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3574168404Spjd 3575168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3576168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3577168404Spjd } else { 3578168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3579168404Spjd } 3580168404Spjd 3581219089Spjd zc.zc_defer_destroy = defer; 3582238422Smm if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && 3583238422Smm errno != ENOENT) { 3584168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3585168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3586168404Spjd zhp->zfs_name)); 3587168404Spjd } 3588168404Spjd 3589168404Spjd remove_mountpoint(zhp); 3590168404Spjd 3591168404Spjd return (0); 3592168404Spjd} 3593168404Spjd 3594168404Spjdstruct destroydata { 3595228103Smm nvlist_t *nvl; 3596228103Smm const char *snapname; 3597168404Spjd}; 3598168404Spjd 3599168404Spjdstatic int 3600219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3601168404Spjd{ 3602168404Spjd struct destroydata *dd = arg; 3603307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3604219089Spjd int rv = 0; 3605168404Spjd 3606228103Smm (void) snprintf(name, sizeof (name), 3607228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3608168404Spjd 3609251646Sdelphij if (lzc_exists(name)) 3610228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3611168404Spjd 3612228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3613228103Smm zfs_close(zhp); 3614168404Spjd return (rv); 3615168404Spjd} 3616168404Spjd 3617168404Spjd/* 3618168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3619168404Spjd */ 3620168404Spjdint 3621219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3622168404Spjd{ 3623168404Spjd int ret; 3624168404Spjd struct destroydata dd = { 0 }; 3625168404Spjd 3626168404Spjd dd.snapname = snapname; 3627228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3628228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3629168404Spjd 3630251646Sdelphij if (nvlist_empty(dd.nvl)) { 3631228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3632168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3633228103Smm zhp->zfs_name, snapname); 3634228103Smm } else { 3635248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3636168404Spjd } 3637228103Smm nvlist_free(dd.nvl); 3638228103Smm return (ret); 3639228103Smm} 3640168404Spjd 3641228103Smm/* 3642248571Smm * Destroys all the snapshots named in the nvlist. 3643228103Smm */ 3644228103Smmint 3645248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3646228103Smm{ 3647228103Smm int ret; 3648307105Smav nvlist_t *errlist = NULL; 3649228103Smm 3650248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3651168404Spjd 3652307105Smav if (ret == 0) { 3653307105Smav nvlist_free(errlist); 3654248571Smm return (0); 3655307105Smav } 3656248571Smm 3657251646Sdelphij if (nvlist_empty(errlist)) { 3658168404Spjd char errbuf[1024]; 3659248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3660248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3661168404Spjd 3662248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3663248571Smm } 3664248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3665248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3666248571Smm char errbuf[1024]; 3667248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3668248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3669248571Smm nvpair_name(pair)); 3670168404Spjd 3671248571Smm switch (fnvpair_value_int32(pair)) { 3672168404Spjd case EEXIST: 3673248571Smm zfs_error_aux(hdl, 3674248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3675248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3676248571Smm break; 3677168404Spjd default: 3678248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3679248571Smm break; 3680168404Spjd } 3681168404Spjd } 3682168404Spjd 3683307105Smav nvlist_free(errlist); 3684248571Smm return (ret); 3685168404Spjd} 3686168404Spjd 3687168404Spjd/* 3688168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3689168404Spjd */ 3690168404Spjdint 3691168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3692168404Spjd{ 3693307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3694168404Spjd int ret; 3695168404Spjd char errbuf[1024]; 3696168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3697168404Spjd uint64_t zoned; 3698168404Spjd 3699168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3700168404Spjd 3701168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3702168404Spjd "cannot create '%s'"), target); 3703168404Spjd 3704228103Smm /* validate the target/clone name */ 3705185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3706168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3707168404Spjd 3708168404Spjd /* validate parents exist */ 3709185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3710168404Spjd return (-1); 3711168404Spjd 3712168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3713168404Spjd 3714168404Spjd /* do the clone */ 3715168404Spjd 3716168404Spjd if (props) { 3717248571Smm zfs_type_t type; 3718248571Smm if (ZFS_IS_VOLUME(zhp)) { 3719248571Smm type = ZFS_TYPE_VOLUME; 3720248571Smm } else { 3721248571Smm type = ZFS_TYPE_FILESYSTEM; 3722248571Smm } 3723185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3724289500Smav zhp, zhp->zpool_hdl, errbuf)) == NULL) 3725168404Spjd return (-1); 3726168404Spjd } 3727168404Spjd 3728248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3729248571Smm nvlist_free(props); 3730168404Spjd 3731168404Spjd if (ret != 0) { 3732168404Spjd switch (errno) { 3733168404Spjd 3734168404Spjd case ENOENT: 3735168404Spjd /* 3736168404Spjd * The parent doesn't exist. We should have caught this 3737168404Spjd * above, but there may a race condition that has since 3738168404Spjd * destroyed the parent. 3739168404Spjd * 3740168404Spjd * At this point, we don't know whether it's the source 3741168404Spjd * that doesn't exist anymore, or whether the target 3742168404Spjd * dataset doesn't exist. 3743168404Spjd */ 3744168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3745168404Spjd "no such parent '%s'"), parent); 3746168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3747168404Spjd 3748168404Spjd case EXDEV: 3749168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3750168404Spjd "source and target pools differ")); 3751168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3752168404Spjd errbuf)); 3753168404Spjd 3754168404Spjd default: 3755168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3756168404Spjd errbuf)); 3757168404Spjd } 3758168404Spjd } 3759168404Spjd 3760168404Spjd return (ret); 3761168404Spjd} 3762168404Spjd 3763168404Spjd/* 3764168404Spjd * Promotes the given clone fs to be the clone parent. 3765168404Spjd */ 3766168404Spjdint 3767168404Spjdzfs_promote(zfs_handle_t *zhp) 3768168404Spjd{ 3769168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3770321577Smav char snapname[ZFS_MAX_DATASET_NAME_LEN]; 3771168404Spjd int ret; 3772168404Spjd char errbuf[1024]; 3773168404Spjd 3774168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3775168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3776168404Spjd 3777168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3778168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3779168404Spjd "snapshots can not be promoted")); 3780168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3781168404Spjd } 3782168404Spjd 3783321577Smav if (zhp->zfs_dmustats.dds_origin[0] == '\0') { 3784168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3785168404Spjd "not a cloned filesystem")); 3786168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3787168404Spjd } 3788168404Spjd 3789321577Smav ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname)); 3790168404Spjd 3791168404Spjd if (ret != 0) { 3792321577Smav switch (ret) { 3793168404Spjd case EEXIST: 3794219089Spjd /* There is a conflicting snapshot name. */ 3795168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3796219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3797321577Smav snapname, zhp->zfs_dmustats.dds_origin); 3798168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3799168404Spjd 3800168404Spjd default: 3801321577Smav return (zfs_standard_error(hdl, ret, errbuf)); 3802168404Spjd } 3803168404Spjd } 3804168404Spjd return (ret); 3805168404Spjd} 3806168404Spjd 3807248571Smmtypedef struct snapdata { 3808248571Smm nvlist_t *sd_nvl; 3809248571Smm const char *sd_snapname; 3810248571Smm} snapdata_t; 3811248571Smm 3812248571Smmstatic int 3813248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3814248571Smm{ 3815248571Smm snapdata_t *sd = arg; 3816307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3817248571Smm int rv = 0; 3818248571Smm 3819253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3820253819Sdelphij (void) snprintf(name, sizeof (name), 3821253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3822248571Smm 3823253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3824248571Smm 3825253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3826253819Sdelphij } 3827248571Smm zfs_close(zhp); 3828253819Sdelphij 3829248571Smm return (rv); 3830248571Smm} 3831248571Smm 3832332525Smavint 3833332525Smavzfs_remap_indirects(libzfs_handle_t *hdl, const char *fs) 3834332525Smav{ 3835332525Smav int err; 3836332525Smav char errbuf[1024]; 3837332525Smav 3838332525Smav (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3839332525Smav "cannot remap filesystem '%s' "), fs); 3840332525Smav 3841332525Smav err = lzc_remap(fs); 3842332525Smav 3843332525Smav if (err != 0) { 3844332525Smav (void) zfs_standard_error(hdl, err, errbuf); 3845332525Smav } 3846332525Smav 3847332525Smav return (err); 3848332525Smav} 3849332525Smav 3850168404Spjd/* 3851248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3852248571Smm * created. 3853168404Spjd */ 3854168404Spjdint 3855248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3856168404Spjd{ 3857168404Spjd int ret; 3858168404Spjd char errbuf[1024]; 3859248571Smm nvpair_t *elem; 3860248571Smm nvlist_t *errors; 3861168404Spjd 3862168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3863248571Smm "cannot create snapshots ")); 3864168404Spjd 3865248571Smm elem = NULL; 3866248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3867248571Smm const char *snapname = nvpair_name(elem); 3868168404Spjd 3869248571Smm /* validate the target name */ 3870248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3871248571Smm B_TRUE)) { 3872248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3873248571Smm dgettext(TEXT_DOMAIN, 3874248571Smm "cannot create snapshot '%s'"), snapname); 3875248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3876248571Smm } 3877248571Smm } 3878185029Spjd 3879289500Smav /* 3880289500Smav * get pool handle for prop validation. assumes all snaps are in the 3881289500Smav * same pool, as does lzc_snapshot (below). 3882289500Smav */ 3883307108Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 3884289500Smav elem = nvlist_next_nvpair(snaps, NULL); 3885289500Smav (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); 3886289500Smav pool[strcspn(pool, "/@")] = '\0'; 3887289500Smav zpool_handle_t *zpool_hdl = zpool_open(hdl, pool); 3888289500Smav 3889248571Smm if (props != NULL && 3890248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3891289500Smav props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) { 3892289500Smav zpool_close(zpool_hdl); 3893248571Smm return (-1); 3894248571Smm } 3895289500Smav zpool_close(zpool_hdl); 3896248571Smm 3897248571Smm ret = lzc_snapshot(snaps, props, &errors); 3898248571Smm 3899248571Smm if (ret != 0) { 3900248571Smm boolean_t printed = B_FALSE; 3901248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 3902248571Smm elem != NULL; 3903248571Smm elem = nvlist_next_nvpair(errors, elem)) { 3904248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3905248571Smm dgettext(TEXT_DOMAIN, 3906248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 3907248571Smm (void) zfs_standard_error(hdl, 3908248571Smm fnvpair_value_int32(elem), errbuf); 3909248571Smm printed = B_TRUE; 3910185029Spjd } 3911248571Smm if (!printed) { 3912248571Smm switch (ret) { 3913248571Smm case EXDEV: 3914248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3915248571Smm "multiple snapshots of same " 3916248571Smm "fs not allowed")); 3917248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3918185029Spjd 3919248571Smm break; 3920248571Smm default: 3921248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 3922248571Smm } 3923248571Smm } 3924185029Spjd } 3925185029Spjd 3926248571Smm nvlist_free(props); 3927248571Smm nvlist_free(errors); 3928248571Smm return (ret); 3929248571Smm} 3930168404Spjd 3931248571Smmint 3932248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3933248571Smm nvlist_t *props) 3934248571Smm{ 3935248571Smm int ret; 3936248571Smm snapdata_t sd = { 0 }; 3937307108Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 3938248571Smm char *cp; 3939248571Smm zfs_handle_t *zhp; 3940248571Smm char errbuf[1024]; 3941248571Smm 3942248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3943248571Smm "cannot snapshot %s"), path); 3944248571Smm 3945248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3946248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3947248571Smm 3948248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 3949248571Smm cp = strchr(fsname, '@'); 3950248571Smm *cp = '\0'; 3951248571Smm sd.sd_snapname = cp + 1; 3952248571Smm 3953248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 3954168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3955168404Spjd return (-1); 3956168404Spjd } 3957168404Spjd 3958248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 3959248571Smm if (recursive) { 3960248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 3961248571Smm } else { 3962248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 3963168404Spjd } 3964168404Spjd 3965248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 3966248571Smm nvlist_free(sd.sd_nvl); 3967168404Spjd zfs_close(zhp); 3968168404Spjd return (ret); 3969168404Spjd} 3970168404Spjd 3971168404Spjd/* 3972168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3973168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3974168404Spjd * is a dependent and we should just destroy it without checking the transaction 3975168404Spjd * group. 3976168404Spjd */ 3977168404Spjdtypedef struct rollback_data { 3978168404Spjd const char *cb_target; /* the snapshot */ 3979168404Spjd uint64_t cb_create; /* creation time reference */ 3980185029Spjd boolean_t cb_error; 3981185029Spjd boolean_t cb_force; 3982168404Spjd} rollback_data_t; 3983168404Spjd 3984168404Spjdstatic int 3985260183Sdelphijrollback_destroy_dependent(zfs_handle_t *zhp, void *data) 3986168404Spjd{ 3987168404Spjd rollback_data_t *cbp = data; 3988260183Sdelphij prop_changelist_t *clp; 3989168404Spjd 3990260183Sdelphij /* We must destroy this clone; first unmount it */ 3991260183Sdelphij clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3992260183Sdelphij cbp->cb_force ? MS_FORCE: 0); 3993260183Sdelphij if (clp == NULL || changelist_prefix(clp) != 0) { 3994260183Sdelphij cbp->cb_error = B_TRUE; 3995260183Sdelphij zfs_close(zhp); 3996260183Sdelphij return (0); 3997260183Sdelphij } 3998260183Sdelphij if (zfs_destroy(zhp, B_FALSE) != 0) 3999260183Sdelphij cbp->cb_error = B_TRUE; 4000260183Sdelphij else 4001260183Sdelphij changelist_remove(clp, zhp->zfs_name); 4002260183Sdelphij (void) changelist_postfix(clp); 4003260183Sdelphij changelist_free(clp); 4004168404Spjd 4005260183Sdelphij zfs_close(zhp); 4006260183Sdelphij return (0); 4007260183Sdelphij} 4008168404Spjd 4009260183Sdelphijstatic int 4010260183Sdelphijrollback_destroy(zfs_handle_t *zhp, void *data) 4011260183Sdelphij{ 4012260183Sdelphij rollback_data_t *cbp = data; 4013185029Spjd 4014260183Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 4015260183Sdelphij cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 4016260183Sdelphij rollback_destroy_dependent, cbp); 4017260183Sdelphij 4018260183Sdelphij cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 4019168404Spjd } 4020168404Spjd 4021168404Spjd zfs_close(zhp); 4022168404Spjd return (0); 4023168404Spjd} 4024168404Spjd 4025168404Spjd/* 4026168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 4027168404Spjd * data changes since then and making it the active dataset. 4028168404Spjd * 4029260183Sdelphij * Any snapshots and bookmarks more recent than the target are 4030260183Sdelphij * destroyed, along with their dependents (i.e. clones). 4031168404Spjd */ 4032168404Spjdint 4033185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 4034168404Spjd{ 4035168404Spjd rollback_data_t cb = { 0 }; 4036185029Spjd int err; 4037185029Spjd boolean_t restore_resv = 0; 4038307107Smav uint64_t old_volsize = 0, new_volsize; 4039185029Spjd zfs_prop_t resv_prop; 4040168404Spjd 4041185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 4042185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 4043168404Spjd 4044168404Spjd /* 4045239774Smm * Destroy all recent snapshots and their dependents. 4046168404Spjd */ 4047185029Spjd cb.cb_force = force; 4048168404Spjd cb.cb_target = snap->zfs_name; 4049168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 4050260183Sdelphij (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb); 4051260183Sdelphij (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); 4052168404Spjd 4053185029Spjd if (cb.cb_error) 4054185029Spjd return (-1); 4055168404Spjd 4056168404Spjd /* 4057168404Spjd * Now that we have verified that the snapshot is the latest, 4058168404Spjd * rollback to the given snapshot. 4059168404Spjd */ 4060168404Spjd 4061185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 4062185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 4063185029Spjd return (-1); 4064185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4065185029Spjd restore_resv = 4066185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 4067168404Spjd } 4068168404Spjd 4069168404Spjd /* 4070323757Savg * Pass both the filesystem and the wanted snapshot names, 4071323757Savg * we would get an error back if the snapshot is destroyed or 4072323757Savg * a new snapshot is created before this request is processed. 4073168404Spjd */ 4074323757Savg err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name); 4075330590Savg if (err != 0) { 4076330590Savg char errbuf[1024]; 4077330590Savg 4078330590Savg (void) snprintf(errbuf, sizeof (errbuf), 4079323757Savg dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 4080323757Savg zhp->zfs_name); 4081330590Savg switch (err) { 4082330590Savg case EEXIST: 4083330590Savg zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4084330590Savg "there is a snapshot or bookmark more recent " 4085330590Savg "than '%s'"), snap->zfs_name); 4086330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf); 4087330590Savg break; 4088330590Savg case ESRCH: 4089330590Savg zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4090330590Savg "'%s' is not found among snapshots of '%s'"), 4091330590Savg snap->zfs_name, zhp->zfs_name); 4092330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf); 4093330590Savg break; 4094330590Savg case EINVAL: 4095330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf); 4096330590Savg break; 4097330590Savg default: 4098330590Savg (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf); 4099330590Savg } 4100323757Savg return (err); 4101185029Spjd } 4102168404Spjd 4103185029Spjd /* 4104185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 4105185029Spjd * rollback reservation and the volsize has changed then set 4106185029Spjd * the reservation property to the post-rollback volsize. 4107185029Spjd * Make a new handle since the rollback closed the dataset. 4108185029Spjd */ 4109185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 4110185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 4111185029Spjd if (restore_resv) { 4112185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4113185029Spjd if (old_volsize != new_volsize) 4114185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 4115185029Spjd new_volsize); 4116185029Spjd } 4117185029Spjd zfs_close(zhp); 4118185029Spjd } 4119185029Spjd return (err); 4120168404Spjd} 4121168404Spjd 4122168404Spjd/* 4123168404Spjd * Renames the given dataset. 4124168404Spjd */ 4125168404Spjdint 4126240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 4127240870Spjd renameflags_t flags) 4128168404Spjd{ 4129307050Smav int ret = 0; 4130168404Spjd zfs_cmd_t zc = { 0 }; 4131168404Spjd char *delim; 4132168676Spjd prop_changelist_t *cl = NULL; 4133168676Spjd zfs_handle_t *zhrp = NULL; 4134168676Spjd char *parentname = NULL; 4135307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 4136226676Spjd char property[ZFS_MAXPROPLEN]; 4137168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4138168404Spjd char errbuf[1024]; 4139168404Spjd 4140168404Spjd /* if we have the same exact name, just return success */ 4141168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 4142168404Spjd return (0); 4143168404Spjd 4144168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4145168404Spjd "cannot rename to '%s'"), target); 4146168404Spjd 4147240870Spjd if (source != NULL) { 4148240870Spjd /* 4149240870Spjd * This is recursive snapshots rename, put snapshot name 4150240870Spjd * (that might not exist) into zfs_name. 4151240870Spjd */ 4152240870Spjd assert(flags.recurse); 4153240870Spjd 4154240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 4155240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 4156240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 4157240870Spjd } 4158240870Spjd 4159168404Spjd /* 4160168404Spjd * Make sure the target name is valid 4161168404Spjd */ 4162168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 4163168404Spjd if ((strchr(target, '@') == NULL) || 4164168404Spjd *target == '@') { 4165168404Spjd /* 4166168404Spjd * Snapshot target name is abbreviated, 4167168404Spjd * reconstruct full dataset name 4168168404Spjd */ 4169168404Spjd (void) strlcpy(parent, zhp->zfs_name, 4170168404Spjd sizeof (parent)); 4171168404Spjd delim = strchr(parent, '@'); 4172168404Spjd if (strchr(target, '@') == NULL) 4173168404Spjd *(++delim) = '\0'; 4174168404Spjd else 4175168404Spjd *delim = '\0'; 4176168404Spjd (void) strlcat(parent, target, sizeof (parent)); 4177168404Spjd target = parent; 4178168404Spjd } else { 4179168404Spjd /* 4180168404Spjd * Make sure we're renaming within the same dataset. 4181168404Spjd */ 4182168404Spjd delim = strchr(target, '@'); 4183168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 4184168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 4185168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4186168404Spjd "snapshots must be part of same " 4187168404Spjd "dataset")); 4188168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 4189168404Spjd errbuf)); 4190168404Spjd } 4191168404Spjd } 4192185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4193168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4194168404Spjd } else { 4195226705Spjd if (flags.recurse) { 4196168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4197168676Spjd "recursive rename must be a snapshot")); 4198168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4199168676Spjd } 4200168676Spjd 4201185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4202168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4203168404Spjd 4204168404Spjd /* validate parents */ 4205219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 4206168404Spjd return (-1); 4207168404Spjd 4208168404Spjd /* make sure we're in the same pool */ 4209168404Spjd verify((delim = strchr(target, '/')) != NULL); 4210168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 4211168404Spjd zhp->zfs_name[delim - target] != '/') { 4212168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4213168404Spjd "datasets must be within same pool")); 4214168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 4215168404Spjd } 4216168404Spjd 4217168404Spjd /* new name cannot be a child of the current dataset name */ 4218219089Spjd if (is_descendant(zhp->zfs_name, target)) { 4219168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4220219089Spjd "New dataset name cannot be a descendant of " 4221168404Spjd "current dataset name")); 4222168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4223168404Spjd } 4224168404Spjd } 4225168404Spjd 4226168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4227168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 4228168404Spjd 4229168404Spjd if (getzoneid() == GLOBAL_ZONEID && 4230168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 4231168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4232168404Spjd "dataset is used in a non-global zone")); 4233168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 4234168404Spjd } 4235168404Spjd 4236226705Spjd /* 4237226705Spjd * Avoid unmounting file systems with mountpoint property set to 4238226705Spjd * 'legacy' or 'none' even if -u option is not given. 4239226705Spjd */ 4240226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 4241226705Spjd !flags.recurse && !flags.nounmount && 4242226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 4243226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 4244226705Spjd (strcmp(property, "legacy") == 0 || 4245226705Spjd strcmp(property, "none") == 0)) { 4246226705Spjd flags.nounmount = B_TRUE; 4247226705Spjd } 4248226705Spjd if (flags.recurse) { 4249226705Spjd 4250185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 4251185029Spjd if (parentname == NULL) { 4252185029Spjd ret = -1; 4253185029Spjd goto error; 4254185029Spjd } 4255168676Spjd delim = strchr(parentname, '@'); 4256168676Spjd *delim = '\0'; 4257185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 4258168676Spjd if (zhrp == NULL) { 4259185029Spjd ret = -1; 4260185029Spjd goto error; 4261168676Spjd } 4262268469Sdelphij } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { 4263226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 4264235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 4265235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 4266168676Spjd return (-1); 4267226676Spjd } 4268168676Spjd 4269168676Spjd if (changelist_haszonedchild(cl)) { 4270168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4271168676Spjd "child dataset with inherited mountpoint is used " 4272168676Spjd "in a non-global zone")); 4273168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 4274307107Smav ret = -1; 4275168676Spjd goto error; 4276168676Spjd } 4277168676Spjd 4278168676Spjd if ((ret = changelist_prefix(cl)) != 0) 4279168676Spjd goto error; 4280168404Spjd } 4281168404Spjd 4282168404Spjd if (ZFS_IS_VOLUME(zhp)) 4283168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 4284168404Spjd else 4285168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4286168404Spjd 4287168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4288168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 4289168404Spjd 4290226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 4291226705Spjd if (flags.nounmount) 4292226676Spjd zc.zc_cookie |= 2; 4293168676Spjd 4294185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 4295168676Spjd /* 4296168676Spjd * if it was recursive, the one that actually failed will 4297168676Spjd * be in zc.zc_name 4298168676Spjd */ 4299168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4300185029Spjd "cannot rename '%s'"), zc.zc_name); 4301168404Spjd 4302226705Spjd if (flags.recurse && errno == EEXIST) { 4303168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4304168676Spjd "a child dataset already has a snapshot " 4305168676Spjd "with the new name")); 4306185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4307168676Spjd } else { 4308168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 4309168676Spjd } 4310168676Spjd 4311168404Spjd /* 4312168404Spjd * On failure, we still want to remount any filesystems that 4313168404Spjd * were previously mounted, so we don't alter the system state. 4314168404Spjd */ 4315268469Sdelphij if (cl != NULL) 4316168676Spjd (void) changelist_postfix(cl); 4317168404Spjd } else { 4318268469Sdelphij if (cl != NULL) { 4319168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 4320168676Spjd ret = changelist_postfix(cl); 4321168676Spjd } 4322168404Spjd } 4323168404Spjd 4324168404Spjderror: 4325268469Sdelphij if (parentname != NULL) { 4326168676Spjd free(parentname); 4327168676Spjd } 4328268469Sdelphij if (zhrp != NULL) { 4329168676Spjd zfs_close(zhrp); 4330168676Spjd } 4331268469Sdelphij if (cl != NULL) { 4332168676Spjd changelist_free(cl); 4333168676Spjd } 4334168404Spjd return (ret); 4335168404Spjd} 4336168404Spjd 4337219089Spjdnvlist_t * 4338219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 4339168404Spjd{ 4340219089Spjd return (zhp->zfs_user_props); 4341168676Spjd} 4342168676Spjd 4343168404Spjdnvlist_t * 4344219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 4345168404Spjd{ 4346219089Spjd if (zhp->zfs_recvd_props == NULL) 4347219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 4348219089Spjd return (NULL); 4349219089Spjd return (zhp->zfs_recvd_props); 4350168404Spjd} 4351168404Spjd 4352168404Spjd/* 4353168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 4354168404Spjd * display, and their maximum widths. This does two main things: 4355168404Spjd * 4356168404Spjd * - If this is a list of all properties, then expand the list to include 4357168404Spjd * all native properties, and set a flag so that for each dataset we look 4358168404Spjd * for new unique user properties and add them to the list. 4359168404Spjd * 4360168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 4361219089Spjd * so that we can size the column appropriately. If the user has 4362219089Spjd * requested received property values, we also need to compute the width 4363219089Spjd * of the RECEIVED column. 4364168404Spjd */ 4365168404Spjdint 4366259850Sdelphijzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 4367259850Sdelphij boolean_t literal) 4368168404Spjd{ 4369168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4370185029Spjd zprop_list_t *entry; 4371185029Spjd zprop_list_t **last, **start; 4372168404Spjd nvlist_t *userprops, *propval; 4373168404Spjd nvpair_t *elem; 4374168404Spjd char *strval; 4375168404Spjd char buf[ZFS_MAXPROPLEN]; 4376168404Spjd 4377185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 4378168404Spjd return (-1); 4379168404Spjd 4380168404Spjd userprops = zfs_get_user_props(zhp); 4381168404Spjd 4382168404Spjd entry = *plp; 4383168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4384168404Spjd /* 4385168404Spjd * Go through and add any user properties as necessary. We 4386168404Spjd * start by incrementing our list pointer to the first 4387168404Spjd * non-native property. 4388168404Spjd */ 4389168404Spjd start = plp; 4390168404Spjd while (*start != NULL) { 4391185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 4392168404Spjd break; 4393168404Spjd start = &(*start)->pl_next; 4394168404Spjd } 4395168404Spjd 4396168404Spjd elem = NULL; 4397168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4398168404Spjd /* 4399168404Spjd * See if we've already found this property in our list. 4400168404Spjd */ 4401168404Spjd for (last = start; *last != NULL; 4402168404Spjd last = &(*last)->pl_next) { 4403168404Spjd if (strcmp((*last)->pl_user_prop, 4404168404Spjd nvpair_name(elem)) == 0) 4405168404Spjd break; 4406168404Spjd } 4407168404Spjd 4408168404Spjd if (*last == NULL) { 4409168404Spjd if ((entry = zfs_alloc(hdl, 4410185029Spjd sizeof (zprop_list_t))) == NULL || 4411168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 4412168404Spjd nvpair_name(elem)))) == NULL) { 4413168404Spjd free(entry); 4414168404Spjd return (-1); 4415168404Spjd } 4416168404Spjd 4417185029Spjd entry->pl_prop = ZPROP_INVAL; 4418168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 4419168404Spjd entry->pl_all = B_TRUE; 4420168404Spjd *last = entry; 4421168404Spjd } 4422168404Spjd } 4423168404Spjd } 4424168404Spjd 4425168404Spjd /* 4426168404Spjd * Now go through and check the width of any non-fixed columns 4427168404Spjd */ 4428168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4429259850Sdelphij if (entry->pl_fixed && !literal) 4430168404Spjd continue; 4431168404Spjd 4432185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 4433168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 4434259850Sdelphij buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4435168404Spjd if (strlen(buf) > entry->pl_width) 4436168404Spjd entry->pl_width = strlen(buf); 4437168404Spjd } 4438219089Spjd if (received && zfs_prop_get_recvd(zhp, 4439219089Spjd zfs_prop_to_name(entry->pl_prop), 4440259850Sdelphij buf, sizeof (buf), literal) == 0) 4441219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4442219089Spjd entry->pl_recvd_width = strlen(buf); 4443219089Spjd } else { 4444219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4445219089Spjd &propval) == 0) { 4446219089Spjd verify(nvlist_lookup_string(propval, 4447219089Spjd ZPROP_VALUE, &strval) == 0); 4448219089Spjd if (strlen(strval) > entry->pl_width) 4449219089Spjd entry->pl_width = strlen(strval); 4450219089Spjd } 4451219089Spjd if (received && zfs_prop_get_recvd(zhp, 4452219089Spjd entry->pl_user_prop, 4453259850Sdelphij buf, sizeof (buf), literal) == 0) 4454219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4455219089Spjd entry->pl_recvd_width = strlen(buf); 4456168404Spjd } 4457168404Spjd } 4458168404Spjd 4459168404Spjd return (0); 4460168404Spjd} 4461168404Spjd 4462185029Spjdint 4463185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4464209962Smm char *resource, void *export, void *sharetab, 4465209962Smm int sharemax, zfs_share_op_t operation) 4466185029Spjd{ 4467185029Spjd zfs_cmd_t zc = { 0 }; 4468185029Spjd int error; 4469185029Spjd 4470185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4471185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4472209962Smm if (resource) 4473209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4474185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4475185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4476185029Spjd zc.zc_share.z_sharetype = operation; 4477185029Spjd zc.zc_share.z_sharemax = sharemax; 4478185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4479185029Spjd return (error); 4480185029Spjd} 4481185029Spjd 4482205198Sdelphijvoid 4483205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4484205198Sdelphij{ 4485205198Sdelphij nvpair_t *curr; 4486205198Sdelphij 4487205198Sdelphij /* 4488205198Sdelphij * Keep a reference to the props-table against which we prune the 4489205198Sdelphij * properties. 4490205198Sdelphij */ 4491205198Sdelphij zhp->zfs_props_table = props; 4492205198Sdelphij 4493205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4494205198Sdelphij 4495205198Sdelphij while (curr) { 4496205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4497205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4498205198Sdelphij 4499206199Sdelphij /* 4500219089Spjd * User properties will result in ZPROP_INVAL, and since we 4501219089Spjd * only know how to prune standard ZFS properties, we always 4502219089Spjd * leave these in the list. This can also happen if we 4503219089Spjd * encounter an unknown DSL property (when running older 4504219089Spjd * software, for example). 4505206199Sdelphij */ 4506206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4507205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4508205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4509205198Sdelphij curr = next; 4510205198Sdelphij } 4511205198Sdelphij} 4512205198Sdelphij 4513277300Ssmh#ifdef illumos 4514209962Smmstatic int 4515209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4516209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4517209962Smm{ 4518209962Smm zfs_cmd_t zc = { 0 }; 4519209962Smm nvlist_t *nvlist = NULL; 4520209962Smm int error; 4521209962Smm 4522209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4523209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4524209962Smm zc.zc_cookie = (uint64_t)cmd; 4525209962Smm 4526209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4527209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4528209962Smm (void) no_memory(hdl); 4529289497Smav return (0); 4530209962Smm } 4531209962Smm } 4532209962Smm 4533209962Smm switch (cmd) { 4534209962Smm case ZFS_SMB_ACL_ADD: 4535209962Smm case ZFS_SMB_ACL_REMOVE: 4536209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4537209962Smm break; 4538209962Smm case ZFS_SMB_ACL_RENAME: 4539209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4540209962Smm resource1) != 0) { 4541209962Smm (void) no_memory(hdl); 4542209962Smm return (-1); 4543209962Smm } 4544209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4545209962Smm resource2) != 0) { 4546209962Smm (void) no_memory(hdl); 4547209962Smm return (-1); 4548209962Smm } 4549209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4550209962Smm nvlist_free(nvlist); 4551209962Smm return (-1); 4552209962Smm } 4553209962Smm break; 4554209962Smm case ZFS_SMB_ACL_PURGE: 4555209962Smm break; 4556209962Smm default: 4557209962Smm return (-1); 4558209962Smm } 4559209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4560296528Smav nvlist_free(nvlist); 4561209962Smm return (error); 4562209962Smm} 4563209962Smm 4564209962Smmint 4565209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4566209962Smm char *path, char *resource) 4567209962Smm{ 4568209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4569209962Smm resource, NULL)); 4570209962Smm} 4571209962Smm 4572209962Smmint 4573209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4574209962Smm char *path, char *resource) 4575209962Smm{ 4576209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4577209962Smm resource, NULL)); 4578209962Smm} 4579209962Smm 4580209962Smmint 4581209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4582209962Smm{ 4583209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4584209962Smm NULL, NULL)); 4585209962Smm} 4586209962Smm 4587209962Smmint 4588209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4589209962Smm char *oldname, char *newname) 4590209962Smm{ 4591209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4592209962Smm oldname, newname)); 4593209962Smm} 4594277300Ssmh#endif /* illumos */ 4595209962Smm 4596209962Smmint 4597209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4598209962Smm zfs_userspace_cb_t func, void *arg) 4599209962Smm{ 4600209962Smm zfs_cmd_t zc = { 0 }; 4601209962Smm zfs_useracct_t buf[100]; 4602240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4603240415Smm int ret; 4604209962Smm 4605228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4606209962Smm 4607209962Smm zc.zc_objset_type = type; 4608209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4609209962Smm 4610240415Smm for (;;) { 4611209962Smm zfs_useracct_t *zua = buf; 4612209962Smm 4613209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4614240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4615248571Smm char errbuf[1024]; 4616240415Smm 4617240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4618240415Smm dgettext(TEXT_DOMAIN, 4619240415Smm "cannot get used/quota for %s"), zc.zc_name); 4620240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4621240415Smm } 4622240415Smm if (zc.zc_nvlist_dst_size == 0) 4623209962Smm break; 4624209962Smm 4625209962Smm while (zc.zc_nvlist_dst_size > 0) { 4626240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4627240415Smm zua->zu_space)) != 0) 4628240415Smm return (ret); 4629209962Smm zua++; 4630209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4631209962Smm } 4632209962Smm } 4633209962Smm 4634240415Smm return (0); 4635209962Smm} 4636209962Smm 4637248571Smmstruct holdarg { 4638248571Smm nvlist_t *nvl; 4639248571Smm const char *snapname; 4640248571Smm const char *tag; 4641248571Smm boolean_t recursive; 4642252219Sdelphij int error; 4643248571Smm}; 4644248571Smm 4645248571Smmstatic int 4646248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4647248571Smm{ 4648248571Smm struct holdarg *ha = arg; 4649307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4650248571Smm int rv = 0; 4651248571Smm 4652248571Smm (void) snprintf(name, sizeof (name), 4653248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4654248571Smm 4655251646Sdelphij if (lzc_exists(name)) 4656248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4657248571Smm 4658248571Smm if (ha->recursive) 4659248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4660248571Smm zfs_close(zhp); 4661248571Smm return (rv); 4662248571Smm} 4663248571Smm 4664219089Spjdint 4665219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4666251646Sdelphij boolean_t recursive, int cleanup_fd) 4667219089Spjd{ 4668248571Smm int ret; 4669248571Smm struct holdarg ha; 4670219089Spjd 4671248571Smm ha.nvl = fnvlist_alloc(); 4672248571Smm ha.snapname = snapname; 4673248571Smm ha.tag = tag; 4674248571Smm ha.recursive = recursive; 4675248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4676249357Smm 4677251646Sdelphij if (nvlist_empty(ha.nvl)) { 4678251646Sdelphij char errbuf[1024]; 4679251646Sdelphij 4680249357Smm fnvlist_free(ha.nvl); 4681249357Smm ret = ENOENT; 4682251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4683251646Sdelphij dgettext(TEXT_DOMAIN, 4684251646Sdelphij "cannot hold snapshot '%s@%s'"), 4685251646Sdelphij zhp->zfs_name, snapname); 4686251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4687249357Smm return (ret); 4688249357Smm } 4689249357Smm 4690251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4691248571Smm fnvlist_free(ha.nvl); 4692219089Spjd 4693251646Sdelphij return (ret); 4694251646Sdelphij} 4695251646Sdelphij 4696251646Sdelphijint 4697251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4698251646Sdelphij{ 4699251646Sdelphij int ret; 4700251646Sdelphij nvlist_t *errors; 4701251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4702251646Sdelphij char errbuf[1024]; 4703251646Sdelphij nvpair_t *elem; 4704251646Sdelphij 4705251646Sdelphij errors = NULL; 4706251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4707251646Sdelphij 4708251646Sdelphij if (ret == 0) { 4709251646Sdelphij /* There may be errors even in the success case. */ 4710251646Sdelphij fnvlist_free(errors); 4711248571Smm return (0); 4712251646Sdelphij } 4713219089Spjd 4714251646Sdelphij if (nvlist_empty(errors)) { 4715248571Smm /* no hold-specific errors */ 4716248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4717248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4718248571Smm switch (ret) { 4719248571Smm case ENOTSUP: 4720248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4721248571Smm "pool must be upgraded")); 4722248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4723248571Smm break; 4724248571Smm case EINVAL: 4725248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4726248571Smm break; 4727248571Smm default: 4728248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4729248571Smm } 4730248571Smm } 4731219089Spjd 4732248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4733248571Smm elem != NULL; 4734248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4735248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4736248571Smm dgettext(TEXT_DOMAIN, 4737248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4738248571Smm switch (fnvpair_value_int32(elem)) { 4739219089Spjd case E2BIG: 4740219089Spjd /* 4741219089Spjd * Temporary tags wind up having the ds object id 4742219089Spjd * prepended. So even if we passed the length check 4743219089Spjd * above, it's still possible for the tag to wind 4744219089Spjd * up being slightly too long. 4745219089Spjd */ 4746248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4747248571Smm break; 4748219089Spjd case EINVAL: 4749248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4750248571Smm break; 4751219089Spjd case EEXIST: 4752248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4753248571Smm break; 4754219089Spjd default: 4755248571Smm (void) zfs_standard_error(hdl, 4756248571Smm fnvpair_value_int32(elem), errbuf); 4757219089Spjd } 4758219089Spjd } 4759219089Spjd 4760248571Smm fnvlist_free(errors); 4761248571Smm return (ret); 4762219089Spjd} 4763219089Spjd 4764248571Smmstatic int 4765248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4766248571Smm{ 4767248571Smm struct holdarg *ha = arg; 4768307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4769248571Smm int rv = 0; 4770252219Sdelphij nvlist_t *existing_holds; 4771248571Smm 4772248571Smm (void) snprintf(name, sizeof (name), 4773248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4774248571Smm 4775252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4776252219Sdelphij ha->error = ENOENT; 4777252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4778252219Sdelphij ha->error = ESRCH; 4779252219Sdelphij } else { 4780252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4781252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4782252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4783252219Sdelphij fnvlist_free(torelease); 4784248571Smm } 4785248571Smm 4786248571Smm if (ha->recursive) 4787248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4788248571Smm zfs_close(zhp); 4789248571Smm return (rv); 4790248571Smm} 4791248571Smm 4792219089Spjdint 4793219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4794219089Spjd boolean_t recursive) 4795219089Spjd{ 4796248571Smm int ret; 4797248571Smm struct holdarg ha; 4798251646Sdelphij nvlist_t *errors = NULL; 4799248571Smm nvpair_t *elem; 4800219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4801249357Smm char errbuf[1024]; 4802219089Spjd 4803248571Smm ha.nvl = fnvlist_alloc(); 4804248571Smm ha.snapname = snapname; 4805248571Smm ha.tag = tag; 4806248571Smm ha.recursive = recursive; 4807252219Sdelphij ha.error = 0; 4808248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4809249357Smm 4810251646Sdelphij if (nvlist_empty(ha.nvl)) { 4811249357Smm fnvlist_free(ha.nvl); 4812252219Sdelphij ret = ha.error; 4813249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4814249357Smm dgettext(TEXT_DOMAIN, 4815249357Smm "cannot release hold from snapshot '%s@%s'"), 4816249357Smm zhp->zfs_name, snapname); 4817252219Sdelphij if (ret == ESRCH) { 4818252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4819252219Sdelphij } else { 4820252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4821252219Sdelphij } 4822249357Smm return (ret); 4823249357Smm } 4824249357Smm 4825248571Smm ret = lzc_release(ha.nvl, &errors); 4826248571Smm fnvlist_free(ha.nvl); 4827219089Spjd 4828251646Sdelphij if (ret == 0) { 4829251646Sdelphij /* There may be errors even in the success case. */ 4830251646Sdelphij fnvlist_free(errors); 4831248571Smm return (0); 4832251646Sdelphij } 4833219089Spjd 4834251646Sdelphij if (nvlist_empty(errors)) { 4835248571Smm /* no hold-specific errors */ 4836219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4837248571Smm "cannot release")); 4838219089Spjd switch (errno) { 4839219089Spjd case ENOTSUP: 4840219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4841219089Spjd "pool must be upgraded")); 4842248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4843248571Smm break; 4844248571Smm default: 4845248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4846248571Smm } 4847248571Smm } 4848248571Smm 4849248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4850248571Smm elem != NULL; 4851248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4852248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4853248571Smm dgettext(TEXT_DOMAIN, 4854248571Smm "cannot release hold from snapshot '%s'"), 4855248571Smm nvpair_name(elem)); 4856248571Smm switch (fnvpair_value_int32(elem)) { 4857248571Smm case ESRCH: 4858248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4859248571Smm break; 4860219089Spjd case EINVAL: 4861248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4862248571Smm break; 4863219089Spjd default: 4864248571Smm (void) zfs_standard_error_fmt(hdl, 4865248571Smm fnvpair_value_int32(elem), errbuf); 4866219089Spjd } 4867219089Spjd } 4868219089Spjd 4869248571Smm fnvlist_free(errors); 4870248571Smm return (ret); 4871219089Spjd} 4872219089Spjd 4873219089Spjdint 4874219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4875219089Spjd{ 4876219089Spjd zfs_cmd_t zc = { 0 }; 4877219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4878219089Spjd int nvsz = 2048; 4879219089Spjd void *nvbuf; 4880219089Spjd int err = 0; 4881248571Smm char errbuf[1024]; 4882219089Spjd 4883219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4884219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4885219089Spjd 4886219089Spjdtryagain: 4887219089Spjd 4888219089Spjd nvbuf = malloc(nvsz); 4889219089Spjd if (nvbuf == NULL) { 4890219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4891219089Spjd goto out; 4892219089Spjd } 4893219089Spjd 4894219089Spjd zc.zc_nvlist_dst_size = nvsz; 4895219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4896219089Spjd 4897307108Smav (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4898219089Spjd 4899230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 4900219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4901219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4902219089Spjd zc.zc_name); 4903219089Spjd switch (errno) { 4904219089Spjd case ENOMEM: 4905219089Spjd free(nvbuf); 4906219089Spjd nvsz = zc.zc_nvlist_dst_size; 4907219089Spjd goto tryagain; 4908219089Spjd 4909219089Spjd case ENOTSUP: 4910219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4911219089Spjd "pool must be upgraded")); 4912219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4913219089Spjd break; 4914219089Spjd case EINVAL: 4915219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4916219089Spjd break; 4917219089Spjd case ENOENT: 4918219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4919219089Spjd break; 4920219089Spjd default: 4921219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4922219089Spjd break; 4923219089Spjd } 4924219089Spjd } else { 4925219089Spjd /* success */ 4926219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4927219089Spjd if (rc) { 4928219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4929219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4930219089Spjd zc.zc_name); 4931219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4932219089Spjd } 4933219089Spjd } 4934219089Spjd 4935219089Spjd free(nvbuf); 4936219089Spjdout: 4937219089Spjd return (err); 4938219089Spjd} 4939219089Spjd 4940219089Spjdint 4941219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4942219089Spjd{ 4943219089Spjd zfs_cmd_t zc = { 0 }; 4944219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4945219089Spjd char *nvbuf; 4946248571Smm char errbuf[1024]; 4947219089Spjd size_t nvsz; 4948219089Spjd int err; 4949219089Spjd 4950219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4951219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4952219089Spjd 4953219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4954219089Spjd assert(err == 0); 4955219089Spjd 4956219089Spjd nvbuf = malloc(nvsz); 4957219089Spjd 4958219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4959219089Spjd assert(err == 0); 4960219089Spjd 4961219089Spjd zc.zc_nvlist_src_size = nvsz; 4962219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4963219089Spjd zc.zc_perm_action = un; 4964219089Spjd 4965219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4966219089Spjd 4967219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4968219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4969219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4970219089Spjd zc.zc_name); 4971219089Spjd switch (errno) { 4972219089Spjd case ENOTSUP: 4973219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4974219089Spjd "pool must be upgraded")); 4975219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4976219089Spjd break; 4977219089Spjd case EINVAL: 4978219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4979219089Spjd break; 4980219089Spjd case ENOENT: 4981219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4982219089Spjd break; 4983219089Spjd default: 4984219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4985219089Spjd break; 4986219089Spjd } 4987219089Spjd } 4988219089Spjd 4989219089Spjd free(nvbuf); 4990219089Spjd 4991219089Spjd return (err); 4992219089Spjd} 4993219089Spjd 4994219089Spjdint 4995219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4996219089Spjd{ 4997248571Smm int err; 4998248571Smm char errbuf[1024]; 4999219089Spjd 5000248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 5001219089Spjd 5002248571Smm if (err != 0) { 5003248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 5004219089Spjd 5005219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 5006219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 5007248571Smm zhp->zfs_name); 5008248571Smm switch (err) { 5009219089Spjd case ENOTSUP: 5010219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5011219089Spjd "pool must be upgraded")); 5012219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5013219089Spjd break; 5014219089Spjd case EINVAL: 5015219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5016219089Spjd break; 5017219089Spjd case ENOENT: 5018219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 5019219089Spjd break; 5020219089Spjd default: 5021219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 5022219089Spjd break; 5023219089Spjd } 5024219089Spjd } 5025219089Spjd 5026219089Spjd return (err); 5027219089Spjd} 5028219089Spjd 5029251629Sdelphij/* 5030251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 5031251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 5032251629Sdelphij * suite's shell version in reservation.kshlib. 5033251629Sdelphij */ 5034219089Spjduint64_t 5035219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 5036219089Spjd{ 5037219089Spjd uint64_t numdb; 5038219089Spjd uint64_t nblocks, volblocksize; 5039219089Spjd int ncopies; 5040219089Spjd char *strval; 5041219089Spjd 5042219089Spjd if (nvlist_lookup_string(props, 5043219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 5044219089Spjd ncopies = atoi(strval); 5045219089Spjd else 5046219089Spjd ncopies = 1; 5047219089Spjd if (nvlist_lookup_uint64(props, 5048219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 5049219089Spjd &volblocksize) != 0) 5050219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 5051219089Spjd nblocks = volsize/volblocksize; 5052219089Spjd /* start with metadnode L0-L6 */ 5053219089Spjd numdb = 7; 5054219089Spjd /* calculate number of indirects */ 5055219089Spjd while (nblocks > 1) { 5056219089Spjd nblocks += DNODES_PER_LEVEL - 1; 5057219089Spjd nblocks /= DNODES_PER_LEVEL; 5058219089Spjd numdb += nblocks; 5059219089Spjd } 5060219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 5061219089Spjd volsize *= ncopies; 5062219089Spjd /* 5063219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 5064219089Spjd * compressed, but in practice they compress down to about 5065219089Spjd * 1100 bytes 5066219089Spjd */ 5067219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 5068219089Spjd volsize += numdb; 5069219089Spjd return (volsize); 5070219089Spjd} 5071219089Spjd 5072168404Spjd/* 5073168404Spjd * Attach/detach the given filesystem to/from the given jail. 5074168404Spjd */ 5075168404Spjdint 5076168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 5077168404Spjd{ 5078168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 5079168404Spjd zfs_cmd_t zc = { 0 }; 5080168404Spjd char errbuf[1024]; 5081224525Smm unsigned long cmd; 5082224525Smm int ret; 5083168404Spjd 5084168404Spjd if (attach) { 5085168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 5086168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 5087168404Spjd } else { 5088168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 5089249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 5090168404Spjd } 5091168404Spjd 5092168404Spjd switch (zhp->zfs_type) { 5093168404Spjd case ZFS_TYPE_VOLUME: 5094168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5095168404Spjd "volumes can not be jailed")); 5096168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 5097168404Spjd case ZFS_TYPE_SNAPSHOT: 5098168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5099168404Spjd "snapshots can not be jailed")); 5100168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 5101168404Spjd } 5102168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5103168404Spjd 5104168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5105168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 5106168404Spjd zc.zc_jailid = jailid; 5107168404Spjd 5108168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 5109168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 5110168404Spjd zfs_standard_error(hdl, errno, errbuf); 5111168404Spjd 5112168404Spjd return (ret); 5113168404Spjd} 5114