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. 24265744Sdelphij * Copyright (c) 2013, Joyent, Inc. All rights reserved. 25325140Savg * Copyright (c) 2011, 2016 by Delphix. All rights reserved. 26252219Sdelphij * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 27307053Smav * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. 28307053Smav * Copyright (c) 2013 Martin Matuska. All rights reserved. 29251646Sdelphij * Copyright (c) 2013 Steven Hartland. All rights reserved. 30297112Smav * Copyright (c) 2014 Integros [integros.com] 31307058Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> 32307120Smav * Copyright 2016 Nexenta Systems, Inc. 33168404Spjd */ 34168404Spjd 35168404Spjd#include <ctype.h> 36168404Spjd#include <errno.h> 37168404Spjd#include <libintl.h> 38168404Spjd#include <math.h> 39168404Spjd#include <stdio.h> 40168404Spjd#include <stdlib.h> 41168404Spjd#include <strings.h> 42168404Spjd#include <unistd.h> 43185029Spjd#include <stddef.h> 44168404Spjd#include <zone.h> 45168404Spjd#include <fcntl.h> 46168404Spjd#include <sys/mntent.h> 47168404Spjd#include <sys/mount.h> 48185029Spjd#include <priv.h> 49185029Spjd#include <pwd.h> 50185029Spjd#include <grp.h> 51185029Spjd#include <stddef.h> 52209962Smm#include <idmap.h> 53168404Spjd 54219089Spjd#include <sys/dnode.h> 55168404Spjd#include <sys/spa.h> 56168404Spjd#include <sys/zap.h> 57209962Smm#include <sys/misc.h> 58168404Spjd#include <libzfs.h> 59168404Spjd 60168404Spjd#include "zfs_namecheck.h" 61168404Spjd#include "zfs_prop.h" 62168404Spjd#include "libzfs_impl.h" 63185029Spjd#include "zfs_deleg.h" 64168404Spjd 65209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 66209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 67168676Spjd 68168404Spjd/* 69168404Spjd * Given a single type (not a mask of types), return the type in a human 70168404Spjd * readable form. 71168404Spjd */ 72168404Spjdconst char * 73168404Spjdzfs_type_to_name(zfs_type_t type) 74168404Spjd{ 75168404Spjd switch (type) { 76168404Spjd case ZFS_TYPE_FILESYSTEM: 77168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 78168404Spjd case ZFS_TYPE_SNAPSHOT: 79168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 80168404Spjd case ZFS_TYPE_VOLUME: 81168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 82307058Smav case ZFS_TYPE_POOL: 83307058Smav return (dgettext(TEXT_DOMAIN, "pool")); 84307058Smav case ZFS_TYPE_BOOKMARK: 85307058Smav return (dgettext(TEXT_DOMAIN, "bookmark")); 86307058Smav default: 87307058Smav assert(!"unhandled zfs_type_t"); 88168404Spjd } 89168404Spjd 90168404Spjd return (NULL); 91168404Spjd} 92168404Spjd 93168404Spjd/* 94168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 95209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 96209962Smm * explain exactly why the name was not valid. 97168404Spjd */ 98219089Spjdint 99185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 100185029Spjd boolean_t modifying) 101168404Spjd{ 102168404Spjd namecheck_err_t why; 103168404Spjd char what; 104168404Spjd 105219089Spjd (void) zfs_prop_get_table(); 106168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 107168404Spjd if (hdl != NULL) { 108168404Spjd switch (why) { 109168404Spjd case NAME_ERR_TOOLONG: 110168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 111168404Spjd "name is too long")); 112168404Spjd break; 113168404Spjd 114168404Spjd case NAME_ERR_LEADING_SLASH: 115168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116168404Spjd "leading slash in name")); 117168404Spjd break; 118168404Spjd 119168404Spjd case NAME_ERR_EMPTY_COMPONENT: 120168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 121168404Spjd "empty component in name")); 122168404Spjd break; 123168404Spjd 124168404Spjd case NAME_ERR_TRAILING_SLASH: 125168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 126168404Spjd "trailing slash in name")); 127168404Spjd break; 128168404Spjd 129168404Spjd case NAME_ERR_INVALCHAR: 130168404Spjd zfs_error_aux(hdl, 131168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 132168404Spjd "'%c' in name"), what); 133168404Spjd break; 134168404Spjd 135168404Spjd case NAME_ERR_MULTIPLE_AT: 136168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 137168404Spjd "multiple '@' delimiters in name")); 138168404Spjd break; 139168404Spjd 140168404Spjd case NAME_ERR_NOLETTER: 141168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 142168404Spjd "pool doesn't begin with a letter")); 143168404Spjd break; 144168404Spjd 145168404Spjd case NAME_ERR_RESERVED: 146168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 147168404Spjd "name is reserved")); 148168404Spjd break; 149168404Spjd 150168404Spjd case NAME_ERR_DISKLIKE: 151168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 152168404Spjd "reserved disk name")); 153168404Spjd break; 154307058Smav 155307058Smav default: 156307058Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 157307058Smav "(%d) not defined"), why); 158307058Smav break; 159168404Spjd } 160168404Spjd } 161168404Spjd 162168404Spjd return (0); 163168404Spjd } 164168404Spjd 165168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 166168404Spjd if (hdl != NULL) 167168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 168168404Spjd "snapshot delimiter '@' in filesystem name")); 169168404Spjd return (0); 170168404Spjd } 171168404Spjd 172168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 173168404Spjd if (hdl != NULL) 174168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 175168404Spjd "missing '@' delimiter in snapshot name")); 176168404Spjd return (0); 177168404Spjd } 178168404Spjd 179185029Spjd if (modifying && strchr(path, '%') != NULL) { 180185029Spjd if (hdl != NULL) 181185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 182185029Spjd "invalid character %c in name"), '%'); 183185029Spjd return (0); 184185029Spjd } 185185029Spjd 186168404Spjd return (-1); 187168404Spjd} 188168404Spjd 189168404Spjdint 190168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 191168404Spjd{ 192185029Spjd if (type == ZFS_TYPE_POOL) 193185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 194185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 195168404Spjd} 196168404Spjd 197168404Spjd/* 198168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 199168404Spjd * properties into a separate nvlist. 200168404Spjd */ 201185029Spjdstatic nvlist_t * 202185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 203168404Spjd{ 204168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 205168404Spjd nvpair_t *elem; 206168404Spjd nvlist_t *propval; 207185029Spjd nvlist_t *nvl; 208168404Spjd 209185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 210185029Spjd (void) no_memory(hdl); 211185029Spjd return (NULL); 212185029Spjd } 213168404Spjd 214168404Spjd elem = NULL; 215185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 216168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 217168404Spjd continue; 218168404Spjd 219168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 220185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 221185029Spjd nvlist_free(nvl); 222185029Spjd (void) no_memory(hdl); 223185029Spjd return (NULL); 224185029Spjd } 225168404Spjd } 226168404Spjd 227185029Spjd return (nvl); 228168404Spjd} 229168404Spjd 230185029Spjdstatic zpool_handle_t * 231185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 232185029Spjd{ 233185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 234185029Spjd zpool_handle_t *zph; 235185029Spjd 236185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 237185029Spjd if (hdl->libzfs_pool_handles != NULL) 238185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 239185029Spjd hdl->libzfs_pool_handles = zph; 240185029Spjd } 241185029Spjd return (zph); 242185029Spjd} 243185029Spjd 244185029Spjdstatic zpool_handle_t * 245185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 246185029Spjd{ 247185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 248185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 249185029Spjd 250185029Spjd while ((zph != NULL) && 251185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 252185029Spjd zph = zph->zpool_next; 253185029Spjd return (zph); 254185029Spjd} 255185029Spjd 256168404Spjd/* 257185029Spjd * Returns a handle to the pool that contains the provided dataset. 258185029Spjd * If a handle to that pool already exists then that handle is returned. 259185029Spjd * Otherwise, a new handle is created and added to the list of handles. 260185029Spjd */ 261185029Spjdstatic zpool_handle_t * 262185029Spjdzpool_handle(zfs_handle_t *zhp) 263185029Spjd{ 264185029Spjd char *pool_name; 265185029Spjd int len; 266185029Spjd zpool_handle_t *zph; 267185029Spjd 268263407Sdelphij len = strcspn(zhp->zfs_name, "/@#") + 1; 269185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 270185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 271185029Spjd 272185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 273185029Spjd if (zph == NULL) 274185029Spjd zph = zpool_add_handle(zhp, pool_name); 275185029Spjd 276185029Spjd free(pool_name); 277185029Spjd return (zph); 278185029Spjd} 279185029Spjd 280185029Spjdvoid 281185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 282185029Spjd{ 283185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 284185029Spjd 285185029Spjd while (zph != NULL) { 286185029Spjd next = zph->zpool_next; 287185029Spjd zpool_close(zph); 288185029Spjd zph = next; 289185029Spjd } 290185029Spjd hdl->libzfs_pool_handles = NULL; 291185029Spjd} 292185029Spjd 293185029Spjd/* 294168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 295168404Spjd */ 296219089Spjdstatic int 297209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 298168404Spjd{ 299168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 300168404Spjd 301209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 302168404Spjd 303209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 304168404Spjd if (errno == ENOMEM) { 305209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 306168404Spjd return (-1); 307168404Spjd } 308168404Spjd } else { 309168404Spjd return (-1); 310168404Spjd } 311168404Spjd } 312209962Smm return (0); 313209962Smm} 314168404Spjd 315219089Spjd/* 316219089Spjd * Utility function to get the received properties of the given object. 317219089Spjd */ 318209962Smmstatic int 319219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 320219089Spjd{ 321219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 322219089Spjd nvlist_t *recvdprops; 323219089Spjd zfs_cmd_t zc = { 0 }; 324219089Spjd int err; 325219089Spjd 326219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 327219089Spjd return (-1); 328219089Spjd 329219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 330219089Spjd 331219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 332219089Spjd if (errno == ENOMEM) { 333219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 334219089Spjd return (-1); 335219089Spjd } 336219089Spjd } else { 337219089Spjd zcmd_free_nvlists(&zc); 338219089Spjd return (-1); 339219089Spjd } 340219089Spjd } 341219089Spjd 342219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 343219089Spjd zcmd_free_nvlists(&zc); 344219089Spjd if (err != 0) 345219089Spjd return (-1); 346219089Spjd 347219089Spjd nvlist_free(zhp->zfs_recvd_props); 348219089Spjd zhp->zfs_recvd_props = recvdprops; 349219089Spjd 350219089Spjd return (0); 351219089Spjd} 352219089Spjd 353219089Spjdstatic int 354209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 355209962Smm{ 356209962Smm nvlist_t *allprops, *userprops; 357168404Spjd 358209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 359209962Smm 360209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 361168404Spjd return (-1); 362168404Spjd } 363168404Spjd 364209962Smm /* 365209962Smm * XXX Why do we store the user props separately, in addition to 366209962Smm * storing them in zfs_props? 367209962Smm */ 368185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 369185029Spjd nvlist_free(allprops); 370168404Spjd return (-1); 371185029Spjd } 372168404Spjd 373185029Spjd nvlist_free(zhp->zfs_props); 374185029Spjd nvlist_free(zhp->zfs_user_props); 375185029Spjd 376185029Spjd zhp->zfs_props = allprops; 377185029Spjd zhp->zfs_user_props = userprops; 378185029Spjd 379168404Spjd return (0); 380168404Spjd} 381168404Spjd 382209962Smmstatic int 383209962Smmget_stats(zfs_handle_t *zhp) 384209962Smm{ 385209962Smm int rc = 0; 386209962Smm zfs_cmd_t zc = { 0 }; 387209962Smm 388209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 389209962Smm return (-1); 390209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 391209962Smm rc = -1; 392209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 393209962Smm rc = -1; 394209962Smm zcmd_free_nvlists(&zc); 395209962Smm return (rc); 396209962Smm} 397209962Smm 398168404Spjd/* 399168404Spjd * Refresh the properties currently stored in the handle. 400168404Spjd */ 401168404Spjdvoid 402168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 403168404Spjd{ 404168404Spjd (void) get_stats(zhp); 405168404Spjd} 406168404Spjd 407168404Spjd/* 408168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 409168404Spjd * zfs_iter_* to create child handles on the fly. 410168404Spjd */ 411209962Smmstatic int 412209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 413168404Spjd{ 414219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 415209962Smm return (-1); 416168404Spjd 417168404Spjd /* 418168404Spjd * We've managed to open the dataset and gather statistics. Determine 419168404Spjd * the high-level type. 420168404Spjd */ 421168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 422168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 423168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 424168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 425168404Spjd else 426168404Spjd abort(); 427168404Spjd 428168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 429168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 430168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 431168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 432168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 433168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 434168404Spjd else 435168404Spjd abort(); /* we should never see any other types */ 436168404Spjd 437219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 438219089Spjd return (-1); 439219089Spjd 440209962Smm return (0); 441209962Smm} 442209962Smm 443209962Smmzfs_handle_t * 444209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 445209962Smm{ 446209962Smm zfs_cmd_t zc = { 0 }; 447209962Smm 448209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 449209962Smm 450209962Smm if (zhp == NULL) 451209962Smm return (NULL); 452209962Smm 453209962Smm zhp->zfs_hdl = hdl; 454209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 455209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 456209962Smm free(zhp); 457209962Smm return (NULL); 458209962Smm } 459209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 460209962Smm zcmd_free_nvlists(&zc); 461209962Smm free(zhp); 462209962Smm return (NULL); 463209962Smm } 464209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 465209962Smm free(zhp); 466209962Smm zhp = NULL; 467209962Smm } 468209962Smm zcmd_free_nvlists(&zc); 469168404Spjd return (zhp); 470168404Spjd} 471168404Spjd 472228103Smmzfs_handle_t * 473209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 474209962Smm{ 475209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 476209962Smm 477209962Smm if (zhp == NULL) 478209962Smm return (NULL); 479209962Smm 480209962Smm zhp->zfs_hdl = hdl; 481209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 482209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 483209962Smm free(zhp); 484209962Smm return (NULL); 485209962Smm } 486209962Smm return (zhp); 487209962Smm} 488209962Smm 489228103Smmzfs_handle_t * 490230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 491230438Spjd{ 492230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 493230438Spjd 494230438Spjd if (zhp == NULL) 495230438Spjd return (NULL); 496230438Spjd 497230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 498230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 499230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 500230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 501230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 502230438Spjd return (zhp); 503230438Spjd} 504230438Spjd 505230438Spjdzfs_handle_t * 506228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 507228103Smm{ 508228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 509228103Smm 510228103Smm if (zhp == NULL) 511228103Smm return (NULL); 512228103Smm 513228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 514228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 515228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 516228103Smm sizeof (zhp->zfs_name)); 517228103Smm zhp->zfs_type = zhp_orig->zfs_type; 518228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 519228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 520228103Smm if (zhp_orig->zfs_props != NULL) { 521228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 522228103Smm (void) no_memory(zhp->zfs_hdl); 523228103Smm zfs_close(zhp); 524228103Smm return (NULL); 525228103Smm } 526228103Smm } 527228103Smm if (zhp_orig->zfs_user_props != NULL) { 528228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 529228103Smm &zhp->zfs_user_props, 0) != 0) { 530228103Smm (void) no_memory(zhp->zfs_hdl); 531228103Smm zfs_close(zhp); 532228103Smm return (NULL); 533228103Smm } 534228103Smm } 535228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 536228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 537228103Smm &zhp->zfs_recvd_props, 0)) { 538228103Smm (void) no_memory(zhp->zfs_hdl); 539228103Smm zfs_close(zhp); 540228103Smm return (NULL); 541228103Smm } 542228103Smm } 543228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 544228103Smm if (zhp_orig->zfs_mntopts != NULL) { 545228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 546228103Smm zhp_orig->zfs_mntopts); 547228103Smm } 548228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 549228103Smm return (zhp); 550228103Smm} 551228103Smm 552263407Sdelphijboolean_t 553263407Sdelphijzfs_bookmark_exists(const char *path) 554263407Sdelphij{ 555263407Sdelphij nvlist_t *bmarks; 556263407Sdelphij nvlist_t *props; 557307122Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 558263407Sdelphij char *bmark_name; 559263407Sdelphij char *pound; 560263407Sdelphij int err; 561263407Sdelphij boolean_t rv; 562263407Sdelphij 563263407Sdelphij 564263407Sdelphij (void) strlcpy(fsname, path, sizeof (fsname)); 565263407Sdelphij pound = strchr(fsname, '#'); 566263407Sdelphij if (pound == NULL) 567263407Sdelphij return (B_FALSE); 568263407Sdelphij 569263407Sdelphij *pound = '\0'; 570263407Sdelphij bmark_name = pound + 1; 571263407Sdelphij props = fnvlist_alloc(); 572263407Sdelphij err = lzc_get_bookmarks(fsname, props, &bmarks); 573263407Sdelphij nvlist_free(props); 574263407Sdelphij if (err != 0) { 575263407Sdelphij nvlist_free(bmarks); 576263407Sdelphij return (B_FALSE); 577263407Sdelphij } 578263407Sdelphij 579263407Sdelphij rv = nvlist_exists(bmarks, bmark_name); 580263407Sdelphij nvlist_free(bmarks); 581263407Sdelphij return (rv); 582263407Sdelphij} 583263407Sdelphij 584263407Sdelphijzfs_handle_t * 585263407Sdelphijmake_bookmark_handle(zfs_handle_t *parent, const char *path, 586263407Sdelphij nvlist_t *bmark_props) 587263407Sdelphij{ 588263407Sdelphij zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 589263407Sdelphij 590263407Sdelphij if (zhp == NULL) 591263407Sdelphij return (NULL); 592263407Sdelphij 593263407Sdelphij /* Fill in the name. */ 594263407Sdelphij zhp->zfs_hdl = parent->zfs_hdl; 595263407Sdelphij (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 596263407Sdelphij 597263407Sdelphij /* Set the property lists. */ 598263407Sdelphij if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 599263407Sdelphij free(zhp); 600263407Sdelphij return (NULL); 601263407Sdelphij } 602263407Sdelphij 603263407Sdelphij /* Set the types. */ 604263407Sdelphij zhp->zfs_head_type = parent->zfs_head_type; 605263407Sdelphij zhp->zfs_type = ZFS_TYPE_BOOKMARK; 606263407Sdelphij 607263407Sdelphij if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 608263407Sdelphij nvlist_free(zhp->zfs_props); 609263407Sdelphij free(zhp); 610263407Sdelphij return (NULL); 611263407Sdelphij } 612263407Sdelphij 613263407Sdelphij return (zhp); 614263407Sdelphij} 615263407Sdelphij 616168404Spjd/* 617168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 618168404Spjd * argument is a mask of acceptable types. The function will print an 619168404Spjd * appropriate error message and return NULL if it can't be opened. 620168404Spjd */ 621168404Spjdzfs_handle_t * 622168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 623168404Spjd{ 624168404Spjd zfs_handle_t *zhp; 625168404Spjd char errbuf[1024]; 626168404Spjd 627168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 628168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 629168404Spjd 630168404Spjd /* 631168404Spjd * Validate the name before we even try to open it. 632168404Spjd */ 633185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 634168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 635168404Spjd "invalid dataset name")); 636168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 637168404Spjd return (NULL); 638168404Spjd } 639168404Spjd 640168404Spjd /* 641168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 642168404Spjd */ 643168404Spjd errno = 0; 644168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 645168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 646168404Spjd return (NULL); 647168404Spjd } 648168404Spjd 649240870Spjd if (zhp == NULL) { 650240870Spjd char *at = strchr(path, '@'); 651240870Spjd 652240870Spjd if (at != NULL) 653240870Spjd *at = '\0'; 654240870Spjd errno = 0; 655240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 656240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 657240870Spjd return (NULL); 658240870Spjd } 659240870Spjd if (at != NULL) 660240870Spjd *at = '@'; 661240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 662240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 663240870Spjd } 664240870Spjd 665168404Spjd if (!(types & zhp->zfs_type)) { 666168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 667168404Spjd zfs_close(zhp); 668168404Spjd return (NULL); 669168404Spjd } 670168404Spjd 671168404Spjd return (zhp); 672168404Spjd} 673168404Spjd 674168404Spjd/* 675168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 676168404Spjd */ 677168404Spjdvoid 678168404Spjdzfs_close(zfs_handle_t *zhp) 679168404Spjd{ 680168404Spjd if (zhp->zfs_mntopts) 681168404Spjd free(zhp->zfs_mntopts); 682168404Spjd nvlist_free(zhp->zfs_props); 683168404Spjd nvlist_free(zhp->zfs_user_props); 684219089Spjd nvlist_free(zhp->zfs_recvd_props); 685168404Spjd free(zhp); 686168404Spjd} 687168404Spjd 688209962Smmtypedef struct mnttab_node { 689209962Smm struct mnttab mtn_mt; 690209962Smm avl_node_t mtn_node; 691209962Smm} mnttab_node_t; 692209962Smm 693209962Smmstatic int 694209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 695209962Smm{ 696209962Smm const mnttab_node_t *mtn1 = arg1; 697209962Smm const mnttab_node_t *mtn2 = arg2; 698209962Smm int rv; 699209962Smm 700209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 701209962Smm 702209962Smm if (rv == 0) 703209962Smm return (0); 704209962Smm return (rv > 0 ? 1 : -1); 705209962Smm} 706209962Smm 707209962Smmvoid 708209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 709209962Smm{ 710209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 711209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 712209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 713209962Smm} 714209962Smm 715209962Smmvoid 716209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 717209962Smm{ 718209962Smm struct mnttab entry; 719209962Smm 720209962Smm rewind(hdl->libzfs_mnttab); 721209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 722209962Smm mnttab_node_t *mtn; 723209962Smm 724209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 725209962Smm continue; 726209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 727209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 728209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 729209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 730209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 731209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 732209962Smm } 733209962Smm} 734209962Smm 735209962Smmvoid 736209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 737209962Smm{ 738209962Smm void *cookie = NULL; 739209962Smm mnttab_node_t *mtn; 740209962Smm 741307058Smav while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) 742307058Smav != NULL) { 743209962Smm free(mtn->mtn_mt.mnt_special); 744209962Smm free(mtn->mtn_mt.mnt_mountp); 745209962Smm free(mtn->mtn_mt.mnt_fstype); 746209962Smm free(mtn->mtn_mt.mnt_mntopts); 747209962Smm free(mtn); 748209962Smm } 749209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 750209962Smm} 751209962Smm 752209962Smmvoid 753209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 754209962Smm{ 755209962Smm hdl->libzfs_mnttab_enable = enable; 756209962Smm} 757209962Smm 758185029Spjdint 759209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 760209962Smm struct mnttab *entry) 761209962Smm{ 762209962Smm mnttab_node_t find; 763209962Smm mnttab_node_t *mtn; 764209962Smm 765209962Smm if (!hdl->libzfs_mnttab_enable) { 766209962Smm struct mnttab srch = { 0 }; 767209962Smm 768209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 769209962Smm libzfs_mnttab_fini(hdl); 770209962Smm rewind(hdl->libzfs_mnttab); 771209962Smm srch.mnt_special = (char *)fsname; 772209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 773209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 774209962Smm return (0); 775209962Smm else 776209962Smm return (ENOENT); 777209962Smm } 778209962Smm 779209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 780209962Smm libzfs_mnttab_update(hdl); 781209962Smm 782209962Smm find.mtn_mt.mnt_special = (char *)fsname; 783209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 784209962Smm if (mtn) { 785209962Smm *entry = mtn->mtn_mt; 786209962Smm return (0); 787209962Smm } 788209962Smm return (ENOENT); 789209962Smm} 790209962Smm 791209962Smmvoid 792209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 793209962Smm const char *mountp, const char *mntopts) 794209962Smm{ 795209962Smm mnttab_node_t *mtn; 796209962Smm 797209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 798209962Smm return; 799209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 800209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 801209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 802209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 803209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 804209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 805209962Smm} 806209962Smm 807209962Smmvoid 808209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 809209962Smm{ 810209962Smm mnttab_node_t find; 811209962Smm mnttab_node_t *ret; 812209962Smm 813209962Smm find.mtn_mt.mnt_special = (char *)fsname; 814307058Smav if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) 815307058Smav != NULL) { 816209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 817209962Smm free(ret->mtn_mt.mnt_special); 818209962Smm free(ret->mtn_mt.mnt_mountp); 819209962Smm free(ret->mtn_mt.mnt_fstype); 820209962Smm free(ret->mtn_mt.mnt_mntopts); 821209962Smm free(ret); 822209962Smm } 823209962Smm} 824209962Smm 825209962Smmint 826185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 827168404Spjd{ 828185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 829168404Spjd 830185029Spjd if (zpool_handle == NULL) 831168404Spjd return (-1); 832168404Spjd 833185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 834185029Spjd ZPOOL_PROP_VERSION, NULL); 835168404Spjd return (0); 836168404Spjd} 837168404Spjd 838168404Spjd/* 839185029Spjd * The choice of reservation property depends on the SPA version. 840168404Spjd */ 841168404Spjdstatic int 842185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 843168404Spjd{ 844185029Spjd int spa_version; 845168404Spjd 846185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 847168404Spjd return (-1); 848168404Spjd 849185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 850185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 851185029Spjd else 852185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 853168404Spjd 854168404Spjd return (0); 855168404Spjd} 856168404Spjd 857168404Spjd/* 858168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 859168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 860168404Spjd * strings. 861168404Spjd */ 862168404Spjdnvlist_t * 863185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 864290760Smav uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl, 865290760Smav const char *errbuf) 866168404Spjd{ 867168404Spjd nvpair_t *elem; 868168404Spjd uint64_t intval; 869168404Spjd char *strval; 870185029Spjd zfs_prop_t prop; 871168404Spjd nvlist_t *ret; 872185029Spjd int chosen_normal = -1; 873185029Spjd int chosen_utf = -1; 874168404Spjd 875168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 876168404Spjd (void) no_memory(hdl); 877168404Spjd return (NULL); 878168404Spjd } 879168404Spjd 880209962Smm /* 881209962Smm * Make sure this property is valid and applies to this type. 882209962Smm */ 883209962Smm 884168404Spjd elem = NULL; 885168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 886185029Spjd const char *propname = nvpair_name(elem); 887168404Spjd 888209962Smm prop = zfs_name_to_prop(propname); 889209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 890185029Spjd /* 891209962Smm * This is a user property: make sure it's a 892185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 893185029Spjd */ 894185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 895185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 896185029Spjd "'%s' must be a string"), propname); 897185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 898185029Spjd goto error; 899168404Spjd } 900168404Spjd 901185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 902185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 903185029Spjd "property name '%s' is too long"), 904185029Spjd propname); 905185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 906185029Spjd goto error; 907185029Spjd } 908185029Spjd 909168404Spjd (void) nvpair_value_string(elem, &strval); 910168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 911168404Spjd (void) no_memory(hdl); 912168404Spjd goto error; 913168404Spjd } 914168404Spjd continue; 915168404Spjd } 916168404Spjd 917209962Smm /* 918209962Smm * Currently, only user properties can be modified on 919209962Smm * snapshots. 920209962Smm */ 921185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 922185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 923185029Spjd "this property can not be modified for snapshots")); 924185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 925185029Spjd goto error; 926185029Spjd } 927168404Spjd 928209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 929209962Smm zfs_userquota_prop_t uqtype; 930209962Smm char newpropname[128]; 931209962Smm char domain[128]; 932209962Smm uint64_t rid; 933209962Smm uint64_t valary[3]; 934209962Smm 935209962Smm if (userquota_propname_decode(propname, zoned, 936209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 937209962Smm zfs_error_aux(hdl, 938209962Smm dgettext(TEXT_DOMAIN, 939209962Smm "'%s' has an invalid user/group name"), 940209962Smm propname); 941209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 942209962Smm goto error; 943209962Smm } 944209962Smm 945209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 946209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 947209962Smm zfs_error_aux(hdl, 948209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 949209962Smm propname); 950209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 951209962Smm errbuf); 952209962Smm goto error; 953209962Smm } 954209962Smm 955209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 956209962Smm (void) nvpair_value_string(elem, &strval); 957209962Smm if (strcmp(strval, "none") == 0) { 958209962Smm intval = 0; 959209962Smm } else if (zfs_nicestrtonum(hdl, 960209962Smm strval, &intval) != 0) { 961209962Smm (void) zfs_error(hdl, 962209962Smm EZFS_BADPROP, errbuf); 963209962Smm goto error; 964209962Smm } 965209962Smm } else if (nvpair_type(elem) == 966209962Smm DATA_TYPE_UINT64) { 967209962Smm (void) nvpair_value_uint64(elem, &intval); 968209962Smm if (intval == 0) { 969209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 970209962Smm "use 'none' to disable " 971209962Smm "userquota/groupquota")); 972209962Smm goto error; 973209962Smm } 974209962Smm } else { 975209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 976209962Smm "'%s' must be a number"), propname); 977209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 978209962Smm goto error; 979209962Smm } 980209962Smm 981219089Spjd /* 982219089Spjd * Encode the prop name as 983219089Spjd * userquota@<hex-rid>-domain, to make it easy 984219089Spjd * for the kernel to decode. 985219089Spjd */ 986209962Smm (void) snprintf(newpropname, sizeof (newpropname), 987219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 988219089Spjd (longlong_t)rid, domain); 989209962Smm valary[0] = uqtype; 990209962Smm valary[1] = rid; 991209962Smm valary[2] = intval; 992209962Smm if (nvlist_add_uint64_array(ret, newpropname, 993209962Smm valary, 3) != 0) { 994209962Smm (void) no_memory(hdl); 995209962Smm goto error; 996209962Smm } 997209962Smm continue; 998228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 999228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1000228103Smm "'%s' is readonly"), 1001228103Smm propname); 1002228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1003228103Smm goto error; 1004209962Smm } 1005209962Smm 1006209962Smm if (prop == ZPROP_INVAL) { 1007209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1008209962Smm "invalid property '%s'"), propname); 1009209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1010209962Smm goto error; 1011209962Smm } 1012209962Smm 1013168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 1014168404Spjd zfs_error_aux(hdl, 1015168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 1016168404Spjd "apply to datasets of this type"), propname); 1017168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1018168404Spjd goto error; 1019168404Spjd } 1020168404Spjd 1021168404Spjd if (zfs_prop_readonly(prop) && 1022185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 1023168404Spjd zfs_error_aux(hdl, 1024168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1025168404Spjd propname); 1026168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1027168404Spjd goto error; 1028168404Spjd } 1029168404Spjd 1030185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 1031185029Spjd &strval, &intval, errbuf) != 0) 1032185029Spjd goto error; 1033185029Spjd 1034168404Spjd /* 1035185029Spjd * Perform some additional checks for specific properties. 1036168404Spjd */ 1037185029Spjd switch (prop) { 1038185029Spjd case ZFS_PROP_VERSION: 1039185029Spjd { 1040185029Spjd int version; 1041168404Spjd 1042185029Spjd if (zhp == NULL) 1043185029Spjd break; 1044185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1045185029Spjd if (intval < version) { 1046168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1047185029Spjd "Can not downgrade; already at version %u"), 1048185029Spjd version); 1049168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1050168404Spjd goto error; 1051168404Spjd } 1052168404Spjd break; 1053168404Spjd } 1054168404Spjd 1055276081Sdelphij case ZFS_PROP_VOLBLOCKSIZE: 1056168404Spjd case ZFS_PROP_RECORDSIZE: 1057276081Sdelphij { 1058276081Sdelphij int maxbs = SPA_MAXBLOCKSIZE; 1059290760Smav if (zpool_hdl != NULL) { 1060290760Smav maxbs = zpool_get_prop_int(zpool_hdl, 1061276081Sdelphij ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1062276081Sdelphij } 1063276081Sdelphij /* 1064276081Sdelphij * Volumes are limited to a volblocksize of 128KB, 1065276081Sdelphij * because they typically service workloads with 1066276081Sdelphij * small random writes, which incur a large performance 1067276081Sdelphij * penalty with large blocks. 1068276081Sdelphij */ 1069276081Sdelphij if (prop == ZFS_PROP_VOLBLOCKSIZE) 1070276081Sdelphij maxbs = SPA_OLD_MAXBLOCKSIZE; 1071276081Sdelphij /* 1072276081Sdelphij * The value must be a power of two between 1073276081Sdelphij * SPA_MINBLOCKSIZE and maxbs. 1074276081Sdelphij */ 1075168404Spjd if (intval < SPA_MINBLOCKSIZE || 1076276081Sdelphij intval > maxbs || !ISP2(intval)) { 1077168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1078276081Sdelphij "'%s' must be power of 2 from 512B " 1079276081Sdelphij "to %uKB"), propname, maxbs >> 10); 1080168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1081168404Spjd goto error; 1082168404Spjd } 1083168404Spjd break; 1084276081Sdelphij } 1085219089Spjd case ZFS_PROP_MLSLABEL: 1086219089Spjd { 1087297077Smav#ifdef illumos 1088219089Spjd /* 1089219089Spjd * Verify the mlslabel string and convert to 1090219089Spjd * internal hex label string. 1091219089Spjd */ 1092219089Spjd 1093219089Spjd m_label_t *new_sl; 1094219089Spjd char *hex = NULL; /* internal label string */ 1095219089Spjd 1096219089Spjd /* Default value is already OK. */ 1097219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1098219089Spjd break; 1099219089Spjd 1100219089Spjd /* Verify the label can be converted to binary form */ 1101219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1102219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1103219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1104219089Spjd goto badlabel; 1105168404Spjd } 1106168404Spjd 1107219089Spjd /* Now translate to hex internal label string */ 1108219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1109219089Spjd DEF_NAMES) != 0) { 1110219089Spjd if (hex) 1111219089Spjd free(hex); 1112219089Spjd goto badlabel; 1113219089Spjd } 1114219089Spjd m_label_free(new_sl); 1115219089Spjd 1116219089Spjd /* If string is already in internal form, we're done. */ 1117219089Spjd if (strcmp(strval, hex) == 0) { 1118219089Spjd free(hex); 1119219089Spjd break; 1120219089Spjd } 1121219089Spjd 1122219089Spjd /* Replace the label string with the internal form. */ 1123219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1124219089Spjd DATA_TYPE_STRING); 1125219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1126219089Spjd hex) == 0); 1127219089Spjd free(hex); 1128219089Spjd 1129168404Spjd break; 1130168404Spjd 1131219089Spjdbadlabel: 1132219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1133219089Spjd "invalid mlslabel '%s'"), strval); 1134219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1135219089Spjd m_label_free(new_sl); /* OK if null */ 1136297077Smav#else /* !illumos */ 1137219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1138219089Spjd "mlslabel is not supported on FreeBSD")); 1139219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1140297077Smav#endif /* illumos */ 1141219089Spjd goto error; 1142219089Spjd 1143219089Spjd } 1144219089Spjd 1145168404Spjd case ZFS_PROP_MOUNTPOINT: 1146185029Spjd { 1147185029Spjd namecheck_err_t why; 1148185029Spjd 1149168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1150168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1151168404Spjd break; 1152168404Spjd 1153185029Spjd if (mountpoint_namecheck(strval, &why)) { 1154185029Spjd switch (why) { 1155185029Spjd case NAME_ERR_LEADING_SLASH: 1156185029Spjd zfs_error_aux(hdl, 1157185029Spjd dgettext(TEXT_DOMAIN, 1158185029Spjd "'%s' must be an absolute path, " 1159185029Spjd "'none', or 'legacy'"), propname); 1160185029Spjd break; 1161185029Spjd case NAME_ERR_TOOLONG: 1162185029Spjd zfs_error_aux(hdl, 1163185029Spjd dgettext(TEXT_DOMAIN, 1164185029Spjd "component of '%s' is too long"), 1165185029Spjd propname); 1166185029Spjd break; 1167307058Smav 1168307058Smav default: 1169307058Smav zfs_error_aux(hdl, 1170307058Smav dgettext(TEXT_DOMAIN, 1171307058Smav "(%d) not defined"), 1172307058Smav why); 1173307058Smav break; 1174185029Spjd } 1175168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1176168404Spjd goto error; 1177168404Spjd } 1178185029Spjd } 1179185029Spjd 1180168404Spjd /*FALLTHRU*/ 1181168404Spjd 1182185029Spjd case ZFS_PROP_SHARESMB: 1183168404Spjd case ZFS_PROP_SHARENFS: 1184168404Spjd /* 1185185029Spjd * For the mountpoint and sharenfs or sharesmb 1186185029Spjd * properties, check if it can be set in a 1187185029Spjd * global/non-global zone based on 1188168404Spjd * the zoned property value: 1189168404Spjd * 1190168404Spjd * global zone non-global zone 1191168404Spjd * -------------------------------------------------- 1192168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1193168404Spjd * sharenfs (no) sharenfs (no) 1194185029Spjd * sharesmb (no) sharesmb (no) 1195168404Spjd * 1196168404Spjd * zoned=off mountpoint (yes) N/A 1197168404Spjd * sharenfs (yes) 1198185029Spjd * sharesmb (yes) 1199168404Spjd */ 1200168404Spjd if (zoned) { 1201168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1202168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1203168404Spjd "'%s' cannot be set on " 1204168404Spjd "dataset in a non-global zone"), 1205168404Spjd propname); 1206168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1207168404Spjd errbuf); 1208168404Spjd goto error; 1209185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1210185029Spjd prop == ZFS_PROP_SHARESMB) { 1211168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1212168404Spjd "'%s' cannot be set in " 1213168404Spjd "a non-global zone"), propname); 1214168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1215168404Spjd errbuf); 1216168404Spjd goto error; 1217168404Spjd } 1218168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1219168404Spjd /* 1220168404Spjd * If zoned property is 'off', this must be in 1221209962Smm * a global zone. If not, something is wrong. 1222168404Spjd */ 1223168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1224168404Spjd "'%s' cannot be set while dataset " 1225168404Spjd "'zoned' property is set"), propname); 1226168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1227168404Spjd goto error; 1228168404Spjd } 1229168404Spjd 1230168404Spjd /* 1231185029Spjd * At this point, it is legitimate to set the 1232185029Spjd * property. Now we want to make sure that the 1233185029Spjd * property value is valid if it is sharenfs. 1234168404Spjd */ 1235185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1236185029Spjd prop == ZFS_PROP_SHARESMB) && 1237185029Spjd strcmp(strval, "on") != 0 && 1238185029Spjd strcmp(strval, "off") != 0) { 1239185029Spjd zfs_share_proto_t proto; 1240168404Spjd 1241185029Spjd if (prop == ZFS_PROP_SHARESMB) 1242185029Spjd proto = PROTO_SMB; 1243185029Spjd else 1244185029Spjd proto = PROTO_NFS; 1245185029Spjd 1246185029Spjd /* 1247185029Spjd * Must be an valid sharing protocol 1248185029Spjd * option string so init the libshare 1249185029Spjd * in order to enable the parser and 1250185029Spjd * then parse the options. We use the 1251185029Spjd * control API since we don't care about 1252185029Spjd * the current configuration and don't 1253185029Spjd * want the overhead of loading it 1254185029Spjd * until we actually do something. 1255185029Spjd */ 1256185029Spjd 1257185029Spjd if (zfs_init_libshare(hdl, 1258185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1259185029Spjd /* 1260185029Spjd * An error occurred so we can't do 1261185029Spjd * anything 1262185029Spjd */ 1263185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1264185029Spjd "'%s' cannot be set: problem " 1265185029Spjd "in share initialization"), 1266185029Spjd propname); 1267185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1268185029Spjd errbuf); 1269185029Spjd goto error; 1270185029Spjd } 1271185029Spjd 1272185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1273185029Spjd /* 1274185029Spjd * There was an error in parsing so 1275185029Spjd * deal with it by issuing an error 1276185029Spjd * message and leaving after 1277185029Spjd * uninitializing the the libshare 1278185029Spjd * interface. 1279185029Spjd */ 1280185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1281185029Spjd "'%s' cannot be set to invalid " 1282185029Spjd "options"), propname); 1283185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1284185029Spjd errbuf); 1285185029Spjd zfs_uninit_libshare(hdl); 1286185029Spjd goto error; 1287185029Spjd } 1288185029Spjd zfs_uninit_libshare(hdl); 1289168404Spjd } 1290185029Spjd 1291168404Spjd break; 1292307058Smav 1293185029Spjd case ZFS_PROP_UTF8ONLY: 1294185029Spjd chosen_utf = (int)intval; 1295185029Spjd break; 1296307058Smav 1297185029Spjd case ZFS_PROP_NORMALIZE: 1298185029Spjd chosen_normal = (int)intval; 1299185029Spjd break; 1300307058Smav 1301307058Smav default: 1302307058Smav break; 1303168404Spjd } 1304168404Spjd 1305168404Spjd /* 1306168404Spjd * For changes to existing volumes, we have some additional 1307168404Spjd * checks to enforce. 1308168404Spjd */ 1309168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1310168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1311168404Spjd ZFS_PROP_VOLSIZE); 1312168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1313168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1314168404Spjd char buf[64]; 1315168404Spjd 1316168404Spjd switch (prop) { 1317168404Spjd case ZFS_PROP_RESERVATION: 1318185029Spjd case ZFS_PROP_REFRESERVATION: 1319168404Spjd if (intval > volsize) { 1320168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1321168404Spjd "'%s' is greater than current " 1322168404Spjd "volume size"), propname); 1323168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1324168404Spjd errbuf); 1325168404Spjd goto error; 1326168404Spjd } 1327168404Spjd break; 1328168404Spjd 1329168404Spjd case ZFS_PROP_VOLSIZE: 1330168404Spjd if (intval % blocksize != 0) { 1331168404Spjd zfs_nicenum(blocksize, buf, 1332168404Spjd sizeof (buf)); 1333168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1334168404Spjd "'%s' must be a multiple of " 1335168404Spjd "volume block size (%s)"), 1336168404Spjd propname, buf); 1337168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1338168404Spjd errbuf); 1339168404Spjd goto error; 1340168404Spjd } 1341168404Spjd 1342168404Spjd if (intval == 0) { 1343168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1344168404Spjd "'%s' cannot be zero"), 1345168404Spjd propname); 1346168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1347168404Spjd errbuf); 1348168404Spjd goto error; 1349168404Spjd } 1350168404Spjd break; 1351307058Smav 1352307058Smav default: 1353307058Smav break; 1354168404Spjd } 1355168404Spjd } 1356168404Spjd } 1357168404Spjd 1358168404Spjd /* 1359185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1360185029Spjd * enforce rejection of non-UTF8 names. 1361185029Spjd * 1362185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1363185029Spjd * was explicitly not chosen, it is an error. 1364185029Spjd */ 1365185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1366185029Spjd if (nvlist_add_uint64(ret, 1367185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1368185029Spjd (void) no_memory(hdl); 1369185029Spjd goto error; 1370185029Spjd } 1371185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1372185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1373185029Spjd "'%s' must be set 'on' if normalization chosen"), 1374185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1375185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1376185029Spjd goto error; 1377185029Spjd } 1378219089Spjd return (ret); 1379185029Spjd 1380219089Spjderror: 1381219089Spjd nvlist_free(ret); 1382219089Spjd return (NULL); 1383219089Spjd} 1384219089Spjd 1385219089Spjdint 1386219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1387219089Spjd{ 1388219089Spjd uint64_t old_volsize; 1389219089Spjd uint64_t new_volsize; 1390219089Spjd uint64_t old_reservation; 1391219089Spjd uint64_t new_reservation; 1392219089Spjd zfs_prop_t resv_prop; 1393290759Smav nvlist_t *props; 1394219089Spjd 1395185029Spjd /* 1396168404Spjd * If this is an existing volume, and someone is setting the volsize, 1397168404Spjd * make sure that it matches the reservation, or add it if necessary. 1398168404Spjd */ 1399219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1400219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1401219089Spjd return (-1); 1402219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1403290759Smav 1404290759Smav props = fnvlist_alloc(); 1405290759Smav fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1406290759Smav zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1407290759Smav 1408290759Smav if ((zvol_volsize_to_reservation(old_volsize, props) != 1409290759Smav old_reservation) || nvlist_exists(nvl, 1410290759Smav zfs_prop_to_name(resv_prop))) { 1411290759Smav fnvlist_free(props); 1412219089Spjd return (0); 1413219089Spjd } 1414219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1415290759Smav &new_volsize) != 0) { 1416290759Smav fnvlist_free(props); 1417219089Spjd return (-1); 1418290759Smav } 1419290759Smav new_reservation = zvol_volsize_to_reservation(new_volsize, props); 1420290759Smav fnvlist_free(props); 1421290759Smav 1422219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1423219089Spjd new_reservation) != 0) { 1424219089Spjd (void) no_memory(zhp->zfs_hdl); 1425219089Spjd return (-1); 1426219089Spjd } 1427219089Spjd return (1); 1428219089Spjd} 1429168404Spjd 1430219089Spjdvoid 1431219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1432219089Spjd char *errbuf) 1433219089Spjd{ 1434219089Spjd switch (err) { 1435185029Spjd 1436219089Spjd case ENOSPC: 1437219089Spjd /* 1438219089Spjd * For quotas and reservations, ENOSPC indicates 1439219089Spjd * something different; setting a quota or reservation 1440219089Spjd * doesn't use any disk space. 1441219089Spjd */ 1442219089Spjd switch (prop) { 1443219089Spjd case ZFS_PROP_QUOTA: 1444219089Spjd case ZFS_PROP_REFQUOTA: 1445219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1446219089Spjd "size is less than current used or " 1447219089Spjd "reserved space")); 1448219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1449219089Spjd break; 1450219089Spjd 1451219089Spjd case ZFS_PROP_RESERVATION: 1452219089Spjd case ZFS_PROP_REFRESERVATION: 1453219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1454219089Spjd "size is greater than available space")); 1455219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1456219089Spjd break; 1457219089Spjd 1458219089Spjd default: 1459219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1460219089Spjd break; 1461168404Spjd } 1462219089Spjd break; 1463219089Spjd 1464219089Spjd case EBUSY: 1465219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1466219089Spjd break; 1467219089Spjd 1468219089Spjd case EROFS: 1469219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1470219089Spjd break; 1471219089Spjd 1472219089Spjd case ENOTSUP: 1473219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1474219089Spjd "pool and or dataset must be upgraded to set this " 1475219089Spjd "property or value")); 1476219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1477219089Spjd break; 1478219089Spjd 1479219089Spjd case ERANGE: 1480276081Sdelphij case EDOM: 1481276081Sdelphij if (prop == ZFS_PROP_COMPRESSION || 1482276081Sdelphij prop == ZFS_PROP_RECORDSIZE) { 1483219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1484219089Spjd "property setting is not allowed on " 1485219089Spjd "bootable datasets")); 1486219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1487290757Smav } else if (prop == ZFS_PROP_CHECKSUM || 1488290757Smav prop == ZFS_PROP_DEDUP) { 1489290757Smav (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1490290757Smav "property setting is not allowed on " 1491290757Smav "root pools")); 1492290757Smav (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1493219089Spjd } else { 1494219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1495219089Spjd } 1496219089Spjd break; 1497219089Spjd 1498219089Spjd case EINVAL: 1499219089Spjd if (prop == ZPROP_INVAL) { 1500219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1501219089Spjd } else { 1502219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1503219089Spjd } 1504219089Spjd break; 1505219089Spjd 1506219089Spjd case EOVERFLOW: 1507219089Spjd /* 1508219089Spjd * This platform can't address a volume this big. 1509219089Spjd */ 1510219089Spjd#ifdef _ILP32 1511219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1512219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1513219089Spjd break; 1514219089Spjd } 1515219089Spjd#endif 1516219089Spjd /* FALLTHROUGH */ 1517219089Spjd default: 1518219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1519168404Spjd } 1520168404Spjd} 1521168404Spjd 1522168404Spjd/* 1523168404Spjd * Given a property name and value, set the property for the given dataset. 1524168404Spjd */ 1525168404Spjdint 1526168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1527168404Spjd{ 1528168404Spjd int ret = -1; 1529168404Spjd char errbuf[1024]; 1530168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1531290758Smav nvlist_t *nvl = NULL; 1532168404Spjd 1533168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1534168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1535168404Spjd zhp->zfs_name); 1536168404Spjd 1537168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1538168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1539168404Spjd (void) no_memory(hdl); 1540168404Spjd goto error; 1541168404Spjd } 1542168404Spjd 1543290758Smav ret = zfs_prop_set_list(zhp, nvl); 1544185029Spjd 1545290758Smaverror: 1546168404Spjd nvlist_free(nvl); 1547290758Smav return (ret); 1548290758Smav} 1549168404Spjd 1550168404Spjd 1551168404Spjd 1552290758Smav/* 1553290758Smav * Given an nvlist of property names and values, set the properties for the 1554290758Smav * given dataset. 1555290758Smav */ 1556290758Smavint 1557290758Smavzfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) 1558290758Smav{ 1559290758Smav zfs_cmd_t zc = { 0 }; 1560290758Smav int ret = -1; 1561290758Smav prop_changelist_t **cls = NULL; 1562290758Smav int cl_idx; 1563290758Smav char errbuf[1024]; 1564290758Smav libzfs_handle_t *hdl = zhp->zfs_hdl; 1565290758Smav nvlist_t *nvl; 1566290758Smav int nvl_len; 1567307121Smav int added_resv = 0; 1568219089Spjd 1569290758Smav (void) snprintf(errbuf, sizeof (errbuf), 1570290758Smav dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1571290758Smav zhp->zfs_name); 1572168404Spjd 1573290758Smav if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, 1574290760Smav zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl, 1575290760Smav errbuf)) == NULL) 1576168404Spjd goto error; 1577168404Spjd 1578185029Spjd /* 1579290758Smav * We have to check for any extra properties which need to be added 1580290758Smav * before computing the length of the nvlist. 1581185029Spjd */ 1582290758Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1583290758Smav elem != NULL; 1584290758Smav elem = nvlist_next_nvpair(nvl, elem)) { 1585290758Smav if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && 1586290758Smav (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { 1587290758Smav goto error; 1588290758Smav } 1589238391Smm } 1590290758Smav /* 1591290758Smav * Check how many properties we're setting and allocate an array to 1592290758Smav * store changelist pointers for postfix(). 1593290758Smav */ 1594290758Smav nvl_len = 0; 1595290758Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1596290758Smav elem != NULL; 1597290758Smav elem = nvlist_next_nvpair(nvl, elem)) 1598290758Smav nvl_len++; 1599290758Smav if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) 1600168404Spjd goto error; 1601168404Spjd 1602290758Smav cl_idx = 0; 1603290758Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1604290758Smav elem != NULL; 1605290758Smav elem = nvlist_next_nvpair(nvl, elem)) { 1606290758Smav 1607290758Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1608290758Smav 1609290758Smav assert(cl_idx < nvl_len); 1610290758Smav /* 1611290758Smav * We don't want to unmount & remount the dataset when changing 1612310069Savg * its canmount property to 'on' or 'noauto'. We only use 1613310069Savg * the changelist logic to unmount when setting canmount=off. 1614290758Smav */ 1615298266Savg if (prop != ZFS_PROP_CANMOUNT || 1616298266Savg (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF && 1617310069Savg zfs_is_mounted(zhp, NULL))) { 1618290758Smav cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); 1619290758Smav if (cls[cl_idx] == NULL) 1620290758Smav goto error; 1621290758Smav } 1622290758Smav 1623290758Smav if (prop == ZFS_PROP_MOUNTPOINT && 1624290758Smav changelist_haszonedchild(cls[cl_idx])) { 1625290758Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1626290758Smav "child dataset with inherited mountpoint is used " 1627290758Smav "in a non-global zone")); 1628290758Smav ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1629290758Smav goto error; 1630290758Smav } 1631290758Smav 1632290758Smav /* We don't support those properties on FreeBSD. */ 1633290758Smav switch (prop) { 1634290758Smav case ZFS_PROP_DEVICES: 1635290758Smav case ZFS_PROP_ISCSIOPTIONS: 1636290758Smav case ZFS_PROP_XATTR: 1637290758Smav case ZFS_PROP_VSCAN: 1638290758Smav case ZFS_PROP_NBMAND: 1639290758Smav case ZFS_PROP_MLSLABEL: 1640290758Smav (void) snprintf(errbuf, sizeof (errbuf), 1641290758Smav "property '%s' not supported on FreeBSD", 1642290758Smav nvpair_name(elem)); 1643290758Smav ret = zfs_error(hdl, EZFS_PERM, errbuf); 1644290758Smav goto error; 1645290758Smav } 1646290758Smav 1647290758Smav if (cls[cl_idx] != NULL && 1648290758Smav (ret = changelist_prefix(cls[cl_idx])) != 0) 1649290758Smav goto error; 1650290758Smav 1651290758Smav cl_idx++; 1652290758Smav } 1653290758Smav assert(cl_idx == nvl_len); 1654290758Smav 1655168404Spjd /* 1656290758Smav * Execute the corresponding ioctl() to set this list of properties. 1657168404Spjd */ 1658168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1659168404Spjd 1660290758Smav if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 || 1661290758Smav (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0) 1662168404Spjd goto error; 1663168404Spjd 1664185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1665209962Smm 1666168404Spjd if (ret != 0) { 1667290758Smav /* Get the list of unset properties back and report them. */ 1668290758Smav nvlist_t *errorprops = NULL; 1669290758Smav if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) 1670290758Smav goto error; 1671290758Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1672290758Smav elem != NULL; 1673290758Smav elem = nvlist_next_nvpair(nvl, elem)) { 1674290758Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1675290758Smav zfs_setprop_error(hdl, prop, errno, errbuf); 1676290758Smav } 1677290758Smav nvlist_free(errorprops); 1678290758Smav 1679219089Spjd if (added_resv && errno == ENOSPC) { 1680219089Spjd /* clean up the volsize property we tried to set */ 1681219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1682219089Spjd ZFS_PROP_VOLSIZE); 1683219089Spjd nvlist_free(nvl); 1684290758Smav nvl = NULL; 1685219089Spjd zcmd_free_nvlists(&zc); 1686290758Smav 1687219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1688219089Spjd goto error; 1689219089Spjd if (nvlist_add_uint64(nvl, 1690219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1691219089Spjd old_volsize) != 0) 1692219089Spjd goto error; 1693219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1694219089Spjd goto error; 1695219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1696168404Spjd } 1697168404Spjd } else { 1698290758Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1699290758Smav if (cls[cl_idx] != NULL) { 1700290758Smav int clp_err = changelist_postfix(cls[cl_idx]); 1701290758Smav if (clp_err != 0) 1702290758Smav ret = clp_err; 1703290758Smav } 1704290758Smav } 1705185029Spjd 1706168404Spjd /* 1707168404Spjd * Refresh the statistics so the new property value 1708168404Spjd * is reflected. 1709168404Spjd */ 1710185029Spjd if (ret == 0) 1711168404Spjd (void) get_stats(zhp); 1712168404Spjd } 1713168404Spjd 1714168404Spjderror: 1715168404Spjd nvlist_free(nvl); 1716168404Spjd zcmd_free_nvlists(&zc); 1717290758Smav if (cls != NULL) { 1718290758Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1719290758Smav if (cls[cl_idx] != NULL) 1720290758Smav changelist_free(cls[cl_idx]); 1721290758Smav } 1722290758Smav free(cls); 1723290758Smav } 1724168404Spjd return (ret); 1725168404Spjd} 1726168404Spjd 1727168404Spjd/* 1728219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1729219089Spjd * is TRUE, revert to the received value, if any. 1730168404Spjd */ 1731168404Spjdint 1732219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1733168404Spjd{ 1734168404Spjd zfs_cmd_t zc = { 0 }; 1735168404Spjd int ret; 1736168404Spjd prop_changelist_t *cl; 1737168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1738168404Spjd char errbuf[1024]; 1739168404Spjd zfs_prop_t prop; 1740168404Spjd 1741168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1742168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1743168404Spjd 1744219089Spjd zc.zc_cookie = received; 1745185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1746168404Spjd /* 1747168404Spjd * For user properties, the amount of work we have to do is very 1748168404Spjd * small, so just do it here. 1749168404Spjd */ 1750168404Spjd if (!zfs_prop_user(propname)) { 1751168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1752168404Spjd "invalid property")); 1753168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1754168404Spjd } 1755168404Spjd 1756168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1757168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1758168404Spjd 1759185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1760168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1761168404Spjd 1762168404Spjd return (0); 1763168404Spjd } 1764168404Spjd 1765168404Spjd /* 1766168404Spjd * Verify that this property is inheritable. 1767168404Spjd */ 1768168404Spjd if (zfs_prop_readonly(prop)) 1769168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1770168404Spjd 1771219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1772168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1773168404Spjd 1774168404Spjd /* 1775168404Spjd * Check to see if the value applies to this type 1776168404Spjd */ 1777168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1778168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1779168404Spjd 1780168404Spjd /* 1781219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1782168404Spjd */ 1783168404Spjd propname = zfs_prop_to_name(prop); 1784168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1785168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1786168404Spjd 1787168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1788168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1789168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1790168404Spjd "dataset is used in a non-global zone")); 1791168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1792168404Spjd } 1793168404Spjd 1794168404Spjd /* 1795168404Spjd * Determine datasets which will be affected by this change, if any. 1796168404Spjd */ 1797185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1798168404Spjd return (-1); 1799168404Spjd 1800168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1801168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1802168404Spjd "child dataset with inherited mountpoint is used " 1803168404Spjd "in a non-global zone")); 1804168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1805168404Spjd goto error; 1806168404Spjd } 1807168404Spjd 1808168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1809168404Spjd goto error; 1810168404Spjd 1811185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1812168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1813168404Spjd } else { 1814168404Spjd 1815168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1816168404Spjd goto error; 1817168404Spjd 1818168404Spjd /* 1819168404Spjd * Refresh the statistics so the new property is reflected. 1820168404Spjd */ 1821168404Spjd (void) get_stats(zhp); 1822168404Spjd } 1823168404Spjd 1824168404Spjderror: 1825168404Spjd changelist_free(cl); 1826168404Spjd return (ret); 1827168404Spjd} 1828168404Spjd 1829168404Spjd/* 1830168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1831168404Spjd * extract them appropriately. 1832168404Spjd */ 1833168404Spjdstatic uint64_t 1834168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1835168404Spjd{ 1836168404Spjd nvlist_t *nv; 1837168404Spjd uint64_t value; 1838168404Spjd 1839168404Spjd *source = NULL; 1840168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1841168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1842185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1843185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1844168404Spjd } else { 1845205198Sdelphij verify(!zhp->zfs_props_table || 1846205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1847168404Spjd value = zfs_prop_default_numeric(prop); 1848168404Spjd *source = ""; 1849168404Spjd } 1850168404Spjd 1851168404Spjd return (value); 1852168404Spjd} 1853168404Spjd 1854290756Smavstatic const char * 1855168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1856168404Spjd{ 1857168404Spjd nvlist_t *nv; 1858290756Smav const char *value; 1859168404Spjd 1860168404Spjd *source = NULL; 1861168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1862168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1863290756Smav value = fnvlist_lookup_string(nv, ZPROP_VALUE); 1864185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1865168404Spjd } else { 1866205198Sdelphij verify(!zhp->zfs_props_table || 1867205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1868290756Smav value = zfs_prop_default_string(prop); 1869168404Spjd *source = ""; 1870168404Spjd } 1871168404Spjd 1872168404Spjd return (value); 1873168404Spjd} 1874168404Spjd 1875219089Spjdstatic boolean_t 1876219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1877219089Spjd{ 1878219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1879219089Spjd} 1880219089Spjd 1881219089Spjdstatic void 1882219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1883219089Spjd{ 1884219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1885219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1886219089Spjd} 1887219089Spjd 1888219089Spjdstatic void 1889219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1890219089Spjd{ 1891219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1892219089Spjd *cookie = 0; 1893219089Spjd} 1894219089Spjd 1895168404Spjd/* 1896168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1897168404Spjd * zfs_prop_get_int() are built using this interface. 1898168404Spjd * 1899168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1900168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1901168404Spjd * If they differ from the on-disk values, report the current values and mark 1902168404Spjd * the source "temporary". 1903168404Spjd */ 1904168404Spjdstatic int 1905185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1906168404Spjd char **source, uint64_t *val) 1907168404Spjd{ 1908185029Spjd zfs_cmd_t zc = { 0 }; 1909185029Spjd nvlist_t *zplprops = NULL; 1910168404Spjd struct mnttab mnt; 1911168404Spjd char *mntopt_on = NULL; 1912168404Spjd char *mntopt_off = NULL; 1913219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1914168404Spjd 1915168404Spjd *source = NULL; 1916168404Spjd 1917168404Spjd switch (prop) { 1918168404Spjd case ZFS_PROP_ATIME: 1919168404Spjd mntopt_on = MNTOPT_ATIME; 1920168404Spjd mntopt_off = MNTOPT_NOATIME; 1921168404Spjd break; 1922168404Spjd 1923168404Spjd case ZFS_PROP_DEVICES: 1924168404Spjd mntopt_on = MNTOPT_DEVICES; 1925168404Spjd mntopt_off = MNTOPT_NODEVICES; 1926168404Spjd break; 1927168404Spjd 1928168404Spjd case ZFS_PROP_EXEC: 1929168404Spjd mntopt_on = MNTOPT_EXEC; 1930168404Spjd mntopt_off = MNTOPT_NOEXEC; 1931168404Spjd break; 1932168404Spjd 1933168404Spjd case ZFS_PROP_READONLY: 1934168404Spjd mntopt_on = MNTOPT_RO; 1935168404Spjd mntopt_off = MNTOPT_RW; 1936168404Spjd break; 1937168404Spjd 1938168404Spjd case ZFS_PROP_SETUID: 1939168404Spjd mntopt_on = MNTOPT_SETUID; 1940168404Spjd mntopt_off = MNTOPT_NOSETUID; 1941168404Spjd break; 1942168404Spjd 1943168404Spjd case ZFS_PROP_XATTR: 1944168404Spjd mntopt_on = MNTOPT_XATTR; 1945168404Spjd mntopt_off = MNTOPT_NOXATTR; 1946168404Spjd break; 1947185029Spjd 1948185029Spjd case ZFS_PROP_NBMAND: 1949185029Spjd mntopt_on = MNTOPT_NBMAND; 1950185029Spjd mntopt_off = MNTOPT_NONBMAND; 1951185029Spjd break; 1952307058Smav 1953307058Smav default: 1954307058Smav break; 1955168404Spjd } 1956168404Spjd 1957168404Spjd /* 1958168404Spjd * Because looking up the mount options is potentially expensive 1959168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1960168404Spjd * we're looking up a property which requires its presence. 1961168404Spjd */ 1962168404Spjd if (!zhp->zfs_mntcheck && 1963168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1964209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1965209962Smm struct mnttab entry; 1966168404Spjd 1967209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1968209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1969168404Spjd entry.mnt_mntopts); 1970168404Spjd if (zhp->zfs_mntopts == NULL) 1971168404Spjd return (-1); 1972168404Spjd } 1973168404Spjd 1974168404Spjd zhp->zfs_mntcheck = B_TRUE; 1975168404Spjd } 1976168404Spjd 1977168404Spjd if (zhp->zfs_mntopts == NULL) 1978168404Spjd mnt.mnt_mntopts = ""; 1979168404Spjd else 1980168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1981168404Spjd 1982168404Spjd switch (prop) { 1983168404Spjd case ZFS_PROP_ATIME: 1984168404Spjd case ZFS_PROP_DEVICES: 1985168404Spjd case ZFS_PROP_EXEC: 1986168404Spjd case ZFS_PROP_READONLY: 1987168404Spjd case ZFS_PROP_SETUID: 1988168404Spjd case ZFS_PROP_XATTR: 1989185029Spjd case ZFS_PROP_NBMAND: 1990168404Spjd *val = getprop_uint64(zhp, prop, source); 1991168404Spjd 1992219089Spjd if (received) 1993219089Spjd break; 1994219089Spjd 1995168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1996168404Spjd *val = B_TRUE; 1997168404Spjd if (src) 1998185029Spjd *src = ZPROP_SRC_TEMPORARY; 1999168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2000168404Spjd *val = B_FALSE; 2001168404Spjd if (src) 2002185029Spjd *src = ZPROP_SRC_TEMPORARY; 2003168404Spjd } 2004168404Spjd break; 2005168404Spjd 2006168404Spjd case ZFS_PROP_CANMOUNT: 2007219089Spjd case ZFS_PROP_VOLSIZE: 2008168404Spjd case ZFS_PROP_QUOTA: 2009185029Spjd case ZFS_PROP_REFQUOTA: 2010168404Spjd case ZFS_PROP_RESERVATION: 2011185029Spjd case ZFS_PROP_REFRESERVATION: 2012265744Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2013265744Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2014265744Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2015265744Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2016168404Spjd *val = getprop_uint64(zhp, prop, source); 2017219089Spjd 2018219089Spjd if (*source == NULL) { 2019219089Spjd /* not default, must be local */ 2020168404Spjd *source = zhp->zfs_name; 2021219089Spjd } 2022168404Spjd break; 2023168404Spjd 2024168404Spjd case ZFS_PROP_MOUNTED: 2025168404Spjd *val = (zhp->zfs_mntopts != NULL); 2026168404Spjd break; 2027168404Spjd 2028168404Spjd case ZFS_PROP_NUMCLONES: 2029168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 2030168404Spjd break; 2031168404Spjd 2032185029Spjd case ZFS_PROP_VERSION: 2033185029Spjd case ZFS_PROP_NORMALIZE: 2034185029Spjd case ZFS_PROP_UTF8ONLY: 2035185029Spjd case ZFS_PROP_CASE: 2036185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 2037185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2038185029Spjd return (-1); 2039185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2040185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2041185029Spjd zcmd_free_nvlists(&zc); 2042219089Spjd return (-1); 2043185029Spjd } 2044185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2045185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2046185029Spjd val) != 0) { 2047185029Spjd zcmd_free_nvlists(&zc); 2048219089Spjd return (-1); 2049185029Spjd } 2050297115Smav nvlist_free(zplprops); 2051185029Spjd zcmd_free_nvlists(&zc); 2052185029Spjd break; 2053185029Spjd 2054253819Sdelphij case ZFS_PROP_INCONSISTENT: 2055253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 2056253819Sdelphij break; 2057253819Sdelphij 2058168404Spjd default: 2059185029Spjd switch (zfs_prop_get_type(prop)) { 2060185029Spjd case PROP_TYPE_NUMBER: 2061185029Spjd case PROP_TYPE_INDEX: 2062185029Spjd *val = getprop_uint64(zhp, prop, source); 2063185029Spjd /* 2064209962Smm * If we tried to use a default value for a 2065185029Spjd * readonly property, it means that it was not 2066219089Spjd * present. 2067185029Spjd */ 2068185029Spjd if (zfs_prop_readonly(prop) && 2069219089Spjd *source != NULL && (*source)[0] == '\0') { 2070219089Spjd *source = NULL; 2071325140Savg return (-1); 2072185029Spjd } 2073185029Spjd break; 2074185029Spjd 2075185029Spjd case PROP_TYPE_STRING: 2076185029Spjd default: 2077185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2078185029Spjd "cannot get non-numeric property")); 2079185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2080185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 2081185029Spjd } 2082168404Spjd } 2083168404Spjd 2084168404Spjd return (0); 2085168404Spjd} 2086168404Spjd 2087168404Spjd/* 2088168404Spjd * Calculate the source type, given the raw source string. 2089168404Spjd */ 2090168404Spjdstatic void 2091185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 2092168404Spjd char *statbuf, size_t statlen) 2093168404Spjd{ 2094185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 2095168404Spjd return; 2096168404Spjd 2097168404Spjd if (source == NULL) { 2098185029Spjd *srctype = ZPROP_SRC_NONE; 2099168404Spjd } else if (source[0] == '\0') { 2100185029Spjd *srctype = ZPROP_SRC_DEFAULT; 2101219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 2102219089Spjd *srctype = ZPROP_SRC_RECEIVED; 2103168404Spjd } else { 2104168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 2105185029Spjd *srctype = ZPROP_SRC_LOCAL; 2106168404Spjd } else { 2107168404Spjd (void) strlcpy(statbuf, source, statlen); 2108185029Spjd *srctype = ZPROP_SRC_INHERITED; 2109168404Spjd } 2110168404Spjd } 2111168404Spjd 2112168404Spjd} 2113168404Spjd 2114219089Spjdint 2115219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2116219089Spjd size_t proplen, boolean_t literal) 2117219089Spjd{ 2118219089Spjd zfs_prop_t prop; 2119219089Spjd int err = 0; 2120219089Spjd 2121219089Spjd if (zhp->zfs_recvd_props == NULL) 2122219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 2123219089Spjd return (-1); 2124219089Spjd 2125219089Spjd prop = zfs_name_to_prop(propname); 2126219089Spjd 2127219089Spjd if (prop != ZPROP_INVAL) { 2128219089Spjd uint64_t cookie; 2129219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2130219089Spjd return (-1); 2131219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 2132219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 2133219089Spjd NULL, NULL, 0, literal); 2134219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 2135219089Spjd } else { 2136219089Spjd nvlist_t *propval; 2137219089Spjd char *recvdval; 2138219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2139219089Spjd propname, &propval) != 0) 2140219089Spjd return (-1); 2141219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 2142219089Spjd &recvdval) == 0); 2143219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 2144219089Spjd } 2145219089Spjd 2146219089Spjd return (err == 0 ? 0 : -1); 2147219089Spjd} 2148219089Spjd 2149228103Smmstatic int 2150228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2151228103Smm{ 2152228103Smm nvlist_t *value; 2153228103Smm nvpair_t *pair; 2154228103Smm 2155228103Smm value = zfs_get_clones_nvl(zhp); 2156228103Smm if (value == NULL) 2157228103Smm return (-1); 2158228103Smm 2159228103Smm propbuf[0] = '\0'; 2160228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2161228103Smm pair = nvlist_next_nvpair(value, pair)) { 2162228103Smm if (propbuf[0] != '\0') 2163228103Smm (void) strlcat(propbuf, ",", proplen); 2164228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 2165228103Smm } 2166228103Smm 2167228103Smm return (0); 2168228103Smm} 2169228103Smm 2170228103Smmstruct get_clones_arg { 2171228103Smm uint64_t numclones; 2172228103Smm nvlist_t *value; 2173228103Smm const char *origin; 2174307122Smav char buf[ZFS_MAX_DATASET_NAME_LEN]; 2175228103Smm}; 2176228103Smm 2177228103Smmint 2178228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2179228103Smm{ 2180228103Smm struct get_clones_arg *gca = arg; 2181228103Smm 2182228103Smm if (gca->numclones == 0) { 2183228103Smm zfs_close(zhp); 2184228103Smm return (0); 2185228103Smm } 2186228103Smm 2187228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2188228103Smm NULL, NULL, 0, B_TRUE) != 0) 2189228103Smm goto out; 2190228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2191248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2192228103Smm gca->numclones--; 2193228103Smm } 2194228103Smm 2195228103Smmout: 2196228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2197228103Smm zfs_close(zhp); 2198228103Smm return (0); 2199228103Smm} 2200228103Smm 2201228103Smmnvlist_t * 2202228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2203228103Smm{ 2204228103Smm nvlist_t *nv, *value; 2205228103Smm 2206228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2207228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2208228103Smm struct get_clones_arg gca; 2209228103Smm 2210228103Smm /* 2211228103Smm * if this is a snapshot, then the kernel wasn't able 2212228103Smm * to get the clones. Do it by slowly iterating. 2213228103Smm */ 2214228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2215228103Smm return (NULL); 2216228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2217228103Smm return (NULL); 2218228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2219228103Smm nvlist_free(nv); 2220228103Smm return (NULL); 2221228103Smm } 2222228103Smm 2223228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2224228103Smm gca.value = value; 2225228103Smm gca.origin = zhp->zfs_name; 2226228103Smm 2227228103Smm if (gca.numclones != 0) { 2228228103Smm zfs_handle_t *root; 2229307122Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 2230228103Smm char *cp = pool; 2231228103Smm 2232228103Smm /* get the pool name */ 2233228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2234228103Smm (void) strsep(&cp, "/@"); 2235228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2236228103Smm ZFS_TYPE_FILESYSTEM); 2237228103Smm 2238228103Smm (void) get_clones_cb(root, &gca); 2239228103Smm } 2240228103Smm 2241228103Smm if (gca.numclones != 0 || 2242228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2243228103Smm nvlist_add_nvlist(zhp->zfs_props, 2244228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2245228103Smm nvlist_free(nv); 2246228103Smm nvlist_free(value); 2247228103Smm return (NULL); 2248228103Smm } 2249228103Smm nvlist_free(nv); 2250228103Smm nvlist_free(value); 2251228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2252228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2253228103Smm } 2254228103Smm 2255228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2256228103Smm 2257228103Smm return (value); 2258228103Smm} 2259228103Smm 2260168404Spjd/* 2261168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2262168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2263168404Spjd * human-readable form. 2264168404Spjd * 2265168404Spjd * Returns 0 on success, or -1 on error. 2266168404Spjd */ 2267168404Spjdint 2268168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2269185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2270168404Spjd{ 2271168404Spjd char *source = NULL; 2272168404Spjd uint64_t val; 2273290756Smav const char *str; 2274168404Spjd const char *strval; 2275219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2276168404Spjd 2277168404Spjd /* 2278168404Spjd * Check to see if this property applies to our object 2279168404Spjd */ 2280168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2281168404Spjd return (-1); 2282168404Spjd 2283219089Spjd if (received && zfs_prop_readonly(prop)) 2284219089Spjd return (-1); 2285219089Spjd 2286168404Spjd if (src) 2287185029Spjd *src = ZPROP_SRC_NONE; 2288168404Spjd 2289168404Spjd switch (prop) { 2290168404Spjd case ZFS_PROP_CREATION: 2291168404Spjd /* 2292168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2293168404Spjd * this into a string unless 'literal' is specified. 2294168404Spjd */ 2295168404Spjd { 2296168404Spjd val = getprop_uint64(zhp, prop, &source); 2297168404Spjd time_t time = (time_t)val; 2298168404Spjd struct tm t; 2299168404Spjd 2300168404Spjd if (literal || 2301168404Spjd localtime_r(&time, &t) == NULL || 2302168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2303168404Spjd &t) == 0) 2304168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2305168404Spjd } 2306168404Spjd break; 2307168404Spjd 2308168404Spjd case ZFS_PROP_MOUNTPOINT: 2309168404Spjd /* 2310168404Spjd * Getting the precise mountpoint can be tricky. 2311168404Spjd * 2312168404Spjd * - for 'none' or 'legacy', return those values. 2313168404Spjd * - for inherited mountpoints, we want to take everything 2314168404Spjd * after our ancestor and append it to the inherited value. 2315168404Spjd * 2316168404Spjd * If the pool has an alternate root, we want to prepend that 2317168404Spjd * root to any values we return. 2318168404Spjd */ 2319185029Spjd 2320168404Spjd str = getprop_string(zhp, prop, &source); 2321168404Spjd 2322185029Spjd if (str[0] == '/') { 2323185029Spjd char buf[MAXPATHLEN]; 2324185029Spjd char *root = buf; 2325219089Spjd const char *relpath; 2326168404Spjd 2327219089Spjd /* 2328219089Spjd * If we inherit the mountpoint, even from a dataset 2329219089Spjd * with a received value, the source will be the path of 2330219089Spjd * the dataset we inherit from. If source is 2331219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2332219089Spjd * inherited. 2333219089Spjd */ 2334219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2335219089Spjd relpath = ""; 2336219089Spjd } else { 2337219089Spjd relpath = zhp->zfs_name + strlen(source); 2338219089Spjd if (relpath[0] == '/') 2339219089Spjd relpath++; 2340219089Spjd } 2341185029Spjd 2342185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2343264335Sdelphij ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, 2344264335Sdelphij B_FALSE)) || (strcmp(root, "-") == 0)) 2345185029Spjd root[0] = '\0'; 2346185029Spjd /* 2347185029Spjd * Special case an alternate root of '/'. This will 2348185029Spjd * avoid having multiple leading slashes in the 2349185029Spjd * mountpoint path. 2350185029Spjd */ 2351185029Spjd if (strcmp(root, "/") == 0) 2352185029Spjd root++; 2353185029Spjd 2354185029Spjd /* 2355185029Spjd * If the mountpoint is '/' then skip over this 2356185029Spjd * if we are obtaining either an alternate root or 2357185029Spjd * an inherited mountpoint. 2358185029Spjd */ 2359185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2360185029Spjd relpath[0] != '\0')) 2361168404Spjd str++; 2362168404Spjd 2363168404Spjd if (relpath[0] == '\0') 2364168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2365168404Spjd root, str); 2366168404Spjd else 2367168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2368168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2369168404Spjd relpath); 2370168404Spjd } else { 2371168404Spjd /* 'legacy' or 'none' */ 2372168404Spjd (void) strlcpy(propbuf, str, proplen); 2373168404Spjd } 2374168404Spjd 2375168404Spjd break; 2376168404Spjd 2377168404Spjd case ZFS_PROP_ORIGIN: 2378290756Smav str = getprop_string(zhp, prop, &source); 2379290756Smav if (str == NULL) 2380168404Spjd return (-1); 2381290756Smav (void) strlcpy(propbuf, str, proplen); 2382168404Spjd break; 2383168404Spjd 2384228103Smm case ZFS_PROP_CLONES: 2385228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2386228103Smm return (-1); 2387228103Smm break; 2388228103Smm 2389168404Spjd case ZFS_PROP_QUOTA: 2390185029Spjd case ZFS_PROP_REFQUOTA: 2391168404Spjd case ZFS_PROP_RESERVATION: 2392185029Spjd case ZFS_PROP_REFRESERVATION: 2393185029Spjd 2394168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2395168404Spjd return (-1); 2396168404Spjd 2397168404Spjd /* 2398168404Spjd * If quota or reservation is 0, we translate this into 'none' 2399168404Spjd * (unless literal is set), and indicate that it's the default 2400168404Spjd * value. Otherwise, we print the number nicely and indicate 2401168404Spjd * that its set locally. 2402168404Spjd */ 2403168404Spjd if (val == 0) { 2404168404Spjd if (literal) 2405168404Spjd (void) strlcpy(propbuf, "0", proplen); 2406168404Spjd else 2407168404Spjd (void) strlcpy(propbuf, "none", proplen); 2408168404Spjd } else { 2409168404Spjd if (literal) 2410168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2411168404Spjd (u_longlong_t)val); 2412168404Spjd else 2413168404Spjd zfs_nicenum(val, propbuf, proplen); 2414168404Spjd } 2415168404Spjd break; 2416168404Spjd 2417265744Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2418265744Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2419265744Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2420265744Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2421265744Sdelphij 2422265744Sdelphij if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2423265744Sdelphij return (-1); 2424265744Sdelphij 2425265744Sdelphij /* 2426265744Sdelphij * If limit is UINT64_MAX, we translate this into 'none' (unless 2427265744Sdelphij * literal is set), and indicate that it's the default value. 2428265744Sdelphij * Otherwise, we print the number nicely and indicate that it's 2429265744Sdelphij * set locally. 2430265744Sdelphij */ 2431265744Sdelphij if (literal) { 2432265744Sdelphij (void) snprintf(propbuf, proplen, "%llu", 2433265744Sdelphij (u_longlong_t)val); 2434265744Sdelphij } else if (val == UINT64_MAX) { 2435265744Sdelphij (void) strlcpy(propbuf, "none", proplen); 2436265744Sdelphij } else { 2437265744Sdelphij zfs_nicenum(val, propbuf, proplen); 2438265744Sdelphij } 2439265744Sdelphij break; 2440265744Sdelphij 2441223623Smm case ZFS_PROP_REFRATIO: 2442168404Spjd case ZFS_PROP_COMPRESSRATIO: 2443168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2444168404Spjd return (-1); 2445219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2446219089Spjd (u_longlong_t)(val / 100), 2447219089Spjd (u_longlong_t)(val % 100)); 2448168404Spjd break; 2449168404Spjd 2450168404Spjd case ZFS_PROP_TYPE: 2451168404Spjd switch (zhp->zfs_type) { 2452168404Spjd case ZFS_TYPE_FILESYSTEM: 2453168404Spjd str = "filesystem"; 2454168404Spjd break; 2455168404Spjd case ZFS_TYPE_VOLUME: 2456168404Spjd str = "volume"; 2457168404Spjd break; 2458168404Spjd case ZFS_TYPE_SNAPSHOT: 2459168404Spjd str = "snapshot"; 2460168404Spjd break; 2461263407Sdelphij case ZFS_TYPE_BOOKMARK: 2462263407Sdelphij str = "bookmark"; 2463263407Sdelphij break; 2464168404Spjd default: 2465168404Spjd abort(); 2466168404Spjd } 2467168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2468168404Spjd break; 2469168404Spjd 2470168404Spjd case ZFS_PROP_MOUNTED: 2471168404Spjd /* 2472168404Spjd * The 'mounted' property is a pseudo-property that described 2473168404Spjd * whether the filesystem is currently mounted. Even though 2474168404Spjd * it's a boolean value, the typical values of "on" and "off" 2475168404Spjd * don't make sense, so we translate to "yes" and "no". 2476168404Spjd */ 2477168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2478168404Spjd src, &source, &val) != 0) 2479168404Spjd return (-1); 2480168404Spjd if (val) 2481168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2482168404Spjd else 2483168404Spjd (void) strlcpy(propbuf, "no", proplen); 2484168404Spjd break; 2485168404Spjd 2486168404Spjd case ZFS_PROP_NAME: 2487168404Spjd /* 2488168404Spjd * The 'name' property is a pseudo-property derived from the 2489168404Spjd * dataset name. It is presented as a real property to simplify 2490168404Spjd * consumers. 2491168404Spjd */ 2492168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2493168404Spjd break; 2494168404Spjd 2495219089Spjd case ZFS_PROP_MLSLABEL: 2496219089Spjd { 2497297077Smav#ifdef illumos 2498219089Spjd m_label_t *new_sl = NULL; 2499219089Spjd char *ascii = NULL; /* human readable label */ 2500219089Spjd 2501219089Spjd (void) strlcpy(propbuf, 2502219089Spjd getprop_string(zhp, prop, &source), proplen); 2503219089Spjd 2504219089Spjd if (literal || (strcasecmp(propbuf, 2505219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2506219089Spjd break; 2507219089Spjd 2508219089Spjd /* 2509219089Spjd * Try to translate the internal hex string to 2510219089Spjd * human-readable output. If there are any 2511219089Spjd * problems just use the hex string. 2512219089Spjd */ 2513219089Spjd 2514219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2515219089Spjd L_NO_CORRECTION, NULL) == -1) { 2516219089Spjd m_label_free(new_sl); 2517219089Spjd break; 2518219089Spjd } 2519219089Spjd 2520219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2521219089Spjd DEF_NAMES) != 0) { 2522219089Spjd if (ascii) 2523219089Spjd free(ascii); 2524219089Spjd m_label_free(new_sl); 2525219089Spjd break; 2526219089Spjd } 2527219089Spjd m_label_free(new_sl); 2528219089Spjd 2529219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2530219089Spjd free(ascii); 2531297077Smav#else /* !illumos */ 2532219089Spjd propbuf[0] = '\0'; 2533297077Smav#endif /* illumos */ 2534219089Spjd } 2535219089Spjd break; 2536219089Spjd 2537236705Smm case ZFS_PROP_GUID: 2538236705Smm /* 2539236705Smm * GUIDs are stored as numbers, but they are identifiers. 2540236705Smm * We don't want them to be pretty printed, because pretty 2541236705Smm * printing mangles the ID into a truncated and useless value. 2542236705Smm */ 2543236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2544236705Smm return (-1); 2545236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2546236705Smm break; 2547236705Smm 2548168404Spjd default: 2549185029Spjd switch (zfs_prop_get_type(prop)) { 2550185029Spjd case PROP_TYPE_NUMBER: 2551185029Spjd if (get_numeric_property(zhp, prop, src, 2552185029Spjd &source, &val) != 0) 2553185029Spjd return (-1); 2554185029Spjd if (literal) 2555185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2556185029Spjd (u_longlong_t)val); 2557185029Spjd else 2558185029Spjd zfs_nicenum(val, propbuf, proplen); 2559185029Spjd break; 2560185029Spjd 2561185029Spjd case PROP_TYPE_STRING: 2562290756Smav str = getprop_string(zhp, prop, &source); 2563290756Smav if (str == NULL) 2564290756Smav return (-1); 2565290756Smav (void) strlcpy(propbuf, str, proplen); 2566185029Spjd break; 2567185029Spjd 2568185029Spjd case PROP_TYPE_INDEX: 2569185029Spjd if (get_numeric_property(zhp, prop, src, 2570185029Spjd &source, &val) != 0) 2571185029Spjd return (-1); 2572185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2573185029Spjd return (-1); 2574185029Spjd (void) strlcpy(propbuf, strval, proplen); 2575185029Spjd break; 2576185029Spjd 2577185029Spjd default: 2578185029Spjd abort(); 2579185029Spjd } 2580168404Spjd } 2581168404Spjd 2582168404Spjd get_source(zhp, src, source, statbuf, statlen); 2583168404Spjd 2584168404Spjd return (0); 2585168404Spjd} 2586168404Spjd 2587168404Spjd/* 2588168404Spjd * Utility function to get the given numeric property. Does no validation that 2589168404Spjd * the given property is the appropriate type; should only be used with 2590168404Spjd * hard-coded property types. 2591168404Spjd */ 2592168404Spjduint64_t 2593168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2594168404Spjd{ 2595168404Spjd char *source; 2596168404Spjd uint64_t val; 2597168404Spjd 2598185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2599168404Spjd 2600168404Spjd return (val); 2601168404Spjd} 2602168404Spjd 2603185029Spjdint 2604185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2605185029Spjd{ 2606185029Spjd char buf[64]; 2607185029Spjd 2608209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2609185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2610185029Spjd} 2611185029Spjd 2612168404Spjd/* 2613168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2614168404Spjd */ 2615168404Spjdint 2616168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2617185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2618168404Spjd{ 2619168404Spjd char *source; 2620168404Spjd 2621168404Spjd /* 2622168404Spjd * Check to see if this property applies to our object 2623168404Spjd */ 2624185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2625168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2626168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2627168404Spjd zfs_prop_to_name(prop))); 2628185029Spjd } 2629168404Spjd 2630168404Spjd if (src) 2631185029Spjd *src = ZPROP_SRC_NONE; 2632168404Spjd 2633168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2634168404Spjd return (-1); 2635168404Spjd 2636168404Spjd get_source(zhp, src, source, statbuf, statlen); 2637168404Spjd 2638168404Spjd return (0); 2639168404Spjd} 2640168404Spjd 2641209962Smmstatic int 2642209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2643209962Smm char **domainp, idmap_rid_t *ridp) 2644209962Smm{ 2645297077Smav#ifdef illumos 2646209962Smm idmap_get_handle_t *get_hdl = NULL; 2647209962Smm idmap_stat status; 2648209962Smm int err = EINVAL; 2649209962Smm 2650219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2651209962Smm goto out; 2652209962Smm 2653209962Smm if (isuser) { 2654209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2655209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2656209962Smm } else { 2657209962Smm err = idmap_get_sidbygid(get_hdl, id, 2658209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2659209962Smm } 2660209962Smm if (err == IDMAP_SUCCESS && 2661209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2662209962Smm status == IDMAP_SUCCESS) 2663209962Smm err = 0; 2664209962Smm else 2665209962Smm err = EINVAL; 2666209962Smmout: 2667209962Smm if (get_hdl) 2668209962Smm idmap_get_destroy(get_hdl); 2669209962Smm return (err); 2670297077Smav#else /* !illumos */ 2671209962Smm assert(!"invalid code path"); 2672274472Ssmh return (EINVAL); // silence compiler warning 2673297077Smav#endif /* illumos */ 2674209962Smm} 2675209962Smm 2676168404Spjd/* 2677209962Smm * convert the propname into parameters needed by kernel 2678209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2679209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2680209962Smm */ 2681209962Smmstatic int 2682209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2683209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2684209962Smm{ 2685209962Smm zfs_userquota_prop_t type; 2686209962Smm char *cp, *end; 2687209962Smm char *numericsid = NULL; 2688209962Smm boolean_t isuser; 2689209962Smm 2690209962Smm domain[0] = '\0'; 2691277552Sdelphij *ridp = 0; 2692209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2693209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2694209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2695209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2696209962Smm break; 2697209962Smm } 2698209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2699209962Smm return (EINVAL); 2700209962Smm *typep = type; 2701209962Smm 2702209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2703209962Smm type == ZFS_PROP_USERUSED); 2704209962Smm 2705209962Smm cp = strchr(propname, '@') + 1; 2706209962Smm 2707209962Smm if (strchr(cp, '@')) { 2708297077Smav#ifdef illumos 2709209962Smm /* 2710209962Smm * It's a SID name (eg "user@domain") that needs to be 2711209962Smm * turned into S-1-domainID-RID. 2712209962Smm */ 2713277552Sdelphij int flag = 0; 2714277552Sdelphij idmap_stat stat, map_stat; 2715277552Sdelphij uid_t pid; 2716277552Sdelphij idmap_rid_t rid; 2717277552Sdelphij idmap_get_handle_t *gh = NULL; 2718277552Sdelphij 2719277552Sdelphij stat = idmap_get_create(&gh); 2720277552Sdelphij if (stat != IDMAP_SUCCESS) { 2721277552Sdelphij idmap_get_destroy(gh); 2722277552Sdelphij return (ENOMEM); 2723277552Sdelphij } 2724209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2725209962Smm return (ENOENT); 2726209962Smm if (isuser) { 2727277552Sdelphij stat = idmap_getuidbywinname(cp, NULL, flag, &pid); 2728277552Sdelphij if (stat < 0) 2729277552Sdelphij return (ENOENT); 2730277552Sdelphij stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid, 2731277552Sdelphij &rid, &map_stat); 2732209962Smm } else { 2733277552Sdelphij stat = idmap_getgidbywinname(cp, NULL, flag, &pid); 2734277552Sdelphij if (stat < 0) 2735277552Sdelphij return (ENOENT); 2736277552Sdelphij stat = idmap_get_sidbygid(gh, pid, flag, &numericsid, 2737277552Sdelphij &rid, &map_stat); 2738209962Smm } 2739277552Sdelphij if (stat < 0) { 2740277552Sdelphij idmap_get_destroy(gh); 2741209962Smm return (ENOENT); 2742209962Smm } 2743277552Sdelphij stat = idmap_get_mappings(gh); 2744277552Sdelphij idmap_get_destroy(gh); 2745277552Sdelphij 2746277552Sdelphij if (stat < 0) { 2747277552Sdelphij return (ENOENT); 2748277552Sdelphij } 2749209962Smm if (numericsid == NULL) 2750209962Smm return (ENOENT); 2751209962Smm cp = numericsid; 2752277552Sdelphij *ridp = rid; 2753209962Smm /* will be further decoded below */ 2754297077Smav#else /* !illumos */ 2755219089Spjd return (ENOENT); 2756297077Smav#endif /* illumos */ 2757209962Smm } 2758209962Smm 2759209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2760209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2761209962Smm (void) strlcpy(domain, cp, domainlen); 2762209962Smm errno = 0; 2763277552Sdelphij if (*ridp == 0) { 2764277552Sdelphij cp = strrchr(domain, '-'); 2765277552Sdelphij *cp = '\0'; 2766277552Sdelphij cp++; 2767277552Sdelphij *ridp = strtoull(cp, &end, 10); 2768277552Sdelphij } else { 2769277552Sdelphij end = ""; 2770277552Sdelphij } 2771209962Smm if (numericsid) { 2772209962Smm free(numericsid); 2773209962Smm numericsid = NULL; 2774209962Smm } 2775209962Smm if (errno != 0 || *end != '\0') 2776209962Smm return (EINVAL); 2777209962Smm } else if (!isdigit(*cp)) { 2778209962Smm /* 2779209962Smm * It's a user/group name (eg "user") that needs to be 2780209962Smm * turned into a uid/gid 2781209962Smm */ 2782209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2783209962Smm return (ENOENT); 2784209962Smm if (isuser) { 2785209962Smm struct passwd *pw; 2786209962Smm pw = getpwnam(cp); 2787209962Smm if (pw == NULL) 2788209962Smm return (ENOENT); 2789209962Smm *ridp = pw->pw_uid; 2790209962Smm } else { 2791209962Smm struct group *gr; 2792209962Smm gr = getgrnam(cp); 2793209962Smm if (gr == NULL) 2794209962Smm return (ENOENT); 2795209962Smm *ridp = gr->gr_gid; 2796209962Smm } 2797209962Smm } else { 2798209962Smm /* It's a user/group ID (eg "12345"). */ 2799209962Smm uid_t id = strtoul(cp, &end, 10); 2800209962Smm idmap_rid_t rid; 2801209962Smm char *mapdomain; 2802209962Smm 2803209962Smm if (*end != '\0') 2804209962Smm return (EINVAL); 2805209962Smm if (id > MAXUID) { 2806209962Smm /* It's an ephemeral ID. */ 2807209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2808209962Smm &mapdomain, &rid) != 0) 2809209962Smm return (ENOENT); 2810209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2811209962Smm *ridp = rid; 2812209962Smm } else { 2813209962Smm *ridp = id; 2814209962Smm } 2815209962Smm } 2816209962Smm 2817209962Smm ASSERT3P(numericsid, ==, NULL); 2818209962Smm return (0); 2819209962Smm} 2820209962Smm 2821209962Smmstatic int 2822209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2823209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2824209962Smm{ 2825209962Smm int err; 2826209962Smm zfs_cmd_t zc = { 0 }; 2827209962Smm 2828228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2829209962Smm 2830209962Smm err = userquota_propname_decode(propname, 2831209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2832209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2833209962Smm zc.zc_objset_type = *typep; 2834209962Smm if (err) 2835209962Smm return (err); 2836209962Smm 2837209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2838209962Smm if (err) 2839209962Smm return (err); 2840209962Smm 2841209962Smm *propvalue = zc.zc_cookie; 2842209962Smm return (0); 2843209962Smm} 2844209962Smm 2845209962Smmint 2846209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2847209962Smm uint64_t *propvalue) 2848209962Smm{ 2849209962Smm zfs_userquota_prop_t type; 2850209962Smm 2851209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2852209962Smm &type)); 2853209962Smm} 2854209962Smm 2855209962Smmint 2856209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2857209962Smm char *propbuf, int proplen, boolean_t literal) 2858209962Smm{ 2859209962Smm int err; 2860209962Smm uint64_t propvalue; 2861209962Smm zfs_userquota_prop_t type; 2862209962Smm 2863209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2864209962Smm &type); 2865209962Smm 2866209962Smm if (err) 2867209962Smm return (err); 2868209962Smm 2869209962Smm if (literal) { 2870209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2871209962Smm } else if (propvalue == 0 && 2872209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2873209962Smm (void) strlcpy(propbuf, "none", proplen); 2874209962Smm } else { 2875209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2876209962Smm } 2877209962Smm return (0); 2878209962Smm} 2879209962Smm 2880228103Smmint 2881228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 2882228103Smm uint64_t *propvalue) 2883168404Spjd{ 2884228103Smm int err; 2885228103Smm zfs_cmd_t zc = { 0 }; 2886228103Smm const char *snapname; 2887168404Spjd 2888228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2889168404Spjd 2890228103Smm snapname = strchr(propname, '@') + 1; 2891228103Smm if (strchr(snapname, '@')) { 2892228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2893228103Smm } else { 2894228103Smm /* snapname is the short name, append it to zhp's fsname */ 2895228103Smm char *cp; 2896209962Smm 2897228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 2898228103Smm sizeof (zc.zc_value)); 2899228103Smm cp = strchr(zc.zc_value, '@'); 2900228103Smm if (cp != NULL) 2901228103Smm *cp = '\0'; 2902228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 2903228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 2904228103Smm } 2905209962Smm 2906228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 2907228103Smm if (err) 2908228103Smm return (err); 2909228103Smm 2910228103Smm *propvalue = zc.zc_cookie; 2911228103Smm return (0); 2912209962Smm} 2913209962Smm 2914168404Spjdint 2915228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 2916228103Smm char *propbuf, int proplen, boolean_t literal) 2917168404Spjd{ 2918228103Smm int err; 2919228103Smm uint64_t propvalue; 2920168404Spjd 2921228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 2922185029Spjd 2923228103Smm if (err) 2924228103Smm return (err); 2925209962Smm 2926228103Smm if (literal) { 2927228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2928228103Smm } else { 2929228103Smm zfs_nicenum(propvalue, propbuf, proplen); 2930168404Spjd } 2931228103Smm return (0); 2932168404Spjd} 2933168404Spjd 2934168404Spjd/* 2935228103Smm * Returns the name of the given zfs handle. 2936168404Spjd */ 2937228103Smmconst char * 2938228103Smmzfs_get_name(const zfs_handle_t *zhp) 2939168404Spjd{ 2940228103Smm return (zhp->zfs_name); 2941228103Smm} 2942168404Spjd 2943228103Smm/* 2944307120Smav * Returns the name of the parent pool for the given zfs handle. 2945307120Smav */ 2946307120Smavconst char * 2947307120Smavzfs_get_pool_name(const zfs_handle_t *zhp) 2948307120Smav{ 2949307120Smav return (zhp->zpool_hdl->zpool_name); 2950307120Smav} 2951307120Smav 2952307120Smav/* 2953228103Smm * Returns the type of the given zfs handle. 2954228103Smm */ 2955228103Smmzfs_type_t 2956228103Smmzfs_get_type(const zfs_handle_t *zhp) 2957228103Smm{ 2958228103Smm return (zhp->zfs_type); 2959168404Spjd} 2960168404Spjd 2961168404Spjd/* 2962219089Spjd * Is one dataset name a child dataset of another? 2963219089Spjd * 2964219089Spjd * Needs to handle these cases: 2965219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2966219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2967219089Spjd * Descendant? No. No. No. Yes. 2968219089Spjd */ 2969219089Spjdstatic boolean_t 2970219089Spjdis_descendant(const char *ds1, const char *ds2) 2971219089Spjd{ 2972219089Spjd size_t d1len = strlen(ds1); 2973219089Spjd 2974219089Spjd /* ds2 can't be a descendant if it's smaller */ 2975219089Spjd if (strlen(ds2) < d1len) 2976219089Spjd return (B_FALSE); 2977219089Spjd 2978219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2979219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2980219089Spjd} 2981219089Spjd 2982219089Spjd/* 2983168404Spjd * Given a complete name, return just the portion that refers to the parent. 2984228103Smm * Will return -1 if there is no parent (path is just the name of the 2985228103Smm * pool). 2986168404Spjd */ 2987168404Spjdstatic int 2988168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2989168404Spjd{ 2990228103Smm char *slashp; 2991168404Spjd 2992228103Smm (void) strlcpy(buf, path, buflen); 2993228103Smm 2994228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 2995168404Spjd return (-1); 2996228103Smm *slashp = '\0'; 2997168404Spjd 2998168404Spjd return (0); 2999168404Spjd} 3000168404Spjd 3001168404Spjd/* 3002185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 3003185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 3004185029Spjd * closest existing ancestor for the given path. In prefixlen return the 3005185029Spjd * length of already existing prefix of the given path. We also fetch the 3006185029Spjd * 'zoned' property, which is used to validate property settings when creating 3007185029Spjd * new datasets. 3008168404Spjd */ 3009168404Spjdstatic int 3010185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 3011185029Spjd boolean_t accept_ancestor, int *prefixlen) 3012168404Spjd{ 3013168404Spjd zfs_cmd_t zc = { 0 }; 3014307122Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3015168404Spjd char *slash; 3016168404Spjd zfs_handle_t *zhp; 3017168404Spjd char errbuf[1024]; 3018219089Spjd uint64_t is_zoned; 3019168404Spjd 3020209962Smm (void) snprintf(errbuf, sizeof (errbuf), 3021209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 3022168404Spjd 3023168404Spjd /* get parent, and check to see if this is just a pool */ 3024168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 3025168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3026168404Spjd "missing dataset name")); 3027168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3028168404Spjd } 3029168404Spjd 3030168404Spjd /* check to see if the pool exists */ 3031168404Spjd if ((slash = strchr(parent, '/')) == NULL) 3032168404Spjd slash = parent + strlen(parent); 3033168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 3034168404Spjd zc.zc_name[slash - parent] = '\0'; 3035168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 3036168404Spjd errno == ENOENT) { 3037168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3038168404Spjd "no such pool '%s'"), zc.zc_name); 3039168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3040168404Spjd } 3041168404Spjd 3042168404Spjd /* check to see if the parent dataset exists */ 3043185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 3044185029Spjd if (errno == ENOENT && accept_ancestor) { 3045185029Spjd /* 3046185029Spjd * Go deeper to find an ancestor, give up on top level. 3047185029Spjd */ 3048185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 3049185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3050185029Spjd "no such pool '%s'"), zc.zc_name); 3051185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3052185029Spjd } 3053185029Spjd } else if (errno == ENOENT) { 3054168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3055168404Spjd "parent does not exist")); 3056168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3057185029Spjd } else 3058168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3059168404Spjd } 3060168404Spjd 3061219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 3062219089Spjd if (zoned != NULL) 3063219089Spjd *zoned = is_zoned; 3064219089Spjd 3065168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 3066219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 3067168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 3068168404Spjd zfs_close(zhp); 3069168404Spjd return (-1); 3070168404Spjd } 3071168404Spjd 3072168404Spjd /* make sure parent is a filesystem */ 3073168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 3074168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3075168404Spjd "parent is not a filesystem")); 3076168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3077168404Spjd zfs_close(zhp); 3078168404Spjd return (-1); 3079168404Spjd } 3080168404Spjd 3081168404Spjd zfs_close(zhp); 3082185029Spjd if (prefixlen != NULL) 3083185029Spjd *prefixlen = strlen(parent); 3084168404Spjd return (0); 3085168404Spjd} 3086168404Spjd 3087168404Spjd/* 3088185029Spjd * Finds whether the dataset of the given type(s) exists. 3089185029Spjd */ 3090185029Spjdboolean_t 3091185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 3092185029Spjd{ 3093185029Spjd zfs_handle_t *zhp; 3094185029Spjd 3095185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 3096185029Spjd return (B_FALSE); 3097185029Spjd 3098185029Spjd /* 3099185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 3100185029Spjd */ 3101185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 3102185029Spjd int ds_type = zhp->zfs_type; 3103185029Spjd 3104185029Spjd zfs_close(zhp); 3105185029Spjd if (types & ds_type) 3106185029Spjd return (B_TRUE); 3107185029Spjd } 3108185029Spjd return (B_FALSE); 3109185029Spjd} 3110185029Spjd 3111185029Spjd/* 3112185029Spjd * Given a path to 'target', create all the ancestors between 3113185029Spjd * the prefixlen portion of the path, and the target itself. 3114185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 3115185029Spjd */ 3116185029Spjdint 3117185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 3118185029Spjd{ 3119185029Spjd zfs_handle_t *h; 3120185029Spjd char *cp; 3121185029Spjd const char *opname; 3122185029Spjd 3123185029Spjd /* make sure prefix exists */ 3124185029Spjd cp = target + prefixlen; 3125185029Spjd if (*cp != '/') { 3126185029Spjd assert(strchr(cp, '/') == NULL); 3127185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3128185029Spjd } else { 3129185029Spjd *cp = '\0'; 3130185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3131185029Spjd *cp = '/'; 3132185029Spjd } 3133185029Spjd if (h == NULL) 3134185029Spjd return (-1); 3135185029Spjd zfs_close(h); 3136185029Spjd 3137185029Spjd /* 3138185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 3139185029Spjd * up to the prefixlen-long one. 3140185029Spjd */ 3141185029Spjd for (cp = target + prefixlen + 1; 3142307058Smav (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) { 3143185029Spjd 3144185029Spjd *cp = '\0'; 3145185029Spjd 3146185029Spjd h = make_dataset_handle(hdl, target); 3147185029Spjd if (h) { 3148185029Spjd /* it already exists, nothing to do here */ 3149185029Spjd zfs_close(h); 3150185029Spjd continue; 3151185029Spjd } 3152185029Spjd 3153185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 3154185029Spjd NULL) != 0) { 3155185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 3156185029Spjd goto ancestorerr; 3157185029Spjd } 3158185029Spjd 3159185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3160185029Spjd if (h == NULL) { 3161185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 3162185029Spjd goto ancestorerr; 3163185029Spjd } 3164185029Spjd 3165185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 3166185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 3167185029Spjd goto ancestorerr; 3168185029Spjd } 3169185029Spjd 3170185029Spjd if (zfs_share(h) != 0) { 3171185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 3172185029Spjd goto ancestorerr; 3173185029Spjd } 3174185029Spjd 3175185029Spjd zfs_close(h); 3176185029Spjd } 3177185029Spjd 3178185029Spjd return (0); 3179185029Spjd 3180185029Spjdancestorerr: 3181185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3182185029Spjd "failed to %s ancestor '%s'"), opname, target); 3183185029Spjd return (-1); 3184185029Spjd} 3185185029Spjd 3186185029Spjd/* 3187185029Spjd * Creates non-existing ancestors of the given path. 3188185029Spjd */ 3189185029Spjdint 3190185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3191185029Spjd{ 3192185029Spjd int prefix; 3193185029Spjd char *path_copy; 3194307121Smav int rc = 0; 3195185029Spjd 3196219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3197185029Spjd return (-1); 3198185029Spjd 3199185029Spjd if ((path_copy = strdup(path)) != NULL) { 3200185029Spjd rc = create_parents(hdl, path_copy, prefix); 3201185029Spjd free(path_copy); 3202185029Spjd } 3203185029Spjd if (path_copy == NULL || rc != 0) 3204185029Spjd return (-1); 3205185029Spjd 3206185029Spjd return (0); 3207185029Spjd} 3208185029Spjd 3209185029Spjd/* 3210168404Spjd * Create a new filesystem or volume. 3211168404Spjd */ 3212168404Spjdint 3213168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3214168404Spjd nvlist_t *props) 3215168404Spjd{ 3216168404Spjd int ret; 3217168404Spjd uint64_t size = 0; 3218168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3219168404Spjd char errbuf[1024]; 3220168404Spjd uint64_t zoned; 3221300028Savg enum lzc_dataset_type ost; 3222168404Spjd 3223168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3224168404Spjd "cannot create '%s'"), path); 3225168404Spjd 3226168404Spjd /* validate the path, taking care to note the extended error message */ 3227185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3228168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3229168404Spjd 3230168404Spjd /* validate parents exist */ 3231185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3232168404Spjd return (-1); 3233168404Spjd 3234168404Spjd /* 3235168404Spjd * The failure modes when creating a dataset of a different type over 3236168404Spjd * one that already exists is a little strange. In particular, if you 3237168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3238168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3239168404Spjd * first try to see if the dataset exists. 3240168404Spjd */ 3241248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3242168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3243168404Spjd "dataset already exists")); 3244168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3245168404Spjd } 3246168404Spjd 3247168404Spjd if (type == ZFS_TYPE_VOLUME) 3248300028Savg ost = LZC_DATSET_TYPE_ZVOL; 3249168404Spjd else 3250300028Savg ost = LZC_DATSET_TYPE_ZFS; 3251168404Spjd 3252290760Smav /* open zpool handle for prop validation */ 3253307122Smav char pool_path[ZFS_MAX_DATASET_NAME_LEN]; 3254290760Smav (void) strlcpy(pool_path, path, sizeof (pool_path)); 3255290760Smav 3256290760Smav /* truncate pool_path at first slash */ 3257290760Smav char *p = strchr(pool_path, '/'); 3258290760Smav if (p != NULL) 3259290760Smav *p = '\0'; 3260290760Smav 3261290760Smav zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path); 3262290760Smav 3263185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3264290760Smav zoned, NULL, zpool_handle, errbuf)) == 0) { 3265290760Smav zpool_close(zpool_handle); 3266168404Spjd return (-1); 3267290760Smav } 3268290760Smav zpool_close(zpool_handle); 3269168404Spjd 3270168404Spjd if (type == ZFS_TYPE_VOLUME) { 3271168404Spjd /* 3272168404Spjd * If we are creating a volume, the size and block size must 3273168404Spjd * satisfy a few restraints. First, the blocksize must be a 3274168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3275168404Spjd * volsize must be a multiple of the block size, and cannot be 3276168404Spjd * zero. 3277168404Spjd */ 3278168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3279168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3280168404Spjd nvlist_free(props); 3281168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3282168404Spjd "missing volume size")); 3283168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3284168404Spjd } 3285168404Spjd 3286168404Spjd if ((ret = nvlist_lookup_uint64(props, 3287168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3288168404Spjd &blocksize)) != 0) { 3289168404Spjd if (ret == ENOENT) { 3290168404Spjd blocksize = zfs_prop_default_numeric( 3291168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3292168404Spjd } else { 3293168404Spjd nvlist_free(props); 3294168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3295168404Spjd "missing volume block size")); 3296168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3297168404Spjd } 3298168404Spjd } 3299168404Spjd 3300168404Spjd if (size == 0) { 3301168404Spjd nvlist_free(props); 3302168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3303168404Spjd "volume size cannot be zero")); 3304168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3305168404Spjd } 3306168404Spjd 3307168404Spjd if (size % blocksize != 0) { 3308168404Spjd nvlist_free(props); 3309168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3310168404Spjd "volume size must be a multiple of volume block " 3311168404Spjd "size")); 3312168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3313168404Spjd } 3314168404Spjd } 3315168404Spjd 3316248571Smm /* create the dataset */ 3317248571Smm ret = lzc_create(path, ost, props); 3318168404Spjd nvlist_free(props); 3319168404Spjd 3320168404Spjd /* check for failure */ 3321168404Spjd if (ret != 0) { 3322307122Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3323168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3324168404Spjd 3325168404Spjd switch (errno) { 3326168404Spjd case ENOENT: 3327168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3328168404Spjd "no such parent '%s'"), parent); 3329168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3330168404Spjd 3331168404Spjd case EINVAL: 3332168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3333168404Spjd "parent '%s' is not a filesystem"), parent); 3334168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3335168404Spjd 3336185029Spjd case ENOTSUP: 3337185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3338185029Spjd "pool must be upgraded to set this " 3339185029Spjd "property or value")); 3340185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3341168404Spjd#ifdef _ILP32 3342168404Spjd case EOVERFLOW: 3343168404Spjd /* 3344168404Spjd * This platform can't address a volume this big. 3345168404Spjd */ 3346168404Spjd if (type == ZFS_TYPE_VOLUME) 3347168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3348168404Spjd errbuf)); 3349168404Spjd#endif 3350168404Spjd /* FALLTHROUGH */ 3351168404Spjd default: 3352168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3353168404Spjd } 3354168404Spjd } 3355168404Spjd 3356168404Spjd return (0); 3357168404Spjd} 3358168404Spjd 3359168404Spjd/* 3360168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3361238422Smm * isn't mounted, and that there are no active dependents. If the file system 3362238422Smm * does not exist this function does nothing. 3363168404Spjd */ 3364168404Spjdint 3365219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3366168404Spjd{ 3367168404Spjd zfs_cmd_t zc = { 0 }; 3368168404Spjd 3369263407Sdelphij if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3370263407Sdelphij nvlist_t *nv = fnvlist_alloc(); 3371263407Sdelphij fnvlist_add_boolean(nv, zhp->zfs_name); 3372263407Sdelphij int error = lzc_destroy_bookmarks(nv, NULL); 3373263407Sdelphij fnvlist_free(nv); 3374263407Sdelphij if (error != 0) { 3375263407Sdelphij return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3376263407Sdelphij dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3377263407Sdelphij zhp->zfs_name)); 3378263407Sdelphij } 3379263407Sdelphij return (0); 3380263407Sdelphij } 3381263407Sdelphij 3382168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3383168404Spjd 3384168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3385168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3386168404Spjd } else { 3387168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3388168404Spjd } 3389168404Spjd 3390219089Spjd zc.zc_defer_destroy = defer; 3391238422Smm if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && 3392238422Smm errno != ENOENT) { 3393168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3394168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3395168404Spjd zhp->zfs_name)); 3396168404Spjd } 3397168404Spjd 3398168404Spjd remove_mountpoint(zhp); 3399168404Spjd 3400168404Spjd return (0); 3401168404Spjd} 3402168404Spjd 3403168404Spjdstruct destroydata { 3404228103Smm nvlist_t *nvl; 3405228103Smm const char *snapname; 3406168404Spjd}; 3407168404Spjd 3408168404Spjdstatic int 3409219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3410168404Spjd{ 3411168404Spjd struct destroydata *dd = arg; 3412307122Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3413219089Spjd int rv = 0; 3414168404Spjd 3415228103Smm (void) snprintf(name, sizeof (name), 3416228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3417168404Spjd 3418251646Sdelphij if (lzc_exists(name)) 3419228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3420168404Spjd 3421228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3422228103Smm zfs_close(zhp); 3423168404Spjd return (rv); 3424168404Spjd} 3425168404Spjd 3426168404Spjd/* 3427168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3428168404Spjd */ 3429168404Spjdint 3430219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3431168404Spjd{ 3432168404Spjd int ret; 3433168404Spjd struct destroydata dd = { 0 }; 3434168404Spjd 3435168404Spjd dd.snapname = snapname; 3436228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3437228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3438168404Spjd 3439251646Sdelphij if (nvlist_empty(dd.nvl)) { 3440228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3441168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3442228103Smm zhp->zfs_name, snapname); 3443228103Smm } else { 3444248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3445168404Spjd } 3446228103Smm nvlist_free(dd.nvl); 3447228103Smm return (ret); 3448228103Smm} 3449168404Spjd 3450228103Smm/* 3451248571Smm * Destroys all the snapshots named in the nvlist. 3452228103Smm */ 3453228103Smmint 3454248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3455228103Smm{ 3456228103Smm int ret; 3457307119Smav nvlist_t *errlist = NULL; 3458228103Smm 3459248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3460168404Spjd 3461307119Smav if (ret == 0) { 3462307119Smav nvlist_free(errlist); 3463248571Smm return (0); 3464307119Smav } 3465248571Smm 3466251646Sdelphij if (nvlist_empty(errlist)) { 3467168404Spjd char errbuf[1024]; 3468248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3469248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3470168404Spjd 3471248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3472248571Smm } 3473248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3474248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3475248571Smm char errbuf[1024]; 3476248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3477248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3478248571Smm nvpair_name(pair)); 3479168404Spjd 3480248571Smm switch (fnvpair_value_int32(pair)) { 3481168404Spjd case EEXIST: 3482248571Smm zfs_error_aux(hdl, 3483248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3484248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3485248571Smm break; 3486168404Spjd default: 3487248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3488248571Smm break; 3489168404Spjd } 3490168404Spjd } 3491168404Spjd 3492307119Smav nvlist_free(errlist); 3493248571Smm return (ret); 3494168404Spjd} 3495168404Spjd 3496168404Spjd/* 3497168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3498168404Spjd */ 3499168404Spjdint 3500168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3501168404Spjd{ 3502307122Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3503168404Spjd int ret; 3504168404Spjd char errbuf[1024]; 3505168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3506168404Spjd uint64_t zoned; 3507168404Spjd 3508168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3509168404Spjd 3510168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3511168404Spjd "cannot create '%s'"), target); 3512168404Spjd 3513228103Smm /* validate the target/clone name */ 3514185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3515168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3516168404Spjd 3517168404Spjd /* validate parents exist */ 3518185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3519168404Spjd return (-1); 3520168404Spjd 3521168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3522168404Spjd 3523168404Spjd /* do the clone */ 3524168404Spjd 3525168404Spjd if (props) { 3526248571Smm zfs_type_t type; 3527248571Smm if (ZFS_IS_VOLUME(zhp)) { 3528248571Smm type = ZFS_TYPE_VOLUME; 3529248571Smm } else { 3530248571Smm type = ZFS_TYPE_FILESYSTEM; 3531248571Smm } 3532185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3533290760Smav zhp, zhp->zpool_hdl, errbuf)) == NULL) 3534168404Spjd return (-1); 3535168404Spjd } 3536168404Spjd 3537248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3538248571Smm nvlist_free(props); 3539168404Spjd 3540168404Spjd if (ret != 0) { 3541168404Spjd switch (errno) { 3542168404Spjd 3543168404Spjd case ENOENT: 3544168404Spjd /* 3545168404Spjd * The parent doesn't exist. We should have caught this 3546168404Spjd * above, but there may a race condition that has since 3547168404Spjd * destroyed the parent. 3548168404Spjd * 3549168404Spjd * At this point, we don't know whether it's the source 3550168404Spjd * that doesn't exist anymore, or whether the target 3551168404Spjd * dataset doesn't exist. 3552168404Spjd */ 3553168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3554168404Spjd "no such parent '%s'"), parent); 3555168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3556168404Spjd 3557168404Spjd case EXDEV: 3558168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3559168404Spjd "source and target pools differ")); 3560168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3561168404Spjd errbuf)); 3562168404Spjd 3563168404Spjd default: 3564168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3565168404Spjd errbuf)); 3566168404Spjd } 3567168404Spjd } 3568168404Spjd 3569168404Spjd return (ret); 3570168404Spjd} 3571168404Spjd 3572168404Spjd/* 3573168404Spjd * Promotes the given clone fs to be the clone parent. 3574168404Spjd */ 3575168404Spjdint 3576168404Spjdzfs_promote(zfs_handle_t *zhp) 3577168404Spjd{ 3578168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3579168404Spjd zfs_cmd_t zc = { 0 }; 3580168404Spjd char parent[MAXPATHLEN]; 3581168404Spjd int ret; 3582168404Spjd char errbuf[1024]; 3583168404Spjd 3584168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3585168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3586168404Spjd 3587168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3588168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3589168404Spjd "snapshots can not be promoted")); 3590168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3591168404Spjd } 3592168404Spjd 3593185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3594168404Spjd if (parent[0] == '\0') { 3595168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3596168404Spjd "not a cloned filesystem")); 3597168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3598168404Spjd } 3599168404Spjd 3600185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3601168404Spjd sizeof (zc.zc_value)); 3602168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3603185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3604168404Spjd 3605168404Spjd if (ret != 0) { 3606168404Spjd int save_errno = errno; 3607168404Spjd 3608168404Spjd switch (save_errno) { 3609168404Spjd case EEXIST: 3610219089Spjd /* There is a conflicting snapshot name. */ 3611168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3612219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3613219089Spjd zc.zc_string, parent); 3614168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3615168404Spjd 3616168404Spjd default: 3617168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3618168404Spjd } 3619168404Spjd } 3620168404Spjd return (ret); 3621168404Spjd} 3622168404Spjd 3623248571Smmtypedef struct snapdata { 3624248571Smm nvlist_t *sd_nvl; 3625248571Smm const char *sd_snapname; 3626248571Smm} snapdata_t; 3627248571Smm 3628248571Smmstatic int 3629248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3630248571Smm{ 3631248571Smm snapdata_t *sd = arg; 3632307122Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 3633248571Smm int rv = 0; 3634248571Smm 3635253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3636253819Sdelphij (void) snprintf(name, sizeof (name), 3637253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3638248571Smm 3639253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3640248571Smm 3641253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3642253819Sdelphij } 3643248571Smm zfs_close(zhp); 3644253819Sdelphij 3645248571Smm return (rv); 3646248571Smm} 3647248571Smm 3648168404Spjd/* 3649248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3650248571Smm * created. 3651168404Spjd */ 3652168404Spjdint 3653248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3654168404Spjd{ 3655168404Spjd int ret; 3656168404Spjd char errbuf[1024]; 3657248571Smm nvpair_t *elem; 3658248571Smm nvlist_t *errors; 3659168404Spjd 3660168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3661248571Smm "cannot create snapshots ")); 3662168404Spjd 3663248571Smm elem = NULL; 3664248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3665248571Smm const char *snapname = nvpair_name(elem); 3666168404Spjd 3667248571Smm /* validate the target name */ 3668248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3669248571Smm B_TRUE)) { 3670248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3671248571Smm dgettext(TEXT_DOMAIN, 3672248571Smm "cannot create snapshot '%s'"), snapname); 3673248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3674248571Smm } 3675248571Smm } 3676185029Spjd 3677290760Smav /* 3678290760Smav * get pool handle for prop validation. assumes all snaps are in the 3679290760Smav * same pool, as does lzc_snapshot (below). 3680290760Smav */ 3681307122Smav char pool[ZFS_MAX_DATASET_NAME_LEN]; 3682290760Smav elem = nvlist_next_nvpair(snaps, NULL); 3683290760Smav (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); 3684290760Smav pool[strcspn(pool, "/@")] = '\0'; 3685290760Smav zpool_handle_t *zpool_hdl = zpool_open(hdl, pool); 3686290760Smav 3687248571Smm if (props != NULL && 3688248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3689290760Smav props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) { 3690290760Smav zpool_close(zpool_hdl); 3691248571Smm return (-1); 3692248571Smm } 3693290760Smav zpool_close(zpool_hdl); 3694248571Smm 3695248571Smm ret = lzc_snapshot(snaps, props, &errors); 3696248571Smm 3697248571Smm if (ret != 0) { 3698248571Smm boolean_t printed = B_FALSE; 3699248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 3700248571Smm elem != NULL; 3701248571Smm elem = nvlist_next_nvpair(errors, elem)) { 3702248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3703248571Smm dgettext(TEXT_DOMAIN, 3704248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 3705248571Smm (void) zfs_standard_error(hdl, 3706248571Smm fnvpair_value_int32(elem), errbuf); 3707248571Smm printed = B_TRUE; 3708185029Spjd } 3709248571Smm if (!printed) { 3710248571Smm switch (ret) { 3711248571Smm case EXDEV: 3712248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3713248571Smm "multiple snapshots of same " 3714248571Smm "fs not allowed")); 3715248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3716185029Spjd 3717248571Smm break; 3718248571Smm default: 3719248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 3720248571Smm } 3721248571Smm } 3722185029Spjd } 3723185029Spjd 3724248571Smm nvlist_free(props); 3725248571Smm nvlist_free(errors); 3726248571Smm return (ret); 3727248571Smm} 3728168404Spjd 3729248571Smmint 3730248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3731248571Smm nvlist_t *props) 3732248571Smm{ 3733248571Smm int ret; 3734248571Smm snapdata_t sd = { 0 }; 3735307122Smav char fsname[ZFS_MAX_DATASET_NAME_LEN]; 3736248571Smm char *cp; 3737248571Smm zfs_handle_t *zhp; 3738248571Smm char errbuf[1024]; 3739248571Smm 3740248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3741248571Smm "cannot snapshot %s"), path); 3742248571Smm 3743248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3744248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3745248571Smm 3746248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 3747248571Smm cp = strchr(fsname, '@'); 3748248571Smm *cp = '\0'; 3749248571Smm sd.sd_snapname = cp + 1; 3750248571Smm 3751248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 3752168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3753168404Spjd return (-1); 3754168404Spjd } 3755168404Spjd 3756248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 3757248571Smm if (recursive) { 3758248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 3759248571Smm } else { 3760248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 3761168404Spjd } 3762168404Spjd 3763248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 3764248571Smm nvlist_free(sd.sd_nvl); 3765168404Spjd zfs_close(zhp); 3766168404Spjd return (ret); 3767168404Spjd} 3768168404Spjd 3769168404Spjd/* 3770168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3771168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3772168404Spjd * is a dependent and we should just destroy it without checking the transaction 3773168404Spjd * group. 3774168404Spjd */ 3775168404Spjdtypedef struct rollback_data { 3776168404Spjd const char *cb_target; /* the snapshot */ 3777168404Spjd uint64_t cb_create; /* creation time reference */ 3778185029Spjd boolean_t cb_error; 3779185029Spjd boolean_t cb_force; 3780168404Spjd} rollback_data_t; 3781168404Spjd 3782168404Spjdstatic int 3783263407Sdelphijrollback_destroy_dependent(zfs_handle_t *zhp, void *data) 3784168404Spjd{ 3785168404Spjd rollback_data_t *cbp = data; 3786263407Sdelphij prop_changelist_t *clp; 3787168404Spjd 3788263407Sdelphij /* We must destroy this clone; first unmount it */ 3789263407Sdelphij clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3790263407Sdelphij cbp->cb_force ? MS_FORCE: 0); 3791263407Sdelphij if (clp == NULL || changelist_prefix(clp) != 0) { 3792263407Sdelphij cbp->cb_error = B_TRUE; 3793263407Sdelphij zfs_close(zhp); 3794263407Sdelphij return (0); 3795263407Sdelphij } 3796263407Sdelphij if (zfs_destroy(zhp, B_FALSE) != 0) 3797263407Sdelphij cbp->cb_error = B_TRUE; 3798263407Sdelphij else 3799263407Sdelphij changelist_remove(clp, zhp->zfs_name); 3800263407Sdelphij (void) changelist_postfix(clp); 3801263407Sdelphij changelist_free(clp); 3802168404Spjd 3803263407Sdelphij zfs_close(zhp); 3804263407Sdelphij return (0); 3805263407Sdelphij} 3806168404Spjd 3807263407Sdelphijstatic int 3808263407Sdelphijrollback_destroy(zfs_handle_t *zhp, void *data) 3809263407Sdelphij{ 3810263407Sdelphij rollback_data_t *cbp = data; 3811185029Spjd 3812263407Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 3813263407Sdelphij cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3814263407Sdelphij rollback_destroy_dependent, cbp); 3815263407Sdelphij 3816263407Sdelphij cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3817168404Spjd } 3818168404Spjd 3819168404Spjd zfs_close(zhp); 3820168404Spjd return (0); 3821168404Spjd} 3822168404Spjd 3823168404Spjd/* 3824168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3825168404Spjd * data changes since then and making it the active dataset. 3826168404Spjd * 3827263407Sdelphij * Any snapshots and bookmarks more recent than the target are 3828263407Sdelphij * destroyed, along with their dependents (i.e. clones). 3829168404Spjd */ 3830168404Spjdint 3831185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3832168404Spjd{ 3833168404Spjd rollback_data_t cb = { 0 }; 3834185029Spjd int err; 3835185029Spjd boolean_t restore_resv = 0; 3836307121Smav uint64_t old_volsize = 0, new_volsize; 3837185029Spjd zfs_prop_t resv_prop; 3838168404Spjd 3839185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3840185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3841168404Spjd 3842168404Spjd /* 3843239774Smm * Destroy all recent snapshots and their dependents. 3844168404Spjd */ 3845185029Spjd cb.cb_force = force; 3846168404Spjd cb.cb_target = snap->zfs_name; 3847168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3848263407Sdelphij (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb); 3849263407Sdelphij (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); 3850168404Spjd 3851185029Spjd if (cb.cb_error) 3852185029Spjd return (-1); 3853168404Spjd 3854168404Spjd /* 3855168404Spjd * Now that we have verified that the snapshot is the latest, 3856168404Spjd * rollback to the given snapshot. 3857168404Spjd */ 3858168404Spjd 3859185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3860185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3861185029Spjd return (-1); 3862185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3863185029Spjd restore_resv = 3864185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3865168404Spjd } 3866168404Spjd 3867168404Spjd /* 3868185029Spjd * We rely on zfs_iter_children() to verify that there are no 3869185029Spjd * newer snapshots for the given dataset. Therefore, we can 3870185029Spjd * simply pass the name on to the ioctl() call. There is still 3871185029Spjd * an unlikely race condition where the user has taken a 3872185029Spjd * snapshot since we verified that this was the most recent. 3873168404Spjd */ 3874254587Sdelphij err = lzc_rollback(zhp->zfs_name, NULL, 0); 3875254587Sdelphij if (err != 0) { 3876185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3877185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3878185029Spjd zhp->zfs_name); 3879185029Spjd return (err); 3880185029Spjd } 3881168404Spjd 3882185029Spjd /* 3883185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3884185029Spjd * rollback reservation and the volsize has changed then set 3885185029Spjd * the reservation property to the post-rollback volsize. 3886185029Spjd * Make a new handle since the rollback closed the dataset. 3887185029Spjd */ 3888185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3889185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3890185029Spjd if (restore_resv) { 3891185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3892185029Spjd if (old_volsize != new_volsize) 3893185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3894185029Spjd new_volsize); 3895185029Spjd } 3896185029Spjd zfs_close(zhp); 3897185029Spjd } 3898185029Spjd return (err); 3899168404Spjd} 3900168404Spjd 3901168404Spjd/* 3902168404Spjd * Renames the given dataset. 3903168404Spjd */ 3904168404Spjdint 3905240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 3906240870Spjd renameflags_t flags) 3907168404Spjd{ 3908307058Smav int ret = 0; 3909168404Spjd zfs_cmd_t zc = { 0 }; 3910168404Spjd char *delim; 3911168676Spjd prop_changelist_t *cl = NULL; 3912168676Spjd zfs_handle_t *zhrp = NULL; 3913168676Spjd char *parentname = NULL; 3914307122Smav char parent[ZFS_MAX_DATASET_NAME_LEN]; 3915226676Spjd char property[ZFS_MAXPROPLEN]; 3916168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3917168404Spjd char errbuf[1024]; 3918168404Spjd 3919168404Spjd /* if we have the same exact name, just return success */ 3920168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3921168404Spjd return (0); 3922168404Spjd 3923168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3924168404Spjd "cannot rename to '%s'"), target); 3925168404Spjd 3926240870Spjd if (source != NULL) { 3927240870Spjd /* 3928240870Spjd * This is recursive snapshots rename, put snapshot name 3929240870Spjd * (that might not exist) into zfs_name. 3930240870Spjd */ 3931240870Spjd assert(flags.recurse); 3932240870Spjd 3933240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 3934240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 3935240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 3936240870Spjd } 3937240870Spjd 3938168404Spjd /* 3939168404Spjd * Make sure the target name is valid 3940168404Spjd */ 3941168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3942168404Spjd if ((strchr(target, '@') == NULL) || 3943168404Spjd *target == '@') { 3944168404Spjd /* 3945168404Spjd * Snapshot target name is abbreviated, 3946168404Spjd * reconstruct full dataset name 3947168404Spjd */ 3948168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3949168404Spjd sizeof (parent)); 3950168404Spjd delim = strchr(parent, '@'); 3951168404Spjd if (strchr(target, '@') == NULL) 3952168404Spjd *(++delim) = '\0'; 3953168404Spjd else 3954168404Spjd *delim = '\0'; 3955168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3956168404Spjd target = parent; 3957168404Spjd } else { 3958168404Spjd /* 3959168404Spjd * Make sure we're renaming within the same dataset. 3960168404Spjd */ 3961168404Spjd delim = strchr(target, '@'); 3962168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3963168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3964168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3965168404Spjd "snapshots must be part of same " 3966168404Spjd "dataset")); 3967168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3968168404Spjd errbuf)); 3969168404Spjd } 3970168404Spjd } 3971185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3972168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3973168404Spjd } else { 3974226705Spjd if (flags.recurse) { 3975168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3976168676Spjd "recursive rename must be a snapshot")); 3977168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3978168676Spjd } 3979168676Spjd 3980185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3981168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3982168404Spjd 3983168404Spjd /* validate parents */ 3984219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3985168404Spjd return (-1); 3986168404Spjd 3987168404Spjd /* make sure we're in the same pool */ 3988168404Spjd verify((delim = strchr(target, '/')) != NULL); 3989168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3990168404Spjd zhp->zfs_name[delim - target] != '/') { 3991168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3992168404Spjd "datasets must be within same pool")); 3993168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3994168404Spjd } 3995168404Spjd 3996168404Spjd /* new name cannot be a child of the current dataset name */ 3997219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3998168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3999219089Spjd "New dataset name cannot be a descendant of " 4000168404Spjd "current dataset name")); 4001168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4002168404Spjd } 4003168404Spjd } 4004168404Spjd 4005168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4006168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 4007168404Spjd 4008168404Spjd if (getzoneid() == GLOBAL_ZONEID && 4009168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 4010168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4011168404Spjd "dataset is used in a non-global zone")); 4012168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 4013168404Spjd } 4014168404Spjd 4015226705Spjd /* 4016226705Spjd * Avoid unmounting file systems with mountpoint property set to 4017226705Spjd * 'legacy' or 'none' even if -u option is not given. 4018226705Spjd */ 4019226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 4020226705Spjd !flags.recurse && !flags.nounmount && 4021226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 4022226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 4023226705Spjd (strcmp(property, "legacy") == 0 || 4024226705Spjd strcmp(property, "none") == 0)) { 4025226705Spjd flags.nounmount = B_TRUE; 4026226705Spjd } 4027226705Spjd if (flags.recurse) { 4028226705Spjd 4029185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 4030185029Spjd if (parentname == NULL) { 4031185029Spjd ret = -1; 4032185029Spjd goto error; 4033185029Spjd } 4034168676Spjd delim = strchr(parentname, '@'); 4035168676Spjd *delim = '\0'; 4036185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 4037168676Spjd if (zhrp == NULL) { 4038185029Spjd ret = -1; 4039185029Spjd goto error; 4040168676Spjd } 4041269003Sdelphij } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { 4042226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 4043235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 4044235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 4045168676Spjd return (-1); 4046226676Spjd } 4047168676Spjd 4048168676Spjd if (changelist_haszonedchild(cl)) { 4049168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4050168676Spjd "child dataset with inherited mountpoint is used " 4051168676Spjd "in a non-global zone")); 4052168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 4053307121Smav ret = -1; 4054168676Spjd goto error; 4055168676Spjd } 4056168676Spjd 4057168676Spjd if ((ret = changelist_prefix(cl)) != 0) 4058168676Spjd goto error; 4059168404Spjd } 4060168404Spjd 4061168404Spjd if (ZFS_IS_VOLUME(zhp)) 4062168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 4063168404Spjd else 4064168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4065168404Spjd 4066168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4067168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 4068168404Spjd 4069226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 4070226705Spjd if (flags.nounmount) 4071226676Spjd zc.zc_cookie |= 2; 4072168676Spjd 4073185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 4074168676Spjd /* 4075168676Spjd * if it was recursive, the one that actually failed will 4076168676Spjd * be in zc.zc_name 4077168676Spjd */ 4078168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4079185029Spjd "cannot rename '%s'"), zc.zc_name); 4080168404Spjd 4081226705Spjd if (flags.recurse && errno == EEXIST) { 4082168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4083168676Spjd "a child dataset already has a snapshot " 4084168676Spjd "with the new name")); 4085185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4086168676Spjd } else { 4087168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 4088168676Spjd } 4089168676Spjd 4090168404Spjd /* 4091168404Spjd * On failure, we still want to remount any filesystems that 4092168404Spjd * were previously mounted, so we don't alter the system state. 4093168404Spjd */ 4094269003Sdelphij if (cl != NULL) 4095168676Spjd (void) changelist_postfix(cl); 4096168404Spjd } else { 4097269003Sdelphij if (cl != NULL) { 4098168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 4099168676Spjd ret = changelist_postfix(cl); 4100168676Spjd } 4101168404Spjd } 4102168404Spjd 4103168404Spjderror: 4104269003Sdelphij if (parentname != NULL) { 4105168676Spjd free(parentname); 4106168676Spjd } 4107269003Sdelphij if (zhrp != NULL) { 4108168676Spjd zfs_close(zhrp); 4109168676Spjd } 4110269003Sdelphij if (cl != NULL) { 4111168676Spjd changelist_free(cl); 4112168676Spjd } 4113168404Spjd return (ret); 4114168404Spjd} 4115168404Spjd 4116219089Spjdnvlist_t * 4117219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 4118168404Spjd{ 4119219089Spjd return (zhp->zfs_user_props); 4120168676Spjd} 4121168676Spjd 4122168404Spjdnvlist_t * 4123219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 4124168404Spjd{ 4125219089Spjd if (zhp->zfs_recvd_props == NULL) 4126219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 4127219089Spjd return (NULL); 4128219089Spjd return (zhp->zfs_recvd_props); 4129168404Spjd} 4130168404Spjd 4131168404Spjd/* 4132168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 4133168404Spjd * display, and their maximum widths. This does two main things: 4134168404Spjd * 4135168404Spjd * - If this is a list of all properties, then expand the list to include 4136168404Spjd * all native properties, and set a flag so that for each dataset we look 4137168404Spjd * for new unique user properties and add them to the list. 4138168404Spjd * 4139168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 4140219089Spjd * so that we can size the column appropriately. If the user has 4141219089Spjd * requested received property values, we also need to compute the width 4142219089Spjd * of the RECEIVED column. 4143168404Spjd */ 4144168404Spjdint 4145263405Sdelphijzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 4146263405Sdelphij boolean_t literal) 4147168404Spjd{ 4148168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4149185029Spjd zprop_list_t *entry; 4150185029Spjd zprop_list_t **last, **start; 4151168404Spjd nvlist_t *userprops, *propval; 4152168404Spjd nvpair_t *elem; 4153168404Spjd char *strval; 4154168404Spjd char buf[ZFS_MAXPROPLEN]; 4155168404Spjd 4156185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 4157168404Spjd return (-1); 4158168404Spjd 4159168404Spjd userprops = zfs_get_user_props(zhp); 4160168404Spjd 4161168404Spjd entry = *plp; 4162168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4163168404Spjd /* 4164168404Spjd * Go through and add any user properties as necessary. We 4165168404Spjd * start by incrementing our list pointer to the first 4166168404Spjd * non-native property. 4167168404Spjd */ 4168168404Spjd start = plp; 4169168404Spjd while (*start != NULL) { 4170185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 4171168404Spjd break; 4172168404Spjd start = &(*start)->pl_next; 4173168404Spjd } 4174168404Spjd 4175168404Spjd elem = NULL; 4176168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4177168404Spjd /* 4178168404Spjd * See if we've already found this property in our list. 4179168404Spjd */ 4180168404Spjd for (last = start; *last != NULL; 4181168404Spjd last = &(*last)->pl_next) { 4182168404Spjd if (strcmp((*last)->pl_user_prop, 4183168404Spjd nvpair_name(elem)) == 0) 4184168404Spjd break; 4185168404Spjd } 4186168404Spjd 4187168404Spjd if (*last == NULL) { 4188168404Spjd if ((entry = zfs_alloc(hdl, 4189185029Spjd sizeof (zprop_list_t))) == NULL || 4190168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 4191168404Spjd nvpair_name(elem)))) == NULL) { 4192168404Spjd free(entry); 4193168404Spjd return (-1); 4194168404Spjd } 4195168404Spjd 4196185029Spjd entry->pl_prop = ZPROP_INVAL; 4197168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 4198168404Spjd entry->pl_all = B_TRUE; 4199168404Spjd *last = entry; 4200168404Spjd } 4201168404Spjd } 4202168404Spjd } 4203168404Spjd 4204168404Spjd /* 4205168404Spjd * Now go through and check the width of any non-fixed columns 4206168404Spjd */ 4207168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4208263405Sdelphij if (entry->pl_fixed && !literal) 4209168404Spjd continue; 4210168404Spjd 4211185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 4212168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 4213263405Sdelphij buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4214168404Spjd if (strlen(buf) > entry->pl_width) 4215168404Spjd entry->pl_width = strlen(buf); 4216168404Spjd } 4217219089Spjd if (received && zfs_prop_get_recvd(zhp, 4218219089Spjd zfs_prop_to_name(entry->pl_prop), 4219263405Sdelphij buf, sizeof (buf), literal) == 0) 4220219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4221219089Spjd entry->pl_recvd_width = strlen(buf); 4222219089Spjd } else { 4223219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4224219089Spjd &propval) == 0) { 4225219089Spjd verify(nvlist_lookup_string(propval, 4226219089Spjd ZPROP_VALUE, &strval) == 0); 4227219089Spjd if (strlen(strval) > entry->pl_width) 4228219089Spjd entry->pl_width = strlen(strval); 4229219089Spjd } 4230219089Spjd if (received && zfs_prop_get_recvd(zhp, 4231219089Spjd entry->pl_user_prop, 4232263405Sdelphij buf, sizeof (buf), literal) == 0) 4233219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4234219089Spjd entry->pl_recvd_width = strlen(buf); 4235168404Spjd } 4236168404Spjd } 4237168404Spjd 4238168404Spjd return (0); 4239168404Spjd} 4240168404Spjd 4241185029Spjdint 4242185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4243209962Smm char *resource, void *export, void *sharetab, 4244209962Smm int sharemax, zfs_share_op_t operation) 4245185029Spjd{ 4246185029Spjd zfs_cmd_t zc = { 0 }; 4247185029Spjd int error; 4248185029Spjd 4249185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4250185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4251209962Smm if (resource) 4252209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4253185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4254185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4255185029Spjd zc.zc_share.z_sharetype = operation; 4256185029Spjd zc.zc_share.z_sharemax = sharemax; 4257185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4258185029Spjd return (error); 4259185029Spjd} 4260185029Spjd 4261205198Sdelphijvoid 4262205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4263205198Sdelphij{ 4264205198Sdelphij nvpair_t *curr; 4265205198Sdelphij 4266205198Sdelphij /* 4267205198Sdelphij * Keep a reference to the props-table against which we prune the 4268205198Sdelphij * properties. 4269205198Sdelphij */ 4270205198Sdelphij zhp->zfs_props_table = props; 4271205198Sdelphij 4272205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4273205198Sdelphij 4274205198Sdelphij while (curr) { 4275205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4276205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4277205198Sdelphij 4278206199Sdelphij /* 4279219089Spjd * User properties will result in ZPROP_INVAL, and since we 4280219089Spjd * only know how to prune standard ZFS properties, we always 4281219089Spjd * leave these in the list. This can also happen if we 4282219089Spjd * encounter an unknown DSL property (when running older 4283219089Spjd * software, for example). 4284206199Sdelphij */ 4285206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4286205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4287205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4288205198Sdelphij curr = next; 4289205198Sdelphij } 4290205198Sdelphij} 4291205198Sdelphij 4292297077Smav#ifdef illumos 4293209962Smmstatic int 4294209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4295209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4296209962Smm{ 4297209962Smm zfs_cmd_t zc = { 0 }; 4298209962Smm nvlist_t *nvlist = NULL; 4299209962Smm int error; 4300209962Smm 4301209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4302209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4303209962Smm zc.zc_cookie = (uint64_t)cmd; 4304209962Smm 4305209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4306209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4307209962Smm (void) no_memory(hdl); 4308290758Smav return (0); 4309209962Smm } 4310209962Smm } 4311209962Smm 4312209962Smm switch (cmd) { 4313209962Smm case ZFS_SMB_ACL_ADD: 4314209962Smm case ZFS_SMB_ACL_REMOVE: 4315209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4316209962Smm break; 4317209962Smm case ZFS_SMB_ACL_RENAME: 4318209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4319209962Smm resource1) != 0) { 4320209962Smm (void) no_memory(hdl); 4321209962Smm return (-1); 4322209962Smm } 4323209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4324209962Smm resource2) != 0) { 4325209962Smm (void) no_memory(hdl); 4326209962Smm return (-1); 4327209962Smm } 4328209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4329209962Smm nvlist_free(nvlist); 4330209962Smm return (-1); 4331209962Smm } 4332209962Smm break; 4333209962Smm case ZFS_SMB_ACL_PURGE: 4334209962Smm break; 4335209962Smm default: 4336209962Smm return (-1); 4337209962Smm } 4338209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4339297115Smav nvlist_free(nvlist); 4340209962Smm return (error); 4341209962Smm} 4342209962Smm 4343209962Smmint 4344209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4345209962Smm char *path, char *resource) 4346209962Smm{ 4347209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4348209962Smm resource, NULL)); 4349209962Smm} 4350209962Smm 4351209962Smmint 4352209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4353209962Smm char *path, char *resource) 4354209962Smm{ 4355209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4356209962Smm resource, NULL)); 4357209962Smm} 4358209962Smm 4359209962Smmint 4360209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4361209962Smm{ 4362209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4363209962Smm NULL, NULL)); 4364209962Smm} 4365209962Smm 4366209962Smmint 4367209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4368209962Smm char *oldname, char *newname) 4369209962Smm{ 4370209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4371209962Smm oldname, newname)); 4372209962Smm} 4373297077Smav#endif /* illumos */ 4374209962Smm 4375209962Smmint 4376209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4377209962Smm zfs_userspace_cb_t func, void *arg) 4378209962Smm{ 4379209962Smm zfs_cmd_t zc = { 0 }; 4380209962Smm zfs_useracct_t buf[100]; 4381240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4382240415Smm int ret; 4383209962Smm 4384228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4385209962Smm 4386209962Smm zc.zc_objset_type = type; 4387209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4388209962Smm 4389240415Smm for (;;) { 4390209962Smm zfs_useracct_t *zua = buf; 4391209962Smm 4392209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4393240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4394248571Smm char errbuf[1024]; 4395240415Smm 4396240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4397240415Smm dgettext(TEXT_DOMAIN, 4398240415Smm "cannot get used/quota for %s"), zc.zc_name); 4399240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4400240415Smm } 4401240415Smm if (zc.zc_nvlist_dst_size == 0) 4402209962Smm break; 4403209962Smm 4404209962Smm while (zc.zc_nvlist_dst_size > 0) { 4405240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4406240415Smm zua->zu_space)) != 0) 4407240415Smm return (ret); 4408209962Smm zua++; 4409209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4410209962Smm } 4411209962Smm } 4412209962Smm 4413240415Smm return (0); 4414209962Smm} 4415209962Smm 4416248571Smmstruct holdarg { 4417248571Smm nvlist_t *nvl; 4418248571Smm const char *snapname; 4419248571Smm const char *tag; 4420248571Smm boolean_t recursive; 4421252219Sdelphij int error; 4422248571Smm}; 4423248571Smm 4424248571Smmstatic int 4425248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4426248571Smm{ 4427248571Smm struct holdarg *ha = arg; 4428307122Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4429248571Smm int rv = 0; 4430248571Smm 4431248571Smm (void) snprintf(name, sizeof (name), 4432248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4433248571Smm 4434251646Sdelphij if (lzc_exists(name)) 4435248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4436248571Smm 4437248571Smm if (ha->recursive) 4438248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4439248571Smm zfs_close(zhp); 4440248571Smm return (rv); 4441248571Smm} 4442248571Smm 4443219089Spjdint 4444219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4445251646Sdelphij boolean_t recursive, int cleanup_fd) 4446219089Spjd{ 4447248571Smm int ret; 4448248571Smm struct holdarg ha; 4449219089Spjd 4450248571Smm ha.nvl = fnvlist_alloc(); 4451248571Smm ha.snapname = snapname; 4452248571Smm ha.tag = tag; 4453248571Smm ha.recursive = recursive; 4454248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4455249357Smm 4456251646Sdelphij if (nvlist_empty(ha.nvl)) { 4457251646Sdelphij char errbuf[1024]; 4458251646Sdelphij 4459249357Smm fnvlist_free(ha.nvl); 4460249357Smm ret = ENOENT; 4461251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4462251646Sdelphij dgettext(TEXT_DOMAIN, 4463251646Sdelphij "cannot hold snapshot '%s@%s'"), 4464251646Sdelphij zhp->zfs_name, snapname); 4465251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4466249357Smm return (ret); 4467249357Smm } 4468249357Smm 4469251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4470248571Smm fnvlist_free(ha.nvl); 4471219089Spjd 4472251646Sdelphij return (ret); 4473251646Sdelphij} 4474251646Sdelphij 4475251646Sdelphijint 4476251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4477251646Sdelphij{ 4478251646Sdelphij int ret; 4479251646Sdelphij nvlist_t *errors; 4480251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4481251646Sdelphij char errbuf[1024]; 4482251646Sdelphij nvpair_t *elem; 4483251646Sdelphij 4484251646Sdelphij errors = NULL; 4485251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4486251646Sdelphij 4487251646Sdelphij if (ret == 0) { 4488251646Sdelphij /* There may be errors even in the success case. */ 4489251646Sdelphij fnvlist_free(errors); 4490248571Smm return (0); 4491251646Sdelphij } 4492219089Spjd 4493251646Sdelphij if (nvlist_empty(errors)) { 4494248571Smm /* no hold-specific errors */ 4495248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4496248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4497248571Smm switch (ret) { 4498248571Smm case ENOTSUP: 4499248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4500248571Smm "pool must be upgraded")); 4501248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4502248571Smm break; 4503248571Smm case EINVAL: 4504248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4505248571Smm break; 4506248571Smm default: 4507248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4508248571Smm } 4509248571Smm } 4510219089Spjd 4511248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4512248571Smm elem != NULL; 4513248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4514248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4515248571Smm dgettext(TEXT_DOMAIN, 4516248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4517248571Smm switch (fnvpair_value_int32(elem)) { 4518219089Spjd case E2BIG: 4519219089Spjd /* 4520219089Spjd * Temporary tags wind up having the ds object id 4521219089Spjd * prepended. So even if we passed the length check 4522219089Spjd * above, it's still possible for the tag to wind 4523219089Spjd * up being slightly too long. 4524219089Spjd */ 4525248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4526248571Smm break; 4527219089Spjd case EINVAL: 4528248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4529248571Smm break; 4530219089Spjd case EEXIST: 4531248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4532248571Smm break; 4533219089Spjd default: 4534248571Smm (void) zfs_standard_error(hdl, 4535248571Smm fnvpair_value_int32(elem), errbuf); 4536219089Spjd } 4537219089Spjd } 4538219089Spjd 4539248571Smm fnvlist_free(errors); 4540248571Smm return (ret); 4541219089Spjd} 4542219089Spjd 4543248571Smmstatic int 4544248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4545248571Smm{ 4546248571Smm struct holdarg *ha = arg; 4547307122Smav char name[ZFS_MAX_DATASET_NAME_LEN]; 4548248571Smm int rv = 0; 4549252219Sdelphij nvlist_t *existing_holds; 4550248571Smm 4551248571Smm (void) snprintf(name, sizeof (name), 4552248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4553248571Smm 4554252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4555252219Sdelphij ha->error = ENOENT; 4556252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4557252219Sdelphij ha->error = ESRCH; 4558252219Sdelphij } else { 4559252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4560252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4561252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4562252219Sdelphij fnvlist_free(torelease); 4563248571Smm } 4564248571Smm 4565248571Smm if (ha->recursive) 4566248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4567248571Smm zfs_close(zhp); 4568248571Smm return (rv); 4569248571Smm} 4570248571Smm 4571219089Spjdint 4572219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4573219089Spjd boolean_t recursive) 4574219089Spjd{ 4575248571Smm int ret; 4576248571Smm struct holdarg ha; 4577251646Sdelphij nvlist_t *errors = NULL; 4578248571Smm nvpair_t *elem; 4579219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4580249357Smm char errbuf[1024]; 4581219089Spjd 4582248571Smm ha.nvl = fnvlist_alloc(); 4583248571Smm ha.snapname = snapname; 4584248571Smm ha.tag = tag; 4585248571Smm ha.recursive = recursive; 4586252219Sdelphij ha.error = 0; 4587248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4588249357Smm 4589251646Sdelphij if (nvlist_empty(ha.nvl)) { 4590249357Smm fnvlist_free(ha.nvl); 4591252219Sdelphij ret = ha.error; 4592249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4593249357Smm dgettext(TEXT_DOMAIN, 4594249357Smm "cannot release hold from snapshot '%s@%s'"), 4595249357Smm zhp->zfs_name, snapname); 4596252219Sdelphij if (ret == ESRCH) { 4597252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4598252219Sdelphij } else { 4599252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4600252219Sdelphij } 4601249357Smm return (ret); 4602249357Smm } 4603249357Smm 4604248571Smm ret = lzc_release(ha.nvl, &errors); 4605248571Smm fnvlist_free(ha.nvl); 4606219089Spjd 4607251646Sdelphij if (ret == 0) { 4608251646Sdelphij /* There may be errors even in the success case. */ 4609251646Sdelphij fnvlist_free(errors); 4610248571Smm return (0); 4611251646Sdelphij } 4612219089Spjd 4613251646Sdelphij if (nvlist_empty(errors)) { 4614248571Smm /* no hold-specific errors */ 4615219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4616248571Smm "cannot release")); 4617219089Spjd switch (errno) { 4618219089Spjd case ENOTSUP: 4619219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4620219089Spjd "pool must be upgraded")); 4621248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4622248571Smm break; 4623248571Smm default: 4624248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4625248571Smm } 4626248571Smm } 4627248571Smm 4628248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4629248571Smm elem != NULL; 4630248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4631248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4632248571Smm dgettext(TEXT_DOMAIN, 4633248571Smm "cannot release hold from snapshot '%s'"), 4634248571Smm nvpair_name(elem)); 4635248571Smm switch (fnvpair_value_int32(elem)) { 4636248571Smm case ESRCH: 4637248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4638248571Smm break; 4639219089Spjd case EINVAL: 4640248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4641248571Smm break; 4642219089Spjd default: 4643248571Smm (void) zfs_standard_error_fmt(hdl, 4644248571Smm fnvpair_value_int32(elem), errbuf); 4645219089Spjd } 4646219089Spjd } 4647219089Spjd 4648248571Smm fnvlist_free(errors); 4649248571Smm return (ret); 4650219089Spjd} 4651219089Spjd 4652219089Spjdint 4653219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4654219089Spjd{ 4655219089Spjd zfs_cmd_t zc = { 0 }; 4656219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4657219089Spjd int nvsz = 2048; 4658219089Spjd void *nvbuf; 4659219089Spjd int err = 0; 4660248571Smm char errbuf[1024]; 4661219089Spjd 4662219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4663219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4664219089Spjd 4665219089Spjdtryagain: 4666219089Spjd 4667219089Spjd nvbuf = malloc(nvsz); 4668219089Spjd if (nvbuf == NULL) { 4669219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4670219089Spjd goto out; 4671219089Spjd } 4672219089Spjd 4673219089Spjd zc.zc_nvlist_dst_size = nvsz; 4674219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4675219089Spjd 4676307122Smav (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4677219089Spjd 4678230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 4679219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4680219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4681219089Spjd zc.zc_name); 4682219089Spjd switch (errno) { 4683219089Spjd case ENOMEM: 4684219089Spjd free(nvbuf); 4685219089Spjd nvsz = zc.zc_nvlist_dst_size; 4686219089Spjd goto tryagain; 4687219089Spjd 4688219089Spjd case ENOTSUP: 4689219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4690219089Spjd "pool must be upgraded")); 4691219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4692219089Spjd break; 4693219089Spjd case EINVAL: 4694219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4695219089Spjd break; 4696219089Spjd case ENOENT: 4697219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4698219089Spjd break; 4699219089Spjd default: 4700219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4701219089Spjd break; 4702219089Spjd } 4703219089Spjd } else { 4704219089Spjd /* success */ 4705219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4706219089Spjd if (rc) { 4707219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4708219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4709219089Spjd zc.zc_name); 4710219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4711219089Spjd } 4712219089Spjd } 4713219089Spjd 4714219089Spjd free(nvbuf); 4715219089Spjdout: 4716219089Spjd return (err); 4717219089Spjd} 4718219089Spjd 4719219089Spjdint 4720219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4721219089Spjd{ 4722219089Spjd zfs_cmd_t zc = { 0 }; 4723219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4724219089Spjd char *nvbuf; 4725248571Smm char errbuf[1024]; 4726219089Spjd size_t nvsz; 4727219089Spjd int err; 4728219089Spjd 4729219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4730219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4731219089Spjd 4732219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4733219089Spjd assert(err == 0); 4734219089Spjd 4735219089Spjd nvbuf = malloc(nvsz); 4736219089Spjd 4737219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4738219089Spjd assert(err == 0); 4739219089Spjd 4740219089Spjd zc.zc_nvlist_src_size = nvsz; 4741219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4742219089Spjd zc.zc_perm_action = un; 4743219089Spjd 4744219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4745219089Spjd 4746219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4747219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4748219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4749219089Spjd zc.zc_name); 4750219089Spjd switch (errno) { 4751219089Spjd case ENOTSUP: 4752219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4753219089Spjd "pool must be upgraded")); 4754219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4755219089Spjd break; 4756219089Spjd case EINVAL: 4757219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4758219089Spjd break; 4759219089Spjd case ENOENT: 4760219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4761219089Spjd break; 4762219089Spjd default: 4763219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4764219089Spjd break; 4765219089Spjd } 4766219089Spjd } 4767219089Spjd 4768219089Spjd free(nvbuf); 4769219089Spjd 4770219089Spjd return (err); 4771219089Spjd} 4772219089Spjd 4773219089Spjdint 4774219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4775219089Spjd{ 4776248571Smm int err; 4777248571Smm char errbuf[1024]; 4778219089Spjd 4779248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 4780219089Spjd 4781248571Smm if (err != 0) { 4782248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4783219089Spjd 4784219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4785219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4786248571Smm zhp->zfs_name); 4787248571Smm switch (err) { 4788219089Spjd case ENOTSUP: 4789219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4790219089Spjd "pool must be upgraded")); 4791219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4792219089Spjd break; 4793219089Spjd case EINVAL: 4794219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4795219089Spjd break; 4796219089Spjd case ENOENT: 4797219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4798219089Spjd break; 4799219089Spjd default: 4800219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4801219089Spjd break; 4802219089Spjd } 4803219089Spjd } 4804219089Spjd 4805219089Spjd return (err); 4806219089Spjd} 4807219089Spjd 4808251629Sdelphij/* 4809251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 4810251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 4811251629Sdelphij * suite's shell version in reservation.kshlib. 4812251629Sdelphij */ 4813219089Spjduint64_t 4814219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4815219089Spjd{ 4816219089Spjd uint64_t numdb; 4817219089Spjd uint64_t nblocks, volblocksize; 4818219089Spjd int ncopies; 4819219089Spjd char *strval; 4820219089Spjd 4821219089Spjd if (nvlist_lookup_string(props, 4822219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4823219089Spjd ncopies = atoi(strval); 4824219089Spjd else 4825219089Spjd ncopies = 1; 4826219089Spjd if (nvlist_lookup_uint64(props, 4827219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4828219089Spjd &volblocksize) != 0) 4829219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4830219089Spjd nblocks = volsize/volblocksize; 4831219089Spjd /* start with metadnode L0-L6 */ 4832219089Spjd numdb = 7; 4833219089Spjd /* calculate number of indirects */ 4834219089Spjd while (nblocks > 1) { 4835219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4836219089Spjd nblocks /= DNODES_PER_LEVEL; 4837219089Spjd numdb += nblocks; 4838219089Spjd } 4839219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4840219089Spjd volsize *= ncopies; 4841219089Spjd /* 4842219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4843219089Spjd * compressed, but in practice they compress down to about 4844219089Spjd * 1100 bytes 4845219089Spjd */ 4846219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4847219089Spjd volsize += numdb; 4848219089Spjd return (volsize); 4849219089Spjd} 4850219089Spjd 4851168404Spjd/* 4852168404Spjd * Attach/detach the given filesystem to/from the given jail. 4853168404Spjd */ 4854168404Spjdint 4855168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4856168404Spjd{ 4857168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4858168404Spjd zfs_cmd_t zc = { 0 }; 4859168404Spjd char errbuf[1024]; 4860224525Smm unsigned long cmd; 4861224525Smm int ret; 4862168404Spjd 4863168404Spjd if (attach) { 4864168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4865168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4866168404Spjd } else { 4867168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4868249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 4869168404Spjd } 4870168404Spjd 4871168404Spjd switch (zhp->zfs_type) { 4872168404Spjd case ZFS_TYPE_VOLUME: 4873168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4874168404Spjd "volumes can not be jailed")); 4875168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4876168404Spjd case ZFS_TYPE_SNAPSHOT: 4877168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4878168404Spjd "snapshots can not be jailed")); 4879168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4880168404Spjd } 4881168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4882168404Spjd 4883168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4884168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4885168404Spjd zc.zc_jailid = jailid; 4886168404Spjd 4887168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4888168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4889168404Spjd zfs_standard_error(hdl, errno, errbuf); 4890168404Spjd 4891168404Spjd return (ret); 4892168404Spjd} 4893