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. 24339103Smav * Copyright (c) 2018, 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> 53339118Smav#ifdef illumos 54209962Smm#include <idmap.h> 55339118Smav#endif 56168404Spjd 57219089Spjd#include <sys/dnode.h> 58168404Spjd#include <sys/spa.h> 59168404Spjd#include <sys/zap.h> 60209962Smm#include <sys/misc.h> 61168404Spjd#include <libzfs.h> 62168404Spjd 63168404Spjd#include "zfs_namecheck.h" 64168404Spjd#include "zfs_prop.h" 65168404Spjd#include "libzfs_impl.h" 66185029Spjd#include "zfs_deleg.h" 67168404Spjd 68209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 69209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 70168676Spjd 71168404Spjd/* 72168404Spjd * Given a single type (not a mask of types), return the type in a human 73168404Spjd * readable form. 74168404Spjd */ 75168404Spjdconst char * 76168404Spjdzfs_type_to_name(zfs_type_t type) 77168404Spjd{ 78168404Spjd switch (type) { 79168404Spjd case ZFS_TYPE_FILESYSTEM: 80168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 81168404Spjd case ZFS_TYPE_SNAPSHOT: 82168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 83168404Spjd case ZFS_TYPE_VOLUME: 84168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 85307050Smav case ZFS_TYPE_POOL: 86307050Smav return (dgettext(TEXT_DOMAIN, "pool")); 87307050Smav case ZFS_TYPE_BOOKMARK: 88307050Smav return (dgettext(TEXT_DOMAIN, "bookmark")); 89307050Smav default: 90307050Smav assert(!"unhandled zfs_type_t"); 91168404Spjd } 92168404Spjd 93168404Spjd return (NULL); 94168404Spjd} 95168404Spjd 96168404Spjd/* 97168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 98209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 99209962Smm * explain exactly why the name was not valid. 100168404Spjd */ 101219089Spjdint 102185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 103185029Spjd boolean_t modifying) 104168404Spjd{ 105168404Spjd namecheck_err_t why; 106168404Spjd char what; 107168404Spjd 108321534Smav if (entity_namecheck(path, &why, &what) != 0) { 109168404Spjd if (hdl != NULL) { 110168404Spjd switch (why) { 111168404Spjd case NAME_ERR_TOOLONG: 112168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 113168404Spjd "name is too long")); 114168404Spjd break; 115168404Spjd 116168404Spjd case NAME_ERR_LEADING_SLASH: 117168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 118168404Spjd "leading slash in name")); 119168404Spjd break; 120168404Spjd 121168404Spjd case NAME_ERR_EMPTY_COMPONENT: 122168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 123168404Spjd "empty component in name")); 124168404Spjd break; 125168404Spjd 126168404Spjd case NAME_ERR_TRAILING_SLASH: 127168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 128168404Spjd "trailing slash in name")); 129168404Spjd break; 130168404Spjd 131168404Spjd case NAME_ERR_INVALCHAR: 132168404Spjd zfs_error_aux(hdl, 133168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 134168404Spjd "'%c' in name"), what); 135168404Spjd break; 136168404Spjd 137321534Smav case NAME_ERR_MULTIPLE_DELIMITERS: 138168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 139321534Smav "multiple '@' and/or '#' delimiters in " 140321534Smav "name")); 141168404Spjd break; 142168404Spjd 143168404Spjd case NAME_ERR_NOLETTER: 144168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 145168404Spjd "pool doesn't begin with a letter")); 146168404Spjd break; 147168404Spjd 148168404Spjd case NAME_ERR_RESERVED: 149168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 150168404Spjd "name is reserved")); 151168404Spjd break; 152168404Spjd 153168404Spjd case NAME_ERR_DISKLIKE: 154168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 155168404Spjd "reserved disk name")); 156168404Spjd break; 157307050Smav 158307050Smav default: 159307050Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 160307050Smav "(%d) not defined"), why); 161307050Smav break; 162168404Spjd } 163168404Spjd } 164168404Spjd 165168404Spjd return (0); 166168404Spjd } 167168404Spjd 168168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 169168404Spjd if (hdl != NULL) 170168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 171321534Smav "snapshot delimiter '@' is not expected here")); 172168404Spjd return (0); 173168404Spjd } 174168404Spjd 175168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 176168404Spjd if (hdl != NULL) 177168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 178168404Spjd "missing '@' delimiter in snapshot name")); 179168404Spjd return (0); 180168404Spjd } 181168404Spjd 182321534Smav if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) { 183321534Smav if (hdl != NULL) 184321534Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 185321534Smav "bookmark delimiter '#' is not expected here")); 186321534Smav return (0); 187321534Smav } 188321534Smav 189321534Smav if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) { 190321534Smav if (hdl != NULL) 191321534Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 192321534Smav "missing '#' delimiter in bookmark name")); 193321534Smav return (0); 194321534Smav } 195321534Smav 196185029Spjd if (modifying && strchr(path, '%') != NULL) { 197185029Spjd if (hdl != NULL) 198185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 199185029Spjd "invalid character %c in name"), '%'); 200185029Spjd return (0); 201185029Spjd } 202185029Spjd 203168404Spjd return (-1); 204168404Spjd} 205168404Spjd 206168404Spjdint 207168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 208168404Spjd{ 209185029Spjd if (type == ZFS_TYPE_POOL) 210185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 211185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 212168404Spjd} 213168404Spjd 214168404Spjd/* 215168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 216168404Spjd * properties into a separate nvlist. 217168404Spjd */ 218185029Spjdstatic nvlist_t * 219185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 220168404Spjd{ 221168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 222168404Spjd nvpair_t *elem; 223168404Spjd nvlist_t *propval; 224185029Spjd nvlist_t *nvl; 225168404Spjd 226185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 227185029Spjd (void) no_memory(hdl); 228185029Spjd return (NULL); 229185029Spjd } 230168404Spjd 231168404Spjd elem = NULL; 232185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 233168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 234168404Spjd continue; 235168404Spjd 236168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 237185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 238185029Spjd nvlist_free(nvl); 239185029Spjd (void) no_memory(hdl); 240185029Spjd return (NULL); 241185029Spjd } 242168404Spjd } 243168404Spjd 244185029Spjd return (nvl); 245168404Spjd} 246168404Spjd 247185029Spjdstatic zpool_handle_t * 248185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 249185029Spjd{ 250185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 251185029Spjd zpool_handle_t *zph; 252185029Spjd 253185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 254185029Spjd if (hdl->libzfs_pool_handles != NULL) 255185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 256185029Spjd hdl->libzfs_pool_handles = zph; 257185029Spjd } 258185029Spjd return (zph); 259185029Spjd} 260185029Spjd 261185029Spjdstatic zpool_handle_t * 262185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 263185029Spjd{ 264185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 265185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 266185029Spjd 267185029Spjd while ((zph != NULL) && 268185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 269185029Spjd zph = zph->zpool_next; 270185029Spjd return (zph); 271185029Spjd} 272185029Spjd 273168404Spjd/* 274185029Spjd * Returns a handle to the pool that contains the provided dataset. 275185029Spjd * If a handle to that pool already exists then that handle is returned. 276185029Spjd * Otherwise, a new handle is created and added to the list of handles. 277185029Spjd */ 278185029Spjdstatic zpool_handle_t * 279185029Spjdzpool_handle(zfs_handle_t *zhp) 280185029Spjd{ 281185029Spjd char *pool_name; 282185029Spjd int len; 283185029Spjd zpool_handle_t *zph; 284185029Spjd 285260183Sdelphij len = strcspn(zhp->zfs_name, "/@#") + 1; 286185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 287185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 288185029Spjd 289185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 290185029Spjd if (zph == NULL) 291185029Spjd zph = zpool_add_handle(zhp, pool_name); 292185029Spjd 293185029Spjd free(pool_name); 294185029Spjd return (zph); 295185029Spjd} 296185029Spjd 297185029Spjdvoid 298185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 299185029Spjd{ 300185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 301185029Spjd 302185029Spjd while (zph != NULL) { 303185029Spjd next = zph->zpool_next; 304185029Spjd zpool_close(zph); 305185029Spjd zph = next; 306185029Spjd } 307185029Spjd hdl->libzfs_pool_handles = NULL; 308185029Spjd} 309185029Spjd 310185029Spjd/* 311168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 312168404Spjd */ 313219089Spjdstatic int 314209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 315168404Spjd{ 316168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 317168404Spjd 318209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 319168404Spjd 320209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 321168404Spjd if (errno == ENOMEM) { 322209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 323168404Spjd return (-1); 324168404Spjd } 325168404Spjd } else { 326168404Spjd return (-1); 327168404Spjd } 328168404Spjd } 329209962Smm return (0); 330209962Smm} 331168404Spjd 332219089Spjd/* 333219089Spjd * Utility function to get the received properties of the given object. 334219089Spjd */ 335209962Smmstatic int 336219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 337219089Spjd{ 338219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 339219089Spjd nvlist_t *recvdprops; 340219089Spjd zfs_cmd_t zc = { 0 }; 341219089Spjd int err; 342219089Spjd 343219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 344219089Spjd return (-1); 345219089Spjd 346219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 347219089Spjd 348219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 349219089Spjd if (errno == ENOMEM) { 350219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 351219089Spjd return (-1); 352219089Spjd } 353219089Spjd } else { 354219089Spjd zcmd_free_nvlists(&zc); 355219089Spjd return (-1); 356219089Spjd } 357219089Spjd } 358219089Spjd 359219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 360219089Spjd zcmd_free_nvlists(&zc); 361219089Spjd if (err != 0) 362219089Spjd return (-1); 363219089Spjd 364219089Spjd nvlist_free(zhp->zfs_recvd_props); 365219089Spjd zhp->zfs_recvd_props = recvdprops; 366219089Spjd 367219089Spjd return (0); 368219089Spjd} 369219089Spjd 370219089Spjdstatic int 371209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 372209962Smm{ 373209962Smm nvlist_t *allprops, *userprops; 374168404Spjd 375209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 376209962Smm 377209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 378168404Spjd return (-1); 379168404Spjd } 380168404Spjd 381209962Smm /* 382209962Smm * XXX Why do we store the user props separately, in addition to 383209962Smm * storing them in zfs_props? 384209962Smm */ 385185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 386185029Spjd nvlist_free(allprops); 387168404Spjd return (-1); 388185029Spjd } 389168404Spjd 390185029Spjd nvlist_free(zhp->zfs_props); 391185029Spjd nvlist_free(zhp->zfs_user_props); 392185029Spjd 393185029Spjd zhp->zfs_props = allprops; 394185029Spjd zhp->zfs_user_props = userprops; 395185029Spjd 396168404Spjd return (0); 397168404Spjd} 398168404Spjd 399209962Smmstatic int 400209962Smmget_stats(zfs_handle_t *zhp) 401209962Smm{ 402209962Smm int rc = 0; 403209962Smm zfs_cmd_t zc = { 0 }; 404209962Smm 405209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 406209962Smm return (-1); 407209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 408209962Smm rc = -1; 409209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 410209962Smm rc = -1; 411209962Smm zcmd_free_nvlists(&zc); 412209962Smm return (rc); 413209962Smm} 414209962Smm 415168404Spjd/* 416168404Spjd * Refresh the properties currently stored in the handle. 417168404Spjd */ 418168404Spjdvoid 419168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 420168404Spjd{ 421168404Spjd (void) get_stats(zhp); 422168404Spjd} 423168404Spjd 424168404Spjd/* 425168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 426168404Spjd * zfs_iter_* to create child handles on the fly. 427168404Spjd */ 428209962Smmstatic int 429209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 430168404Spjd{ 431219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 432209962Smm return (-1); 433168404Spjd 434168404Spjd /* 435168404Spjd * We've managed to open the dataset and gather statistics. Determine 436168404Spjd * the high-level type. 437168404Spjd */ 438168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 439168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 440168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 441168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 442168404Spjd else 443168404Spjd abort(); 444168404Spjd 445168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 446168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 447168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 448168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 449168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 450168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 451168404Spjd else 452168404Spjd abort(); /* we should never see any other types */ 453168404Spjd 454219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 455219089Spjd return (-1); 456219089Spjd 457209962Smm return (0); 458209962Smm} 459209962Smm 460209962Smmzfs_handle_t * 461209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 462209962Smm{ 463209962Smm zfs_cmd_t zc = { 0 }; 464209962Smm 465209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 466209962Smm 467209962Smm if (zhp == NULL) 468209962Smm return (NULL); 469209962Smm 470209962Smm zhp->zfs_hdl = hdl; 471209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 472209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 473209962Smm free(zhp); 474209962Smm return (NULL); 475209962Smm } 476209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 477209962Smm zcmd_free_nvlists(&zc); 478209962Smm free(zhp); 479209962Smm return (NULL); 480209962Smm } 481209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 482209962Smm free(zhp); 483209962Smm zhp = NULL; 484209962Smm } 485209962Smm zcmd_free_nvlists(&zc); 486168404Spjd return (zhp); 487168404Spjd} 488168404Spjd 489228103Smmzfs_handle_t * 490209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 491209962Smm{ 492209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 493209962Smm 494209962Smm if (zhp == NULL) 495209962Smm return (NULL); 496209962Smm 497209962Smm zhp->zfs_hdl = hdl; 498209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 499209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 500209962Smm free(zhp); 501209962Smm return (NULL); 502209962Smm } 503209962Smm return (zhp); 504209962Smm} 505209962Smm 506228103Smmzfs_handle_t * 507230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 508230438Spjd{ 509230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 510230438Spjd 511230438Spjd if (zhp == NULL) 512230438Spjd return (NULL); 513230438Spjd 514230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 515230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 516230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 517230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 518230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 519230438Spjd return (zhp); 520230438Spjd} 521230438Spjd 522230438Spjdzfs_handle_t * 523228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 524228103Smm{ 525228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 526228103Smm 527228103Smm if (zhp == NULL) 528228103Smm return (NULL); 529228103Smm 530228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 531228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 532228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 533228103Smm sizeof (zhp->zfs_name)); 534228103Smm zhp->zfs_type = zhp_orig->zfs_type; 535228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 536228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 537228103Smm if (zhp_orig->zfs_props != NULL) { 538228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 539228103Smm (void) no_memory(zhp->zfs_hdl); 540228103Smm zfs_close(zhp); 541228103Smm return (NULL); 542228103Smm } 543228103Smm } 544228103Smm if (zhp_orig->zfs_user_props != NULL) { 545228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 546228103Smm &zhp->zfs_user_props, 0) != 0) { 547228103Smm (void) no_memory(zhp->zfs_hdl); 548228103Smm zfs_close(zhp); 549228103Smm return (NULL); 550228103Smm } 551228103Smm } 552228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 553228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 554228103Smm &zhp->zfs_recvd_props, 0)) { 555228103Smm (void) no_memory(zhp->zfs_hdl); 556228103Smm zfs_close(zhp); 557228103Smm return (NULL); 558228103Smm } 559228103Smm } 560228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 561228103Smm if (zhp_orig->zfs_mntopts != NULL) { 562228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 563228103Smm zhp_orig->zfs_mntopts); 564228103Smm } 565228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 566228103Smm return (zhp); 567228103Smm} 568228103Smm 569260183Sdelphijboolean_t 570260183Sdelphijzfs_bookmark_exists(const char *path) 571260183Sdelphij{ 572260183Sdelphij nvlist_t *bmarks; 573260183Sdelphij nvlist_t *props; 574307108Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 575260183Sdelphij char *bmark_name; 576260183Sdelphij char *pound; 577260183Sdelphij int err; 578260183Sdelphij boolean_t rv; 579260183Sdelphij 580260183Sdelphij 581260183Sdelphij (void) strlcpy(fsname, path, sizeof (fsname)); 582260183Sdelphij pound = strchr(fsname, '#'); 583260183Sdelphij if (pound == NULL) 584260183Sdelphij return (B_FALSE); 585260183Sdelphij 586260183Sdelphij *pound = '\0'; 587260183Sdelphij bmark_name = pound + 1; 588260183Sdelphij props = fnvlist_alloc(); 589260183Sdelphij err = lzc_get_bookmarks(fsname, props, &bmarks); 590260183Sdelphij nvlist_free(props); 591260183Sdelphij if (err != 0) { 592260183Sdelphij nvlist_free(bmarks); 593260183Sdelphij return (B_FALSE); 594260183Sdelphij } 595260183Sdelphij 596260183Sdelphij rv = nvlist_exists(bmarks, bmark_name); 597260183Sdelphij nvlist_free(bmarks); 598260183Sdelphij return (rv); 599260183Sdelphij} 600260183Sdelphij 601260183Sdelphijzfs_handle_t * 602260183Sdelphijmake_bookmark_handle(zfs_handle_t *parent, const char *path, 603260183Sdelphij nvlist_t *bmark_props) 604260183Sdelphij{ 605260183Sdelphij zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 606260183Sdelphij 607260183Sdelphij if (zhp == NULL) 608260183Sdelphij return (NULL); 609260183Sdelphij 610260183Sdelphij /* Fill in the name. */ 611260183Sdelphij zhp->zfs_hdl = parent->zfs_hdl; 612260183Sdelphij (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 613260183Sdelphij 614260183Sdelphij /* Set the property lists. */ 615260183Sdelphij if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 616260183Sdelphij free(zhp); 617260183Sdelphij return (NULL); 618260183Sdelphij } 619260183Sdelphij 620260183Sdelphij /* Set the types. */ 621260183Sdelphij zhp->zfs_head_type = parent->zfs_head_type; 622260183Sdelphij zhp->zfs_type = ZFS_TYPE_BOOKMARK; 623260183Sdelphij 624260183Sdelphij if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 625260183Sdelphij nvlist_free(zhp->zfs_props); 626260183Sdelphij free(zhp); 627260183Sdelphij return (NULL); 628260183Sdelphij } 629260183Sdelphij 630260183Sdelphij return (zhp); 631260183Sdelphij} 632260183Sdelphij 633321534Smavstruct zfs_open_bookmarks_cb_data { 634321534Smav const char *path; 635321534Smav zfs_handle_t *zhp; 636321534Smav}; 637321534Smav 638321534Smavstatic int 639321534Smavzfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data) 640321534Smav{ 641321534Smav struct zfs_open_bookmarks_cb_data *dp = data; 642321534Smav 643321534Smav /* 644321534Smav * Is it the one we are looking for? 645321534Smav */ 646321534Smav if (strcmp(dp->path, zfs_get_name(zhp)) == 0) { 647321534Smav /* 648321534Smav * We found it. Save it and let the caller know we are done. 649321534Smav */ 650321534Smav dp->zhp = zhp; 651321534Smav return (EEXIST); 652321534Smav } 653321534Smav 654321534Smav /* 655321534Smav * Not found. Close the handle and ask for another one. 656321534Smav */ 657321534Smav zfs_close(zhp); 658321534Smav return (0); 659321534Smav} 660321534Smav 661168404Spjd/* 662321534Smav * Opens the given snapshot, bookmark, filesystem, or volume. The 'types' 663168404Spjd * argument is a mask of acceptable types. The function will print an 664168404Spjd * appropriate error message and return NULL if it can't be opened. 665168404Spjd */ 666168404Spjdzfs_handle_t * 667168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 668168404Spjd{ 669168404Spjd zfs_handle_t *zhp; 670168404Spjd char errbuf[1024]; 671321534Smav char *bookp; 672168404Spjd 673168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 674168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 675168404Spjd 676168404Spjd /* 677168404Spjd * Validate the name before we even try to open it. 678168404Spjd */ 679321534Smav if (!zfs_validate_name(hdl, path, types, B_FALSE)) { 680168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 681168404Spjd return (NULL); 682168404Spjd } 683168404Spjd 684168404Spjd /* 685321534Smav * Bookmarks needs to be handled separately. 686168404Spjd */ 687321534Smav bookp = strchr(path, '#'); 688321534Smav if (bookp == NULL) { 689321534Smav /* 690321534Smav * Try to get stats for the dataset, which will tell us if it 691321534Smav * exists. 692321534Smav */ 693321534Smav errno = 0; 694321534Smav if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 695321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 696321534Smav return (NULL); 697321534Smav } 698321534Smav } else { 699321534Smav char dsname[ZFS_MAX_DATASET_NAME_LEN]; 700321534Smav zfs_handle_t *pzhp; 701321534Smav struct zfs_open_bookmarks_cb_data cb_data = {path, NULL}; 702321534Smav 703321534Smav /* 704321534Smav * We need to cut out '#' and everything after '#' 705321534Smav * to get the parent dataset name only. 706321534Smav */ 707321534Smav assert(bookp - path < sizeof (dsname)); 708321534Smav (void) strncpy(dsname, path, bookp - path); 709321534Smav dsname[bookp - path] = '\0'; 710321534Smav 711321534Smav /* 712321534Smav * Create handle for the parent dataset. 713321534Smav */ 714321534Smav errno = 0; 715321534Smav if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) { 716321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 717321534Smav return (NULL); 718321534Smav } 719321534Smav 720321534Smav /* 721321534Smav * Iterate bookmarks to find the right one. 722321534Smav */ 723321534Smav errno = 0; 724321534Smav if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb, 725321534Smav &cb_data) == 0) && (cb_data.zhp == NULL)) { 726321534Smav (void) zfs_error(hdl, EZFS_NOENT, errbuf); 727321534Smav zfs_close(pzhp); 728321534Smav return (NULL); 729321534Smav } 730321534Smav if (cb_data.zhp == NULL) { 731321534Smav (void) zfs_standard_error(hdl, errno, errbuf); 732321534Smav zfs_close(pzhp); 733321534Smav return (NULL); 734321534Smav } 735321534Smav zhp = cb_data.zhp; 736321534Smav 737321534Smav /* 738321534Smav * Cleanup. 739321534Smav */ 740321534Smav zfs_close(pzhp); 741168404Spjd } 742168404Spjd 743240870Spjd if (zhp == NULL) { 744240870Spjd char *at = strchr(path, '@'); 745240870Spjd 746240870Spjd if (at != NULL) 747240870Spjd *at = '\0'; 748240870Spjd errno = 0; 749240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 750240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 751240870Spjd return (NULL); 752240870Spjd } 753240870Spjd if (at != NULL) 754240870Spjd *at = '@'; 755240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 756240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 757240870Spjd } 758240870Spjd 759168404Spjd if (!(types & zhp->zfs_type)) { 760168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 761168404Spjd zfs_close(zhp); 762168404Spjd return (NULL); 763168404Spjd } 764168404Spjd 765168404Spjd return (zhp); 766168404Spjd} 767168404Spjd 768168404Spjd/* 769168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 770168404Spjd */ 771168404Spjdvoid 772168404Spjdzfs_close(zfs_handle_t *zhp) 773168404Spjd{ 774168404Spjd if (zhp->zfs_mntopts) 775168404Spjd free(zhp->zfs_mntopts); 776168404Spjd nvlist_free(zhp->zfs_props); 777168404Spjd nvlist_free(zhp->zfs_user_props); 778219089Spjd nvlist_free(zhp->zfs_recvd_props); 779168404Spjd free(zhp); 780168404Spjd} 781168404Spjd 782209962Smmtypedef struct mnttab_node { 783209962Smm struct mnttab mtn_mt; 784209962Smm avl_node_t mtn_node; 785209962Smm} mnttab_node_t; 786209962Smm 787209962Smmstatic int 788209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 789209962Smm{ 790339158Smav const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1; 791339158Smav const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2; 792209962Smm int rv; 793209962Smm 794209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 795209962Smm 796339158Smav return (AVL_ISIGN(rv)); 797209962Smm} 798209962Smm 799209962Smmvoid 800209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 801209962Smm{ 802346690Smav pthread_mutex_init(&hdl->libzfs_mnttab_cache_lock, NULL); 803209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 804209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 805209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 806209962Smm} 807209962Smm 808209962Smmvoid 809209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 810209962Smm{ 811209962Smm struct mnttab entry; 812209962Smm 813209962Smm rewind(hdl->libzfs_mnttab); 814209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 815209962Smm mnttab_node_t *mtn; 816209962Smm 817209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 818209962Smm continue; 819209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 820209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 821209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 822209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 823209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 824209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 825209962Smm } 826209962Smm} 827209962Smm 828209962Smmvoid 829209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 830209962Smm{ 831209962Smm void *cookie = NULL; 832209962Smm mnttab_node_t *mtn; 833209962Smm 834307050Smav while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) 835307050Smav != NULL) { 836209962Smm free(mtn->mtn_mt.mnt_special); 837209962Smm free(mtn->mtn_mt.mnt_mountp); 838209962Smm free(mtn->mtn_mt.mnt_fstype); 839209962Smm free(mtn->mtn_mt.mnt_mntopts); 840209962Smm free(mtn); 841209962Smm } 842209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 843346690Smav (void) pthread_mutex_destroy(&hdl->libzfs_mnttab_cache_lock); 844209962Smm} 845209962Smm 846209962Smmvoid 847209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 848209962Smm{ 849209962Smm hdl->libzfs_mnttab_enable = enable; 850209962Smm} 851209962Smm 852185029Spjdint 853209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 854209962Smm struct mnttab *entry) 855209962Smm{ 856209962Smm mnttab_node_t find; 857209962Smm mnttab_node_t *mtn; 858346690Smav int ret = ENOENT; 859209962Smm 860209962Smm if (!hdl->libzfs_mnttab_enable) { 861209962Smm struct mnttab srch = { 0 }; 862209962Smm 863209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 864209962Smm libzfs_mnttab_fini(hdl); 865209962Smm rewind(hdl->libzfs_mnttab); 866209962Smm srch.mnt_special = (char *)fsname; 867209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 868209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 869209962Smm return (0); 870209962Smm else 871209962Smm return (ENOENT); 872209962Smm } 873209962Smm 874346690Smav pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 875209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 876209962Smm libzfs_mnttab_update(hdl); 877209962Smm 878209962Smm find.mtn_mt.mnt_special = (char *)fsname; 879209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 880209962Smm if (mtn) { 881209962Smm *entry = mtn->mtn_mt; 882346690Smav ret = 0; 883209962Smm } 884346690Smav pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 885346690Smav return (ret); 886209962Smm} 887209962Smm 888209962Smmvoid 889209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 890209962Smm const char *mountp, const char *mntopts) 891209962Smm{ 892209962Smm mnttab_node_t *mtn; 893209962Smm 894346690Smav pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 895346690Smav if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) { 896346690Smav mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 897346690Smav mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 898346690Smav mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 899346690Smav mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 900346690Smav mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 901346690Smav avl_add(&hdl->libzfs_mnttab_cache, mtn); 902346690Smav } 903346690Smav pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 904346690Smav} 905209962Smm 906209962Smmvoid 907209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 908209962Smm{ 909209962Smm mnttab_node_t find; 910209962Smm mnttab_node_t *ret; 911209962Smm 912346690Smav pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock); 913209962Smm find.mtn_mt.mnt_special = (char *)fsname; 914307050Smav if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) 915307050Smav != NULL) { 916209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 917209962Smm free(ret->mtn_mt.mnt_special); 918209962Smm free(ret->mtn_mt.mnt_mountp); 919209962Smm free(ret->mtn_mt.mnt_fstype); 920209962Smm free(ret->mtn_mt.mnt_mntopts); 921209962Smm free(ret); 922209962Smm } 923346690Smav pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock); 924209962Smm} 925209962Smm 926209962Smmint 927185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 928168404Spjd{ 929185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 930168404Spjd 931185029Spjd if (zpool_handle == NULL) 932168404Spjd return (-1); 933168404Spjd 934185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 935185029Spjd ZPOOL_PROP_VERSION, NULL); 936168404Spjd return (0); 937168404Spjd} 938168404Spjd 939168404Spjd/* 940185029Spjd * The choice of reservation property depends on the SPA version. 941168404Spjd */ 942168404Spjdstatic int 943185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 944168404Spjd{ 945185029Spjd int spa_version; 946168404Spjd 947185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 948168404Spjd return (-1); 949168404Spjd 950185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 951185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 952185029Spjd else 953185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 954168404Spjd 955168404Spjd return (0); 956168404Spjd} 957168404Spjd 958168404Spjd/* 959168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 960168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 961168404Spjd * strings. 962168404Spjd */ 963168404Spjdnvlist_t * 964185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 965289500Smav uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl, 966289500Smav const char *errbuf) 967168404Spjd{ 968168404Spjd nvpair_t *elem; 969168404Spjd uint64_t intval; 970168404Spjd char *strval; 971185029Spjd zfs_prop_t prop; 972168404Spjd nvlist_t *ret; 973185029Spjd int chosen_normal = -1; 974185029Spjd int chosen_utf = -1; 975168404Spjd 976168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 977168404Spjd (void) no_memory(hdl); 978168404Spjd return (NULL); 979168404Spjd } 980168404Spjd 981209962Smm /* 982209962Smm * Make sure this property is valid and applies to this type. 983209962Smm */ 984209962Smm 985168404Spjd elem = NULL; 986168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 987185029Spjd const char *propname = nvpair_name(elem); 988168404Spjd 989209962Smm prop = zfs_name_to_prop(propname); 990209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 991185029Spjd /* 992209962Smm * This is a user property: make sure it's a 993185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 994185029Spjd */ 995185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 996185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 997185029Spjd "'%s' must be a string"), propname); 998185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 999185029Spjd goto error; 1000168404Spjd } 1001168404Spjd 1002185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 1003185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1004185029Spjd "property name '%s' is too long"), 1005185029Spjd propname); 1006185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1007185029Spjd goto error; 1008185029Spjd } 1009185029Spjd 1010168404Spjd (void) nvpair_value_string(elem, &strval); 1011168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 1012168404Spjd (void) no_memory(hdl); 1013168404Spjd goto error; 1014168404Spjd } 1015168404Spjd continue; 1016168404Spjd } 1017168404Spjd 1018209962Smm /* 1019209962Smm * Currently, only user properties can be modified on 1020209962Smm * snapshots. 1021209962Smm */ 1022185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 1023185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1024185029Spjd "this property can not be modified for snapshots")); 1025185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1026185029Spjd goto error; 1027185029Spjd } 1028168404Spjd 1029209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 1030209962Smm zfs_userquota_prop_t uqtype; 1031209962Smm char newpropname[128]; 1032209962Smm char domain[128]; 1033209962Smm uint64_t rid; 1034209962Smm uint64_t valary[3]; 1035209962Smm 1036209962Smm if (userquota_propname_decode(propname, zoned, 1037209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 1038209962Smm zfs_error_aux(hdl, 1039209962Smm dgettext(TEXT_DOMAIN, 1040209962Smm "'%s' has an invalid user/group name"), 1041209962Smm propname); 1042209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1043209962Smm goto error; 1044209962Smm } 1045209962Smm 1046209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 1047209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 1048209962Smm zfs_error_aux(hdl, 1049209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1050209962Smm propname); 1051209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 1052209962Smm errbuf); 1053209962Smm goto error; 1054209962Smm } 1055209962Smm 1056209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 1057209962Smm (void) nvpair_value_string(elem, &strval); 1058209962Smm if (strcmp(strval, "none") == 0) { 1059209962Smm intval = 0; 1060209962Smm } else if (zfs_nicestrtonum(hdl, 1061209962Smm strval, &intval) != 0) { 1062209962Smm (void) zfs_error(hdl, 1063209962Smm EZFS_BADPROP, errbuf); 1064209962Smm goto error; 1065209962Smm } 1066209962Smm } else if (nvpair_type(elem) == 1067209962Smm DATA_TYPE_UINT64) { 1068209962Smm (void) nvpair_value_uint64(elem, &intval); 1069209962Smm if (intval == 0) { 1070209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1071209962Smm "use 'none' to disable " 1072209962Smm "userquota/groupquota")); 1073209962Smm goto error; 1074209962Smm } 1075209962Smm } else { 1076209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1077209962Smm "'%s' must be a number"), propname); 1078209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1079209962Smm goto error; 1080209962Smm } 1081209962Smm 1082219089Spjd /* 1083219089Spjd * Encode the prop name as 1084219089Spjd * userquota@<hex-rid>-domain, to make it easy 1085219089Spjd * for the kernel to decode. 1086219089Spjd */ 1087209962Smm (void) snprintf(newpropname, sizeof (newpropname), 1088219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 1089219089Spjd (longlong_t)rid, domain); 1090209962Smm valary[0] = uqtype; 1091209962Smm valary[1] = rid; 1092209962Smm valary[2] = intval; 1093209962Smm if (nvlist_add_uint64_array(ret, newpropname, 1094209962Smm valary, 3) != 0) { 1095209962Smm (void) no_memory(hdl); 1096209962Smm goto error; 1097209962Smm } 1098209962Smm continue; 1099228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 1100228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1101228103Smm "'%s' is readonly"), 1102228103Smm propname); 1103228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1104228103Smm goto error; 1105209962Smm } 1106209962Smm 1107209962Smm if (prop == ZPROP_INVAL) { 1108209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1109209962Smm "invalid property '%s'"), propname); 1110209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1111209962Smm goto error; 1112209962Smm } 1113209962Smm 1114168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 1115168404Spjd zfs_error_aux(hdl, 1116168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 1117168404Spjd "apply to datasets of this type"), propname); 1118168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1119168404Spjd goto error; 1120168404Spjd } 1121168404Spjd 1122168404Spjd if (zfs_prop_readonly(prop) && 1123185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 1124168404Spjd zfs_error_aux(hdl, 1125168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1126168404Spjd propname); 1127168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1128168404Spjd goto error; 1129168404Spjd } 1130168404Spjd 1131185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 1132185029Spjd &strval, &intval, errbuf) != 0) 1133185029Spjd goto error; 1134185029Spjd 1135168404Spjd /* 1136185029Spjd * Perform some additional checks for specific properties. 1137168404Spjd */ 1138185029Spjd switch (prop) { 1139185029Spjd case ZFS_PROP_VERSION: 1140185029Spjd { 1141185029Spjd int version; 1142168404Spjd 1143185029Spjd if (zhp == NULL) 1144185029Spjd break; 1145185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1146185029Spjd if (intval < version) { 1147168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1148185029Spjd "Can not downgrade; already at version %u"), 1149185029Spjd version); 1150168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1151168404Spjd goto error; 1152168404Spjd } 1153168404Spjd break; 1154168404Spjd } 1155168404Spjd 1156274337Sdelphij case ZFS_PROP_VOLBLOCKSIZE: 1157168404Spjd case ZFS_PROP_RECORDSIZE: 1158274337Sdelphij { 1159274337Sdelphij int maxbs = SPA_MAXBLOCKSIZE; 1160289500Smav if (zpool_hdl != NULL) { 1161289500Smav maxbs = zpool_get_prop_int(zpool_hdl, 1162274337Sdelphij ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1163274337Sdelphij } 1164274337Sdelphij /* 1165274337Sdelphij * Volumes are limited to a volblocksize of 128KB, 1166274337Sdelphij * because they typically service workloads with 1167274337Sdelphij * small random writes, which incur a large performance 1168274337Sdelphij * penalty with large blocks. 1169274337Sdelphij */ 1170274337Sdelphij if (prop == ZFS_PROP_VOLBLOCKSIZE) 1171274337Sdelphij maxbs = SPA_OLD_MAXBLOCKSIZE; 1172274337Sdelphij /* 1173274337Sdelphij * The value must be a power of two between 1174274337Sdelphij * SPA_MINBLOCKSIZE and maxbs. 1175274337Sdelphij */ 1176168404Spjd if (intval < SPA_MINBLOCKSIZE || 1177274337Sdelphij intval > maxbs || !ISP2(intval)) { 1178168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1179274337Sdelphij "'%s' must be power of 2 from 512B " 1180274337Sdelphij "to %uKB"), propname, maxbs >> 10); 1181168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1182168404Spjd goto error; 1183168404Spjd } 1184168404Spjd break; 1185274337Sdelphij } 1186219089Spjd case ZFS_PROP_MLSLABEL: 1187219089Spjd { 1188277300Ssmh#ifdef illumos 1189219089Spjd /* 1190219089Spjd * Verify the mlslabel string and convert to 1191219089Spjd * internal hex label string. 1192219089Spjd */ 1193219089Spjd 1194219089Spjd m_label_t *new_sl; 1195219089Spjd char *hex = NULL; /* internal label string */ 1196219089Spjd 1197219089Spjd /* Default value is already OK. */ 1198219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1199219089Spjd break; 1200219089Spjd 1201219089Spjd /* Verify the label can be converted to binary form */ 1202219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1203219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1204219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1205219089Spjd goto badlabel; 1206168404Spjd } 1207168404Spjd 1208219089Spjd /* Now translate to hex internal label string */ 1209219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1210219089Spjd DEF_NAMES) != 0) { 1211219089Spjd if (hex) 1212219089Spjd free(hex); 1213219089Spjd goto badlabel; 1214219089Spjd } 1215219089Spjd m_label_free(new_sl); 1216219089Spjd 1217219089Spjd /* If string is already in internal form, we're done. */ 1218219089Spjd if (strcmp(strval, hex) == 0) { 1219219089Spjd free(hex); 1220219089Spjd break; 1221219089Spjd } 1222219089Spjd 1223219089Spjd /* Replace the label string with the internal form. */ 1224219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1225219089Spjd DATA_TYPE_STRING); 1226219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1227219089Spjd hex) == 0); 1228219089Spjd free(hex); 1229219089Spjd 1230168404Spjd break; 1231168404Spjd 1232219089Spjdbadlabel: 1233219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1234219089Spjd "invalid mlslabel '%s'"), strval); 1235219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1236219089Spjd m_label_free(new_sl); /* OK if null */ 1237277300Ssmh#else /* !illumos */ 1238219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1239219089Spjd "mlslabel is not supported on FreeBSD")); 1240219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1241277300Ssmh#endif /* illumos */ 1242219089Spjd goto error; 1243219089Spjd 1244219089Spjd } 1245219089Spjd 1246168404Spjd case ZFS_PROP_MOUNTPOINT: 1247185029Spjd { 1248185029Spjd namecheck_err_t why; 1249185029Spjd 1250168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1251168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1252168404Spjd break; 1253168404Spjd 1254185029Spjd if (mountpoint_namecheck(strval, &why)) { 1255185029Spjd switch (why) { 1256185029Spjd case NAME_ERR_LEADING_SLASH: 1257185029Spjd zfs_error_aux(hdl, 1258185029Spjd dgettext(TEXT_DOMAIN, 1259185029Spjd "'%s' must be an absolute path, " 1260185029Spjd "'none', or 'legacy'"), propname); 1261185029Spjd break; 1262185029Spjd case NAME_ERR_TOOLONG: 1263185029Spjd zfs_error_aux(hdl, 1264185029Spjd dgettext(TEXT_DOMAIN, 1265185029Spjd "component of '%s' is too long"), 1266185029Spjd propname); 1267185029Spjd break; 1268307050Smav 1269307050Smav default: 1270307050Smav zfs_error_aux(hdl, 1271307050Smav dgettext(TEXT_DOMAIN, 1272307050Smav "(%d) not defined"), 1273307050Smav why); 1274307050Smav break; 1275185029Spjd } 1276168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1277168404Spjd goto error; 1278168404Spjd } 1279185029Spjd } 1280185029Spjd 1281168404Spjd /*FALLTHRU*/ 1282168404Spjd 1283185029Spjd case ZFS_PROP_SHARESMB: 1284168404Spjd case ZFS_PROP_SHARENFS: 1285168404Spjd /* 1286185029Spjd * For the mountpoint and sharenfs or sharesmb 1287185029Spjd * properties, check if it can be set in a 1288185029Spjd * global/non-global zone based on 1289168404Spjd * the zoned property value: 1290168404Spjd * 1291168404Spjd * global zone non-global zone 1292168404Spjd * -------------------------------------------------- 1293168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1294168404Spjd * sharenfs (no) sharenfs (no) 1295185029Spjd * sharesmb (no) sharesmb (no) 1296168404Spjd * 1297168404Spjd * zoned=off mountpoint (yes) N/A 1298168404Spjd * sharenfs (yes) 1299185029Spjd * sharesmb (yes) 1300168404Spjd */ 1301168404Spjd if (zoned) { 1302168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1303168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1304168404Spjd "'%s' cannot be set on " 1305168404Spjd "dataset in a non-global zone"), 1306168404Spjd propname); 1307168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1308168404Spjd errbuf); 1309168404Spjd goto error; 1310185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1311185029Spjd prop == ZFS_PROP_SHARESMB) { 1312168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1313168404Spjd "'%s' cannot be set in " 1314168404Spjd "a non-global zone"), propname); 1315168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1316168404Spjd errbuf); 1317168404Spjd goto error; 1318168404Spjd } 1319168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1320168404Spjd /* 1321168404Spjd * If zoned property is 'off', this must be in 1322209962Smm * a global zone. If not, something is wrong. 1323168404Spjd */ 1324168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1325168404Spjd "'%s' cannot be set while dataset " 1326168404Spjd "'zoned' property is set"), propname); 1327168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1328168404Spjd goto error; 1329168404Spjd } 1330168404Spjd 1331168404Spjd /* 1332185029Spjd * At this point, it is legitimate to set the 1333185029Spjd * property. Now we want to make sure that the 1334185029Spjd * property value is valid if it is sharenfs. 1335168404Spjd */ 1336185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1337185029Spjd prop == ZFS_PROP_SHARESMB) && 1338185029Spjd strcmp(strval, "on") != 0 && 1339185029Spjd strcmp(strval, "off") != 0) { 1340185029Spjd zfs_share_proto_t proto; 1341168404Spjd 1342185029Spjd if (prop == ZFS_PROP_SHARESMB) 1343185029Spjd proto = PROTO_SMB; 1344185029Spjd else 1345185029Spjd proto = PROTO_NFS; 1346185029Spjd 1347185029Spjd /* 1348185029Spjd * Must be an valid sharing protocol 1349185029Spjd * option string so init the libshare 1350185029Spjd * in order to enable the parser and 1351185029Spjd * then parse the options. We use the 1352185029Spjd * control API since we don't care about 1353185029Spjd * the current configuration and don't 1354185029Spjd * want the overhead of loading it 1355185029Spjd * until we actually do something. 1356185029Spjd */ 1357185029Spjd 1358185029Spjd if (zfs_init_libshare(hdl, 1359185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1360185029Spjd /* 1361185029Spjd * An error occurred so we can't do 1362185029Spjd * anything 1363185029Spjd */ 1364185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1365185029Spjd "'%s' cannot be set: problem " 1366185029Spjd "in share initialization"), 1367185029Spjd propname); 1368185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1369185029Spjd errbuf); 1370185029Spjd goto error; 1371185029Spjd } 1372185029Spjd 1373185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1374185029Spjd /* 1375185029Spjd * There was an error in parsing so 1376185029Spjd * deal with it by issuing an error 1377185029Spjd * message and leaving after 1378185029Spjd * uninitializing the the libshare 1379185029Spjd * interface. 1380185029Spjd */ 1381185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1382185029Spjd "'%s' cannot be set to invalid " 1383185029Spjd "options"), propname); 1384185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1385185029Spjd errbuf); 1386185029Spjd zfs_uninit_libshare(hdl); 1387185029Spjd goto error; 1388185029Spjd } 1389185029Spjd zfs_uninit_libshare(hdl); 1390168404Spjd } 1391185029Spjd 1392168404Spjd break; 1393307050Smav 1394185029Spjd case ZFS_PROP_UTF8ONLY: 1395185029Spjd chosen_utf = (int)intval; 1396185029Spjd break; 1397307050Smav 1398185029Spjd case ZFS_PROP_NORMALIZE: 1399185029Spjd chosen_normal = (int)intval; 1400185029Spjd break; 1401307050Smav 1402307050Smav default: 1403307050Smav break; 1404168404Spjd } 1405168404Spjd 1406168404Spjd /* 1407168404Spjd * For changes to existing volumes, we have some additional 1408168404Spjd * checks to enforce. 1409168404Spjd */ 1410168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1411168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1412168404Spjd ZFS_PROP_VOLSIZE); 1413168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1414168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1415168404Spjd char buf[64]; 1416168404Spjd 1417168404Spjd switch (prop) { 1418168404Spjd case ZFS_PROP_RESERVATION: 1419168404Spjd if (intval > volsize) { 1420168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1421168404Spjd "'%s' is greater than current " 1422168404Spjd "volume size"), propname); 1423168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1424168404Spjd errbuf); 1425168404Spjd goto error; 1426168404Spjd } 1427168404Spjd break; 1428168404Spjd 1429339103Smav case ZFS_PROP_REFRESERVATION: 1430339103Smav if (intval > volsize && intval != UINT64_MAX) { 1431339103Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1432339103Smav "'%s' is greater than current " 1433339103Smav "volume size"), propname); 1434339103Smav (void) zfs_error(hdl, EZFS_BADPROP, 1435339103Smav errbuf); 1436339103Smav goto error; 1437339103Smav } 1438339103Smav break; 1439339103Smav 1440168404Spjd case ZFS_PROP_VOLSIZE: 1441168404Spjd if (intval % blocksize != 0) { 1442168404Spjd zfs_nicenum(blocksize, buf, 1443168404Spjd sizeof (buf)); 1444168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1445168404Spjd "'%s' must be a multiple of " 1446168404Spjd "volume block size (%s)"), 1447168404Spjd propname, buf); 1448168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1449168404Spjd errbuf); 1450168404Spjd goto error; 1451168404Spjd } 1452168404Spjd 1453168404Spjd if (intval == 0) { 1454168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1455168404Spjd "'%s' cannot be zero"), 1456168404Spjd propname); 1457168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1458168404Spjd errbuf); 1459168404Spjd goto error; 1460168404Spjd } 1461168404Spjd break; 1462307050Smav 1463307050Smav default: 1464307050Smav break; 1465168404Spjd } 1466168404Spjd } 1467168404Spjd } 1468168404Spjd 1469168404Spjd /* 1470185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1471185029Spjd * enforce rejection of non-UTF8 names. 1472185029Spjd * 1473185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1474185029Spjd * was explicitly not chosen, it is an error. 1475185029Spjd */ 1476185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1477185029Spjd if (nvlist_add_uint64(ret, 1478185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1479185029Spjd (void) no_memory(hdl); 1480185029Spjd goto error; 1481185029Spjd } 1482185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1483185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1484185029Spjd "'%s' must be set 'on' if normalization chosen"), 1485185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1486185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1487185029Spjd goto error; 1488185029Spjd } 1489219089Spjd return (ret); 1490185029Spjd 1491219089Spjderror: 1492219089Spjd nvlist_free(ret); 1493219089Spjd return (NULL); 1494219089Spjd} 1495219089Spjd 1496219089Spjdint 1497219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1498219089Spjd{ 1499219089Spjd uint64_t old_volsize; 1500219089Spjd uint64_t new_volsize; 1501219089Spjd uint64_t old_reservation; 1502219089Spjd uint64_t new_reservation; 1503219089Spjd zfs_prop_t resv_prop; 1504289499Smav nvlist_t *props; 1505219089Spjd 1506185029Spjd /* 1507168404Spjd * If this is an existing volume, and someone is setting the volsize, 1508168404Spjd * make sure that it matches the reservation, or add it if necessary. 1509168404Spjd */ 1510219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1511219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1512219089Spjd return (-1); 1513219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1514289499Smav 1515289499Smav props = fnvlist_alloc(); 1516289499Smav fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1517289499Smav zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1518289499Smav 1519289499Smav if ((zvol_volsize_to_reservation(old_volsize, props) != 1520289499Smav old_reservation) || nvlist_exists(nvl, 1521289499Smav zfs_prop_to_name(resv_prop))) { 1522289499Smav fnvlist_free(props); 1523219089Spjd return (0); 1524219089Spjd } 1525219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1526289499Smav &new_volsize) != 0) { 1527289499Smav fnvlist_free(props); 1528219089Spjd return (-1); 1529289499Smav } 1530289499Smav new_reservation = zvol_volsize_to_reservation(new_volsize, props); 1531289499Smav fnvlist_free(props); 1532289499Smav 1533219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1534219089Spjd new_reservation) != 0) { 1535219089Spjd (void) no_memory(zhp->zfs_hdl); 1536219089Spjd return (-1); 1537219089Spjd } 1538219089Spjd return (1); 1539219089Spjd} 1540168404Spjd 1541339103Smav/* 1542339103Smav * Helper for 'zfs {set|clone} refreservation=auto'. Must be called after 1543339103Smav * zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinal value. 1544339103Smav * Return codes must match zfs_add_synthetic_resv(). 1545339103Smav */ 1546339103Smavstatic int 1547339103Smavzfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1548339103Smav{ 1549339103Smav uint64_t volsize; 1550339103Smav uint64_t resvsize; 1551339103Smav zfs_prop_t prop; 1552339103Smav nvlist_t *props; 1553339103Smav 1554339103Smav if (!ZFS_IS_VOLUME(zhp)) { 1555339103Smav return (0); 1556339103Smav } 1557339103Smav 1558339103Smav if (zfs_which_resv_prop(zhp, &prop) != 0) { 1559339103Smav return (-1); 1560339103Smav } 1561339103Smav 1562339103Smav if (prop != ZFS_PROP_REFRESERVATION) { 1563339103Smav return (0); 1564339103Smav } 1565339103Smav 1566339103Smav if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) { 1567339103Smav /* No value being set, so it can't be "auto" */ 1568339103Smav return (0); 1569339103Smav } 1570339103Smav if (resvsize != UINT64_MAX) { 1571339103Smav /* Being set to a value other than "auto" */ 1572339103Smav return (0); 1573339103Smav } 1574339103Smav 1575339103Smav props = fnvlist_alloc(); 1576339103Smav 1577339103Smav fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1578339103Smav zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1579339103Smav 1580339103Smav if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1581339103Smav &volsize) != 0) { 1582339103Smav volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1583339103Smav } 1584339103Smav 1585339103Smav resvsize = zvol_volsize_to_reservation(volsize, props); 1586339103Smav fnvlist_free(props); 1587339103Smav 1588339103Smav (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop)); 1589339103Smav if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) { 1590339103Smav (void) no_memory(zhp->zfs_hdl); 1591339103Smav return (-1); 1592339103Smav } 1593339103Smav return (1); 1594339103Smav} 1595339103Smav 1596219089Spjdvoid 1597219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1598219089Spjd char *errbuf) 1599219089Spjd{ 1600219089Spjd switch (err) { 1601185029Spjd 1602219089Spjd case ENOSPC: 1603219089Spjd /* 1604219089Spjd * For quotas and reservations, ENOSPC indicates 1605219089Spjd * something different; setting a quota or reservation 1606219089Spjd * doesn't use any disk space. 1607219089Spjd */ 1608219089Spjd switch (prop) { 1609219089Spjd case ZFS_PROP_QUOTA: 1610219089Spjd case ZFS_PROP_REFQUOTA: 1611219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1612219089Spjd "size is less than current used or " 1613219089Spjd "reserved space")); 1614219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1615219089Spjd break; 1616219089Spjd 1617219089Spjd case ZFS_PROP_RESERVATION: 1618219089Spjd case ZFS_PROP_REFRESERVATION: 1619219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1620219089Spjd "size is greater than available space")); 1621219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1622219089Spjd break; 1623219089Spjd 1624219089Spjd default: 1625219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1626219089Spjd break; 1627168404Spjd } 1628219089Spjd break; 1629219089Spjd 1630219089Spjd case EBUSY: 1631219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1632219089Spjd break; 1633219089Spjd 1634219089Spjd case EROFS: 1635219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1636219089Spjd break; 1637219089Spjd 1638271764Swill case E2BIG: 1639271764Swill zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1640271764Swill "property value too long")); 1641271764Swill (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1642271764Swill break; 1643271764Swill 1644219089Spjd case ENOTSUP: 1645219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1646219089Spjd "pool and or dataset must be upgraded to set this " 1647219089Spjd "property or value")); 1648219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1649219089Spjd break; 1650219089Spjd 1651219089Spjd case ERANGE: 1652274337Sdelphij case EDOM: 1653274337Sdelphij if (prop == ZFS_PROP_COMPRESSION || 1654274337Sdelphij prop == ZFS_PROP_RECORDSIZE) { 1655219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1656219089Spjd "property setting is not allowed on " 1657219089Spjd "bootable datasets")); 1658219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1659289422Smav } else if (prop == ZFS_PROP_CHECKSUM || 1660289422Smav prop == ZFS_PROP_DEDUP) { 1661289422Smav (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1662289422Smav "property setting is not allowed on " 1663289422Smav "root pools")); 1664289422Smav (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1665219089Spjd } else { 1666219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1667219089Spjd } 1668219089Spjd break; 1669219089Spjd 1670219089Spjd case EINVAL: 1671219089Spjd if (prop == ZPROP_INVAL) { 1672219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1673219089Spjd } else { 1674219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1675219089Spjd } 1676219089Spjd break; 1677219089Spjd 1678219089Spjd case EOVERFLOW: 1679219089Spjd /* 1680219089Spjd * This platform can't address a volume this big. 1681219089Spjd */ 1682219089Spjd#ifdef _ILP32 1683219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1684219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1685219089Spjd break; 1686219089Spjd } 1687219089Spjd#endif 1688219089Spjd /* FALLTHROUGH */ 1689219089Spjd default: 1690219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1691168404Spjd } 1692168404Spjd} 1693168404Spjd 1694168404Spjd/* 1695168404Spjd * Given a property name and value, set the property for the given dataset. 1696168404Spjd */ 1697168404Spjdint 1698168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1699168404Spjd{ 1700168404Spjd int ret = -1; 1701168404Spjd char errbuf[1024]; 1702168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1703289497Smav nvlist_t *nvl = NULL; 1704168404Spjd 1705168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1706168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1707168404Spjd zhp->zfs_name); 1708168404Spjd 1709168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1710168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1711168404Spjd (void) no_memory(hdl); 1712168404Spjd goto error; 1713168404Spjd } 1714168404Spjd 1715289497Smav ret = zfs_prop_set_list(zhp, nvl); 1716185029Spjd 1717289497Smaverror: 1718168404Spjd nvlist_free(nvl); 1719289497Smav return (ret); 1720289497Smav} 1721168404Spjd 1722168404Spjd 1723168404Spjd 1724289497Smav/* 1725289497Smav * Given an nvlist of property names and values, set the properties for the 1726289497Smav * given dataset. 1727289497Smav */ 1728289497Smavint 1729289497Smavzfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) 1730289497Smav{ 1731289497Smav zfs_cmd_t zc = { 0 }; 1732289497Smav int ret = -1; 1733289497Smav prop_changelist_t **cls = NULL; 1734289497Smav int cl_idx; 1735289497Smav char errbuf[1024]; 1736289497Smav libzfs_handle_t *hdl = zhp->zfs_hdl; 1737289497Smav nvlist_t *nvl; 1738289497Smav int nvl_len; 1739307107Smav int added_resv = 0; 1740219089Spjd 1741289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1742289497Smav dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1743289497Smav zhp->zfs_name); 1744168404Spjd 1745289497Smav if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, 1746289500Smav zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl, 1747289500Smav errbuf)) == NULL) 1748168404Spjd goto error; 1749168404Spjd 1750185029Spjd /* 1751289497Smav * We have to check for any extra properties which need to be added 1752289497Smav * before computing the length of the nvlist. 1753185029Spjd */ 1754289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1755289497Smav elem != NULL; 1756289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1757289497Smav if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && 1758289497Smav (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { 1759289497Smav goto error; 1760289497Smav } 1761238391Smm } 1762339103Smav 1763339103Smav if (added_resv != 1 && 1764339103Smav (added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) { 1765339103Smav goto error; 1766339103Smav } 1767339103Smav 1768289497Smav /* 1769289497Smav * Check how many properties we're setting and allocate an array to 1770289497Smav * store changelist pointers for postfix(). 1771289497Smav */ 1772289497Smav nvl_len = 0; 1773289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1774289497Smav elem != NULL; 1775289497Smav elem = nvlist_next_nvpair(nvl, elem)) 1776289497Smav nvl_len++; 1777289497Smav if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) 1778168404Spjd goto error; 1779168404Spjd 1780289497Smav cl_idx = 0; 1781289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1782289497Smav elem != NULL; 1783289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1784289497Smav 1785289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1786289497Smav 1787289497Smav assert(cl_idx < nvl_len); 1788289497Smav /* 1789289497Smav * We don't want to unmount & remount the dataset when changing 1790310068Savg * its canmount property to 'on' or 'noauto'. We only use 1791310068Savg * the changelist logic to unmount when setting canmount=off. 1792289497Smav */ 1793297521Savg if (prop != ZFS_PROP_CANMOUNT || 1794297521Savg (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF && 1795321522Smav zfs_is_mounted(zhp, NULL))) { 1796289497Smav cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); 1797289497Smav if (cls[cl_idx] == NULL) 1798289497Smav goto error; 1799289497Smav } 1800289497Smav 1801289497Smav if (prop == ZFS_PROP_MOUNTPOINT && 1802289497Smav changelist_haszonedchild(cls[cl_idx])) { 1803289497Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1804289497Smav "child dataset with inherited mountpoint is used " 1805289497Smav "in a non-global zone")); 1806289497Smav ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1807289497Smav goto error; 1808289497Smav } 1809289497Smav 1810289497Smav /* We don't support those properties on FreeBSD. */ 1811289497Smav switch (prop) { 1812289497Smav case ZFS_PROP_DEVICES: 1813289497Smav case ZFS_PROP_ISCSIOPTIONS: 1814289497Smav case ZFS_PROP_XATTR: 1815289497Smav case ZFS_PROP_VSCAN: 1816289497Smav case ZFS_PROP_NBMAND: 1817289497Smav case ZFS_PROP_MLSLABEL: 1818289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1819289497Smav "property '%s' not supported on FreeBSD", 1820289497Smav nvpair_name(elem)); 1821289497Smav ret = zfs_error(hdl, EZFS_PERM, errbuf); 1822289497Smav goto error; 1823289497Smav } 1824289497Smav 1825289497Smav if (cls[cl_idx] != NULL && 1826289497Smav (ret = changelist_prefix(cls[cl_idx])) != 0) 1827289497Smav goto error; 1828289497Smav 1829289497Smav cl_idx++; 1830289497Smav } 1831289497Smav assert(cl_idx == nvl_len); 1832289497Smav 1833168404Spjd /* 1834289497Smav * Execute the corresponding ioctl() to set this list of properties. 1835168404Spjd */ 1836168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1837168404Spjd 1838289497Smav if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 || 1839289497Smav (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0) 1840168404Spjd goto error; 1841168404Spjd 1842185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1843209962Smm 1844168404Spjd if (ret != 0) { 1845289497Smav /* Get the list of unset properties back and report them. */ 1846289497Smav nvlist_t *errorprops = NULL; 1847289497Smav if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) 1848289497Smav goto error; 1849289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1850289497Smav elem != NULL; 1851289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1852289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1853289497Smav zfs_setprop_error(hdl, prop, errno, errbuf); 1854289497Smav } 1855289497Smav nvlist_free(errorprops); 1856289497Smav 1857219089Spjd if (added_resv && errno == ENOSPC) { 1858219089Spjd /* clean up the volsize property we tried to set */ 1859219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1860219089Spjd ZFS_PROP_VOLSIZE); 1861219089Spjd nvlist_free(nvl); 1862289497Smav nvl = NULL; 1863219089Spjd zcmd_free_nvlists(&zc); 1864289497Smav 1865219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1866219089Spjd goto error; 1867219089Spjd if (nvlist_add_uint64(nvl, 1868219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1869219089Spjd old_volsize) != 0) 1870219089Spjd goto error; 1871219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1872219089Spjd goto error; 1873219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1874168404Spjd } 1875168404Spjd } else { 1876289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1877289497Smav if (cls[cl_idx] != NULL) { 1878289497Smav int clp_err = changelist_postfix(cls[cl_idx]); 1879289497Smav if (clp_err != 0) 1880289497Smav ret = clp_err; 1881289497Smav } 1882289497Smav } 1883185029Spjd 1884168404Spjd /* 1885168404Spjd * Refresh the statistics so the new property value 1886168404Spjd * is reflected. 1887168404Spjd */ 1888185029Spjd if (ret == 0) 1889168404Spjd (void) get_stats(zhp); 1890168404Spjd } 1891168404Spjd 1892168404Spjderror: 1893168404Spjd nvlist_free(nvl); 1894168404Spjd zcmd_free_nvlists(&zc); 1895289497Smav if (cls != NULL) { 1896289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1897289497Smav if (cls[cl_idx] != NULL) 1898289497Smav changelist_free(cls[cl_idx]); 1899289497Smav } 1900289497Smav free(cls); 1901289497Smav } 1902168404Spjd return (ret); 1903168404Spjd} 1904168404Spjd 1905168404Spjd/* 1906219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1907219089Spjd * is TRUE, revert to the received value, if any. 1908168404Spjd */ 1909168404Spjdint 1910219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1911168404Spjd{ 1912168404Spjd zfs_cmd_t zc = { 0 }; 1913168404Spjd int ret; 1914168404Spjd prop_changelist_t *cl; 1915168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1916168404Spjd char errbuf[1024]; 1917168404Spjd zfs_prop_t prop; 1918168404Spjd 1919168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1920168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1921168404Spjd 1922219089Spjd zc.zc_cookie = received; 1923185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1924168404Spjd /* 1925168404Spjd * For user properties, the amount of work we have to do is very 1926168404Spjd * small, so just do it here. 1927168404Spjd */ 1928168404Spjd if (!zfs_prop_user(propname)) { 1929168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1930168404Spjd "invalid property")); 1931168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1932168404Spjd } 1933168404Spjd 1934168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1935168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1936168404Spjd 1937185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1938168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1939168404Spjd 1940168404Spjd return (0); 1941168404Spjd } 1942168404Spjd 1943168404Spjd /* 1944168404Spjd * Verify that this property is inheritable. 1945168404Spjd */ 1946168404Spjd if (zfs_prop_readonly(prop)) 1947168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1948168404Spjd 1949219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1950168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1951168404Spjd 1952168404Spjd /* 1953168404Spjd * Check to see if the value applies to this type 1954168404Spjd */ 1955168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1956168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1957168404Spjd 1958168404Spjd /* 1959219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1960168404Spjd */ 1961168404Spjd propname = zfs_prop_to_name(prop); 1962168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1963168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1964168404Spjd 1965168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1966168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1967168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1968168404Spjd "dataset is used in a non-global zone")); 1969168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1970168404Spjd } 1971168404Spjd 1972168404Spjd /* 1973168404Spjd * Determine datasets which will be affected by this change, if any. 1974168404Spjd */ 1975185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1976168404Spjd return (-1); 1977168404Spjd 1978168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1979168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1980168404Spjd "child dataset with inherited mountpoint is used " 1981168404Spjd "in a non-global zone")); 1982168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1983168404Spjd goto error; 1984168404Spjd } 1985168404Spjd 1986168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1987168404Spjd goto error; 1988168404Spjd 1989185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1990168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1991168404Spjd } else { 1992168404Spjd 1993168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1994168404Spjd goto error; 1995168404Spjd 1996168404Spjd /* 1997168404Spjd * Refresh the statistics so the new property is reflected. 1998168404Spjd */ 1999168404Spjd (void) get_stats(zhp); 2000168404Spjd } 2001168404Spjd 2002168404Spjderror: 2003168404Spjd changelist_free(cl); 2004168404Spjd return (ret); 2005168404Spjd} 2006168404Spjd 2007168404Spjd/* 2008168404Spjd * True DSL properties are stored in an nvlist. The following two functions 2009168404Spjd * extract them appropriately. 2010168404Spjd */ 2011168404Spjdstatic uint64_t 2012168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2013168404Spjd{ 2014168404Spjd nvlist_t *nv; 2015168404Spjd uint64_t value; 2016168404Spjd 2017168404Spjd *source = NULL; 2018168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 2019168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 2020185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 2021185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 2022168404Spjd } else { 2023205198Sdelphij verify(!zhp->zfs_props_table || 2024205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 2025168404Spjd value = zfs_prop_default_numeric(prop); 2026168404Spjd *source = ""; 2027168404Spjd } 2028168404Spjd 2029168404Spjd return (value); 2030168404Spjd} 2031168404Spjd 2032289362Smavstatic const char * 2033168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2034168404Spjd{ 2035168404Spjd nvlist_t *nv; 2036289362Smav const char *value; 2037168404Spjd 2038168404Spjd *source = NULL; 2039168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 2040168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 2041289362Smav value = fnvlist_lookup_string(nv, ZPROP_VALUE); 2042185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 2043168404Spjd } else { 2044205198Sdelphij verify(!zhp->zfs_props_table || 2045205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 2046289362Smav value = zfs_prop_default_string(prop); 2047168404Spjd *source = ""; 2048168404Spjd } 2049168404Spjd 2050168404Spjd return (value); 2051168404Spjd} 2052168404Spjd 2053219089Spjdstatic boolean_t 2054219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 2055219089Spjd{ 2056219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 2057219089Spjd} 2058219089Spjd 2059219089Spjdstatic void 2060219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 2061219089Spjd{ 2062219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 2063219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 2064219089Spjd} 2065219089Spjd 2066219089Spjdstatic void 2067219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 2068219089Spjd{ 2069219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 2070219089Spjd *cookie = 0; 2071219089Spjd} 2072219089Spjd 2073168404Spjd/* 2074168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 2075168404Spjd * zfs_prop_get_int() are built using this interface. 2076168404Spjd * 2077168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 2078168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 2079168404Spjd * If they differ from the on-disk values, report the current values and mark 2080168404Spjd * the source "temporary". 2081168404Spjd */ 2082168404Spjdstatic int 2083185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 2084168404Spjd char **source, uint64_t *val) 2085168404Spjd{ 2086185029Spjd zfs_cmd_t zc = { 0 }; 2087185029Spjd nvlist_t *zplprops = NULL; 2088168404Spjd struct mnttab mnt; 2089168404Spjd char *mntopt_on = NULL; 2090168404Spjd char *mntopt_off = NULL; 2091219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2092168404Spjd 2093168404Spjd *source = NULL; 2094168404Spjd 2095168404Spjd switch (prop) { 2096168404Spjd case ZFS_PROP_ATIME: 2097168404Spjd mntopt_on = MNTOPT_ATIME; 2098168404Spjd mntopt_off = MNTOPT_NOATIME; 2099168404Spjd break; 2100168404Spjd 2101168404Spjd case ZFS_PROP_DEVICES: 2102168404Spjd mntopt_on = MNTOPT_DEVICES; 2103168404Spjd mntopt_off = MNTOPT_NODEVICES; 2104168404Spjd break; 2105168404Spjd 2106168404Spjd case ZFS_PROP_EXEC: 2107168404Spjd mntopt_on = MNTOPT_EXEC; 2108168404Spjd mntopt_off = MNTOPT_NOEXEC; 2109168404Spjd break; 2110168404Spjd 2111168404Spjd case ZFS_PROP_READONLY: 2112168404Spjd mntopt_on = MNTOPT_RO; 2113168404Spjd mntopt_off = MNTOPT_RW; 2114168404Spjd break; 2115168404Spjd 2116168404Spjd case ZFS_PROP_SETUID: 2117168404Spjd mntopt_on = MNTOPT_SETUID; 2118168404Spjd mntopt_off = MNTOPT_NOSETUID; 2119168404Spjd break; 2120168404Spjd 2121168404Spjd case ZFS_PROP_XATTR: 2122168404Spjd mntopt_on = MNTOPT_XATTR; 2123168404Spjd mntopt_off = MNTOPT_NOXATTR; 2124168404Spjd break; 2125185029Spjd 2126185029Spjd case ZFS_PROP_NBMAND: 2127185029Spjd mntopt_on = MNTOPT_NBMAND; 2128185029Spjd mntopt_off = MNTOPT_NONBMAND; 2129185029Spjd break; 2130307050Smav 2131307050Smav default: 2132307050Smav break; 2133168404Spjd } 2134168404Spjd 2135168404Spjd /* 2136168404Spjd * Because looking up the mount options is potentially expensive 2137168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 2138168404Spjd * we're looking up a property which requires its presence. 2139168404Spjd */ 2140168404Spjd if (!zhp->zfs_mntcheck && 2141168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 2142209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 2143209962Smm struct mnttab entry; 2144168404Spjd 2145209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 2146209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 2147168404Spjd entry.mnt_mntopts); 2148168404Spjd if (zhp->zfs_mntopts == NULL) 2149168404Spjd return (-1); 2150168404Spjd } 2151168404Spjd 2152168404Spjd zhp->zfs_mntcheck = B_TRUE; 2153168404Spjd } 2154168404Spjd 2155168404Spjd if (zhp->zfs_mntopts == NULL) 2156168404Spjd mnt.mnt_mntopts = ""; 2157168404Spjd else 2158168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 2159168404Spjd 2160168404Spjd switch (prop) { 2161168404Spjd case ZFS_PROP_ATIME: 2162168404Spjd case ZFS_PROP_DEVICES: 2163168404Spjd case ZFS_PROP_EXEC: 2164168404Spjd case ZFS_PROP_READONLY: 2165168404Spjd case ZFS_PROP_SETUID: 2166168404Spjd case ZFS_PROP_XATTR: 2167185029Spjd case ZFS_PROP_NBMAND: 2168168404Spjd *val = getprop_uint64(zhp, prop, source); 2169168404Spjd 2170219089Spjd if (received) 2171219089Spjd break; 2172219089Spjd 2173168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 2174168404Spjd *val = B_TRUE; 2175168404Spjd if (src) 2176185029Spjd *src = ZPROP_SRC_TEMPORARY; 2177168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2178168404Spjd *val = B_FALSE; 2179168404Spjd if (src) 2180185029Spjd *src = ZPROP_SRC_TEMPORARY; 2181168404Spjd } 2182168404Spjd break; 2183168404Spjd 2184168404Spjd case ZFS_PROP_CANMOUNT: 2185219089Spjd case ZFS_PROP_VOLSIZE: 2186168404Spjd case ZFS_PROP_QUOTA: 2187185029Spjd case ZFS_PROP_REFQUOTA: 2188168404Spjd case ZFS_PROP_RESERVATION: 2189185029Spjd case ZFS_PROP_REFRESERVATION: 2190264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2191264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2192264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2193264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2194168404Spjd *val = getprop_uint64(zhp, prop, source); 2195219089Spjd 2196219089Spjd if (*source == NULL) { 2197219089Spjd /* not default, must be local */ 2198168404Spjd *source = zhp->zfs_name; 2199219089Spjd } 2200168404Spjd break; 2201168404Spjd 2202168404Spjd case ZFS_PROP_MOUNTED: 2203168404Spjd *val = (zhp->zfs_mntopts != NULL); 2204168404Spjd break; 2205168404Spjd 2206168404Spjd case ZFS_PROP_NUMCLONES: 2207168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 2208168404Spjd break; 2209168404Spjd 2210185029Spjd case ZFS_PROP_VERSION: 2211185029Spjd case ZFS_PROP_NORMALIZE: 2212185029Spjd case ZFS_PROP_UTF8ONLY: 2213185029Spjd case ZFS_PROP_CASE: 2214185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 2215185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2216185029Spjd return (-1); 2217185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2218185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2219185029Spjd zcmd_free_nvlists(&zc); 2220219089Spjd return (-1); 2221185029Spjd } 2222185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2223185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2224185029Spjd val) != 0) { 2225185029Spjd zcmd_free_nvlists(&zc); 2226219089Spjd return (-1); 2227185029Spjd } 2228296528Smav nvlist_free(zplprops); 2229185029Spjd zcmd_free_nvlists(&zc); 2230185029Spjd break; 2231185029Spjd 2232253819Sdelphij case ZFS_PROP_INCONSISTENT: 2233253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 2234253819Sdelphij break; 2235253819Sdelphij 2236168404Spjd default: 2237185029Spjd switch (zfs_prop_get_type(prop)) { 2238185029Spjd case PROP_TYPE_NUMBER: 2239185029Spjd case PROP_TYPE_INDEX: 2240185029Spjd *val = getprop_uint64(zhp, prop, source); 2241185029Spjd /* 2242209962Smm * If we tried to use a default value for a 2243185029Spjd * readonly property, it means that it was not 2244331391Smav * present. Note this only applies to "truly" 2245331391Smav * readonly properties, not set-once properties 2246331391Smav * like volblocksize. 2247185029Spjd */ 2248185029Spjd if (zfs_prop_readonly(prop) && 2249331391Smav !zfs_prop_setonce(prop) && 2250219089Spjd *source != NULL && (*source)[0] == '\0') { 2251219089Spjd *source = NULL; 2252325139Savg return (-1); 2253185029Spjd } 2254185029Spjd break; 2255185029Spjd 2256185029Spjd case PROP_TYPE_STRING: 2257185029Spjd default: 2258185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2259185029Spjd "cannot get non-numeric property")); 2260185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2261185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 2262185029Spjd } 2263168404Spjd } 2264168404Spjd 2265168404Spjd return (0); 2266168404Spjd} 2267168404Spjd 2268168404Spjd/* 2269168404Spjd * Calculate the source type, given the raw source string. 2270168404Spjd */ 2271168404Spjdstatic void 2272185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 2273168404Spjd char *statbuf, size_t statlen) 2274168404Spjd{ 2275185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 2276168404Spjd return; 2277168404Spjd 2278168404Spjd if (source == NULL) { 2279185029Spjd *srctype = ZPROP_SRC_NONE; 2280168404Spjd } else if (source[0] == '\0') { 2281185029Spjd *srctype = ZPROP_SRC_DEFAULT; 2282219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 2283219089Spjd *srctype = ZPROP_SRC_RECEIVED; 2284168404Spjd } else { 2285168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 2286185029Spjd *srctype = ZPROP_SRC_LOCAL; 2287168404Spjd } else { 2288168404Spjd (void) strlcpy(statbuf, source, statlen); 2289185029Spjd *srctype = ZPROP_SRC_INHERITED; 2290168404Spjd } 2291168404Spjd } 2292168404Spjd 2293168404Spjd} 2294168404Spjd 2295219089Spjdint 2296219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2297219089Spjd size_t proplen, boolean_t literal) 2298219089Spjd{ 2299219089Spjd zfs_prop_t prop; 2300219089Spjd int err = 0; 2301219089Spjd 2302219089Spjd if (zhp->zfs_recvd_props == NULL) 2303219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 2304219089Spjd return (-1); 2305219089Spjd 2306219089Spjd prop = zfs_name_to_prop(propname); 2307219089Spjd 2308219089Spjd if (prop != ZPROP_INVAL) { 2309219089Spjd uint64_t cookie; 2310219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2311219089Spjd return (-1); 2312219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 2313219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 2314219089Spjd NULL, NULL, 0, literal); 2315219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 2316219089Spjd } else { 2317219089Spjd nvlist_t *propval; 2318219089Spjd char *recvdval; 2319219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2320219089Spjd propname, &propval) != 0) 2321219089Spjd return (-1); 2322219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 2323219089Spjd &recvdval) == 0); 2324219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 2325219089Spjd } 2326219089Spjd 2327219089Spjd return (err == 0 ? 0 : -1); 2328219089Spjd} 2329219089Spjd 2330228103Smmstatic int 2331228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2332228103Smm{ 2333228103Smm nvlist_t *value; 2334228103Smm nvpair_t *pair; 2335228103Smm 2336228103Smm value = zfs_get_clones_nvl(zhp); 2337228103Smm if (value == NULL) 2338228103Smm return (-1); 2339228103Smm 2340228103Smm propbuf[0] = '\0'; 2341228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2342228103Smm pair = nvlist_next_nvpair(value, pair)) { 2343228103Smm if (propbuf[0] != '\0') 2344228103Smm (void) strlcat(propbuf, ",", proplen); 2345228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 2346228103Smm } 2347228103Smm 2348228103Smm return (0); 2349228103Smm} 2350228103Smm 2351228103Smmstruct get_clones_arg { 2352228103Smm uint64_t numclones; 2353228103Smm nvlist_t *value; 2354228103Smm const char *origin; 2355307108Smav char buf[ZFS_MAX_DATASET_NAME_LEN]; 2356228103Smm}; 2357228103Smm 2358228103Smmint 2359228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2360228103Smm{ 2361228103Smm struct get_clones_arg *gca = arg; 2362228103Smm 2363228103Smm if (gca->numclones == 0) { 2364228103Smm zfs_close(zhp); 2365228103Smm return (0); 2366228103Smm } 2367228103Smm 2368228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2369228103Smm NULL, NULL, 0, B_TRUE) != 0) 2370228103Smm goto out; 2371228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2372248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2373228103Smm gca->numclones--; 2374228103Smm } 2375228103Smm 2376228103Smmout: 2377228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2378228103Smm zfs_close(zhp); 2379228103Smm return (0); 2380228103Smm} 2381228103Smm 2382228103Smmnvlist_t * 2383228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2384228103Smm{ 2385228103Smm nvlist_t *nv, *value; 2386228103Smm 2387228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2388228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2389228103Smm struct get_clones_arg gca; 2390228103Smm 2391228103Smm /* 2392228103Smm * if this is a snapshot, then the kernel wasn't able 2393228103Smm * to get the clones. Do it by slowly iterating. 2394228103Smm */ 2395228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2396228103Smm return (NULL); 2397228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2398228103Smm return (NULL); 2399228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2400228103Smm nvlist_free(nv); 2401228103Smm return (NULL); 2402228103Smm } 2403228103Smm 2404228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2405228103Smm gca.value = value; 2406228103Smm gca.origin = zhp->zfs_name; 2407228103Smm 2408228103Smm if (gca.numclones != 0) { 2409228103Smm zfs_handle_t *root; 2410307108Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 2411228103Smm char *cp = pool; 2412228103Smm 2413228103Smm /* get the pool name */ 2414228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2415228103Smm (void) strsep(&cp, "/@"); 2416228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2417228103Smm ZFS_TYPE_FILESYSTEM); 2418228103Smm 2419228103Smm (void) get_clones_cb(root, &gca); 2420228103Smm } 2421228103Smm 2422228103Smm if (gca.numclones != 0 || 2423228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2424228103Smm nvlist_add_nvlist(zhp->zfs_props, 2425228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2426228103Smm nvlist_free(nv); 2427228103Smm nvlist_free(value); 2428228103Smm return (NULL); 2429228103Smm } 2430228103Smm nvlist_free(nv); 2431228103Smm nvlist_free(value); 2432228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2433228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2434228103Smm } 2435228103Smm 2436228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2437228103Smm 2438228103Smm return (value); 2439228103Smm} 2440228103Smm 2441168404Spjd/* 2442325534Savg * Accepts a property and value and checks that the value 2443325534Savg * matches the one found by the channel program. If they are 2444325534Savg * not equal, print both of them. 2445325534Savg */ 2446325534Savgvoid 2447325534Savgzcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval, 2448325534Savg const char *strval) 2449325534Savg{ 2450325534Savg if (!zhp->zfs_hdl->libzfs_prop_debug) 2451325534Savg return; 2452325534Savg int error; 2453325534Savg char *poolname = zhp->zpool_hdl->zpool_name; 2454325534Savg const char *program = 2455325534Savg "args = ...\n" 2456325534Savg "ds = args['dataset']\n" 2457325534Savg "prop = args['property']\n" 2458325534Savg "value, setpoint = zfs.get_prop(ds, prop)\n" 2459325534Savg "return {value=value, setpoint=setpoint}\n"; 2460325534Savg nvlist_t *outnvl; 2461325534Savg nvlist_t *retnvl; 2462325534Savg nvlist_t *argnvl = fnvlist_alloc(); 2463325534Savg 2464325534Savg fnvlist_add_string(argnvl, "dataset", zhp->zfs_name); 2465325534Savg fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop)); 2466325534Savg 2467329484Smav error = lzc_channel_program_nosync(poolname, program, 2468325534Savg 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl); 2469325534Savg 2470325534Savg if (error == 0) { 2471325534Savg retnvl = fnvlist_lookup_nvlist(outnvl, "return"); 2472325534Savg if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) { 2473325534Savg int64_t ans; 2474325534Savg error = nvlist_lookup_int64(retnvl, "value", &ans); 2475325534Savg if (error != 0) { 2476325534Savg (void) fprintf(stderr, "zcp check error: %u\n", 2477325534Savg error); 2478325534Savg return; 2479325534Savg } 2480325534Savg if (ans != intval) { 2481325534Savg (void) fprintf(stderr, 2482325534Savg "%s: zfs found %lld, but zcp found %lld\n", 2483325534Savg zfs_prop_to_name(prop), 2484325534Savg (longlong_t)intval, (longlong_t)ans); 2485325534Savg } 2486325534Savg } else { 2487325534Savg char *str_ans; 2488325534Savg error = nvlist_lookup_string(retnvl, "value", &str_ans); 2489325534Savg if (error != 0) { 2490325534Savg (void) fprintf(stderr, "zcp check error: %u\n", 2491325534Savg error); 2492325534Savg return; 2493325534Savg } 2494325534Savg if (strcmp(strval, str_ans) != 0) { 2495325534Savg (void) fprintf(stderr, 2496325534Savg "%s: zfs found %s, but zcp found %s\n", 2497325534Savg zfs_prop_to_name(prop), 2498325534Savg strval, str_ans); 2499325534Savg } 2500325534Savg } 2501325534Savg } else { 2502325534Savg (void) fprintf(stderr, 2503325534Savg "zcp check failed, channel program error: %u\n", error); 2504325534Savg } 2505325534Savg nvlist_free(argnvl); 2506325534Savg nvlist_free(outnvl); 2507325534Savg} 2508325534Savg 2509325534Savg/* 2510168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2511168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2512168404Spjd * human-readable form. 2513168404Spjd * 2514168404Spjd * Returns 0 on success, or -1 on error. 2515168404Spjd */ 2516168404Spjdint 2517168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2518185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2519168404Spjd{ 2520168404Spjd char *source = NULL; 2521168404Spjd uint64_t val; 2522289362Smav const char *str; 2523168404Spjd const char *strval; 2524219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2525168404Spjd 2526168404Spjd /* 2527168404Spjd * Check to see if this property applies to our object 2528168404Spjd */ 2529168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2530168404Spjd return (-1); 2531168404Spjd 2532219089Spjd if (received && zfs_prop_readonly(prop)) 2533219089Spjd return (-1); 2534219089Spjd 2535168404Spjd if (src) 2536185029Spjd *src = ZPROP_SRC_NONE; 2537168404Spjd 2538168404Spjd switch (prop) { 2539168404Spjd case ZFS_PROP_CREATION: 2540168404Spjd /* 2541168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2542168404Spjd * this into a string unless 'literal' is specified. 2543168404Spjd */ 2544168404Spjd { 2545168404Spjd val = getprop_uint64(zhp, prop, &source); 2546168404Spjd time_t time = (time_t)val; 2547168404Spjd struct tm t; 2548168404Spjd 2549168404Spjd if (literal || 2550168404Spjd localtime_r(&time, &t) == NULL || 2551168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2552168404Spjd &t) == 0) 2553168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2554168404Spjd } 2555325534Savg zcp_check(zhp, prop, val, NULL); 2556168404Spjd break; 2557168404Spjd 2558168404Spjd case ZFS_PROP_MOUNTPOINT: 2559168404Spjd /* 2560168404Spjd * Getting the precise mountpoint can be tricky. 2561168404Spjd * 2562168404Spjd * - for 'none' or 'legacy', return those values. 2563168404Spjd * - for inherited mountpoints, we want to take everything 2564168404Spjd * after our ancestor and append it to the inherited value. 2565168404Spjd * 2566168404Spjd * If the pool has an alternate root, we want to prepend that 2567168404Spjd * root to any values we return. 2568168404Spjd */ 2569185029Spjd 2570168404Spjd str = getprop_string(zhp, prop, &source); 2571168404Spjd 2572185029Spjd if (str[0] == '/') { 2573185029Spjd char buf[MAXPATHLEN]; 2574185029Spjd char *root = buf; 2575219089Spjd const char *relpath; 2576168404Spjd 2577219089Spjd /* 2578219089Spjd * If we inherit the mountpoint, even from a dataset 2579219089Spjd * with a received value, the source will be the path of 2580219089Spjd * the dataset we inherit from. If source is 2581219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2582219089Spjd * inherited. 2583219089Spjd */ 2584219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2585219089Spjd relpath = ""; 2586219089Spjd } else { 2587219089Spjd relpath = zhp->zfs_name + strlen(source); 2588219089Spjd if (relpath[0] == '/') 2589219089Spjd relpath++; 2590219089Spjd } 2591185029Spjd 2592185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2593263889Sdelphij ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, 2594263889Sdelphij B_FALSE)) || (strcmp(root, "-") == 0)) 2595185029Spjd root[0] = '\0'; 2596185029Spjd /* 2597185029Spjd * Special case an alternate root of '/'. This will 2598185029Spjd * avoid having multiple leading slashes in the 2599185029Spjd * mountpoint path. 2600185029Spjd */ 2601185029Spjd if (strcmp(root, "/") == 0) 2602185029Spjd root++; 2603185029Spjd 2604185029Spjd /* 2605185029Spjd * If the mountpoint is '/' then skip over this 2606185029Spjd * if we are obtaining either an alternate root or 2607185029Spjd * an inherited mountpoint. 2608185029Spjd */ 2609185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2610185029Spjd relpath[0] != '\0')) 2611168404Spjd str++; 2612168404Spjd 2613168404Spjd if (relpath[0] == '\0') 2614168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2615168404Spjd root, str); 2616168404Spjd else 2617168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2618168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2619168404Spjd relpath); 2620168404Spjd } else { 2621168404Spjd /* 'legacy' or 'none' */ 2622168404Spjd (void) strlcpy(propbuf, str, proplen); 2623168404Spjd } 2624325534Savg zcp_check(zhp, prop, NULL, propbuf); 2625168404Spjd break; 2626168404Spjd 2627168404Spjd case ZFS_PROP_ORIGIN: 2628289362Smav str = getprop_string(zhp, prop, &source); 2629289362Smav if (str == NULL) 2630168404Spjd return (-1); 2631289362Smav (void) strlcpy(propbuf, str, proplen); 2632325534Savg zcp_check(zhp, prop, NULL, str); 2633168404Spjd break; 2634168404Spjd 2635228103Smm case ZFS_PROP_CLONES: 2636228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2637228103Smm return (-1); 2638228103Smm break; 2639228103Smm 2640168404Spjd case ZFS_PROP_QUOTA: 2641185029Spjd case ZFS_PROP_REFQUOTA: 2642168404Spjd case ZFS_PROP_RESERVATION: 2643185029Spjd case ZFS_PROP_REFRESERVATION: 2644185029Spjd 2645168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2646168404Spjd return (-1); 2647168404Spjd /* 2648168404Spjd * If quota or reservation is 0, we translate this into 'none' 2649168404Spjd * (unless literal is set), and indicate that it's the default 2650168404Spjd * value. Otherwise, we print the number nicely and indicate 2651168404Spjd * that its set locally. 2652168404Spjd */ 2653168404Spjd if (val == 0) { 2654168404Spjd if (literal) 2655168404Spjd (void) strlcpy(propbuf, "0", proplen); 2656168404Spjd else 2657168404Spjd (void) strlcpy(propbuf, "none", proplen); 2658168404Spjd } else { 2659168404Spjd if (literal) 2660168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2661168404Spjd (u_longlong_t)val); 2662168404Spjd else 2663168404Spjd zfs_nicenum(val, propbuf, proplen); 2664168404Spjd } 2665325534Savg zcp_check(zhp, prop, val, NULL); 2666168404Spjd break; 2667168404Spjd 2668264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2669264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2670264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2671264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2672264835Sdelphij 2673264835Sdelphij if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2674264835Sdelphij return (-1); 2675264835Sdelphij 2676264835Sdelphij /* 2677264835Sdelphij * If limit is UINT64_MAX, we translate this into 'none' (unless 2678264835Sdelphij * literal is set), and indicate that it's the default value. 2679264835Sdelphij * Otherwise, we print the number nicely and indicate that it's 2680264835Sdelphij * set locally. 2681264835Sdelphij */ 2682264835Sdelphij if (literal) { 2683264835Sdelphij (void) snprintf(propbuf, proplen, "%llu", 2684264835Sdelphij (u_longlong_t)val); 2685264835Sdelphij } else if (val == UINT64_MAX) { 2686264835Sdelphij (void) strlcpy(propbuf, "none", proplen); 2687264835Sdelphij } else { 2688264835Sdelphij zfs_nicenum(val, propbuf, proplen); 2689264835Sdelphij } 2690325534Savg 2691325534Savg zcp_check(zhp, prop, val, NULL); 2692264835Sdelphij break; 2693264835Sdelphij 2694223623Smm case ZFS_PROP_REFRATIO: 2695168404Spjd case ZFS_PROP_COMPRESSRATIO: 2696168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2697168404Spjd return (-1); 2698219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2699219089Spjd (u_longlong_t)(val / 100), 2700219089Spjd (u_longlong_t)(val % 100)); 2701325534Savg zcp_check(zhp, prop, val, NULL); 2702168404Spjd break; 2703168404Spjd 2704168404Spjd case ZFS_PROP_TYPE: 2705168404Spjd switch (zhp->zfs_type) { 2706168404Spjd case ZFS_TYPE_FILESYSTEM: 2707168404Spjd str = "filesystem"; 2708168404Spjd break; 2709168404Spjd case ZFS_TYPE_VOLUME: 2710168404Spjd str = "volume"; 2711168404Spjd break; 2712168404Spjd case ZFS_TYPE_SNAPSHOT: 2713168404Spjd str = "snapshot"; 2714168404Spjd break; 2715260183Sdelphij case ZFS_TYPE_BOOKMARK: 2716260183Sdelphij str = "bookmark"; 2717260183Sdelphij break; 2718168404Spjd default: 2719168404Spjd abort(); 2720168404Spjd } 2721168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2722325534Savg zcp_check(zhp, prop, NULL, propbuf); 2723168404Spjd break; 2724168404Spjd 2725168404Spjd case ZFS_PROP_MOUNTED: 2726168404Spjd /* 2727168404Spjd * The 'mounted' property is a pseudo-property that described 2728168404Spjd * whether the filesystem is currently mounted. Even though 2729168404Spjd * it's a boolean value, the typical values of "on" and "off" 2730168404Spjd * don't make sense, so we translate to "yes" and "no". 2731168404Spjd */ 2732168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2733168404Spjd src, &source, &val) != 0) 2734168404Spjd return (-1); 2735168404Spjd if (val) 2736168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2737168404Spjd else 2738168404Spjd (void) strlcpy(propbuf, "no", proplen); 2739168404Spjd break; 2740168404Spjd 2741168404Spjd case ZFS_PROP_NAME: 2742168404Spjd /* 2743168404Spjd * The 'name' property is a pseudo-property derived from the 2744168404Spjd * dataset name. It is presented as a real property to simplify 2745168404Spjd * consumers. 2746168404Spjd */ 2747168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2748325534Savg zcp_check(zhp, prop, NULL, propbuf); 2749168404Spjd break; 2750168404Spjd 2751219089Spjd case ZFS_PROP_MLSLABEL: 2752219089Spjd { 2753277300Ssmh#ifdef illumos 2754219089Spjd m_label_t *new_sl = NULL; 2755219089Spjd char *ascii = NULL; /* human readable label */ 2756219089Spjd 2757219089Spjd (void) strlcpy(propbuf, 2758219089Spjd getprop_string(zhp, prop, &source), proplen); 2759219089Spjd 2760219089Spjd if (literal || (strcasecmp(propbuf, 2761219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2762219089Spjd break; 2763219089Spjd 2764219089Spjd /* 2765219089Spjd * Try to translate the internal hex string to 2766219089Spjd * human-readable output. If there are any 2767219089Spjd * problems just use the hex string. 2768219089Spjd */ 2769219089Spjd 2770219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2771219089Spjd L_NO_CORRECTION, NULL) == -1) { 2772219089Spjd m_label_free(new_sl); 2773219089Spjd break; 2774219089Spjd } 2775219089Spjd 2776219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2777219089Spjd DEF_NAMES) != 0) { 2778219089Spjd if (ascii) 2779219089Spjd free(ascii); 2780219089Spjd m_label_free(new_sl); 2781219089Spjd break; 2782219089Spjd } 2783219089Spjd m_label_free(new_sl); 2784219089Spjd 2785219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2786219089Spjd free(ascii); 2787277300Ssmh#else /* !illumos */ 2788219089Spjd propbuf[0] = '\0'; 2789277300Ssmh#endif /* illumos */ 2790219089Spjd } 2791219089Spjd break; 2792219089Spjd 2793236705Smm case ZFS_PROP_GUID: 2794339142Smav case ZFS_PROP_CREATETXG: 2795236705Smm /* 2796236705Smm * GUIDs are stored as numbers, but they are identifiers. 2797236705Smm * We don't want them to be pretty printed, because pretty 2798236705Smm * printing mangles the ID into a truncated and useless value. 2799236705Smm */ 2800236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2801236705Smm return (-1); 2802236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2803325534Savg zcp_check(zhp, prop, val, NULL); 2804236705Smm break; 2805236705Smm 2806168404Spjd default: 2807185029Spjd switch (zfs_prop_get_type(prop)) { 2808185029Spjd case PROP_TYPE_NUMBER: 2809185029Spjd if (get_numeric_property(zhp, prop, src, 2810325534Savg &source, &val) != 0) { 2811185029Spjd return (-1); 2812325534Savg } 2813325534Savg 2814325534Savg if (literal) { 2815185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2816185029Spjd (u_longlong_t)val); 2817325534Savg } else { 2818185029Spjd zfs_nicenum(val, propbuf, proplen); 2819325534Savg } 2820325534Savg zcp_check(zhp, prop, val, NULL); 2821185029Spjd break; 2822185029Spjd 2823185029Spjd case PROP_TYPE_STRING: 2824289362Smav str = getprop_string(zhp, prop, &source); 2825289362Smav if (str == NULL) 2826289362Smav return (-1); 2827325534Savg 2828289362Smav (void) strlcpy(propbuf, str, proplen); 2829325534Savg zcp_check(zhp, prop, NULL, str); 2830185029Spjd break; 2831185029Spjd 2832185029Spjd case PROP_TYPE_INDEX: 2833185029Spjd if (get_numeric_property(zhp, prop, src, 2834185029Spjd &source, &val) != 0) 2835185029Spjd return (-1); 2836185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2837185029Spjd return (-1); 2838325534Savg 2839185029Spjd (void) strlcpy(propbuf, strval, proplen); 2840325534Savg zcp_check(zhp, prop, NULL, strval); 2841185029Spjd break; 2842185029Spjd 2843185029Spjd default: 2844185029Spjd abort(); 2845185029Spjd } 2846168404Spjd } 2847168404Spjd 2848168404Spjd get_source(zhp, src, source, statbuf, statlen); 2849168404Spjd 2850168404Spjd return (0); 2851168404Spjd} 2852168404Spjd 2853168404Spjd/* 2854168404Spjd * Utility function to get the given numeric property. Does no validation that 2855168404Spjd * the given property is the appropriate type; should only be used with 2856168404Spjd * hard-coded property types. 2857168404Spjd */ 2858168404Spjduint64_t 2859168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2860168404Spjd{ 2861168404Spjd char *source; 2862168404Spjd uint64_t val; 2863168404Spjd 2864185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2865168404Spjd 2866168404Spjd return (val); 2867168404Spjd} 2868168404Spjd 2869185029Spjdint 2870185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2871185029Spjd{ 2872185029Spjd char buf[64]; 2873185029Spjd 2874209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2875185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2876185029Spjd} 2877185029Spjd 2878168404Spjd/* 2879168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2880168404Spjd */ 2881168404Spjdint 2882168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2883185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2884168404Spjd{ 2885168404Spjd char *source; 2886168404Spjd 2887168404Spjd /* 2888168404Spjd * Check to see if this property applies to our object 2889168404Spjd */ 2890185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2891168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2892168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2893168404Spjd zfs_prop_to_name(prop))); 2894185029Spjd } 2895168404Spjd 2896168404Spjd if (src) 2897185029Spjd *src = ZPROP_SRC_NONE; 2898168404Spjd 2899168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2900168404Spjd return (-1); 2901168404Spjd 2902168404Spjd get_source(zhp, src, source, statbuf, statlen); 2903168404Spjd 2904168404Spjd return (0); 2905168404Spjd} 2906168404Spjd 2907209962Smmstatic int 2908209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2909209962Smm char **domainp, idmap_rid_t *ridp) 2910209962Smm{ 2911277300Ssmh#ifdef illumos 2912209962Smm idmap_get_handle_t *get_hdl = NULL; 2913209962Smm idmap_stat status; 2914209962Smm int err = EINVAL; 2915209962Smm 2916219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2917209962Smm goto out; 2918209962Smm 2919209962Smm if (isuser) { 2920209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2921209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2922209962Smm } else { 2923209962Smm err = idmap_get_sidbygid(get_hdl, id, 2924209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2925209962Smm } 2926209962Smm if (err == IDMAP_SUCCESS && 2927209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2928209962Smm status == IDMAP_SUCCESS) 2929209962Smm err = 0; 2930209962Smm else 2931209962Smm err = EINVAL; 2932209962Smmout: 2933209962Smm if (get_hdl) 2934209962Smm idmap_get_destroy(get_hdl); 2935209962Smm return (err); 2936277300Ssmh#else /* !illumos */ 2937209962Smm assert(!"invalid code path"); 2938264852Ssmh return (EINVAL); // silence compiler warning 2939277300Ssmh#endif /* illumos */ 2940209962Smm} 2941209962Smm 2942168404Spjd/* 2943209962Smm * convert the propname into parameters needed by kernel 2944209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2945209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2946209962Smm */ 2947209962Smmstatic int 2948209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2949209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2950209962Smm{ 2951209962Smm zfs_userquota_prop_t type; 2952209962Smm char *cp, *end; 2953209962Smm char *numericsid = NULL; 2954209962Smm boolean_t isuser; 2955209962Smm 2956209962Smm domain[0] = '\0'; 2957275579Sdelphij *ridp = 0; 2958209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2959209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2960209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2961209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2962209962Smm break; 2963209962Smm } 2964209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2965209962Smm return (EINVAL); 2966209962Smm *typep = type; 2967209962Smm 2968209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2969209962Smm type == ZFS_PROP_USERUSED); 2970209962Smm 2971209962Smm cp = strchr(propname, '@') + 1; 2972209962Smm 2973209962Smm if (strchr(cp, '@')) { 2974277300Ssmh#ifdef illumos 2975209962Smm /* 2976209962Smm * It's a SID name (eg "user@domain") that needs to be 2977209962Smm * turned into S-1-domainID-RID. 2978209962Smm */ 2979275579Sdelphij int flag = 0; 2980275579Sdelphij idmap_stat stat, map_stat; 2981275579Sdelphij uid_t pid; 2982275579Sdelphij idmap_rid_t rid; 2983275579Sdelphij idmap_get_handle_t *gh = NULL; 2984275579Sdelphij 2985275579Sdelphij stat = idmap_get_create(&gh); 2986275579Sdelphij if (stat != IDMAP_SUCCESS) { 2987275579Sdelphij idmap_get_destroy(gh); 2988275579Sdelphij return (ENOMEM); 2989275579Sdelphij } 2990209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2991209962Smm return (ENOENT); 2992209962Smm if (isuser) { 2993275579Sdelphij stat = idmap_getuidbywinname(cp, NULL, flag, &pid); 2994275579Sdelphij if (stat < 0) 2995275579Sdelphij return (ENOENT); 2996275579Sdelphij stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid, 2997275579Sdelphij &rid, &map_stat); 2998209962Smm } else { 2999275579Sdelphij stat = idmap_getgidbywinname(cp, NULL, flag, &pid); 3000275579Sdelphij if (stat < 0) 3001275579Sdelphij return (ENOENT); 3002275579Sdelphij stat = idmap_get_sidbygid(gh, pid, flag, &numericsid, 3003275579Sdelphij &rid, &map_stat); 3004209962Smm } 3005275579Sdelphij if (stat < 0) { 3006275579Sdelphij idmap_get_destroy(gh); 3007209962Smm return (ENOENT); 3008209962Smm } 3009275579Sdelphij stat = idmap_get_mappings(gh); 3010275579Sdelphij idmap_get_destroy(gh); 3011275579Sdelphij 3012275579Sdelphij if (stat < 0) { 3013275579Sdelphij return (ENOENT); 3014275579Sdelphij } 3015209962Smm if (numericsid == NULL) 3016209962Smm return (ENOENT); 3017209962Smm cp = numericsid; 3018275579Sdelphij *ridp = rid; 3019209962Smm /* will be further decoded below */ 3020277300Ssmh#else /* !illumos */ 3021219089Spjd return (ENOENT); 3022277300Ssmh#endif /* illumos */ 3023209962Smm } 3024209962Smm 3025209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 3026209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 3027209962Smm (void) strlcpy(domain, cp, domainlen); 3028209962Smm errno = 0; 3029275579Sdelphij if (*ridp == 0) { 3030275579Sdelphij cp = strrchr(domain, '-'); 3031275579Sdelphij *cp = '\0'; 3032275579Sdelphij cp++; 3033275579Sdelphij *ridp = strtoull(cp, &end, 10); 3034275579Sdelphij } else { 3035275579Sdelphij end = ""; 3036275579Sdelphij } 3037209962Smm if (numericsid) { 3038209962Smm free(numericsid); 3039209962Smm numericsid = NULL; 3040209962Smm } 3041209962Smm if (errno != 0 || *end != '\0') 3042209962Smm return (EINVAL); 3043209962Smm } else if (!isdigit(*cp)) { 3044209962Smm /* 3045209962Smm * It's a user/group name (eg "user") that needs to be 3046209962Smm * turned into a uid/gid 3047209962Smm */ 3048209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 3049209962Smm return (ENOENT); 3050209962Smm if (isuser) { 3051209962Smm struct passwd *pw; 3052209962Smm pw = getpwnam(cp); 3053209962Smm if (pw == NULL) 3054209962Smm return (ENOENT); 3055209962Smm *ridp = pw->pw_uid; 3056209962Smm } else { 3057209962Smm struct group *gr; 3058209962Smm gr = getgrnam(cp); 3059209962Smm if (gr == NULL) 3060209962Smm return (ENOENT); 3061209962Smm *ridp = gr->gr_gid; 3062209962Smm } 3063209962Smm } else { 3064209962Smm /* It's a user/group ID (eg "12345"). */ 3065209962Smm uid_t id = strtoul(cp, &end, 10); 3066209962Smm idmap_rid_t rid; 3067209962Smm char *mapdomain; 3068209962Smm 3069209962Smm if (*end != '\0') 3070209962Smm return (EINVAL); 3071209962Smm if (id > MAXUID) { 3072209962Smm /* It's an ephemeral ID. */ 3073209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 3074209962Smm &mapdomain, &rid) != 0) 3075209962Smm return (ENOENT); 3076209962Smm (void) strlcpy(domain, mapdomain, domainlen); 3077209962Smm *ridp = rid; 3078209962Smm } else { 3079209962Smm *ridp = id; 3080209962Smm } 3081209962Smm } 3082209962Smm 3083209962Smm ASSERT3P(numericsid, ==, NULL); 3084209962Smm return (0); 3085209962Smm} 3086209962Smm 3087209962Smmstatic int 3088209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 3089209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 3090209962Smm{ 3091209962Smm int err; 3092209962Smm zfs_cmd_t zc = { 0 }; 3093209962Smm 3094228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3095209962Smm 3096209962Smm err = userquota_propname_decode(propname, 3097209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 3098209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 3099209962Smm zc.zc_objset_type = *typep; 3100209962Smm if (err) 3101209962Smm return (err); 3102209962Smm 3103209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 3104209962Smm if (err) 3105209962Smm return (err); 3106209962Smm 3107209962Smm *propvalue = zc.zc_cookie; 3108209962Smm return (0); 3109209962Smm} 3110209962Smm 3111209962Smmint 3112209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 3113209962Smm uint64_t *propvalue) 3114209962Smm{ 3115209962Smm zfs_userquota_prop_t type; 3116209962Smm 3117209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 3118209962Smm &type)); 3119209962Smm} 3120209962Smm 3121209962Smmint 3122209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 3123209962Smm char *propbuf, int proplen, boolean_t literal) 3124209962Smm{ 3125209962Smm int err; 3126209962Smm uint64_t propvalue; 3127209962Smm zfs_userquota_prop_t type; 3128209962Smm 3129209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 3130209962Smm &type); 3131209962Smm 3132209962Smm if (err) 3133209962Smm return (err); 3134209962Smm 3135209962Smm if (literal) { 3136209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 3137209962Smm } else if (propvalue == 0 && 3138209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 3139209962Smm (void) strlcpy(propbuf, "none", proplen); 3140209962Smm } else { 3141209962Smm zfs_nicenum(propvalue, propbuf, proplen); 3142209962Smm } 3143209962Smm return (0); 3144209962Smm} 3145209962Smm 3146228103Smmint 3147228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 3148228103Smm uint64_t *propvalue) 3149168404Spjd{ 3150228103Smm int err; 3151228103Smm zfs_cmd_t zc = { 0 }; 3152228103Smm const char *snapname; 3153168404Spjd 3154228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3155168404Spjd 3156228103Smm snapname = strchr(propname, '@') + 1; 3157228103Smm if (strchr(snapname, '@')) { 3158228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3159228103Smm } else { 3160228103Smm /* snapname is the short name, append it to zhp's fsname */ 3161228103Smm char *cp; 3162209962Smm 3163228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 3164228103Smm sizeof (zc.zc_value)); 3165228103Smm cp = strchr(zc.zc_value, '@'); 3166228103Smm if (cp != NULL) 3167228103Smm *cp = '\0'; 3168228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 3169228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 3170228103Smm } 3171209962Smm 3172228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 3173228103Smm if (err) 3174228103Smm return (err); 3175228103Smm 3176228103Smm *propvalue = zc.zc_cookie; 3177228103Smm return (0); 3178209962Smm} 3179209962Smm 3180168404Spjdint 3181228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 3182228103Smm char *propbuf, int proplen, boolean_t literal) 3183168404Spjd{ 3184228103Smm int err; 3185228103Smm uint64_t propvalue; 3186168404Spjd 3187228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 3188185029Spjd 3189228103Smm if (err) 3190228103Smm return (err); 3191209962Smm 3192228103Smm if (literal) { 3193228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 3194228103Smm } else { 3195228103Smm zfs_nicenum(propvalue, propbuf, proplen); 3196168404Spjd } 3197228103Smm return (0); 3198168404Spjd} 3199168404Spjd 3200168404Spjd/* 3201228103Smm * Returns the name of the given zfs handle. 3202168404Spjd */ 3203228103Smmconst char * 3204228103Smmzfs_get_name(const zfs_handle_t *zhp) 3205168404Spjd{ 3206228103Smm return (zhp->zfs_name); 3207228103Smm} 3208168404Spjd 3209228103Smm/* 3210307106Smav * Returns the name of the parent pool for the given zfs handle. 3211307106Smav */ 3212307106Smavconst char * 3213307106Smavzfs_get_pool_name(const zfs_handle_t *zhp) 3214307106Smav{ 3215307106Smav return (zhp->zpool_hdl->zpool_name); 3216307106Smav} 3217307106Smav 3218307106Smav/* 3219228103Smm * Returns the type of the given zfs handle. 3220228103Smm */ 3221228103Smmzfs_type_t 3222228103Smmzfs_get_type(const zfs_handle_t *zhp) 3223228103Smm{ 3224228103Smm return (zhp->zfs_type); 3225168404Spjd} 3226168404Spjd 3227168404Spjd/* 3228219089Spjd * Is one dataset name a child dataset of another? 3229219089Spjd * 3230219089Spjd * Needs to handle these cases: 3231219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 3232219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 3233219089Spjd * Descendant? No. No. No. Yes. 3234219089Spjd */ 3235219089Spjdstatic boolean_t 3236219089Spjdis_descendant(const char *ds1, const char *ds2) 3237219089Spjd{ 3238219089Spjd size_t d1len = strlen(ds1); 3239219089Spjd 3240219089Spjd /* ds2 can't be a descendant if it's smaller */ 3241219089Spjd if (strlen(ds2) < d1len) 3242219089Spjd return (B_FALSE); 3243219089Spjd 3244219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 3245219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 3246219089Spjd} 3247219089Spjd 3248219089Spjd/* 3249168404Spjd * Given a complete name, return just the portion that refers to the parent. 3250228103Smm * Will return -1 if there is no parent (path is just the name of the 3251228103Smm * pool). 3252168404Spjd */ 3253168404Spjdstatic int 3254168404Spjdparent_name(const char *path, char *buf, size_t buflen) 3255168404Spjd{ 3256228103Smm char *slashp; 3257168404Spjd 3258228103Smm (void) strlcpy(buf, path, buflen); 3259228103Smm 3260228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 3261168404Spjd return (-1); 3262228103Smm *slashp = '\0'; 3263168404Spjd 3264168404Spjd return (0); 3265168404Spjd} 3266168404Spjd 3267168404Spjd/* 3268185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 3269185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 3270185029Spjd * closest existing ancestor for the given path. In prefixlen return the 3271185029Spjd * length of already existing prefix of the given path. We also fetch the 3272185029Spjd * 'zoned' property, which is used to validate property settings when creating 3273185029Spjd * new datasets. 3274168404Spjd */ 3275168404Spjdstatic int 3276185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 3277185029Spjd boolean_t accept_ancestor, int *prefixlen) 3278168404Spjd{ 3279168404Spjd zfs_cmd_t zc = { 0 }; 3280307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3281168404Spjd char *slash; 3282168404Spjd zfs_handle_t *zhp; 3283168404Spjd char errbuf[1024]; 3284219089Spjd uint64_t is_zoned; 3285168404Spjd 3286209962Smm (void) snprintf(errbuf, sizeof (errbuf), 3287209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 3288168404Spjd 3289168404Spjd /* get parent, and check to see if this is just a pool */ 3290168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 3291168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3292168404Spjd "missing dataset name")); 3293168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3294168404Spjd } 3295168404Spjd 3296168404Spjd /* check to see if the pool exists */ 3297168404Spjd if ((slash = strchr(parent, '/')) == NULL) 3298168404Spjd slash = parent + strlen(parent); 3299168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 3300168404Spjd zc.zc_name[slash - parent] = '\0'; 3301168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 3302168404Spjd errno == ENOENT) { 3303168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3304168404Spjd "no such pool '%s'"), zc.zc_name); 3305168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3306168404Spjd } 3307168404Spjd 3308168404Spjd /* check to see if the parent dataset exists */ 3309185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 3310185029Spjd if (errno == ENOENT && accept_ancestor) { 3311185029Spjd /* 3312185029Spjd * Go deeper to find an ancestor, give up on top level. 3313185029Spjd */ 3314185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 3315185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3316185029Spjd "no such pool '%s'"), zc.zc_name); 3317185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3318185029Spjd } 3319185029Spjd } else if (errno == ENOENT) { 3320168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3321168404Spjd "parent does not exist")); 3322168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3323185029Spjd } else 3324168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3325168404Spjd } 3326168404Spjd 3327219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 3328219089Spjd if (zoned != NULL) 3329219089Spjd *zoned = is_zoned; 3330219089Spjd 3331168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 3332219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 3333168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 3334168404Spjd zfs_close(zhp); 3335168404Spjd return (-1); 3336168404Spjd } 3337168404Spjd 3338168404Spjd /* make sure parent is a filesystem */ 3339168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 3340168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3341168404Spjd "parent is not a filesystem")); 3342168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3343168404Spjd zfs_close(zhp); 3344168404Spjd return (-1); 3345168404Spjd } 3346168404Spjd 3347168404Spjd zfs_close(zhp); 3348185029Spjd if (prefixlen != NULL) 3349185029Spjd *prefixlen = strlen(parent); 3350168404Spjd return (0); 3351168404Spjd} 3352168404Spjd 3353168404Spjd/* 3354185029Spjd * Finds whether the dataset of the given type(s) exists. 3355185029Spjd */ 3356185029Spjdboolean_t 3357185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 3358185029Spjd{ 3359185029Spjd zfs_handle_t *zhp; 3360185029Spjd 3361185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 3362185029Spjd return (B_FALSE); 3363185029Spjd 3364185029Spjd /* 3365185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 3366185029Spjd */ 3367185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 3368185029Spjd int ds_type = zhp->zfs_type; 3369185029Spjd 3370185029Spjd zfs_close(zhp); 3371185029Spjd if (types & ds_type) 3372185029Spjd return (B_TRUE); 3373185029Spjd } 3374185029Spjd return (B_FALSE); 3375185029Spjd} 3376185029Spjd 3377185029Spjd/* 3378185029Spjd * Given a path to 'target', create all the ancestors between 3379185029Spjd * the prefixlen portion of the path, and the target itself. 3380185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 3381185029Spjd */ 3382185029Spjdint 3383185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 3384185029Spjd{ 3385185029Spjd zfs_handle_t *h; 3386185029Spjd char *cp; 3387185029Spjd const char *opname; 3388185029Spjd 3389185029Spjd /* make sure prefix exists */ 3390185029Spjd cp = target + prefixlen; 3391185029Spjd if (*cp != '/') { 3392185029Spjd assert(strchr(cp, '/') == NULL); 3393185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3394185029Spjd } else { 3395185029Spjd *cp = '\0'; 3396185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3397185029Spjd *cp = '/'; 3398185029Spjd } 3399185029Spjd if (h == NULL) 3400185029Spjd return (-1); 3401185029Spjd zfs_close(h); 3402185029Spjd 3403185029Spjd /* 3404185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 3405185029Spjd * up to the prefixlen-long one. 3406185029Spjd */ 3407185029Spjd for (cp = target + prefixlen + 1; 3408307050Smav (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) { 3409185029Spjd 3410185029Spjd *cp = '\0'; 3411185029Spjd 3412185029Spjd h = make_dataset_handle(hdl, target); 3413185029Spjd if (h) { 3414185029Spjd /* it already exists, nothing to do here */ 3415185029Spjd zfs_close(h); 3416185029Spjd continue; 3417185029Spjd } 3418185029Spjd 3419185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 3420185029Spjd NULL) != 0) { 3421185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 3422185029Spjd goto ancestorerr; 3423185029Spjd } 3424185029Spjd 3425185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3426185029Spjd if (h == NULL) { 3427185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 3428185029Spjd goto ancestorerr; 3429185029Spjd } 3430185029Spjd 3431185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 3432185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 3433185029Spjd goto ancestorerr; 3434185029Spjd } 3435185029Spjd 3436185029Spjd if (zfs_share(h) != 0) { 3437185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 3438185029Spjd goto ancestorerr; 3439185029Spjd } 3440185029Spjd 3441185029Spjd zfs_close(h); 3442185029Spjd } 3443185029Spjd 3444185029Spjd return (0); 3445185029Spjd 3446185029Spjdancestorerr: 3447185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3448185029Spjd "failed to %s ancestor '%s'"), opname, target); 3449185029Spjd return (-1); 3450185029Spjd} 3451185029Spjd 3452185029Spjd/* 3453185029Spjd * Creates non-existing ancestors of the given path. 3454185029Spjd */ 3455185029Spjdint 3456185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3457185029Spjd{ 3458185029Spjd int prefix; 3459185029Spjd char *path_copy; 3460339129Smav char errbuf[1024]; 3461307107Smav int rc = 0; 3462185029Spjd 3463339129Smav (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3464339129Smav "cannot create '%s'"), path); 3465339129Smav 3466339129Smav /* 3467339129Smav * Check that we are not passing the nesting limit 3468339129Smav * before we start creating any ancestors. 3469339129Smav */ 3470339129Smav if (dataset_nestcheck(path) != 0) { 3471339129Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3472339129Smav "maximum name nesting depth exceeded")); 3473339129Smav return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3474339129Smav } 3475339129Smav 3476219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3477185029Spjd return (-1); 3478185029Spjd 3479185029Spjd if ((path_copy = strdup(path)) != NULL) { 3480185029Spjd rc = create_parents(hdl, path_copy, prefix); 3481185029Spjd free(path_copy); 3482185029Spjd } 3483185029Spjd if (path_copy == NULL || rc != 0) 3484185029Spjd return (-1); 3485185029Spjd 3486185029Spjd return (0); 3487185029Spjd} 3488185029Spjd 3489185029Spjd/* 3490168404Spjd * Create a new filesystem or volume. 3491168404Spjd */ 3492168404Spjdint 3493168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3494168404Spjd nvlist_t *props) 3495168404Spjd{ 3496168404Spjd int ret; 3497168404Spjd uint64_t size = 0; 3498168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3499168404Spjd char errbuf[1024]; 3500168404Spjd uint64_t zoned; 3501298472Savg enum lzc_dataset_type ost; 3502321576Smav zpool_handle_t *zpool_handle; 3503168404Spjd 3504168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3505168404Spjd "cannot create '%s'"), path); 3506168404Spjd 3507168404Spjd /* validate the path, taking care to note the extended error message */ 3508185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3509168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3510168404Spjd 3511339129Smav if (dataset_nestcheck(path) != 0) { 3512339129Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3513339129Smav "maximum name nesting depth exceeded")); 3514339129Smav return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3515339129Smav } 3516339129Smav 3517168404Spjd /* validate parents exist */ 3518185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3519168404Spjd return (-1); 3520168404Spjd 3521168404Spjd /* 3522168404Spjd * The failure modes when creating a dataset of a different type over 3523168404Spjd * one that already exists is a little strange. In particular, if you 3524168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3525168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3526168404Spjd * first try to see if the dataset exists. 3527168404Spjd */ 3528248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3529168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3530168404Spjd "dataset already exists")); 3531168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3532168404Spjd } 3533168404Spjd 3534168404Spjd if (type == ZFS_TYPE_VOLUME) 3535298472Savg ost = LZC_DATSET_TYPE_ZVOL; 3536168404Spjd else 3537298472Savg ost = LZC_DATSET_TYPE_ZFS; 3538168404Spjd 3539289500Smav /* open zpool handle for prop validation */ 3540307108Smav char pool_path[ZFS_MAX_DATASET_NAME_LEN]; 3541289500Smav (void) strlcpy(pool_path, path, sizeof (pool_path)); 3542289500Smav 3543289500Smav /* truncate pool_path at first slash */ 3544289500Smav char *p = strchr(pool_path, '/'); 3545289500Smav if (p != NULL) 3546289500Smav *p = '\0'; 3547289500Smav 3548321576Smav if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL) 3549321576Smav return (-1); 3550289500Smav 3551185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3552289500Smav zoned, NULL, zpool_handle, errbuf)) == 0) { 3553289500Smav zpool_close(zpool_handle); 3554168404Spjd return (-1); 3555289500Smav } 3556289500Smav zpool_close(zpool_handle); 3557168404Spjd 3558168404Spjd if (type == ZFS_TYPE_VOLUME) { 3559168404Spjd /* 3560168404Spjd * If we are creating a volume, the size and block size must 3561168404Spjd * satisfy a few restraints. First, the blocksize must be a 3562168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3563168404Spjd * volsize must be a multiple of the block size, and cannot be 3564168404Spjd * zero. 3565168404Spjd */ 3566168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3567168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3568168404Spjd nvlist_free(props); 3569168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3570168404Spjd "missing volume size")); 3571168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3572168404Spjd } 3573168404Spjd 3574168404Spjd if ((ret = nvlist_lookup_uint64(props, 3575168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3576168404Spjd &blocksize)) != 0) { 3577168404Spjd if (ret == ENOENT) { 3578168404Spjd blocksize = zfs_prop_default_numeric( 3579168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3580168404Spjd } else { 3581168404Spjd nvlist_free(props); 3582168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3583168404Spjd "missing volume block size")); 3584168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3585168404Spjd } 3586168404Spjd } 3587168404Spjd 3588168404Spjd if (size == 0) { 3589168404Spjd nvlist_free(props); 3590168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3591168404Spjd "volume size cannot be zero")); 3592168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3593168404Spjd } 3594168404Spjd 3595168404Spjd if (size % blocksize != 0) { 3596168404Spjd nvlist_free(props); 3597168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3598168404Spjd "volume size must be a multiple of volume block " 3599168404Spjd "size")); 3600168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3601168404Spjd } 3602168404Spjd } 3603168404Spjd 3604248571Smm /* create the dataset */ 3605248571Smm ret = lzc_create(path, ost, props); 3606168404Spjd nvlist_free(props); 3607168404Spjd 3608168404Spjd /* check for failure */ 3609168404Spjd if (ret != 0) { 3610307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3611168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3612168404Spjd 3613168404Spjd switch (errno) { 3614168404Spjd case ENOENT: 3615168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3616168404Spjd "no such parent '%s'"), parent); 3617168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3618168404Spjd 3619185029Spjd case ENOTSUP: 3620185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3621185029Spjd "pool must be upgraded to set this " 3622185029Spjd "property or value")); 3623185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3624329489Smav case ERANGE: 3625329489Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3626329489Smav "invalid property value(s) specified")); 3627329489Smav return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3628168404Spjd#ifdef _ILP32 3629168404Spjd case EOVERFLOW: 3630168404Spjd /* 3631168404Spjd * This platform can't address a volume this big. 3632168404Spjd */ 3633168404Spjd if (type == ZFS_TYPE_VOLUME) 3634168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3635168404Spjd errbuf)); 3636168404Spjd#endif 3637168404Spjd /* FALLTHROUGH */ 3638168404Spjd default: 3639168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3640168404Spjd } 3641168404Spjd } 3642168404Spjd 3643168404Spjd return (0); 3644168404Spjd} 3645168404Spjd 3646168404Spjd/* 3647168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3648238422Smm * isn't mounted, and that there are no active dependents. If the file system 3649238422Smm * does not exist this function does nothing. 3650168404Spjd */ 3651168404Spjdint 3652219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3653168404Spjd{ 3654342943Savg int error; 3655168404Spjd 3656342943Savg if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer) 3657342943Savg return (EINVAL); 3658342943Savg 3659260183Sdelphij if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3660260183Sdelphij nvlist_t *nv = fnvlist_alloc(); 3661260183Sdelphij fnvlist_add_boolean(nv, zhp->zfs_name); 3662342943Savg error = lzc_destroy_bookmarks(nv, NULL); 3663260183Sdelphij fnvlist_free(nv); 3664260183Sdelphij if (error != 0) { 3665342943Savg return (zfs_standard_error_fmt(zhp->zfs_hdl, error, 3666260183Sdelphij dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3667260183Sdelphij zhp->zfs_name)); 3668260183Sdelphij } 3669260183Sdelphij return (0); 3670260183Sdelphij } 3671260183Sdelphij 3672342943Savg if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3673342943Savg nvlist_t *nv = fnvlist_alloc(); 3674342943Savg fnvlist_add_boolean(nv, zhp->zfs_name); 3675342943Savg error = lzc_destroy_snaps(nv, defer, NULL); 3676342943Savg fnvlist_free(nv); 3677168404Spjd } else { 3678342943Savg error = lzc_destroy(zhp->zfs_name); 3679168404Spjd } 3680168404Spjd 3681342943Savg if (error != 0 && error != ENOENT) { 3682168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3683168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3684168404Spjd zhp->zfs_name)); 3685168404Spjd } 3686168404Spjd 3687168404Spjd remove_mountpoint(zhp); 3688168404Spjd 3689168404Spjd return (0); 3690168404Spjd} 3691168404Spjd 3692168404Spjdstruct destroydata { 3693228103Smm nvlist_t *nvl; 3694228103Smm const char *snapname; 3695168404Spjd}; 3696168404Spjd 3697168404Spjdstatic int 3698219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3699168404Spjd{ 3700168404Spjd struct destroydata *dd = arg; 3701307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3702219089Spjd int rv = 0; 3703168404Spjd 3704228103Smm (void) snprintf(name, sizeof (name), 3705228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3706168404Spjd 3707251646Sdelphij if (lzc_exists(name)) 3708228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3709168404Spjd 3710228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3711228103Smm zfs_close(zhp); 3712168404Spjd return (rv); 3713168404Spjd} 3714168404Spjd 3715168404Spjd/* 3716168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3717168404Spjd */ 3718168404Spjdint 3719219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3720168404Spjd{ 3721168404Spjd int ret; 3722168404Spjd struct destroydata dd = { 0 }; 3723168404Spjd 3724168404Spjd dd.snapname = snapname; 3725228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3726228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3727168404Spjd 3728251646Sdelphij if (nvlist_empty(dd.nvl)) { 3729228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3730168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3731228103Smm zhp->zfs_name, snapname); 3732228103Smm } else { 3733248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3734168404Spjd } 3735228103Smm nvlist_free(dd.nvl); 3736228103Smm return (ret); 3737228103Smm} 3738168404Spjd 3739228103Smm/* 3740248571Smm * Destroys all the snapshots named in the nvlist. 3741228103Smm */ 3742228103Smmint 3743248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3744228103Smm{ 3745228103Smm int ret; 3746307105Smav nvlist_t *errlist = NULL; 3747228103Smm 3748248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3749168404Spjd 3750307105Smav if (ret == 0) { 3751307105Smav nvlist_free(errlist); 3752248571Smm return (0); 3753307105Smav } 3754248571Smm 3755251646Sdelphij if (nvlist_empty(errlist)) { 3756168404Spjd char errbuf[1024]; 3757248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3758248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3759168404Spjd 3760248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3761248571Smm } 3762248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3763248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3764248571Smm char errbuf[1024]; 3765248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3766248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3767248571Smm nvpair_name(pair)); 3768168404Spjd 3769248571Smm switch (fnvpair_value_int32(pair)) { 3770168404Spjd case EEXIST: 3771248571Smm zfs_error_aux(hdl, 3772248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3773248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3774248571Smm break; 3775168404Spjd default: 3776248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3777248571Smm break; 3778168404Spjd } 3779168404Spjd } 3780168404Spjd 3781307105Smav nvlist_free(errlist); 3782248571Smm return (ret); 3783168404Spjd} 3784168404Spjd 3785168404Spjd/* 3786168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3787168404Spjd */ 3788168404Spjdint 3789168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3790168404Spjd{ 3791307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3792168404Spjd int ret; 3793168404Spjd char errbuf[1024]; 3794168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3795168404Spjd uint64_t zoned; 3796168404Spjd 3797168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3798168404Spjd 3799168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3800168404Spjd "cannot create '%s'"), target); 3801168404Spjd 3802228103Smm /* validate the target/clone name */ 3803185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3804168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3805168404Spjd 3806168404Spjd /* validate parents exist */ 3807185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3808168404Spjd return (-1); 3809168404Spjd 3810168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3811168404Spjd 3812168404Spjd /* do the clone */ 3813168404Spjd 3814168404Spjd if (props) { 3815248571Smm zfs_type_t type; 3816339103Smav 3817248571Smm if (ZFS_IS_VOLUME(zhp)) { 3818248571Smm type = ZFS_TYPE_VOLUME; 3819248571Smm } else { 3820248571Smm type = ZFS_TYPE_FILESYSTEM; 3821248571Smm } 3822185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3823289500Smav zhp, zhp->zpool_hdl, errbuf)) == NULL) 3824168404Spjd return (-1); 3825339103Smav if (zfs_fix_auto_resv(zhp, props) == -1) { 3826339103Smav nvlist_free(props); 3827339103Smav return (-1); 3828339103Smav } 3829168404Spjd } 3830168404Spjd 3831248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3832248571Smm nvlist_free(props); 3833168404Spjd 3834168404Spjd if (ret != 0) { 3835168404Spjd switch (errno) { 3836168404Spjd 3837168404Spjd case ENOENT: 3838168404Spjd /* 3839168404Spjd * The parent doesn't exist. We should have caught this 3840168404Spjd * above, but there may a race condition that has since 3841168404Spjd * destroyed the parent. 3842168404Spjd * 3843168404Spjd * At this point, we don't know whether it's the source 3844168404Spjd * that doesn't exist anymore, or whether the target 3845168404Spjd * dataset doesn't exist. 3846168404Spjd */ 3847168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3848168404Spjd "no such parent '%s'"), parent); 3849168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3850168404Spjd 3851168404Spjd case EXDEV: 3852168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3853168404Spjd "source and target pools differ")); 3854168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3855168404Spjd errbuf)); 3856168404Spjd 3857168404Spjd default: 3858168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3859168404Spjd errbuf)); 3860168404Spjd } 3861168404Spjd } 3862168404Spjd 3863168404Spjd return (ret); 3864168404Spjd} 3865168404Spjd 3866168404Spjd/* 3867168404Spjd * Promotes the given clone fs to be the clone parent. 3868168404Spjd */ 3869168404Spjdint 3870168404Spjdzfs_promote(zfs_handle_t *zhp) 3871168404Spjd{ 3872168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3873321577Smav char snapname[ZFS_MAX_DATASET_NAME_LEN]; 3874168404Spjd int ret; 3875168404Spjd char errbuf[1024]; 3876168404Spjd 3877168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3878168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3879168404Spjd 3880168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3881168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3882168404Spjd "snapshots can not be promoted")); 3883168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3884168404Spjd } 3885168404Spjd 3886321577Smav if (zhp->zfs_dmustats.dds_origin[0] == '\0') { 3887168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3888168404Spjd "not a cloned filesystem")); 3889168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3890168404Spjd } 3891168404Spjd 3892332535Smav if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE)) 3893332535Smav return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3894332535Smav 3895321577Smav ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname)); 3896168404Spjd 3897168404Spjd if (ret != 0) { 3898321577Smav switch (ret) { 3899168404Spjd case EEXIST: 3900219089Spjd /* There is a conflicting snapshot name. */ 3901168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3902219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3903321577Smav snapname, zhp->zfs_dmustats.dds_origin); 3904168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3905168404Spjd 3906168404Spjd default: 3907321577Smav return (zfs_standard_error(hdl, ret, errbuf)); 3908168404Spjd } 3909168404Spjd } 3910168404Spjd return (ret); 3911168404Spjd} 3912168404Spjd 3913248571Smmtypedef struct snapdata { 3914248571Smm nvlist_t *sd_nvl; 3915248571Smm const char *sd_snapname; 3916248571Smm} snapdata_t; 3917248571Smm 3918248571Smmstatic int 3919248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3920248571Smm{ 3921248571Smm snapdata_t *sd = arg; 3922307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3923248571Smm int rv = 0; 3924248571Smm 3925253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3926253819Sdelphij (void) snprintf(name, sizeof (name), 3927253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3928248571Smm 3929253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3930248571Smm 3931253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3932253819Sdelphij } 3933248571Smm zfs_close(zhp); 3934253819Sdelphij 3935248571Smm return (rv); 3936248571Smm} 3937248571Smm 3938332525Smavint 3939332525Smavzfs_remap_indirects(libzfs_handle_t *hdl, const char *fs) 3940332525Smav{ 3941332525Smav int err; 3942332525Smav char errbuf[1024]; 3943332525Smav 3944332525Smav (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3945339119Smav "cannot remap dataset '%s'"), fs); 3946332525Smav 3947332525Smav err = lzc_remap(fs); 3948332525Smav 3949332525Smav if (err != 0) { 3950339119Smav switch (err) { 3951339119Smav case ENOTSUP: 3952339119Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3953339119Smav "pool must be upgraded")); 3954339119Smav (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 3955339119Smav break; 3956339119Smav case EINVAL: 3957339119Smav (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3958339119Smav break; 3959339119Smav default: 3960339119Smav (void) zfs_standard_error(hdl, err, errbuf); 3961339119Smav break; 3962339119Smav } 3963332525Smav } 3964332525Smav 3965332525Smav return (err); 3966332525Smav} 3967332525Smav 3968168404Spjd/* 3969248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3970248571Smm * created. 3971168404Spjd */ 3972168404Spjdint 3973248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3974168404Spjd{ 3975168404Spjd int ret; 3976168404Spjd char errbuf[1024]; 3977248571Smm nvpair_t *elem; 3978248571Smm nvlist_t *errors; 3979168404Spjd 3980168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3981248571Smm "cannot create snapshots ")); 3982168404Spjd 3983248571Smm elem = NULL; 3984248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3985248571Smm const char *snapname = nvpair_name(elem); 3986168404Spjd 3987248571Smm /* validate the target name */ 3988248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3989248571Smm B_TRUE)) { 3990248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3991248571Smm dgettext(TEXT_DOMAIN, 3992248571Smm "cannot create snapshot '%s'"), snapname); 3993248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3994248571Smm } 3995248571Smm } 3996185029Spjd 3997289500Smav /* 3998289500Smav * get pool handle for prop validation. assumes all snaps are in the 3999289500Smav * same pool, as does lzc_snapshot (below). 4000289500Smav */ 4001307108Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 4002289500Smav elem = nvlist_next_nvpair(snaps, NULL); 4003289500Smav (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); 4004289500Smav pool[strcspn(pool, "/@")] = '\0'; 4005289500Smav zpool_handle_t *zpool_hdl = zpool_open(hdl, pool); 4006289500Smav 4007248571Smm if (props != NULL && 4008248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 4009289500Smav props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) { 4010289500Smav zpool_close(zpool_hdl); 4011248571Smm return (-1); 4012248571Smm } 4013289500Smav zpool_close(zpool_hdl); 4014248571Smm 4015248571Smm ret = lzc_snapshot(snaps, props, &errors); 4016248571Smm 4017248571Smm if (ret != 0) { 4018248571Smm boolean_t printed = B_FALSE; 4019248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4020248571Smm elem != NULL; 4021248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4022248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4023248571Smm dgettext(TEXT_DOMAIN, 4024248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 4025248571Smm (void) zfs_standard_error(hdl, 4026248571Smm fnvpair_value_int32(elem), errbuf); 4027248571Smm printed = B_TRUE; 4028185029Spjd } 4029248571Smm if (!printed) { 4030248571Smm switch (ret) { 4031248571Smm case EXDEV: 4032248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4033248571Smm "multiple snapshots of same " 4034248571Smm "fs not allowed")); 4035248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4036185029Spjd 4037248571Smm break; 4038248571Smm default: 4039248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4040248571Smm } 4041248571Smm } 4042185029Spjd } 4043185029Spjd 4044248571Smm nvlist_free(props); 4045248571Smm nvlist_free(errors); 4046248571Smm return (ret); 4047248571Smm} 4048168404Spjd 4049248571Smmint 4050248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 4051248571Smm nvlist_t *props) 4052248571Smm{ 4053248571Smm int ret; 4054248571Smm snapdata_t sd = { 0 }; 4055307108Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 4056248571Smm char *cp; 4057248571Smm zfs_handle_t *zhp; 4058248571Smm char errbuf[1024]; 4059248571Smm 4060248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4061248571Smm "cannot snapshot %s"), path); 4062248571Smm 4063248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 4064248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4065248571Smm 4066248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 4067248571Smm cp = strchr(fsname, '@'); 4068248571Smm *cp = '\0'; 4069248571Smm sd.sd_snapname = cp + 1; 4070248571Smm 4071248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 4072168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 4073168404Spjd return (-1); 4074168404Spjd } 4075168404Spjd 4076248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 4077248571Smm if (recursive) { 4078248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 4079248571Smm } else { 4080248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 4081168404Spjd } 4082168404Spjd 4083248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 4084248571Smm nvlist_free(sd.sd_nvl); 4085168404Spjd zfs_close(zhp); 4086168404Spjd return (ret); 4087168404Spjd} 4088168404Spjd 4089168404Spjd/* 4090168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 4091168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 4092168404Spjd * is a dependent and we should just destroy it without checking the transaction 4093168404Spjd * group. 4094168404Spjd */ 4095168404Spjdtypedef struct rollback_data { 4096168404Spjd const char *cb_target; /* the snapshot */ 4097168404Spjd uint64_t cb_create; /* creation time reference */ 4098185029Spjd boolean_t cb_error; 4099185029Spjd boolean_t cb_force; 4100168404Spjd} rollback_data_t; 4101168404Spjd 4102168404Spjdstatic int 4103260183Sdelphijrollback_destroy_dependent(zfs_handle_t *zhp, void *data) 4104168404Spjd{ 4105168404Spjd rollback_data_t *cbp = data; 4106260183Sdelphij prop_changelist_t *clp; 4107168404Spjd 4108260183Sdelphij /* We must destroy this clone; first unmount it */ 4109260183Sdelphij clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 4110260183Sdelphij cbp->cb_force ? MS_FORCE: 0); 4111260183Sdelphij if (clp == NULL || changelist_prefix(clp) != 0) { 4112260183Sdelphij cbp->cb_error = B_TRUE; 4113260183Sdelphij zfs_close(zhp); 4114260183Sdelphij return (0); 4115260183Sdelphij } 4116260183Sdelphij if (zfs_destroy(zhp, B_FALSE) != 0) 4117260183Sdelphij cbp->cb_error = B_TRUE; 4118260183Sdelphij else 4119260183Sdelphij changelist_remove(clp, zhp->zfs_name); 4120260183Sdelphij (void) changelist_postfix(clp); 4121260183Sdelphij changelist_free(clp); 4122168404Spjd 4123260183Sdelphij zfs_close(zhp); 4124260183Sdelphij return (0); 4125260183Sdelphij} 4126168404Spjd 4127260183Sdelphijstatic int 4128260183Sdelphijrollback_destroy(zfs_handle_t *zhp, void *data) 4129260183Sdelphij{ 4130260183Sdelphij rollback_data_t *cbp = data; 4131185029Spjd 4132260183Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 4133260183Sdelphij cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 4134260183Sdelphij rollback_destroy_dependent, cbp); 4135260183Sdelphij 4136260183Sdelphij cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 4137168404Spjd } 4138168404Spjd 4139168404Spjd zfs_close(zhp); 4140168404Spjd return (0); 4141168404Spjd} 4142168404Spjd 4143168404Spjd/* 4144168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 4145168404Spjd * data changes since then and making it the active dataset. 4146168404Spjd * 4147260183Sdelphij * Any snapshots and bookmarks more recent than the target are 4148260183Sdelphij * destroyed, along with their dependents (i.e. clones). 4149168404Spjd */ 4150168404Spjdint 4151185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 4152168404Spjd{ 4153168404Spjd rollback_data_t cb = { 0 }; 4154185029Spjd int err; 4155185029Spjd boolean_t restore_resv = 0; 4156307107Smav uint64_t old_volsize = 0, new_volsize; 4157185029Spjd zfs_prop_t resv_prop; 4158168404Spjd 4159185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 4160185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 4161168404Spjd 4162168404Spjd /* 4163239774Smm * Destroy all recent snapshots and their dependents. 4164168404Spjd */ 4165185029Spjd cb.cb_force = force; 4166168404Spjd cb.cb_target = snap->zfs_name; 4167168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 4168260183Sdelphij (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb); 4169260183Sdelphij (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); 4170168404Spjd 4171185029Spjd if (cb.cb_error) 4172185029Spjd return (-1); 4173168404Spjd 4174168404Spjd /* 4175168404Spjd * Now that we have verified that the snapshot is the latest, 4176168404Spjd * rollback to the given snapshot. 4177168404Spjd */ 4178168404Spjd 4179185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 4180185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 4181185029Spjd return (-1); 4182185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4183185029Spjd restore_resv = 4184185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 4185168404Spjd } 4186168404Spjd 4187168404Spjd /* 4188323757Savg * Pass both the filesystem and the wanted snapshot names, 4189323757Savg * we would get an error back if the snapshot is destroyed or 4190323757Savg * a new snapshot is created before this request is processed. 4191168404Spjd */ 4192323757Savg err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name); 4193330590Savg if (err != 0) { 4194330590Savg char errbuf[1024]; 4195330590Savg 4196330590Savg (void) snprintf(errbuf, sizeof (errbuf), 4197323757Savg dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 4198323757Savg zhp->zfs_name); 4199330590Savg switch (err) { 4200330590Savg case EEXIST: 4201330590Savg zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4202330590Savg "there is a snapshot or bookmark more recent " 4203330590Savg "than '%s'"), snap->zfs_name); 4204330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf); 4205330590Savg break; 4206330590Savg case ESRCH: 4207330590Savg zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 4208330590Savg "'%s' is not found among snapshots of '%s'"), 4209330590Savg snap->zfs_name, zhp->zfs_name); 4210330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf); 4211330590Savg break; 4212330590Savg case EINVAL: 4213330590Savg (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf); 4214330590Savg break; 4215330590Savg default: 4216330590Savg (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf); 4217330590Savg } 4218323757Savg return (err); 4219185029Spjd } 4220168404Spjd 4221185029Spjd /* 4222185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 4223185029Spjd * rollback reservation and the volsize has changed then set 4224185029Spjd * the reservation property to the post-rollback volsize. 4225185029Spjd * Make a new handle since the rollback closed the dataset. 4226185029Spjd */ 4227185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 4228185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 4229185029Spjd if (restore_resv) { 4230185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 4231185029Spjd if (old_volsize != new_volsize) 4232185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 4233185029Spjd new_volsize); 4234185029Spjd } 4235185029Spjd zfs_close(zhp); 4236185029Spjd } 4237185029Spjd return (err); 4238168404Spjd} 4239168404Spjd 4240168404Spjd/* 4241168404Spjd * Renames the given dataset. 4242168404Spjd */ 4243168404Spjdint 4244240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 4245240870Spjd renameflags_t flags) 4246168404Spjd{ 4247307050Smav int ret = 0; 4248168404Spjd zfs_cmd_t zc = { 0 }; 4249168404Spjd char *delim; 4250168676Spjd prop_changelist_t *cl = NULL; 4251168676Spjd zfs_handle_t *zhrp = NULL; 4252168676Spjd char *parentname = NULL; 4253307108Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 4254226676Spjd char property[ZFS_MAXPROPLEN]; 4255168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4256168404Spjd char errbuf[1024]; 4257168404Spjd 4258168404Spjd /* if we have the same exact name, just return success */ 4259168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 4260168404Spjd return (0); 4261168404Spjd 4262168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4263168404Spjd "cannot rename to '%s'"), target); 4264168404Spjd 4265240870Spjd if (source != NULL) { 4266240870Spjd /* 4267240870Spjd * This is recursive snapshots rename, put snapshot name 4268240870Spjd * (that might not exist) into zfs_name. 4269240870Spjd */ 4270240870Spjd assert(flags.recurse); 4271240870Spjd 4272240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 4273240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 4274240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 4275240870Spjd } 4276240870Spjd 4277332535Smav /* make sure source name is valid */ 4278332535Smav if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE)) 4279332535Smav return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4280332535Smav 4281168404Spjd /* 4282168404Spjd * Make sure the target name is valid 4283168404Spjd */ 4284353759Savg if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT || 4285353759Savg zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 4286353759Savg const char sep = zhp->zfs_type == ZFS_TYPE_SNAPSHOT ? '@' : '#'; 4287353759Savg 4288353759Savg if ((strchr(target, sep) == NULL) || *target == sep) { 4289168404Spjd /* 4290168404Spjd * Snapshot target name is abbreviated, 4291168404Spjd * reconstruct full dataset name 4292168404Spjd */ 4293353759Savg (void) strlcpy(parent, zhp->zfs_name, sizeof (parent)); 4294353759Savg delim = strchr(parent, sep); 4295353759Savg if (strchr(target, sep) == NULL) 4296168404Spjd *(++delim) = '\0'; 4297168404Spjd else 4298168404Spjd *delim = '\0'; 4299168404Spjd (void) strlcat(parent, target, sizeof (parent)); 4300168404Spjd target = parent; 4301168404Spjd } else { 4302168404Spjd /* 4303168404Spjd * Make sure we're renaming within the same dataset. 4304168404Spjd */ 4305353759Savg delim = strchr(target, sep); 4306168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 4307353759Savg != 0 || zhp->zfs_name[delim - target] != sep) { 4308168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4309353759Savg "%s must be part of same dataset"), 4310353759Savg zhp->zfs_type == ZFS_TYPE_SNAPSHOT ? 4311353759Savg "snapshots" : "bookmarks"); 4312168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 4313168404Spjd errbuf)); 4314168404Spjd } 4315168404Spjd } 4316339129Smav 4317185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4318168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4319168404Spjd } else { 4320226705Spjd if (flags.recurse) { 4321168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4322168676Spjd "recursive rename must be a snapshot")); 4323168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4324168676Spjd } 4325168676Spjd 4326185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 4327168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4328168404Spjd 4329168404Spjd /* validate parents */ 4330219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 4331168404Spjd return (-1); 4332168404Spjd 4333168404Spjd /* make sure we're in the same pool */ 4334168404Spjd verify((delim = strchr(target, '/')) != NULL); 4335168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 4336168404Spjd zhp->zfs_name[delim - target] != '/') { 4337168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4338168404Spjd "datasets must be within same pool")); 4339168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 4340168404Spjd } 4341168404Spjd 4342168404Spjd /* new name cannot be a child of the current dataset name */ 4343219089Spjd if (is_descendant(zhp->zfs_name, target)) { 4344168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4345219089Spjd "New dataset name cannot be a descendant of " 4346168404Spjd "current dataset name")); 4347168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4348168404Spjd } 4349168404Spjd } 4350168404Spjd 4351168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4352168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 4353168404Spjd 4354168404Spjd if (getzoneid() == GLOBAL_ZONEID && 4355168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 4356168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4357168404Spjd "dataset is used in a non-global zone")); 4358168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 4359168404Spjd } 4360168404Spjd 4361226705Spjd /* 4362226705Spjd * Avoid unmounting file systems with mountpoint property set to 4363226705Spjd * 'legacy' or 'none' even if -u option is not given. 4364226705Spjd */ 4365226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 4366226705Spjd !flags.recurse && !flags.nounmount && 4367226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 4368226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 4369226705Spjd (strcmp(property, "legacy") == 0 || 4370226705Spjd strcmp(property, "none") == 0)) { 4371226705Spjd flags.nounmount = B_TRUE; 4372226705Spjd } 4373226705Spjd if (flags.recurse) { 4374185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 4375185029Spjd if (parentname == NULL) { 4376185029Spjd ret = -1; 4377185029Spjd goto error; 4378185029Spjd } 4379168676Spjd delim = strchr(parentname, '@'); 4380168676Spjd *delim = '\0'; 4381185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 4382168676Spjd if (zhrp == NULL) { 4383185029Spjd ret = -1; 4384185029Spjd goto error; 4385168676Spjd } 4386353759Savg } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && 4387353759Savg zhp->zfs_type != ZFS_TYPE_BOOKMARK) { 4388226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 4389235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 4390235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 4391168676Spjd return (-1); 4392226676Spjd } 4393168676Spjd 4394168676Spjd if (changelist_haszonedchild(cl)) { 4395168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4396168676Spjd "child dataset with inherited mountpoint is used " 4397168676Spjd "in a non-global zone")); 4398168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 4399307107Smav ret = -1; 4400168676Spjd goto error; 4401168676Spjd } 4402168676Spjd 4403168676Spjd if ((ret = changelist_prefix(cl)) != 0) 4404168676Spjd goto error; 4405168404Spjd } 4406168404Spjd 4407168404Spjd if (ZFS_IS_VOLUME(zhp)) 4408168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 4409168404Spjd else 4410168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4411168404Spjd 4412168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4413168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 4414168404Spjd 4415226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 4416226705Spjd if (flags.nounmount) 4417226676Spjd zc.zc_cookie |= 2; 4418168676Spjd 4419185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 4420168676Spjd /* 4421168676Spjd * if it was recursive, the one that actually failed will 4422168676Spjd * be in zc.zc_name 4423168676Spjd */ 4424168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4425185029Spjd "cannot rename '%s'"), zc.zc_name); 4426168404Spjd 4427226705Spjd if (flags.recurse && errno == EEXIST) { 4428168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4429168676Spjd "a child dataset already has a snapshot " 4430168676Spjd "with the new name")); 4431185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4432353759Savg } else if (errno == EINVAL) { 4433353759Savg (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4434168676Spjd } else { 4435168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 4436168676Spjd } 4437168676Spjd 4438168404Spjd /* 4439168404Spjd * On failure, we still want to remount any filesystems that 4440168404Spjd * were previously mounted, so we don't alter the system state. 4441168404Spjd */ 4442268469Sdelphij if (cl != NULL) 4443168676Spjd (void) changelist_postfix(cl); 4444168404Spjd } else { 4445268469Sdelphij if (cl != NULL) { 4446168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 4447168676Spjd ret = changelist_postfix(cl); 4448168676Spjd } 4449168404Spjd } 4450168404Spjd 4451168404Spjderror: 4452268469Sdelphij if (parentname != NULL) { 4453168676Spjd free(parentname); 4454168676Spjd } 4455268469Sdelphij if (zhrp != NULL) { 4456168676Spjd zfs_close(zhrp); 4457168676Spjd } 4458268469Sdelphij if (cl != NULL) { 4459168676Spjd changelist_free(cl); 4460168676Spjd } 4461168404Spjd return (ret); 4462168404Spjd} 4463168404Spjd 4464219089Spjdnvlist_t * 4465219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 4466168404Spjd{ 4467219089Spjd return (zhp->zfs_user_props); 4468168676Spjd} 4469168676Spjd 4470168404Spjdnvlist_t * 4471219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 4472168404Spjd{ 4473219089Spjd if (zhp->zfs_recvd_props == NULL) 4474219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 4475219089Spjd return (NULL); 4476219089Spjd return (zhp->zfs_recvd_props); 4477168404Spjd} 4478168404Spjd 4479168404Spjd/* 4480168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 4481168404Spjd * display, and their maximum widths. This does two main things: 4482168404Spjd * 4483168404Spjd * - If this is a list of all properties, then expand the list to include 4484168404Spjd * all native properties, and set a flag so that for each dataset we look 4485168404Spjd * for new unique user properties and add them to the list. 4486168404Spjd * 4487168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 4488219089Spjd * so that we can size the column appropriately. If the user has 4489219089Spjd * requested received property values, we also need to compute the width 4490219089Spjd * of the RECEIVED column. 4491168404Spjd */ 4492168404Spjdint 4493259850Sdelphijzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 4494259850Sdelphij boolean_t literal) 4495168404Spjd{ 4496168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4497185029Spjd zprop_list_t *entry; 4498185029Spjd zprop_list_t **last, **start; 4499168404Spjd nvlist_t *userprops, *propval; 4500168404Spjd nvpair_t *elem; 4501168404Spjd char *strval; 4502168404Spjd char buf[ZFS_MAXPROPLEN]; 4503168404Spjd 4504185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 4505168404Spjd return (-1); 4506168404Spjd 4507168404Spjd userprops = zfs_get_user_props(zhp); 4508168404Spjd 4509168404Spjd entry = *plp; 4510168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4511168404Spjd /* 4512168404Spjd * Go through and add any user properties as necessary. We 4513168404Spjd * start by incrementing our list pointer to the first 4514168404Spjd * non-native property. 4515168404Spjd */ 4516168404Spjd start = plp; 4517168404Spjd while (*start != NULL) { 4518185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 4519168404Spjd break; 4520168404Spjd start = &(*start)->pl_next; 4521168404Spjd } 4522168404Spjd 4523168404Spjd elem = NULL; 4524168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4525168404Spjd /* 4526168404Spjd * See if we've already found this property in our list. 4527168404Spjd */ 4528168404Spjd for (last = start; *last != NULL; 4529168404Spjd last = &(*last)->pl_next) { 4530168404Spjd if (strcmp((*last)->pl_user_prop, 4531168404Spjd nvpair_name(elem)) == 0) 4532168404Spjd break; 4533168404Spjd } 4534168404Spjd 4535168404Spjd if (*last == NULL) { 4536168404Spjd if ((entry = zfs_alloc(hdl, 4537185029Spjd sizeof (zprop_list_t))) == NULL || 4538168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 4539168404Spjd nvpair_name(elem)))) == NULL) { 4540168404Spjd free(entry); 4541168404Spjd return (-1); 4542168404Spjd } 4543168404Spjd 4544185029Spjd entry->pl_prop = ZPROP_INVAL; 4545168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 4546168404Spjd entry->pl_all = B_TRUE; 4547168404Spjd *last = entry; 4548168404Spjd } 4549168404Spjd } 4550168404Spjd } 4551168404Spjd 4552168404Spjd /* 4553168404Spjd * Now go through and check the width of any non-fixed columns 4554168404Spjd */ 4555168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4556259850Sdelphij if (entry->pl_fixed && !literal) 4557168404Spjd continue; 4558168404Spjd 4559185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 4560168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 4561259850Sdelphij buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4562168404Spjd if (strlen(buf) > entry->pl_width) 4563168404Spjd entry->pl_width = strlen(buf); 4564168404Spjd } 4565219089Spjd if (received && zfs_prop_get_recvd(zhp, 4566219089Spjd zfs_prop_to_name(entry->pl_prop), 4567259850Sdelphij buf, sizeof (buf), literal) == 0) 4568219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4569219089Spjd entry->pl_recvd_width = strlen(buf); 4570219089Spjd } else { 4571219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4572219089Spjd &propval) == 0) { 4573219089Spjd verify(nvlist_lookup_string(propval, 4574219089Spjd ZPROP_VALUE, &strval) == 0); 4575219089Spjd if (strlen(strval) > entry->pl_width) 4576219089Spjd entry->pl_width = strlen(strval); 4577219089Spjd } 4578219089Spjd if (received && zfs_prop_get_recvd(zhp, 4579219089Spjd entry->pl_user_prop, 4580259850Sdelphij buf, sizeof (buf), literal) == 0) 4581219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4582219089Spjd entry->pl_recvd_width = strlen(buf); 4583168404Spjd } 4584168404Spjd } 4585168404Spjd 4586168404Spjd return (0); 4587168404Spjd} 4588168404Spjd 4589185029Spjdint 4590185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4591209962Smm char *resource, void *export, void *sharetab, 4592209962Smm int sharemax, zfs_share_op_t operation) 4593185029Spjd{ 4594185029Spjd zfs_cmd_t zc = { 0 }; 4595185029Spjd int error; 4596185029Spjd 4597185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4598185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4599209962Smm if (resource) 4600209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4601185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4602185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4603185029Spjd zc.zc_share.z_sharetype = operation; 4604185029Spjd zc.zc_share.z_sharemax = sharemax; 4605185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4606185029Spjd return (error); 4607185029Spjd} 4608185029Spjd 4609205198Sdelphijvoid 4610205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4611205198Sdelphij{ 4612205198Sdelphij nvpair_t *curr; 4613205198Sdelphij 4614205198Sdelphij /* 4615205198Sdelphij * Keep a reference to the props-table against which we prune the 4616205198Sdelphij * properties. 4617205198Sdelphij */ 4618205198Sdelphij zhp->zfs_props_table = props; 4619205198Sdelphij 4620205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4621205198Sdelphij 4622205198Sdelphij while (curr) { 4623205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4624205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4625205198Sdelphij 4626206199Sdelphij /* 4627219089Spjd * User properties will result in ZPROP_INVAL, and since we 4628219089Spjd * only know how to prune standard ZFS properties, we always 4629219089Spjd * leave these in the list. This can also happen if we 4630219089Spjd * encounter an unknown DSL property (when running older 4631219089Spjd * software, for example). 4632206199Sdelphij */ 4633206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4634205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4635205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4636205198Sdelphij curr = next; 4637205198Sdelphij } 4638205198Sdelphij} 4639205198Sdelphij 4640277300Ssmh#ifdef illumos 4641209962Smmstatic int 4642209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4643209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4644209962Smm{ 4645209962Smm zfs_cmd_t zc = { 0 }; 4646209962Smm nvlist_t *nvlist = NULL; 4647209962Smm int error; 4648209962Smm 4649209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4650209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4651209962Smm zc.zc_cookie = (uint64_t)cmd; 4652209962Smm 4653209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4654209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4655209962Smm (void) no_memory(hdl); 4656289497Smav return (0); 4657209962Smm } 4658209962Smm } 4659209962Smm 4660209962Smm switch (cmd) { 4661209962Smm case ZFS_SMB_ACL_ADD: 4662209962Smm case ZFS_SMB_ACL_REMOVE: 4663209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4664209962Smm break; 4665209962Smm case ZFS_SMB_ACL_RENAME: 4666209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4667209962Smm resource1) != 0) { 4668209962Smm (void) no_memory(hdl); 4669209962Smm return (-1); 4670209962Smm } 4671209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4672209962Smm resource2) != 0) { 4673209962Smm (void) no_memory(hdl); 4674209962Smm return (-1); 4675209962Smm } 4676209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4677209962Smm nvlist_free(nvlist); 4678209962Smm return (-1); 4679209962Smm } 4680209962Smm break; 4681209962Smm case ZFS_SMB_ACL_PURGE: 4682209962Smm break; 4683209962Smm default: 4684209962Smm return (-1); 4685209962Smm } 4686209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4687296528Smav nvlist_free(nvlist); 4688209962Smm return (error); 4689209962Smm} 4690209962Smm 4691209962Smmint 4692209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4693209962Smm char *path, char *resource) 4694209962Smm{ 4695209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4696209962Smm resource, NULL)); 4697209962Smm} 4698209962Smm 4699209962Smmint 4700209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4701209962Smm char *path, char *resource) 4702209962Smm{ 4703209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4704209962Smm resource, NULL)); 4705209962Smm} 4706209962Smm 4707209962Smmint 4708209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4709209962Smm{ 4710209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4711209962Smm NULL, NULL)); 4712209962Smm} 4713209962Smm 4714209962Smmint 4715209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4716209962Smm char *oldname, char *newname) 4717209962Smm{ 4718209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4719209962Smm oldname, newname)); 4720209962Smm} 4721277300Ssmh#endif /* illumos */ 4722209962Smm 4723209962Smmint 4724209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4725209962Smm zfs_userspace_cb_t func, void *arg) 4726209962Smm{ 4727209962Smm zfs_cmd_t zc = { 0 }; 4728209962Smm zfs_useracct_t buf[100]; 4729240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4730240415Smm int ret; 4731209962Smm 4732228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4733209962Smm 4734209962Smm zc.zc_objset_type = type; 4735209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4736209962Smm 4737240415Smm for (;;) { 4738209962Smm zfs_useracct_t *zua = buf; 4739209962Smm 4740209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4741240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4742248571Smm char errbuf[1024]; 4743240415Smm 4744240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4745240415Smm dgettext(TEXT_DOMAIN, 4746240415Smm "cannot get used/quota for %s"), zc.zc_name); 4747240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4748240415Smm } 4749240415Smm if (zc.zc_nvlist_dst_size == 0) 4750209962Smm break; 4751209962Smm 4752209962Smm while (zc.zc_nvlist_dst_size > 0) { 4753240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4754240415Smm zua->zu_space)) != 0) 4755240415Smm return (ret); 4756209962Smm zua++; 4757209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4758209962Smm } 4759209962Smm } 4760209962Smm 4761240415Smm return (0); 4762209962Smm} 4763209962Smm 4764248571Smmstruct holdarg { 4765248571Smm nvlist_t *nvl; 4766248571Smm const char *snapname; 4767248571Smm const char *tag; 4768248571Smm boolean_t recursive; 4769252219Sdelphij int error; 4770248571Smm}; 4771248571Smm 4772248571Smmstatic int 4773248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4774248571Smm{ 4775248571Smm struct holdarg *ha = arg; 4776307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4777248571Smm int rv = 0; 4778248571Smm 4779248571Smm (void) snprintf(name, sizeof (name), 4780248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4781248571Smm 4782251646Sdelphij if (lzc_exists(name)) 4783248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4784248571Smm 4785248571Smm if (ha->recursive) 4786248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4787248571Smm zfs_close(zhp); 4788248571Smm return (rv); 4789248571Smm} 4790248571Smm 4791219089Spjdint 4792219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4793251646Sdelphij boolean_t recursive, int cleanup_fd) 4794219089Spjd{ 4795248571Smm int ret; 4796248571Smm struct holdarg ha; 4797219089Spjd 4798248571Smm ha.nvl = fnvlist_alloc(); 4799248571Smm ha.snapname = snapname; 4800248571Smm ha.tag = tag; 4801248571Smm ha.recursive = recursive; 4802248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4803249357Smm 4804251646Sdelphij if (nvlist_empty(ha.nvl)) { 4805251646Sdelphij char errbuf[1024]; 4806251646Sdelphij 4807249357Smm fnvlist_free(ha.nvl); 4808249357Smm ret = ENOENT; 4809251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4810251646Sdelphij dgettext(TEXT_DOMAIN, 4811251646Sdelphij "cannot hold snapshot '%s@%s'"), 4812251646Sdelphij zhp->zfs_name, snapname); 4813251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4814249357Smm return (ret); 4815249357Smm } 4816249357Smm 4817251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4818248571Smm fnvlist_free(ha.nvl); 4819219089Spjd 4820251646Sdelphij return (ret); 4821251646Sdelphij} 4822251646Sdelphij 4823251646Sdelphijint 4824251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4825251646Sdelphij{ 4826251646Sdelphij int ret; 4827251646Sdelphij nvlist_t *errors; 4828251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4829251646Sdelphij char errbuf[1024]; 4830251646Sdelphij nvpair_t *elem; 4831251646Sdelphij 4832251646Sdelphij errors = NULL; 4833251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4834251646Sdelphij 4835251646Sdelphij if (ret == 0) { 4836251646Sdelphij /* There may be errors even in the success case. */ 4837251646Sdelphij fnvlist_free(errors); 4838248571Smm return (0); 4839251646Sdelphij } 4840219089Spjd 4841251646Sdelphij if (nvlist_empty(errors)) { 4842248571Smm /* no hold-specific errors */ 4843248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4844248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4845248571Smm switch (ret) { 4846248571Smm case ENOTSUP: 4847248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4848248571Smm "pool must be upgraded")); 4849248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4850248571Smm break; 4851248571Smm case EINVAL: 4852248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4853248571Smm break; 4854248571Smm default: 4855248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4856248571Smm } 4857248571Smm } 4858219089Spjd 4859248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4860248571Smm elem != NULL; 4861248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4862248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4863248571Smm dgettext(TEXT_DOMAIN, 4864248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4865248571Smm switch (fnvpair_value_int32(elem)) { 4866219089Spjd case E2BIG: 4867219089Spjd /* 4868219089Spjd * Temporary tags wind up having the ds object id 4869219089Spjd * prepended. So even if we passed the length check 4870219089Spjd * above, it's still possible for the tag to wind 4871219089Spjd * up being slightly too long. 4872219089Spjd */ 4873248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4874248571Smm break; 4875219089Spjd case EINVAL: 4876248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4877248571Smm break; 4878219089Spjd case EEXIST: 4879248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4880248571Smm break; 4881219089Spjd default: 4882248571Smm (void) zfs_standard_error(hdl, 4883248571Smm fnvpair_value_int32(elem), errbuf); 4884219089Spjd } 4885219089Spjd } 4886219089Spjd 4887248571Smm fnvlist_free(errors); 4888248571Smm return (ret); 4889219089Spjd} 4890219089Spjd 4891248571Smmstatic int 4892248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4893248571Smm{ 4894248571Smm struct holdarg *ha = arg; 4895307108Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4896248571Smm int rv = 0; 4897252219Sdelphij nvlist_t *existing_holds; 4898248571Smm 4899248571Smm (void) snprintf(name, sizeof (name), 4900248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4901248571Smm 4902252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4903252219Sdelphij ha->error = ENOENT; 4904252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4905252219Sdelphij ha->error = ESRCH; 4906252219Sdelphij } else { 4907252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4908252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4909252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4910252219Sdelphij fnvlist_free(torelease); 4911248571Smm } 4912248571Smm 4913248571Smm if (ha->recursive) 4914248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4915248571Smm zfs_close(zhp); 4916248571Smm return (rv); 4917248571Smm} 4918248571Smm 4919219089Spjdint 4920219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4921219089Spjd boolean_t recursive) 4922219089Spjd{ 4923248571Smm int ret; 4924248571Smm struct holdarg ha; 4925251646Sdelphij nvlist_t *errors = NULL; 4926248571Smm nvpair_t *elem; 4927219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4928249357Smm char errbuf[1024]; 4929219089Spjd 4930248571Smm ha.nvl = fnvlist_alloc(); 4931248571Smm ha.snapname = snapname; 4932248571Smm ha.tag = tag; 4933248571Smm ha.recursive = recursive; 4934252219Sdelphij ha.error = 0; 4935248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4936249357Smm 4937251646Sdelphij if (nvlist_empty(ha.nvl)) { 4938249357Smm fnvlist_free(ha.nvl); 4939252219Sdelphij ret = ha.error; 4940249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4941249357Smm dgettext(TEXT_DOMAIN, 4942249357Smm "cannot release hold from snapshot '%s@%s'"), 4943249357Smm zhp->zfs_name, snapname); 4944252219Sdelphij if (ret == ESRCH) { 4945252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4946252219Sdelphij } else { 4947252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4948252219Sdelphij } 4949249357Smm return (ret); 4950249357Smm } 4951249357Smm 4952248571Smm ret = lzc_release(ha.nvl, &errors); 4953248571Smm fnvlist_free(ha.nvl); 4954219089Spjd 4955251646Sdelphij if (ret == 0) { 4956251646Sdelphij /* There may be errors even in the success case. */ 4957251646Sdelphij fnvlist_free(errors); 4958248571Smm return (0); 4959251646Sdelphij } 4960219089Spjd 4961251646Sdelphij if (nvlist_empty(errors)) { 4962248571Smm /* no hold-specific errors */ 4963219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4964248571Smm "cannot release")); 4965219089Spjd switch (errno) { 4966219089Spjd case ENOTSUP: 4967219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4968219089Spjd "pool must be upgraded")); 4969248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4970248571Smm break; 4971248571Smm default: 4972248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4973248571Smm } 4974248571Smm } 4975248571Smm 4976248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4977248571Smm elem != NULL; 4978248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4979248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4980248571Smm dgettext(TEXT_DOMAIN, 4981248571Smm "cannot release hold from snapshot '%s'"), 4982248571Smm nvpair_name(elem)); 4983248571Smm switch (fnvpair_value_int32(elem)) { 4984248571Smm case ESRCH: 4985248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4986248571Smm break; 4987219089Spjd case EINVAL: 4988248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4989248571Smm break; 4990219089Spjd default: 4991248571Smm (void) zfs_standard_error_fmt(hdl, 4992248571Smm fnvpair_value_int32(elem), errbuf); 4993219089Spjd } 4994219089Spjd } 4995219089Spjd 4996248571Smm fnvlist_free(errors); 4997248571Smm return (ret); 4998219089Spjd} 4999219089Spjd 5000219089Spjdint 5001219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 5002219089Spjd{ 5003219089Spjd zfs_cmd_t zc = { 0 }; 5004219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 5005219089Spjd int nvsz = 2048; 5006219089Spjd void *nvbuf; 5007219089Spjd int err = 0; 5008248571Smm char errbuf[1024]; 5009219089Spjd 5010219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 5011219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5012219089Spjd 5013219089Spjdtryagain: 5014219089Spjd 5015219089Spjd nvbuf = malloc(nvsz); 5016219089Spjd if (nvbuf == NULL) { 5017219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 5018219089Spjd goto out; 5019219089Spjd } 5020219089Spjd 5021219089Spjd zc.zc_nvlist_dst_size = nvsz; 5022219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 5023219089Spjd 5024307108Smav (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5025219089Spjd 5026230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 5027219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 5028219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 5029219089Spjd zc.zc_name); 5030219089Spjd switch (errno) { 5031219089Spjd case ENOMEM: 5032219089Spjd free(nvbuf); 5033219089Spjd nvsz = zc.zc_nvlist_dst_size; 5034219089Spjd goto tryagain; 5035219089Spjd 5036219089Spjd case ENOTSUP: 5037219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5038219089Spjd "pool must be upgraded")); 5039219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5040219089Spjd break; 5041219089Spjd case EINVAL: 5042219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5043219089Spjd break; 5044219089Spjd case ENOENT: 5045219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 5046219089Spjd break; 5047219089Spjd default: 5048219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 5049219089Spjd break; 5050219089Spjd } 5051219089Spjd } else { 5052219089Spjd /* success */ 5053219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 5054219089Spjd if (rc) { 5055219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 5056219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 5057219089Spjd zc.zc_name); 5058219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 5059219089Spjd } 5060219089Spjd } 5061219089Spjd 5062219089Spjd free(nvbuf); 5063219089Spjdout: 5064219089Spjd return (err); 5065219089Spjd} 5066219089Spjd 5067219089Spjdint 5068219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 5069219089Spjd{ 5070219089Spjd zfs_cmd_t zc = { 0 }; 5071219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 5072219089Spjd char *nvbuf; 5073248571Smm char errbuf[1024]; 5074219089Spjd size_t nvsz; 5075219089Spjd int err; 5076219089Spjd 5077219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 5078219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5079219089Spjd 5080219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 5081219089Spjd assert(err == 0); 5082219089Spjd 5083219089Spjd nvbuf = malloc(nvsz); 5084219089Spjd 5085219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 5086219089Spjd assert(err == 0); 5087219089Spjd 5088219089Spjd zc.zc_nvlist_src_size = nvsz; 5089219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 5090219089Spjd zc.zc_perm_action = un; 5091219089Spjd 5092219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5093219089Spjd 5094219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 5095219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 5096219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 5097219089Spjd zc.zc_name); 5098219089Spjd switch (errno) { 5099219089Spjd case ENOTSUP: 5100219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5101219089Spjd "pool must be upgraded")); 5102219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5103219089Spjd break; 5104219089Spjd case EINVAL: 5105219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5106219089Spjd break; 5107219089Spjd case ENOENT: 5108219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 5109219089Spjd break; 5110219089Spjd default: 5111219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 5112219089Spjd break; 5113219089Spjd } 5114219089Spjd } 5115219089Spjd 5116219089Spjd free(nvbuf); 5117219089Spjd 5118219089Spjd return (err); 5119219089Spjd} 5120219089Spjd 5121219089Spjdint 5122219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 5123219089Spjd{ 5124248571Smm int err; 5125248571Smm char errbuf[1024]; 5126219089Spjd 5127248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 5128219089Spjd 5129248571Smm if (err != 0) { 5130248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 5131219089Spjd 5132219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 5133219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 5134248571Smm zhp->zfs_name); 5135248571Smm switch (err) { 5136219089Spjd case ENOTSUP: 5137219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5138219089Spjd "pool must be upgraded")); 5139219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 5140219089Spjd break; 5141219089Spjd case EINVAL: 5142219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 5143219089Spjd break; 5144219089Spjd case ENOENT: 5145219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 5146219089Spjd break; 5147219089Spjd default: 5148219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 5149219089Spjd break; 5150219089Spjd } 5151219089Spjd } 5152219089Spjd 5153219089Spjd return (err); 5154219089Spjd} 5155219089Spjd 5156251629Sdelphij/* 5157251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 5158251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 5159251629Sdelphij * suite's shell version in reservation.kshlib. 5160251629Sdelphij */ 5161219089Spjduint64_t 5162219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 5163219089Spjd{ 5164219089Spjd uint64_t numdb; 5165219089Spjd uint64_t nblocks, volblocksize; 5166219089Spjd int ncopies; 5167219089Spjd char *strval; 5168219089Spjd 5169219089Spjd if (nvlist_lookup_string(props, 5170219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 5171219089Spjd ncopies = atoi(strval); 5172219089Spjd else 5173219089Spjd ncopies = 1; 5174219089Spjd if (nvlist_lookup_uint64(props, 5175219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 5176219089Spjd &volblocksize) != 0) 5177219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 5178219089Spjd nblocks = volsize/volblocksize; 5179219089Spjd /* start with metadnode L0-L6 */ 5180219089Spjd numdb = 7; 5181219089Spjd /* calculate number of indirects */ 5182219089Spjd while (nblocks > 1) { 5183219089Spjd nblocks += DNODES_PER_LEVEL - 1; 5184219089Spjd nblocks /= DNODES_PER_LEVEL; 5185219089Spjd numdb += nblocks; 5186219089Spjd } 5187219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 5188219089Spjd volsize *= ncopies; 5189219089Spjd /* 5190219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 5191219089Spjd * compressed, but in practice they compress down to about 5192219089Spjd * 1100 bytes 5193219089Spjd */ 5194219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 5195219089Spjd volsize += numdb; 5196219089Spjd return (volsize); 5197219089Spjd} 5198219089Spjd 5199168404Spjd/* 5200168404Spjd * Attach/detach the given filesystem to/from the given jail. 5201168404Spjd */ 5202168404Spjdint 5203168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 5204168404Spjd{ 5205168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 5206168404Spjd zfs_cmd_t zc = { 0 }; 5207168404Spjd char errbuf[1024]; 5208224525Smm unsigned long cmd; 5209224525Smm int ret; 5210168404Spjd 5211168404Spjd if (attach) { 5212168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 5213168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 5214168404Spjd } else { 5215168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 5216249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 5217168404Spjd } 5218168404Spjd 5219168404Spjd switch (zhp->zfs_type) { 5220168404Spjd case ZFS_TYPE_VOLUME: 5221168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5222168404Spjd "volumes can not be jailed")); 5223168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 5224168404Spjd case ZFS_TYPE_SNAPSHOT: 5225168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5226168404Spjd "snapshots can not be jailed")); 5227168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 5228168404Spjd } 5229168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 5230168404Spjd 5231168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 5232168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 5233168404Spjd zc.zc_jailid = jailid; 5234168404Spjd 5235168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 5236168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 5237168404Spjd zfs_standard_error(hdl, errno, errbuf); 5238168404Spjd 5239168404Spjd return (ret); 5240168404Spjd} 5241