libzfs_dataset.c revision 296528
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24264835Sdelphij * Copyright (c) 2013, Joyent, Inc. All rights reserved. 25289500Smav * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 26252219Sdelphij * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 27230438Spjd * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>. 28226706Spjd * All rights reserved. 29235216Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 30251646Sdelphij * Copyright (c) 2013 Steven Hartland. All rights reserved. 31259850Sdelphij * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 32296519Smav * Copyright (c) 2014 Integros [integros.com] 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")); 82168404Spjd } 83168404Spjd 84168404Spjd return (NULL); 85168404Spjd} 86168404Spjd 87168404Spjd/* 88168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 89168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 90168404Spjd * We guess what the type would have been based on the path and the mask of 91168404Spjd * acceptable types. 92168404Spjd */ 93168404Spjdstatic const char * 94168404Spjdpath_to_str(const char *path, int types) 95168404Spjd{ 96168404Spjd /* 97168404Spjd * When given a single type, always report the exact type. 98168404Spjd */ 99168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 100168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 101168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 102168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 103168404Spjd if (types == ZFS_TYPE_VOLUME) 104168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 105168404Spjd 106168404Spjd /* 107168404Spjd * The user is requesting more than one type of dataset. If this is the 108168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 109168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 110168404Spjd * snapshot attribute and try again. 111168404Spjd */ 112168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 113168404Spjd if (strchr(path, '@') != NULL) 114168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 115168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 116168404Spjd } 117168404Spjd 118168404Spjd /* 119168404Spjd * The user has requested either filesystems or volumes. 120168404Spjd * We have no way of knowing a priori what type this would be, so always 121168404Spjd * report it as "filesystem" or "volume", our two primitive types. 122168404Spjd */ 123168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 124168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 125168404Spjd 126168404Spjd assert(types & ZFS_TYPE_VOLUME); 127168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 128168404Spjd} 129168404Spjd 130168404Spjd/* 131168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 132209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 133209962Smm * explain exactly why the name was not valid. 134168404Spjd */ 135219089Spjdint 136185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 137185029Spjd boolean_t modifying) 138168404Spjd{ 139168404Spjd namecheck_err_t why; 140168404Spjd char what; 141168404Spjd 142219089Spjd (void) zfs_prop_get_table(); 143168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 144168404Spjd if (hdl != NULL) { 145168404Spjd switch (why) { 146168404Spjd case NAME_ERR_TOOLONG: 147168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 148168404Spjd "name is too long")); 149168404Spjd break; 150168404Spjd 151168404Spjd case NAME_ERR_LEADING_SLASH: 152168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 153168404Spjd "leading slash in name")); 154168404Spjd break; 155168404Spjd 156168404Spjd case NAME_ERR_EMPTY_COMPONENT: 157168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 158168404Spjd "empty component in name")); 159168404Spjd break; 160168404Spjd 161168404Spjd case NAME_ERR_TRAILING_SLASH: 162168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 163168404Spjd "trailing slash in name")); 164168404Spjd break; 165168404Spjd 166168404Spjd case NAME_ERR_INVALCHAR: 167168404Spjd zfs_error_aux(hdl, 168168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 169168404Spjd "'%c' in name"), what); 170168404Spjd break; 171168404Spjd 172168404Spjd case NAME_ERR_MULTIPLE_AT: 173168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 174168404Spjd "multiple '@' delimiters in name")); 175168404Spjd break; 176168404Spjd 177168404Spjd case NAME_ERR_NOLETTER: 178168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 179168404Spjd "pool doesn't begin with a letter")); 180168404Spjd break; 181168404Spjd 182168404Spjd case NAME_ERR_RESERVED: 183168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 184168404Spjd "name is reserved")); 185168404Spjd break; 186168404Spjd 187168404Spjd case NAME_ERR_DISKLIKE: 188168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 189168404Spjd "reserved disk name")); 190168404Spjd break; 191168404Spjd } 192168404Spjd } 193168404Spjd 194168404Spjd return (0); 195168404Spjd } 196168404Spjd 197168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 198168404Spjd if (hdl != NULL) 199168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 200168404Spjd "snapshot delimiter '@' in filesystem name")); 201168404Spjd return (0); 202168404Spjd } 203168404Spjd 204168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 205168404Spjd if (hdl != NULL) 206168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 207168404Spjd "missing '@' delimiter in snapshot name")); 208168404Spjd return (0); 209168404Spjd } 210168404Spjd 211185029Spjd if (modifying && strchr(path, '%') != NULL) { 212185029Spjd if (hdl != NULL) 213185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 214185029Spjd "invalid character %c in name"), '%'); 215185029Spjd return (0); 216185029Spjd } 217185029Spjd 218168404Spjd return (-1); 219168404Spjd} 220168404Spjd 221168404Spjdint 222168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 223168404Spjd{ 224185029Spjd if (type == ZFS_TYPE_POOL) 225185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 226185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 227168404Spjd} 228168404Spjd 229168404Spjd/* 230168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 231168404Spjd * properties into a separate nvlist. 232168404Spjd */ 233185029Spjdstatic nvlist_t * 234185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 235168404Spjd{ 236168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 237168404Spjd nvpair_t *elem; 238168404Spjd nvlist_t *propval; 239185029Spjd nvlist_t *nvl; 240168404Spjd 241185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 242185029Spjd (void) no_memory(hdl); 243185029Spjd return (NULL); 244185029Spjd } 245168404Spjd 246168404Spjd elem = NULL; 247185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 248168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 249168404Spjd continue; 250168404Spjd 251168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 252185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 253185029Spjd nvlist_free(nvl); 254185029Spjd (void) no_memory(hdl); 255185029Spjd return (NULL); 256185029Spjd } 257168404Spjd } 258168404Spjd 259185029Spjd return (nvl); 260168404Spjd} 261168404Spjd 262185029Spjdstatic zpool_handle_t * 263185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 264185029Spjd{ 265185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 266185029Spjd zpool_handle_t *zph; 267185029Spjd 268185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 269185029Spjd if (hdl->libzfs_pool_handles != NULL) 270185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 271185029Spjd hdl->libzfs_pool_handles = zph; 272185029Spjd } 273185029Spjd return (zph); 274185029Spjd} 275185029Spjd 276185029Spjdstatic zpool_handle_t * 277185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 278185029Spjd{ 279185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 280185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 281185029Spjd 282185029Spjd while ((zph != NULL) && 283185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 284185029Spjd zph = zph->zpool_next; 285185029Spjd return (zph); 286185029Spjd} 287185029Spjd 288168404Spjd/* 289185029Spjd * Returns a handle to the pool that contains the provided dataset. 290185029Spjd * If a handle to that pool already exists then that handle is returned. 291185029Spjd * Otherwise, a new handle is created and added to the list of handles. 292185029Spjd */ 293185029Spjdstatic zpool_handle_t * 294185029Spjdzpool_handle(zfs_handle_t *zhp) 295185029Spjd{ 296185029Spjd char *pool_name; 297185029Spjd int len; 298185029Spjd zpool_handle_t *zph; 299185029Spjd 300260183Sdelphij len = strcspn(zhp->zfs_name, "/@#") + 1; 301185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 302185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 303185029Spjd 304185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 305185029Spjd if (zph == NULL) 306185029Spjd zph = zpool_add_handle(zhp, pool_name); 307185029Spjd 308185029Spjd free(pool_name); 309185029Spjd return (zph); 310185029Spjd} 311185029Spjd 312185029Spjdvoid 313185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 314185029Spjd{ 315185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 316185029Spjd 317185029Spjd while (zph != NULL) { 318185029Spjd next = zph->zpool_next; 319185029Spjd zpool_close(zph); 320185029Spjd zph = next; 321185029Spjd } 322185029Spjd hdl->libzfs_pool_handles = NULL; 323185029Spjd} 324185029Spjd 325185029Spjd/* 326168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 327168404Spjd */ 328219089Spjdstatic int 329209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 330168404Spjd{ 331168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 332168404Spjd 333209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 334168404Spjd 335209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 336168404Spjd if (errno == ENOMEM) { 337209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 338168404Spjd return (-1); 339168404Spjd } 340168404Spjd } else { 341168404Spjd return (-1); 342168404Spjd } 343168404Spjd } 344209962Smm return (0); 345209962Smm} 346168404Spjd 347219089Spjd/* 348219089Spjd * Utility function to get the received properties of the given object. 349219089Spjd */ 350209962Smmstatic int 351219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 352219089Spjd{ 353219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 354219089Spjd nvlist_t *recvdprops; 355219089Spjd zfs_cmd_t zc = { 0 }; 356219089Spjd int err; 357219089Spjd 358219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 359219089Spjd return (-1); 360219089Spjd 361219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 362219089Spjd 363219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 364219089Spjd if (errno == ENOMEM) { 365219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 366219089Spjd return (-1); 367219089Spjd } 368219089Spjd } else { 369219089Spjd zcmd_free_nvlists(&zc); 370219089Spjd return (-1); 371219089Spjd } 372219089Spjd } 373219089Spjd 374219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 375219089Spjd zcmd_free_nvlists(&zc); 376219089Spjd if (err != 0) 377219089Spjd return (-1); 378219089Spjd 379219089Spjd nvlist_free(zhp->zfs_recvd_props); 380219089Spjd zhp->zfs_recvd_props = recvdprops; 381219089Spjd 382219089Spjd return (0); 383219089Spjd} 384219089Spjd 385219089Spjdstatic int 386209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 387209962Smm{ 388209962Smm nvlist_t *allprops, *userprops; 389168404Spjd 390209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 391209962Smm 392209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 393168404Spjd return (-1); 394168404Spjd } 395168404Spjd 396209962Smm /* 397209962Smm * XXX Why do we store the user props separately, in addition to 398209962Smm * storing them in zfs_props? 399209962Smm */ 400185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 401185029Spjd nvlist_free(allprops); 402168404Spjd return (-1); 403185029Spjd } 404168404Spjd 405185029Spjd nvlist_free(zhp->zfs_props); 406185029Spjd nvlist_free(zhp->zfs_user_props); 407185029Spjd 408185029Spjd zhp->zfs_props = allprops; 409185029Spjd zhp->zfs_user_props = userprops; 410185029Spjd 411168404Spjd return (0); 412168404Spjd} 413168404Spjd 414209962Smmstatic int 415209962Smmget_stats(zfs_handle_t *zhp) 416209962Smm{ 417209962Smm int rc = 0; 418209962Smm zfs_cmd_t zc = { 0 }; 419209962Smm 420209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 421209962Smm return (-1); 422209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 423209962Smm rc = -1; 424209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 425209962Smm rc = -1; 426209962Smm zcmd_free_nvlists(&zc); 427209962Smm return (rc); 428209962Smm} 429209962Smm 430168404Spjd/* 431168404Spjd * Refresh the properties currently stored in the handle. 432168404Spjd */ 433168404Spjdvoid 434168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 435168404Spjd{ 436168404Spjd (void) get_stats(zhp); 437168404Spjd} 438168404Spjd 439168404Spjd/* 440168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 441168404Spjd * zfs_iter_* to create child handles on the fly. 442168404Spjd */ 443209962Smmstatic int 444209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 445168404Spjd{ 446219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 447209962Smm return (-1); 448168404Spjd 449168404Spjd /* 450168404Spjd * We've managed to open the dataset and gather statistics. Determine 451168404Spjd * the high-level type. 452168404Spjd */ 453168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 454168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 455168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 456168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 457168404Spjd else 458168404Spjd abort(); 459168404Spjd 460168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 461168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 462168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 463168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 464168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 465168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 466168404Spjd else 467168404Spjd abort(); /* we should never see any other types */ 468168404Spjd 469219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 470219089Spjd return (-1); 471219089Spjd 472209962Smm return (0); 473209962Smm} 474209962Smm 475209962Smmzfs_handle_t * 476209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 477209962Smm{ 478209962Smm zfs_cmd_t zc = { 0 }; 479209962Smm 480209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 481209962Smm 482209962Smm if (zhp == NULL) 483209962Smm return (NULL); 484209962Smm 485209962Smm zhp->zfs_hdl = hdl; 486209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 487209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 488209962Smm free(zhp); 489209962Smm return (NULL); 490209962Smm } 491209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 492209962Smm zcmd_free_nvlists(&zc); 493209962Smm free(zhp); 494209962Smm return (NULL); 495209962Smm } 496209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 497209962Smm free(zhp); 498209962Smm zhp = NULL; 499209962Smm } 500209962Smm zcmd_free_nvlists(&zc); 501168404Spjd return (zhp); 502168404Spjd} 503168404Spjd 504228103Smmzfs_handle_t * 505209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 506209962Smm{ 507209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 508209962Smm 509209962Smm if (zhp == NULL) 510209962Smm return (NULL); 511209962Smm 512209962Smm zhp->zfs_hdl = hdl; 513209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 514209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 515209962Smm free(zhp); 516209962Smm return (NULL); 517209962Smm } 518209962Smm return (zhp); 519209962Smm} 520209962Smm 521228103Smmzfs_handle_t * 522230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 523230438Spjd{ 524230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 525230438Spjd 526230438Spjd if (zhp == NULL) 527230438Spjd return (NULL); 528230438Spjd 529230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 530230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 531230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 532230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 533230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 534230438Spjd return (zhp); 535230438Spjd} 536230438Spjd 537230438Spjdzfs_handle_t * 538228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 539228103Smm{ 540228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 541228103Smm 542228103Smm if (zhp == NULL) 543228103Smm return (NULL); 544228103Smm 545228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 546228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 547228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 548228103Smm sizeof (zhp->zfs_name)); 549228103Smm zhp->zfs_type = zhp_orig->zfs_type; 550228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 551228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 552228103Smm if (zhp_orig->zfs_props != NULL) { 553228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 554228103Smm (void) no_memory(zhp->zfs_hdl); 555228103Smm zfs_close(zhp); 556228103Smm return (NULL); 557228103Smm } 558228103Smm } 559228103Smm if (zhp_orig->zfs_user_props != NULL) { 560228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 561228103Smm &zhp->zfs_user_props, 0) != 0) { 562228103Smm (void) no_memory(zhp->zfs_hdl); 563228103Smm zfs_close(zhp); 564228103Smm return (NULL); 565228103Smm } 566228103Smm } 567228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 568228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 569228103Smm &zhp->zfs_recvd_props, 0)) { 570228103Smm (void) no_memory(zhp->zfs_hdl); 571228103Smm zfs_close(zhp); 572228103Smm return (NULL); 573228103Smm } 574228103Smm } 575228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 576228103Smm if (zhp_orig->zfs_mntopts != NULL) { 577228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 578228103Smm zhp_orig->zfs_mntopts); 579228103Smm } 580228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 581228103Smm return (zhp); 582228103Smm} 583228103Smm 584260183Sdelphijboolean_t 585260183Sdelphijzfs_bookmark_exists(const char *path) 586260183Sdelphij{ 587260183Sdelphij nvlist_t *bmarks; 588260183Sdelphij nvlist_t *props; 589260183Sdelphij char fsname[ZFS_MAXNAMELEN]; 590260183Sdelphij char *bmark_name; 591260183Sdelphij char *pound; 592260183Sdelphij int err; 593260183Sdelphij boolean_t rv; 594260183Sdelphij 595260183Sdelphij 596260183Sdelphij (void) strlcpy(fsname, path, sizeof (fsname)); 597260183Sdelphij pound = strchr(fsname, '#'); 598260183Sdelphij if (pound == NULL) 599260183Sdelphij return (B_FALSE); 600260183Sdelphij 601260183Sdelphij *pound = '\0'; 602260183Sdelphij bmark_name = pound + 1; 603260183Sdelphij props = fnvlist_alloc(); 604260183Sdelphij err = lzc_get_bookmarks(fsname, props, &bmarks); 605260183Sdelphij nvlist_free(props); 606260183Sdelphij if (err != 0) { 607260183Sdelphij nvlist_free(bmarks); 608260183Sdelphij return (B_FALSE); 609260183Sdelphij } 610260183Sdelphij 611260183Sdelphij rv = nvlist_exists(bmarks, bmark_name); 612260183Sdelphij nvlist_free(bmarks); 613260183Sdelphij return (rv); 614260183Sdelphij} 615260183Sdelphij 616260183Sdelphijzfs_handle_t * 617260183Sdelphijmake_bookmark_handle(zfs_handle_t *parent, const char *path, 618260183Sdelphij nvlist_t *bmark_props) 619260183Sdelphij{ 620260183Sdelphij zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 621260183Sdelphij 622260183Sdelphij if (zhp == NULL) 623260183Sdelphij return (NULL); 624260183Sdelphij 625260183Sdelphij /* Fill in the name. */ 626260183Sdelphij zhp->zfs_hdl = parent->zfs_hdl; 627260183Sdelphij (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 628260183Sdelphij 629260183Sdelphij /* Set the property lists. */ 630260183Sdelphij if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 631260183Sdelphij free(zhp); 632260183Sdelphij return (NULL); 633260183Sdelphij } 634260183Sdelphij 635260183Sdelphij /* Set the types. */ 636260183Sdelphij zhp->zfs_head_type = parent->zfs_head_type; 637260183Sdelphij zhp->zfs_type = ZFS_TYPE_BOOKMARK; 638260183Sdelphij 639260183Sdelphij if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 640260183Sdelphij nvlist_free(zhp->zfs_props); 641260183Sdelphij free(zhp); 642260183Sdelphij return (NULL); 643260183Sdelphij } 644260183Sdelphij 645260183Sdelphij return (zhp); 646260183Sdelphij} 647260183Sdelphij 648168404Spjd/* 649168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 650168404Spjd * argument is a mask of acceptable types. The function will print an 651168404Spjd * appropriate error message and return NULL if it can't be opened. 652168404Spjd */ 653168404Spjdzfs_handle_t * 654168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 655168404Spjd{ 656168404Spjd zfs_handle_t *zhp; 657168404Spjd char errbuf[1024]; 658168404Spjd 659168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 660168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 661168404Spjd 662168404Spjd /* 663168404Spjd * Validate the name before we even try to open it. 664168404Spjd */ 665185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 666168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 667168404Spjd "invalid dataset name")); 668168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 669168404Spjd return (NULL); 670168404Spjd } 671168404Spjd 672168404Spjd /* 673168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 674168404Spjd */ 675168404Spjd errno = 0; 676168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 677168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 678168404Spjd return (NULL); 679168404Spjd } 680168404Spjd 681240870Spjd if (zhp == NULL) { 682240870Spjd char *at = strchr(path, '@'); 683240870Spjd 684240870Spjd if (at != NULL) 685240870Spjd *at = '\0'; 686240870Spjd errno = 0; 687240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 688240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 689240870Spjd return (NULL); 690240870Spjd } 691240870Spjd if (at != NULL) 692240870Spjd *at = '@'; 693240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 694240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 695240870Spjd } 696240870Spjd 697168404Spjd if (!(types & zhp->zfs_type)) { 698168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 699168404Spjd zfs_close(zhp); 700168404Spjd return (NULL); 701168404Spjd } 702168404Spjd 703168404Spjd return (zhp); 704168404Spjd} 705168404Spjd 706168404Spjd/* 707168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 708168404Spjd */ 709168404Spjdvoid 710168404Spjdzfs_close(zfs_handle_t *zhp) 711168404Spjd{ 712168404Spjd if (zhp->zfs_mntopts) 713168404Spjd free(zhp->zfs_mntopts); 714168404Spjd nvlist_free(zhp->zfs_props); 715168404Spjd nvlist_free(zhp->zfs_user_props); 716219089Spjd nvlist_free(zhp->zfs_recvd_props); 717168404Spjd free(zhp); 718168404Spjd} 719168404Spjd 720209962Smmtypedef struct mnttab_node { 721209962Smm struct mnttab mtn_mt; 722209962Smm avl_node_t mtn_node; 723209962Smm} mnttab_node_t; 724209962Smm 725209962Smmstatic int 726209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 727209962Smm{ 728209962Smm const mnttab_node_t *mtn1 = arg1; 729209962Smm const mnttab_node_t *mtn2 = arg2; 730209962Smm int rv; 731209962Smm 732209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 733209962Smm 734209962Smm if (rv == 0) 735209962Smm return (0); 736209962Smm return (rv > 0 ? 1 : -1); 737209962Smm} 738209962Smm 739209962Smmvoid 740209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 741209962Smm{ 742209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 743209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 744209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 745209962Smm} 746209962Smm 747209962Smmvoid 748209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 749209962Smm{ 750209962Smm struct mnttab entry; 751209962Smm 752209962Smm rewind(hdl->libzfs_mnttab); 753209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 754209962Smm mnttab_node_t *mtn; 755209962Smm 756209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 757209962Smm continue; 758209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 759209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 760209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 761209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 762209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 763209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 764209962Smm } 765209962Smm} 766209962Smm 767209962Smmvoid 768209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 769209962Smm{ 770209962Smm void *cookie = NULL; 771209962Smm mnttab_node_t *mtn; 772209962Smm 773209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 774209962Smm free(mtn->mtn_mt.mnt_special); 775209962Smm free(mtn->mtn_mt.mnt_mountp); 776209962Smm free(mtn->mtn_mt.mnt_fstype); 777209962Smm free(mtn->mtn_mt.mnt_mntopts); 778209962Smm free(mtn); 779209962Smm } 780209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 781209962Smm} 782209962Smm 783209962Smmvoid 784209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 785209962Smm{ 786209962Smm hdl->libzfs_mnttab_enable = enable; 787209962Smm} 788209962Smm 789185029Spjdint 790209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 791209962Smm struct mnttab *entry) 792209962Smm{ 793209962Smm mnttab_node_t find; 794209962Smm mnttab_node_t *mtn; 795209962Smm 796209962Smm if (!hdl->libzfs_mnttab_enable) { 797209962Smm struct mnttab srch = { 0 }; 798209962Smm 799209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 800209962Smm libzfs_mnttab_fini(hdl); 801209962Smm rewind(hdl->libzfs_mnttab); 802209962Smm srch.mnt_special = (char *)fsname; 803209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 804209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 805209962Smm return (0); 806209962Smm else 807209962Smm return (ENOENT); 808209962Smm } 809209962Smm 810209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 811209962Smm libzfs_mnttab_update(hdl); 812209962Smm 813209962Smm find.mtn_mt.mnt_special = (char *)fsname; 814209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 815209962Smm if (mtn) { 816209962Smm *entry = mtn->mtn_mt; 817209962Smm return (0); 818209962Smm } 819209962Smm return (ENOENT); 820209962Smm} 821209962Smm 822209962Smmvoid 823209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 824209962Smm const char *mountp, const char *mntopts) 825209962Smm{ 826209962Smm mnttab_node_t *mtn; 827209962Smm 828209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 829209962Smm return; 830209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 831209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 832209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 833209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 834209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 835209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 836209962Smm} 837209962Smm 838209962Smmvoid 839209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 840209962Smm{ 841209962Smm mnttab_node_t find; 842209962Smm mnttab_node_t *ret; 843209962Smm 844209962Smm find.mtn_mt.mnt_special = (char *)fsname; 845209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 846209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 847209962Smm free(ret->mtn_mt.mnt_special); 848209962Smm free(ret->mtn_mt.mnt_mountp); 849209962Smm free(ret->mtn_mt.mnt_fstype); 850209962Smm free(ret->mtn_mt.mnt_mntopts); 851209962Smm free(ret); 852209962Smm } 853209962Smm} 854209962Smm 855209962Smmint 856185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 857168404Spjd{ 858185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 859168404Spjd 860185029Spjd if (zpool_handle == NULL) 861168404Spjd return (-1); 862168404Spjd 863185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 864185029Spjd ZPOOL_PROP_VERSION, NULL); 865168404Spjd return (0); 866168404Spjd} 867168404Spjd 868168404Spjd/* 869185029Spjd * The choice of reservation property depends on the SPA version. 870168404Spjd */ 871168404Spjdstatic int 872185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 873168404Spjd{ 874185029Spjd int spa_version; 875168404Spjd 876185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 877168404Spjd return (-1); 878168404Spjd 879185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 880185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 881185029Spjd else 882185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 883168404Spjd 884168404Spjd return (0); 885168404Spjd} 886168404Spjd 887168404Spjd/* 888168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 889168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 890168404Spjd * strings. 891168404Spjd */ 892168404Spjdnvlist_t * 893185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 894289500Smav uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl, 895289500Smav const char *errbuf) 896168404Spjd{ 897168404Spjd nvpair_t *elem; 898168404Spjd uint64_t intval; 899168404Spjd char *strval; 900185029Spjd zfs_prop_t prop; 901168404Spjd nvlist_t *ret; 902185029Spjd int chosen_normal = -1; 903185029Spjd int chosen_utf = -1; 904168404Spjd 905168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 906168404Spjd (void) no_memory(hdl); 907168404Spjd return (NULL); 908168404Spjd } 909168404Spjd 910209962Smm /* 911209962Smm * Make sure this property is valid and applies to this type. 912209962Smm */ 913209962Smm 914168404Spjd elem = NULL; 915168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 916185029Spjd const char *propname = nvpair_name(elem); 917168404Spjd 918209962Smm prop = zfs_name_to_prop(propname); 919209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 920185029Spjd /* 921209962Smm * This is a user property: make sure it's a 922185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 923185029Spjd */ 924185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 925185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 926185029Spjd "'%s' must be a string"), propname); 927185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 928185029Spjd goto error; 929168404Spjd } 930168404Spjd 931185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 932185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 933185029Spjd "property name '%s' is too long"), 934185029Spjd propname); 935185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 936185029Spjd goto error; 937185029Spjd } 938185029Spjd 939168404Spjd (void) nvpair_value_string(elem, &strval); 940168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 941168404Spjd (void) no_memory(hdl); 942168404Spjd goto error; 943168404Spjd } 944168404Spjd continue; 945168404Spjd } 946168404Spjd 947209962Smm /* 948209962Smm * Currently, only user properties can be modified on 949209962Smm * snapshots. 950209962Smm */ 951185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 952185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 953185029Spjd "this property can not be modified for snapshots")); 954185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 955185029Spjd goto error; 956185029Spjd } 957168404Spjd 958209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 959209962Smm zfs_userquota_prop_t uqtype; 960209962Smm char newpropname[128]; 961209962Smm char domain[128]; 962209962Smm uint64_t rid; 963209962Smm uint64_t valary[3]; 964209962Smm 965209962Smm if (userquota_propname_decode(propname, zoned, 966209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 967209962Smm zfs_error_aux(hdl, 968209962Smm dgettext(TEXT_DOMAIN, 969209962Smm "'%s' has an invalid user/group name"), 970209962Smm propname); 971209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 972209962Smm goto error; 973209962Smm } 974209962Smm 975209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 976209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 977209962Smm zfs_error_aux(hdl, 978209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 979209962Smm propname); 980209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 981209962Smm errbuf); 982209962Smm goto error; 983209962Smm } 984209962Smm 985209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 986209962Smm (void) nvpair_value_string(elem, &strval); 987209962Smm if (strcmp(strval, "none") == 0) { 988209962Smm intval = 0; 989209962Smm } else if (zfs_nicestrtonum(hdl, 990209962Smm strval, &intval) != 0) { 991209962Smm (void) zfs_error(hdl, 992209962Smm EZFS_BADPROP, errbuf); 993209962Smm goto error; 994209962Smm } 995209962Smm } else if (nvpair_type(elem) == 996209962Smm DATA_TYPE_UINT64) { 997209962Smm (void) nvpair_value_uint64(elem, &intval); 998209962Smm if (intval == 0) { 999209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1000209962Smm "use 'none' to disable " 1001209962Smm "userquota/groupquota")); 1002209962Smm goto error; 1003209962Smm } 1004209962Smm } else { 1005209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1006209962Smm "'%s' must be a number"), propname); 1007209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1008209962Smm goto error; 1009209962Smm } 1010209962Smm 1011219089Spjd /* 1012219089Spjd * Encode the prop name as 1013219089Spjd * userquota@<hex-rid>-domain, to make it easy 1014219089Spjd * for the kernel to decode. 1015219089Spjd */ 1016209962Smm (void) snprintf(newpropname, sizeof (newpropname), 1017219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 1018219089Spjd (longlong_t)rid, domain); 1019209962Smm valary[0] = uqtype; 1020209962Smm valary[1] = rid; 1021209962Smm valary[2] = intval; 1022209962Smm if (nvlist_add_uint64_array(ret, newpropname, 1023209962Smm valary, 3) != 0) { 1024209962Smm (void) no_memory(hdl); 1025209962Smm goto error; 1026209962Smm } 1027209962Smm continue; 1028228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 1029228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1030228103Smm "'%s' is readonly"), 1031228103Smm propname); 1032228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1033228103Smm goto error; 1034209962Smm } 1035209962Smm 1036209962Smm if (prop == ZPROP_INVAL) { 1037209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1038209962Smm "invalid property '%s'"), propname); 1039209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1040209962Smm goto error; 1041209962Smm } 1042209962Smm 1043168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 1044168404Spjd zfs_error_aux(hdl, 1045168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 1046168404Spjd "apply to datasets of this type"), propname); 1047168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1048168404Spjd goto error; 1049168404Spjd } 1050168404Spjd 1051168404Spjd if (zfs_prop_readonly(prop) && 1052185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 1053168404Spjd zfs_error_aux(hdl, 1054168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1055168404Spjd propname); 1056168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1057168404Spjd goto error; 1058168404Spjd } 1059168404Spjd 1060185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 1061185029Spjd &strval, &intval, errbuf) != 0) 1062185029Spjd goto error; 1063185029Spjd 1064168404Spjd /* 1065185029Spjd * Perform some additional checks for specific properties. 1066168404Spjd */ 1067185029Spjd switch (prop) { 1068185029Spjd case ZFS_PROP_VERSION: 1069185029Spjd { 1070185029Spjd int version; 1071168404Spjd 1072185029Spjd if (zhp == NULL) 1073185029Spjd break; 1074185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1075185029Spjd if (intval < version) { 1076168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1077185029Spjd "Can not downgrade; already at version %u"), 1078185029Spjd version); 1079168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1080168404Spjd goto error; 1081168404Spjd } 1082168404Spjd break; 1083168404Spjd } 1084168404Spjd 1085274337Sdelphij case ZFS_PROP_VOLBLOCKSIZE: 1086168404Spjd case ZFS_PROP_RECORDSIZE: 1087274337Sdelphij { 1088274337Sdelphij int maxbs = SPA_MAXBLOCKSIZE; 1089289500Smav if (zpool_hdl != NULL) { 1090289500Smav maxbs = zpool_get_prop_int(zpool_hdl, 1091274337Sdelphij ZPOOL_PROP_MAXBLOCKSIZE, NULL); 1092274337Sdelphij } 1093274337Sdelphij /* 1094274337Sdelphij * Volumes are limited to a volblocksize of 128KB, 1095274337Sdelphij * because they typically service workloads with 1096274337Sdelphij * small random writes, which incur a large performance 1097274337Sdelphij * penalty with large blocks. 1098274337Sdelphij */ 1099274337Sdelphij if (prop == ZFS_PROP_VOLBLOCKSIZE) 1100274337Sdelphij maxbs = SPA_OLD_MAXBLOCKSIZE; 1101274337Sdelphij /* 1102274337Sdelphij * The value must be a power of two between 1103274337Sdelphij * SPA_MINBLOCKSIZE and maxbs. 1104274337Sdelphij */ 1105168404Spjd if (intval < SPA_MINBLOCKSIZE || 1106274337Sdelphij intval > maxbs || !ISP2(intval)) { 1107168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1108274337Sdelphij "'%s' must be power of 2 from 512B " 1109274337Sdelphij "to %uKB"), propname, maxbs >> 10); 1110168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1111168404Spjd goto error; 1112168404Spjd } 1113168404Spjd break; 1114274337Sdelphij } 1115219089Spjd case ZFS_PROP_MLSLABEL: 1116219089Spjd { 1117277300Ssmh#ifdef illumos 1118219089Spjd /* 1119219089Spjd * Verify the mlslabel string and convert to 1120219089Spjd * internal hex label string. 1121219089Spjd */ 1122219089Spjd 1123219089Spjd m_label_t *new_sl; 1124219089Spjd char *hex = NULL; /* internal label string */ 1125219089Spjd 1126219089Spjd /* Default value is already OK. */ 1127219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1128219089Spjd break; 1129219089Spjd 1130219089Spjd /* Verify the label can be converted to binary form */ 1131219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1132219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1133219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1134219089Spjd goto badlabel; 1135168404Spjd } 1136168404Spjd 1137219089Spjd /* Now translate to hex internal label string */ 1138219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1139219089Spjd DEF_NAMES) != 0) { 1140219089Spjd if (hex) 1141219089Spjd free(hex); 1142219089Spjd goto badlabel; 1143219089Spjd } 1144219089Spjd m_label_free(new_sl); 1145219089Spjd 1146219089Spjd /* If string is already in internal form, we're done. */ 1147219089Spjd if (strcmp(strval, hex) == 0) { 1148219089Spjd free(hex); 1149219089Spjd break; 1150219089Spjd } 1151219089Spjd 1152219089Spjd /* Replace the label string with the internal form. */ 1153219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1154219089Spjd DATA_TYPE_STRING); 1155219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1156219089Spjd hex) == 0); 1157219089Spjd free(hex); 1158219089Spjd 1159168404Spjd break; 1160168404Spjd 1161219089Spjdbadlabel: 1162219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1163219089Spjd "invalid mlslabel '%s'"), strval); 1164219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1165219089Spjd m_label_free(new_sl); /* OK if null */ 1166277300Ssmh#else /* !illumos */ 1167219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1168219089Spjd "mlslabel is not supported on FreeBSD")); 1169219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1170277300Ssmh#endif /* illumos */ 1171219089Spjd goto error; 1172219089Spjd 1173219089Spjd } 1174219089Spjd 1175168404Spjd case ZFS_PROP_MOUNTPOINT: 1176185029Spjd { 1177185029Spjd namecheck_err_t why; 1178185029Spjd 1179168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1180168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1181168404Spjd break; 1182168404Spjd 1183185029Spjd if (mountpoint_namecheck(strval, &why)) { 1184185029Spjd switch (why) { 1185185029Spjd case NAME_ERR_LEADING_SLASH: 1186185029Spjd zfs_error_aux(hdl, 1187185029Spjd dgettext(TEXT_DOMAIN, 1188185029Spjd "'%s' must be an absolute path, " 1189185029Spjd "'none', or 'legacy'"), propname); 1190185029Spjd break; 1191185029Spjd case NAME_ERR_TOOLONG: 1192185029Spjd zfs_error_aux(hdl, 1193185029Spjd dgettext(TEXT_DOMAIN, 1194185029Spjd "component of '%s' is too long"), 1195185029Spjd propname); 1196185029Spjd break; 1197185029Spjd } 1198168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1199168404Spjd goto error; 1200168404Spjd } 1201185029Spjd } 1202185029Spjd 1203168404Spjd /*FALLTHRU*/ 1204168404Spjd 1205185029Spjd case ZFS_PROP_SHARESMB: 1206168404Spjd case ZFS_PROP_SHARENFS: 1207168404Spjd /* 1208185029Spjd * For the mountpoint and sharenfs or sharesmb 1209185029Spjd * properties, check if it can be set in a 1210185029Spjd * global/non-global zone based on 1211168404Spjd * the zoned property value: 1212168404Spjd * 1213168404Spjd * global zone non-global zone 1214168404Spjd * -------------------------------------------------- 1215168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1216168404Spjd * sharenfs (no) sharenfs (no) 1217185029Spjd * sharesmb (no) sharesmb (no) 1218168404Spjd * 1219168404Spjd * zoned=off mountpoint (yes) N/A 1220168404Spjd * sharenfs (yes) 1221185029Spjd * sharesmb (yes) 1222168404Spjd */ 1223168404Spjd if (zoned) { 1224168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1225168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1226168404Spjd "'%s' cannot be set on " 1227168404Spjd "dataset in a non-global zone"), 1228168404Spjd propname); 1229168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1230168404Spjd errbuf); 1231168404Spjd goto error; 1232185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1233185029Spjd prop == ZFS_PROP_SHARESMB) { 1234168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1235168404Spjd "'%s' cannot be set in " 1236168404Spjd "a non-global zone"), propname); 1237168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1238168404Spjd errbuf); 1239168404Spjd goto error; 1240168404Spjd } 1241168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1242168404Spjd /* 1243168404Spjd * If zoned property is 'off', this must be in 1244209962Smm * a global zone. If not, something is wrong. 1245168404Spjd */ 1246168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1247168404Spjd "'%s' cannot be set while dataset " 1248168404Spjd "'zoned' property is set"), propname); 1249168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1250168404Spjd goto error; 1251168404Spjd } 1252168404Spjd 1253168404Spjd /* 1254185029Spjd * At this point, it is legitimate to set the 1255185029Spjd * property. Now we want to make sure that the 1256185029Spjd * property value is valid if it is sharenfs. 1257168404Spjd */ 1258185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1259185029Spjd prop == ZFS_PROP_SHARESMB) && 1260185029Spjd strcmp(strval, "on") != 0 && 1261185029Spjd strcmp(strval, "off") != 0) { 1262185029Spjd zfs_share_proto_t proto; 1263168404Spjd 1264185029Spjd if (prop == ZFS_PROP_SHARESMB) 1265185029Spjd proto = PROTO_SMB; 1266185029Spjd else 1267185029Spjd proto = PROTO_NFS; 1268185029Spjd 1269185029Spjd /* 1270185029Spjd * Must be an valid sharing protocol 1271185029Spjd * option string so init the libshare 1272185029Spjd * in order to enable the parser and 1273185029Spjd * then parse the options. We use the 1274185029Spjd * control API since we don't care about 1275185029Spjd * the current configuration and don't 1276185029Spjd * want the overhead of loading it 1277185029Spjd * until we actually do something. 1278185029Spjd */ 1279185029Spjd 1280185029Spjd if (zfs_init_libshare(hdl, 1281185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1282185029Spjd /* 1283185029Spjd * An error occurred so we can't do 1284185029Spjd * anything 1285185029Spjd */ 1286185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1287185029Spjd "'%s' cannot be set: problem " 1288185029Spjd "in share initialization"), 1289185029Spjd propname); 1290185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1291185029Spjd errbuf); 1292185029Spjd goto error; 1293185029Spjd } 1294185029Spjd 1295185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1296185029Spjd /* 1297185029Spjd * There was an error in parsing so 1298185029Spjd * deal with it by issuing an error 1299185029Spjd * message and leaving after 1300185029Spjd * uninitializing the the libshare 1301185029Spjd * interface. 1302185029Spjd */ 1303185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1304185029Spjd "'%s' cannot be set to invalid " 1305185029Spjd "options"), propname); 1306185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1307185029Spjd errbuf); 1308185029Spjd zfs_uninit_libshare(hdl); 1309185029Spjd goto error; 1310185029Spjd } 1311185029Spjd zfs_uninit_libshare(hdl); 1312168404Spjd } 1313185029Spjd 1314168404Spjd break; 1315185029Spjd case ZFS_PROP_UTF8ONLY: 1316185029Spjd chosen_utf = (int)intval; 1317185029Spjd break; 1318185029Spjd case ZFS_PROP_NORMALIZE: 1319185029Spjd chosen_normal = (int)intval; 1320185029Spjd break; 1321168404Spjd } 1322168404Spjd 1323168404Spjd /* 1324168404Spjd * For changes to existing volumes, we have some additional 1325168404Spjd * checks to enforce. 1326168404Spjd */ 1327168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1328168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1329168404Spjd ZFS_PROP_VOLSIZE); 1330168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1331168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1332168404Spjd char buf[64]; 1333168404Spjd 1334168404Spjd switch (prop) { 1335168404Spjd case ZFS_PROP_RESERVATION: 1336185029Spjd case ZFS_PROP_REFRESERVATION: 1337168404Spjd if (intval > volsize) { 1338168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1339168404Spjd "'%s' is greater than current " 1340168404Spjd "volume size"), propname); 1341168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1342168404Spjd errbuf); 1343168404Spjd goto error; 1344168404Spjd } 1345168404Spjd break; 1346168404Spjd 1347168404Spjd case ZFS_PROP_VOLSIZE: 1348168404Spjd if (intval % blocksize != 0) { 1349168404Spjd zfs_nicenum(blocksize, buf, 1350168404Spjd sizeof (buf)); 1351168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1352168404Spjd "'%s' must be a multiple of " 1353168404Spjd "volume block size (%s)"), 1354168404Spjd propname, buf); 1355168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1356168404Spjd errbuf); 1357168404Spjd goto error; 1358168404Spjd } 1359168404Spjd 1360168404Spjd if (intval == 0) { 1361168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1362168404Spjd "'%s' cannot be zero"), 1363168404Spjd propname); 1364168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1365168404Spjd errbuf); 1366168404Spjd goto error; 1367168404Spjd } 1368168404Spjd break; 1369168404Spjd } 1370168404Spjd } 1371168404Spjd } 1372168404Spjd 1373168404Spjd /* 1374185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1375185029Spjd * enforce rejection of non-UTF8 names. 1376185029Spjd * 1377185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1378185029Spjd * was explicitly not chosen, it is an error. 1379185029Spjd */ 1380185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1381185029Spjd if (nvlist_add_uint64(ret, 1382185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1383185029Spjd (void) no_memory(hdl); 1384185029Spjd goto error; 1385185029Spjd } 1386185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1387185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1388185029Spjd "'%s' must be set 'on' if normalization chosen"), 1389185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1390185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1391185029Spjd goto error; 1392185029Spjd } 1393219089Spjd return (ret); 1394185029Spjd 1395219089Spjderror: 1396219089Spjd nvlist_free(ret); 1397219089Spjd return (NULL); 1398219089Spjd} 1399219089Spjd 1400219089Spjdint 1401219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1402219089Spjd{ 1403219089Spjd uint64_t old_volsize; 1404219089Spjd uint64_t new_volsize; 1405219089Spjd uint64_t old_reservation; 1406219089Spjd uint64_t new_reservation; 1407219089Spjd zfs_prop_t resv_prop; 1408289499Smav nvlist_t *props; 1409219089Spjd 1410185029Spjd /* 1411168404Spjd * If this is an existing volume, and someone is setting the volsize, 1412168404Spjd * make sure that it matches the reservation, or add it if necessary. 1413168404Spjd */ 1414219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1415219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1416219089Spjd return (-1); 1417219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1418289499Smav 1419289499Smav props = fnvlist_alloc(); 1420289499Smav fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1421289499Smav zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); 1422289499Smav 1423289499Smav if ((zvol_volsize_to_reservation(old_volsize, props) != 1424289499Smav old_reservation) || nvlist_exists(nvl, 1425289499Smav zfs_prop_to_name(resv_prop))) { 1426289499Smav fnvlist_free(props); 1427219089Spjd return (0); 1428219089Spjd } 1429219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1430289499Smav &new_volsize) != 0) { 1431289499Smav fnvlist_free(props); 1432219089Spjd return (-1); 1433289499Smav } 1434289499Smav new_reservation = zvol_volsize_to_reservation(new_volsize, props); 1435289499Smav fnvlist_free(props); 1436289499Smav 1437219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1438219089Spjd new_reservation) != 0) { 1439219089Spjd (void) no_memory(zhp->zfs_hdl); 1440219089Spjd return (-1); 1441219089Spjd } 1442219089Spjd return (1); 1443219089Spjd} 1444168404Spjd 1445219089Spjdvoid 1446219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1447219089Spjd char *errbuf) 1448219089Spjd{ 1449219089Spjd switch (err) { 1450185029Spjd 1451219089Spjd case ENOSPC: 1452219089Spjd /* 1453219089Spjd * For quotas and reservations, ENOSPC indicates 1454219089Spjd * something different; setting a quota or reservation 1455219089Spjd * doesn't use any disk space. 1456219089Spjd */ 1457219089Spjd switch (prop) { 1458219089Spjd case ZFS_PROP_QUOTA: 1459219089Spjd case ZFS_PROP_REFQUOTA: 1460219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1461219089Spjd "size is less than current used or " 1462219089Spjd "reserved space")); 1463219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1464219089Spjd break; 1465219089Spjd 1466219089Spjd case ZFS_PROP_RESERVATION: 1467219089Spjd case ZFS_PROP_REFRESERVATION: 1468219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1469219089Spjd "size is greater than available space")); 1470219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1471219089Spjd break; 1472219089Spjd 1473219089Spjd default: 1474219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1475219089Spjd break; 1476168404Spjd } 1477219089Spjd break; 1478219089Spjd 1479219089Spjd case EBUSY: 1480219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1481219089Spjd break; 1482219089Spjd 1483219089Spjd case EROFS: 1484219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1485219089Spjd break; 1486219089Spjd 1487271764Swill case E2BIG: 1488271764Swill zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1489271764Swill "property value too long")); 1490271764Swill (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1491271764Swill break; 1492271764Swill 1493219089Spjd case ENOTSUP: 1494219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1495219089Spjd "pool and or dataset must be upgraded to set this " 1496219089Spjd "property or value")); 1497219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1498219089Spjd break; 1499219089Spjd 1500219089Spjd case ERANGE: 1501274337Sdelphij case EDOM: 1502274337Sdelphij if (prop == ZFS_PROP_COMPRESSION || 1503274337Sdelphij prop == ZFS_PROP_RECORDSIZE) { 1504219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1505219089Spjd "property setting is not allowed on " 1506219089Spjd "bootable datasets")); 1507219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1508289422Smav } else if (prop == ZFS_PROP_CHECKSUM || 1509289422Smav prop == ZFS_PROP_DEDUP) { 1510289422Smav (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1511289422Smav "property setting is not allowed on " 1512289422Smav "root pools")); 1513289422Smav (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1514219089Spjd } else { 1515219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1516219089Spjd } 1517219089Spjd break; 1518219089Spjd 1519219089Spjd case EINVAL: 1520219089Spjd if (prop == ZPROP_INVAL) { 1521219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1522219089Spjd } else { 1523219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1524219089Spjd } 1525219089Spjd break; 1526219089Spjd 1527219089Spjd case EOVERFLOW: 1528219089Spjd /* 1529219089Spjd * This platform can't address a volume this big. 1530219089Spjd */ 1531219089Spjd#ifdef _ILP32 1532219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1533219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1534219089Spjd break; 1535219089Spjd } 1536219089Spjd#endif 1537219089Spjd /* FALLTHROUGH */ 1538219089Spjd default: 1539219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1540168404Spjd } 1541168404Spjd} 1542168404Spjd 1543168404Spjd/* 1544168404Spjd * Given a property name and value, set the property for the given dataset. 1545168404Spjd */ 1546168404Spjdint 1547168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1548168404Spjd{ 1549168404Spjd int ret = -1; 1550168404Spjd char errbuf[1024]; 1551168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1552289497Smav nvlist_t *nvl = NULL; 1553168404Spjd 1554168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1555168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1556168404Spjd zhp->zfs_name); 1557168404Spjd 1558168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1559168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1560168404Spjd (void) no_memory(hdl); 1561168404Spjd goto error; 1562168404Spjd } 1563168404Spjd 1564289497Smav ret = zfs_prop_set_list(zhp, nvl); 1565185029Spjd 1566289497Smaverror: 1567168404Spjd nvlist_free(nvl); 1568289497Smav return (ret); 1569289497Smav} 1570168404Spjd 1571168404Spjd 1572168404Spjd 1573289497Smav/* 1574289497Smav * Given an nvlist of property names and values, set the properties for the 1575289497Smav * given dataset. 1576289497Smav */ 1577289497Smavint 1578289497Smavzfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props) 1579289497Smav{ 1580289497Smav zfs_cmd_t zc = { 0 }; 1581289497Smav int ret = -1; 1582289497Smav prop_changelist_t **cls = NULL; 1583289497Smav int cl_idx; 1584289497Smav char errbuf[1024]; 1585289497Smav libzfs_handle_t *hdl = zhp->zfs_hdl; 1586289497Smav nvlist_t *nvl; 1587289497Smav int nvl_len; 1588289497Smav int added_resv; 1589219089Spjd 1590289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1591289497Smav dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1592289497Smav zhp->zfs_name); 1593168404Spjd 1594289497Smav if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props, 1595289500Smav zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl, 1596289500Smav errbuf)) == NULL) 1597168404Spjd goto error; 1598168404Spjd 1599185029Spjd /* 1600289497Smav * We have to check for any extra properties which need to be added 1601289497Smav * before computing the length of the nvlist. 1602185029Spjd */ 1603289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1604289497Smav elem != NULL; 1605289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1606289497Smav if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE && 1607289497Smav (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) { 1608289497Smav goto error; 1609289497Smav } 1610238391Smm } 1611289497Smav /* 1612289497Smav * Check how many properties we're setting and allocate an array to 1613289497Smav * store changelist pointers for postfix(). 1614289497Smav */ 1615289497Smav nvl_len = 0; 1616289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1617289497Smav elem != NULL; 1618289497Smav elem = nvlist_next_nvpair(nvl, elem)) 1619289497Smav nvl_len++; 1620289497Smav if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL) 1621168404Spjd goto error; 1622168404Spjd 1623289497Smav cl_idx = 0; 1624289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1625289497Smav elem != NULL; 1626289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1627289497Smav 1628289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1629289497Smav 1630289497Smav assert(cl_idx < nvl_len); 1631289497Smav /* 1632289497Smav * We don't want to unmount & remount the dataset when changing 1633289497Smav * its canmount property to 'on' or 'noauto'. We only use 1634289497Smav * the changelist logic to unmount when setting canmount=off. 1635289497Smav */ 1636289497Smav if (!(prop == ZFS_PROP_CANMOUNT && 1637289497Smav fnvpair_value_uint64(elem) != ZFS_CANMOUNT_OFF)) { 1638289497Smav cls[cl_idx] = changelist_gather(zhp, prop, 0, 0); 1639289497Smav if (cls[cl_idx] == NULL) 1640289497Smav goto error; 1641289497Smav } 1642289497Smav 1643289497Smav if (prop == ZFS_PROP_MOUNTPOINT && 1644289497Smav changelist_haszonedchild(cls[cl_idx])) { 1645289497Smav zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1646289497Smav "child dataset with inherited mountpoint is used " 1647289497Smav "in a non-global zone")); 1648289497Smav ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1649289497Smav goto error; 1650289497Smav } 1651289497Smav 1652289497Smav /* We don't support those properties on FreeBSD. */ 1653289497Smav switch (prop) { 1654289497Smav case ZFS_PROP_DEVICES: 1655289497Smav case ZFS_PROP_ISCSIOPTIONS: 1656289497Smav case ZFS_PROP_XATTR: 1657289497Smav case ZFS_PROP_VSCAN: 1658289497Smav case ZFS_PROP_NBMAND: 1659289497Smav case ZFS_PROP_MLSLABEL: 1660289497Smav (void) snprintf(errbuf, sizeof (errbuf), 1661289497Smav "property '%s' not supported on FreeBSD", 1662289497Smav nvpair_name(elem)); 1663289497Smav ret = zfs_error(hdl, EZFS_PERM, errbuf); 1664289497Smav goto error; 1665289497Smav } 1666289497Smav 1667289497Smav if (cls[cl_idx] != NULL && 1668289497Smav (ret = changelist_prefix(cls[cl_idx])) != 0) 1669289497Smav goto error; 1670289497Smav 1671289497Smav cl_idx++; 1672289497Smav } 1673289497Smav assert(cl_idx == nvl_len); 1674289497Smav 1675168404Spjd /* 1676289497Smav * Execute the corresponding ioctl() to set this list of properties. 1677168404Spjd */ 1678168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1679168404Spjd 1680289497Smav if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 || 1681289497Smav (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0) 1682168404Spjd goto error; 1683168404Spjd 1684185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1685209962Smm 1686168404Spjd if (ret != 0) { 1687289497Smav /* Get the list of unset properties back and report them. */ 1688289497Smav nvlist_t *errorprops = NULL; 1689289497Smav if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0) 1690289497Smav goto error; 1691289497Smav for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL); 1692289497Smav elem != NULL; 1693289497Smav elem = nvlist_next_nvpair(nvl, elem)) { 1694289497Smav zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem)); 1695289497Smav zfs_setprop_error(hdl, prop, errno, errbuf); 1696289497Smav } 1697289497Smav nvlist_free(errorprops); 1698289497Smav 1699219089Spjd if (added_resv && errno == ENOSPC) { 1700219089Spjd /* clean up the volsize property we tried to set */ 1701219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1702219089Spjd ZFS_PROP_VOLSIZE); 1703219089Spjd nvlist_free(nvl); 1704289497Smav nvl = NULL; 1705219089Spjd zcmd_free_nvlists(&zc); 1706289497Smav 1707219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1708219089Spjd goto error; 1709219089Spjd if (nvlist_add_uint64(nvl, 1710219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1711219089Spjd old_volsize) != 0) 1712219089Spjd goto error; 1713219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1714219089Spjd goto error; 1715219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1716168404Spjd } 1717168404Spjd } else { 1718289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1719289497Smav if (cls[cl_idx] != NULL) { 1720289497Smav int clp_err = changelist_postfix(cls[cl_idx]); 1721289497Smav if (clp_err != 0) 1722289497Smav ret = clp_err; 1723289497Smav } 1724289497Smav } 1725185029Spjd 1726168404Spjd /* 1727168404Spjd * Refresh the statistics so the new property value 1728168404Spjd * is reflected. 1729168404Spjd */ 1730185029Spjd if (ret == 0) 1731168404Spjd (void) get_stats(zhp); 1732168404Spjd } 1733168404Spjd 1734168404Spjderror: 1735168404Spjd nvlist_free(nvl); 1736168404Spjd zcmd_free_nvlists(&zc); 1737289497Smav if (cls != NULL) { 1738289497Smav for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) { 1739289497Smav if (cls[cl_idx] != NULL) 1740289497Smav changelist_free(cls[cl_idx]); 1741289497Smav } 1742289497Smav free(cls); 1743289497Smav } 1744168404Spjd return (ret); 1745168404Spjd} 1746168404Spjd 1747168404Spjd/* 1748219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1749219089Spjd * is TRUE, revert to the received value, if any. 1750168404Spjd */ 1751168404Spjdint 1752219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1753168404Spjd{ 1754168404Spjd zfs_cmd_t zc = { 0 }; 1755168404Spjd int ret; 1756168404Spjd prop_changelist_t *cl; 1757168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1758168404Spjd char errbuf[1024]; 1759168404Spjd zfs_prop_t prop; 1760168404Spjd 1761168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1762168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1763168404Spjd 1764219089Spjd zc.zc_cookie = received; 1765185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1766168404Spjd /* 1767168404Spjd * For user properties, the amount of work we have to do is very 1768168404Spjd * small, so just do it here. 1769168404Spjd */ 1770168404Spjd if (!zfs_prop_user(propname)) { 1771168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1772168404Spjd "invalid property")); 1773168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1774168404Spjd } 1775168404Spjd 1776168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1777168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1778168404Spjd 1779185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1780168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1781168404Spjd 1782168404Spjd return (0); 1783168404Spjd } 1784168404Spjd 1785168404Spjd /* 1786168404Spjd * Verify that this property is inheritable. 1787168404Spjd */ 1788168404Spjd if (zfs_prop_readonly(prop)) 1789168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1790168404Spjd 1791219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1792168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1793168404Spjd 1794168404Spjd /* 1795168404Spjd * Check to see if the value applies to this type 1796168404Spjd */ 1797168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1798168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1799168404Spjd 1800168404Spjd /* 1801219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1802168404Spjd */ 1803168404Spjd propname = zfs_prop_to_name(prop); 1804168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1805168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1806168404Spjd 1807168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1808168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1809168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1810168404Spjd "dataset is used in a non-global zone")); 1811168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1812168404Spjd } 1813168404Spjd 1814168404Spjd /* 1815168404Spjd * Determine datasets which will be affected by this change, if any. 1816168404Spjd */ 1817185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1818168404Spjd return (-1); 1819168404Spjd 1820168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1821168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1822168404Spjd "child dataset with inherited mountpoint is used " 1823168404Spjd "in a non-global zone")); 1824168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1825168404Spjd goto error; 1826168404Spjd } 1827168404Spjd 1828168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1829168404Spjd goto error; 1830168404Spjd 1831185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1832168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1833168404Spjd } else { 1834168404Spjd 1835168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1836168404Spjd goto error; 1837168404Spjd 1838168404Spjd /* 1839168404Spjd * Refresh the statistics so the new property is reflected. 1840168404Spjd */ 1841168404Spjd (void) get_stats(zhp); 1842168404Spjd } 1843168404Spjd 1844168404Spjderror: 1845168404Spjd changelist_free(cl); 1846168404Spjd return (ret); 1847168404Spjd} 1848168404Spjd 1849168404Spjd/* 1850168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1851168404Spjd * extract them appropriately. 1852168404Spjd */ 1853168404Spjdstatic uint64_t 1854168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1855168404Spjd{ 1856168404Spjd nvlist_t *nv; 1857168404Spjd uint64_t value; 1858168404Spjd 1859168404Spjd *source = NULL; 1860168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1861168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1862185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1863185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1864168404Spjd } else { 1865205198Sdelphij verify(!zhp->zfs_props_table || 1866205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1867168404Spjd value = zfs_prop_default_numeric(prop); 1868168404Spjd *source = ""; 1869168404Spjd } 1870168404Spjd 1871168404Spjd return (value); 1872168404Spjd} 1873168404Spjd 1874289362Smavstatic const char * 1875168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1876168404Spjd{ 1877168404Spjd nvlist_t *nv; 1878289362Smav const char *value; 1879168404Spjd 1880168404Spjd *source = NULL; 1881168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1882168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1883289362Smav value = fnvlist_lookup_string(nv, ZPROP_VALUE); 1884185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1885168404Spjd } else { 1886205198Sdelphij verify(!zhp->zfs_props_table || 1887205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1888289362Smav value = zfs_prop_default_string(prop); 1889168404Spjd *source = ""; 1890168404Spjd } 1891168404Spjd 1892168404Spjd return (value); 1893168404Spjd} 1894168404Spjd 1895219089Spjdstatic boolean_t 1896219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1897219089Spjd{ 1898219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1899219089Spjd} 1900219089Spjd 1901219089Spjdstatic void 1902219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1903219089Spjd{ 1904219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1905219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1906219089Spjd} 1907219089Spjd 1908219089Spjdstatic void 1909219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1910219089Spjd{ 1911219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1912219089Spjd *cookie = 0; 1913219089Spjd} 1914219089Spjd 1915168404Spjd/* 1916168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1917168404Spjd * zfs_prop_get_int() are built using this interface. 1918168404Spjd * 1919168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1920168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1921168404Spjd * If they differ from the on-disk values, report the current values and mark 1922168404Spjd * the source "temporary". 1923168404Spjd */ 1924168404Spjdstatic int 1925185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1926168404Spjd char **source, uint64_t *val) 1927168404Spjd{ 1928185029Spjd zfs_cmd_t zc = { 0 }; 1929185029Spjd nvlist_t *zplprops = NULL; 1930168404Spjd struct mnttab mnt; 1931168404Spjd char *mntopt_on = NULL; 1932168404Spjd char *mntopt_off = NULL; 1933219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1934168404Spjd 1935168404Spjd *source = NULL; 1936168404Spjd 1937168404Spjd switch (prop) { 1938168404Spjd case ZFS_PROP_ATIME: 1939168404Spjd mntopt_on = MNTOPT_ATIME; 1940168404Spjd mntopt_off = MNTOPT_NOATIME; 1941168404Spjd break; 1942168404Spjd 1943168404Spjd case ZFS_PROP_DEVICES: 1944168404Spjd mntopt_on = MNTOPT_DEVICES; 1945168404Spjd mntopt_off = MNTOPT_NODEVICES; 1946168404Spjd break; 1947168404Spjd 1948168404Spjd case ZFS_PROP_EXEC: 1949168404Spjd mntopt_on = MNTOPT_EXEC; 1950168404Spjd mntopt_off = MNTOPT_NOEXEC; 1951168404Spjd break; 1952168404Spjd 1953168404Spjd case ZFS_PROP_READONLY: 1954168404Spjd mntopt_on = MNTOPT_RO; 1955168404Spjd mntopt_off = MNTOPT_RW; 1956168404Spjd break; 1957168404Spjd 1958168404Spjd case ZFS_PROP_SETUID: 1959168404Spjd mntopt_on = MNTOPT_SETUID; 1960168404Spjd mntopt_off = MNTOPT_NOSETUID; 1961168404Spjd break; 1962168404Spjd 1963168404Spjd case ZFS_PROP_XATTR: 1964168404Spjd mntopt_on = MNTOPT_XATTR; 1965168404Spjd mntopt_off = MNTOPT_NOXATTR; 1966168404Spjd break; 1967185029Spjd 1968185029Spjd case ZFS_PROP_NBMAND: 1969185029Spjd mntopt_on = MNTOPT_NBMAND; 1970185029Spjd mntopt_off = MNTOPT_NONBMAND; 1971185029Spjd break; 1972168404Spjd } 1973168404Spjd 1974168404Spjd /* 1975168404Spjd * Because looking up the mount options is potentially expensive 1976168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1977168404Spjd * we're looking up a property which requires its presence. 1978168404Spjd */ 1979168404Spjd if (!zhp->zfs_mntcheck && 1980168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1981209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1982209962Smm struct mnttab entry; 1983168404Spjd 1984209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1985209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1986168404Spjd entry.mnt_mntopts); 1987168404Spjd if (zhp->zfs_mntopts == NULL) 1988168404Spjd return (-1); 1989168404Spjd } 1990168404Spjd 1991168404Spjd zhp->zfs_mntcheck = B_TRUE; 1992168404Spjd } 1993168404Spjd 1994168404Spjd if (zhp->zfs_mntopts == NULL) 1995168404Spjd mnt.mnt_mntopts = ""; 1996168404Spjd else 1997168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1998168404Spjd 1999168404Spjd switch (prop) { 2000168404Spjd case ZFS_PROP_ATIME: 2001168404Spjd case ZFS_PROP_DEVICES: 2002168404Spjd case ZFS_PROP_EXEC: 2003168404Spjd case ZFS_PROP_READONLY: 2004168404Spjd case ZFS_PROP_SETUID: 2005168404Spjd case ZFS_PROP_XATTR: 2006185029Spjd case ZFS_PROP_NBMAND: 2007168404Spjd *val = getprop_uint64(zhp, prop, source); 2008168404Spjd 2009219089Spjd if (received) 2010219089Spjd break; 2011219089Spjd 2012168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 2013168404Spjd *val = B_TRUE; 2014168404Spjd if (src) 2015185029Spjd *src = ZPROP_SRC_TEMPORARY; 2016168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2017168404Spjd *val = B_FALSE; 2018168404Spjd if (src) 2019185029Spjd *src = ZPROP_SRC_TEMPORARY; 2020168404Spjd } 2021168404Spjd break; 2022168404Spjd 2023168404Spjd case ZFS_PROP_CANMOUNT: 2024219089Spjd case ZFS_PROP_VOLSIZE: 2025168404Spjd case ZFS_PROP_QUOTA: 2026185029Spjd case ZFS_PROP_REFQUOTA: 2027168404Spjd case ZFS_PROP_RESERVATION: 2028185029Spjd case ZFS_PROP_REFRESERVATION: 2029264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2030264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2031264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2032264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2033168404Spjd *val = getprop_uint64(zhp, prop, source); 2034219089Spjd 2035219089Spjd if (*source == NULL) { 2036219089Spjd /* not default, must be local */ 2037168404Spjd *source = zhp->zfs_name; 2038219089Spjd } 2039168404Spjd break; 2040168404Spjd 2041168404Spjd case ZFS_PROP_MOUNTED: 2042168404Spjd *val = (zhp->zfs_mntopts != NULL); 2043168404Spjd break; 2044168404Spjd 2045168404Spjd case ZFS_PROP_NUMCLONES: 2046168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 2047168404Spjd break; 2048168404Spjd 2049185029Spjd case ZFS_PROP_VERSION: 2050185029Spjd case ZFS_PROP_NORMALIZE: 2051185029Spjd case ZFS_PROP_UTF8ONLY: 2052185029Spjd case ZFS_PROP_CASE: 2053185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 2054185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2055185029Spjd return (-1); 2056185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2057185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2058185029Spjd zcmd_free_nvlists(&zc); 2059219089Spjd return (-1); 2060185029Spjd } 2061185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2062185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2063185029Spjd val) != 0) { 2064185029Spjd zcmd_free_nvlists(&zc); 2065219089Spjd return (-1); 2066185029Spjd } 2067296528Smav nvlist_free(zplprops); 2068185029Spjd zcmd_free_nvlists(&zc); 2069185029Spjd break; 2070185029Spjd 2071253819Sdelphij case ZFS_PROP_INCONSISTENT: 2072253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 2073253819Sdelphij break; 2074253819Sdelphij 2075168404Spjd default: 2076185029Spjd switch (zfs_prop_get_type(prop)) { 2077185029Spjd case PROP_TYPE_NUMBER: 2078185029Spjd case PROP_TYPE_INDEX: 2079185029Spjd *val = getprop_uint64(zhp, prop, source); 2080185029Spjd /* 2081209962Smm * If we tried to use a default value for a 2082185029Spjd * readonly property, it means that it was not 2083219089Spjd * present. 2084185029Spjd */ 2085185029Spjd if (zfs_prop_readonly(prop) && 2086219089Spjd *source != NULL && (*source)[0] == '\0') { 2087219089Spjd *source = NULL; 2088185029Spjd } 2089185029Spjd break; 2090185029Spjd 2091185029Spjd case PROP_TYPE_STRING: 2092185029Spjd default: 2093185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2094185029Spjd "cannot get non-numeric property")); 2095185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2096185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 2097185029Spjd } 2098168404Spjd } 2099168404Spjd 2100168404Spjd return (0); 2101168404Spjd} 2102168404Spjd 2103168404Spjd/* 2104168404Spjd * Calculate the source type, given the raw source string. 2105168404Spjd */ 2106168404Spjdstatic void 2107185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 2108168404Spjd char *statbuf, size_t statlen) 2109168404Spjd{ 2110185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 2111168404Spjd return; 2112168404Spjd 2113168404Spjd if (source == NULL) { 2114185029Spjd *srctype = ZPROP_SRC_NONE; 2115168404Spjd } else if (source[0] == '\0') { 2116185029Spjd *srctype = ZPROP_SRC_DEFAULT; 2117219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 2118219089Spjd *srctype = ZPROP_SRC_RECEIVED; 2119168404Spjd } else { 2120168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 2121185029Spjd *srctype = ZPROP_SRC_LOCAL; 2122168404Spjd } else { 2123168404Spjd (void) strlcpy(statbuf, source, statlen); 2124185029Spjd *srctype = ZPROP_SRC_INHERITED; 2125168404Spjd } 2126168404Spjd } 2127168404Spjd 2128168404Spjd} 2129168404Spjd 2130219089Spjdint 2131219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2132219089Spjd size_t proplen, boolean_t literal) 2133219089Spjd{ 2134219089Spjd zfs_prop_t prop; 2135219089Spjd int err = 0; 2136219089Spjd 2137219089Spjd if (zhp->zfs_recvd_props == NULL) 2138219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 2139219089Spjd return (-1); 2140219089Spjd 2141219089Spjd prop = zfs_name_to_prop(propname); 2142219089Spjd 2143219089Spjd if (prop != ZPROP_INVAL) { 2144219089Spjd uint64_t cookie; 2145219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2146219089Spjd return (-1); 2147219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 2148219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 2149219089Spjd NULL, NULL, 0, literal); 2150219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 2151219089Spjd } else { 2152219089Spjd nvlist_t *propval; 2153219089Spjd char *recvdval; 2154219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2155219089Spjd propname, &propval) != 0) 2156219089Spjd return (-1); 2157219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 2158219089Spjd &recvdval) == 0); 2159219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 2160219089Spjd } 2161219089Spjd 2162219089Spjd return (err == 0 ? 0 : -1); 2163219089Spjd} 2164219089Spjd 2165228103Smmstatic int 2166228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2167228103Smm{ 2168228103Smm nvlist_t *value; 2169228103Smm nvpair_t *pair; 2170228103Smm 2171228103Smm value = zfs_get_clones_nvl(zhp); 2172228103Smm if (value == NULL) 2173228103Smm return (-1); 2174228103Smm 2175228103Smm propbuf[0] = '\0'; 2176228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2177228103Smm pair = nvlist_next_nvpair(value, pair)) { 2178228103Smm if (propbuf[0] != '\0') 2179228103Smm (void) strlcat(propbuf, ",", proplen); 2180228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 2181228103Smm } 2182228103Smm 2183228103Smm return (0); 2184228103Smm} 2185228103Smm 2186228103Smmstruct get_clones_arg { 2187228103Smm uint64_t numclones; 2188228103Smm nvlist_t *value; 2189228103Smm const char *origin; 2190228103Smm char buf[ZFS_MAXNAMELEN]; 2191228103Smm}; 2192228103Smm 2193228103Smmint 2194228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2195228103Smm{ 2196228103Smm struct get_clones_arg *gca = arg; 2197228103Smm 2198228103Smm if (gca->numclones == 0) { 2199228103Smm zfs_close(zhp); 2200228103Smm return (0); 2201228103Smm } 2202228103Smm 2203228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2204228103Smm NULL, NULL, 0, B_TRUE) != 0) 2205228103Smm goto out; 2206228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2207248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2208228103Smm gca->numclones--; 2209228103Smm } 2210228103Smm 2211228103Smmout: 2212228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2213228103Smm zfs_close(zhp); 2214228103Smm return (0); 2215228103Smm} 2216228103Smm 2217228103Smmnvlist_t * 2218228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2219228103Smm{ 2220228103Smm nvlist_t *nv, *value; 2221228103Smm 2222228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2223228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2224228103Smm struct get_clones_arg gca; 2225228103Smm 2226228103Smm /* 2227228103Smm * if this is a snapshot, then the kernel wasn't able 2228228103Smm * to get the clones. Do it by slowly iterating. 2229228103Smm */ 2230228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2231228103Smm return (NULL); 2232228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2233228103Smm return (NULL); 2234228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2235228103Smm nvlist_free(nv); 2236228103Smm return (NULL); 2237228103Smm } 2238228103Smm 2239228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2240228103Smm gca.value = value; 2241228103Smm gca.origin = zhp->zfs_name; 2242228103Smm 2243228103Smm if (gca.numclones != 0) { 2244228103Smm zfs_handle_t *root; 2245228103Smm char pool[ZFS_MAXNAMELEN]; 2246228103Smm char *cp = pool; 2247228103Smm 2248228103Smm /* get the pool name */ 2249228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2250228103Smm (void) strsep(&cp, "/@"); 2251228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2252228103Smm ZFS_TYPE_FILESYSTEM); 2253228103Smm 2254228103Smm (void) get_clones_cb(root, &gca); 2255228103Smm } 2256228103Smm 2257228103Smm if (gca.numclones != 0 || 2258228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2259228103Smm nvlist_add_nvlist(zhp->zfs_props, 2260228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2261228103Smm nvlist_free(nv); 2262228103Smm nvlist_free(value); 2263228103Smm return (NULL); 2264228103Smm } 2265228103Smm nvlist_free(nv); 2266228103Smm nvlist_free(value); 2267228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2268228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2269228103Smm } 2270228103Smm 2271228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2272228103Smm 2273228103Smm return (value); 2274228103Smm} 2275228103Smm 2276168404Spjd/* 2277168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2278168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2279168404Spjd * human-readable form. 2280168404Spjd * 2281168404Spjd * Returns 0 on success, or -1 on error. 2282168404Spjd */ 2283168404Spjdint 2284168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2285185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2286168404Spjd{ 2287168404Spjd char *source = NULL; 2288168404Spjd uint64_t val; 2289289362Smav const char *str; 2290168404Spjd const char *strval; 2291219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2292168404Spjd 2293168404Spjd /* 2294168404Spjd * Check to see if this property applies to our object 2295168404Spjd */ 2296168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2297168404Spjd return (-1); 2298168404Spjd 2299219089Spjd if (received && zfs_prop_readonly(prop)) 2300219089Spjd return (-1); 2301219089Spjd 2302168404Spjd if (src) 2303185029Spjd *src = ZPROP_SRC_NONE; 2304168404Spjd 2305168404Spjd switch (prop) { 2306168404Spjd case ZFS_PROP_CREATION: 2307168404Spjd /* 2308168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2309168404Spjd * this into a string unless 'literal' is specified. 2310168404Spjd */ 2311168404Spjd { 2312168404Spjd val = getprop_uint64(zhp, prop, &source); 2313168404Spjd time_t time = (time_t)val; 2314168404Spjd struct tm t; 2315168404Spjd 2316168404Spjd if (literal || 2317168404Spjd localtime_r(&time, &t) == NULL || 2318168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2319168404Spjd &t) == 0) 2320168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2321168404Spjd } 2322168404Spjd break; 2323168404Spjd 2324168404Spjd case ZFS_PROP_MOUNTPOINT: 2325168404Spjd /* 2326168404Spjd * Getting the precise mountpoint can be tricky. 2327168404Spjd * 2328168404Spjd * - for 'none' or 'legacy', return those values. 2329168404Spjd * - for inherited mountpoints, we want to take everything 2330168404Spjd * after our ancestor and append it to the inherited value. 2331168404Spjd * 2332168404Spjd * If the pool has an alternate root, we want to prepend that 2333168404Spjd * root to any values we return. 2334168404Spjd */ 2335185029Spjd 2336168404Spjd str = getprop_string(zhp, prop, &source); 2337168404Spjd 2338185029Spjd if (str[0] == '/') { 2339185029Spjd char buf[MAXPATHLEN]; 2340185029Spjd char *root = buf; 2341219089Spjd const char *relpath; 2342168404Spjd 2343219089Spjd /* 2344219089Spjd * If we inherit the mountpoint, even from a dataset 2345219089Spjd * with a received value, the source will be the path of 2346219089Spjd * the dataset we inherit from. If source is 2347219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2348219089Spjd * inherited. 2349219089Spjd */ 2350219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2351219089Spjd relpath = ""; 2352219089Spjd } else { 2353219089Spjd relpath = zhp->zfs_name + strlen(source); 2354219089Spjd if (relpath[0] == '/') 2355219089Spjd relpath++; 2356219089Spjd } 2357185029Spjd 2358185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2359263889Sdelphij ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, 2360263889Sdelphij B_FALSE)) || (strcmp(root, "-") == 0)) 2361185029Spjd root[0] = '\0'; 2362185029Spjd /* 2363185029Spjd * Special case an alternate root of '/'. This will 2364185029Spjd * avoid having multiple leading slashes in the 2365185029Spjd * mountpoint path. 2366185029Spjd */ 2367185029Spjd if (strcmp(root, "/") == 0) 2368185029Spjd root++; 2369185029Spjd 2370185029Spjd /* 2371185029Spjd * If the mountpoint is '/' then skip over this 2372185029Spjd * if we are obtaining either an alternate root or 2373185029Spjd * an inherited mountpoint. 2374185029Spjd */ 2375185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2376185029Spjd relpath[0] != '\0')) 2377168404Spjd str++; 2378168404Spjd 2379168404Spjd if (relpath[0] == '\0') 2380168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2381168404Spjd root, str); 2382168404Spjd else 2383168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2384168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2385168404Spjd relpath); 2386168404Spjd } else { 2387168404Spjd /* 'legacy' or 'none' */ 2388168404Spjd (void) strlcpy(propbuf, str, proplen); 2389168404Spjd } 2390168404Spjd 2391168404Spjd break; 2392168404Spjd 2393168404Spjd case ZFS_PROP_ORIGIN: 2394289362Smav str = getprop_string(zhp, prop, &source); 2395289362Smav if (str == NULL) 2396168404Spjd return (-1); 2397289362Smav (void) strlcpy(propbuf, str, proplen); 2398168404Spjd break; 2399168404Spjd 2400228103Smm case ZFS_PROP_CLONES: 2401228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2402228103Smm return (-1); 2403228103Smm break; 2404228103Smm 2405168404Spjd case ZFS_PROP_QUOTA: 2406185029Spjd case ZFS_PROP_REFQUOTA: 2407168404Spjd case ZFS_PROP_RESERVATION: 2408185029Spjd case ZFS_PROP_REFRESERVATION: 2409185029Spjd 2410168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2411168404Spjd return (-1); 2412168404Spjd 2413168404Spjd /* 2414168404Spjd * If quota or reservation is 0, we translate this into 'none' 2415168404Spjd * (unless literal is set), and indicate that it's the default 2416168404Spjd * value. Otherwise, we print the number nicely and indicate 2417168404Spjd * that its set locally. 2418168404Spjd */ 2419168404Spjd if (val == 0) { 2420168404Spjd if (literal) 2421168404Spjd (void) strlcpy(propbuf, "0", proplen); 2422168404Spjd else 2423168404Spjd (void) strlcpy(propbuf, "none", proplen); 2424168404Spjd } else { 2425168404Spjd if (literal) 2426168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2427168404Spjd (u_longlong_t)val); 2428168404Spjd else 2429168404Spjd zfs_nicenum(val, propbuf, proplen); 2430168404Spjd } 2431168404Spjd break; 2432168404Spjd 2433264835Sdelphij case ZFS_PROP_FILESYSTEM_LIMIT: 2434264835Sdelphij case ZFS_PROP_SNAPSHOT_LIMIT: 2435264835Sdelphij case ZFS_PROP_FILESYSTEM_COUNT: 2436264835Sdelphij case ZFS_PROP_SNAPSHOT_COUNT: 2437264835Sdelphij 2438264835Sdelphij if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2439264835Sdelphij return (-1); 2440264835Sdelphij 2441264835Sdelphij /* 2442264835Sdelphij * If limit is UINT64_MAX, we translate this into 'none' (unless 2443264835Sdelphij * literal is set), and indicate that it's the default value. 2444264835Sdelphij * Otherwise, we print the number nicely and indicate that it's 2445264835Sdelphij * set locally. 2446264835Sdelphij */ 2447264835Sdelphij if (literal) { 2448264835Sdelphij (void) snprintf(propbuf, proplen, "%llu", 2449264835Sdelphij (u_longlong_t)val); 2450264835Sdelphij } else if (val == UINT64_MAX) { 2451264835Sdelphij (void) strlcpy(propbuf, "none", proplen); 2452264835Sdelphij } else { 2453264835Sdelphij zfs_nicenum(val, propbuf, proplen); 2454264835Sdelphij } 2455264835Sdelphij break; 2456264835Sdelphij 2457223623Smm case ZFS_PROP_REFRATIO: 2458168404Spjd case ZFS_PROP_COMPRESSRATIO: 2459168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2460168404Spjd return (-1); 2461219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2462219089Spjd (u_longlong_t)(val / 100), 2463219089Spjd (u_longlong_t)(val % 100)); 2464168404Spjd break; 2465168404Spjd 2466168404Spjd case ZFS_PROP_TYPE: 2467168404Spjd switch (zhp->zfs_type) { 2468168404Spjd case ZFS_TYPE_FILESYSTEM: 2469168404Spjd str = "filesystem"; 2470168404Spjd break; 2471168404Spjd case ZFS_TYPE_VOLUME: 2472168404Spjd str = "volume"; 2473168404Spjd break; 2474168404Spjd case ZFS_TYPE_SNAPSHOT: 2475168404Spjd str = "snapshot"; 2476168404Spjd break; 2477260183Sdelphij case ZFS_TYPE_BOOKMARK: 2478260183Sdelphij str = "bookmark"; 2479260183Sdelphij break; 2480168404Spjd default: 2481168404Spjd abort(); 2482168404Spjd } 2483168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2484168404Spjd break; 2485168404Spjd 2486168404Spjd case ZFS_PROP_MOUNTED: 2487168404Spjd /* 2488168404Spjd * The 'mounted' property is a pseudo-property that described 2489168404Spjd * whether the filesystem is currently mounted. Even though 2490168404Spjd * it's a boolean value, the typical values of "on" and "off" 2491168404Spjd * don't make sense, so we translate to "yes" and "no". 2492168404Spjd */ 2493168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2494168404Spjd src, &source, &val) != 0) 2495168404Spjd return (-1); 2496168404Spjd if (val) 2497168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2498168404Spjd else 2499168404Spjd (void) strlcpy(propbuf, "no", proplen); 2500168404Spjd break; 2501168404Spjd 2502168404Spjd case ZFS_PROP_NAME: 2503168404Spjd /* 2504168404Spjd * The 'name' property is a pseudo-property derived from the 2505168404Spjd * dataset name. It is presented as a real property to simplify 2506168404Spjd * consumers. 2507168404Spjd */ 2508168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2509168404Spjd break; 2510168404Spjd 2511219089Spjd case ZFS_PROP_MLSLABEL: 2512219089Spjd { 2513277300Ssmh#ifdef illumos 2514219089Spjd m_label_t *new_sl = NULL; 2515219089Spjd char *ascii = NULL; /* human readable label */ 2516219089Spjd 2517219089Spjd (void) strlcpy(propbuf, 2518219089Spjd getprop_string(zhp, prop, &source), proplen); 2519219089Spjd 2520219089Spjd if (literal || (strcasecmp(propbuf, 2521219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2522219089Spjd break; 2523219089Spjd 2524219089Spjd /* 2525219089Spjd * Try to translate the internal hex string to 2526219089Spjd * human-readable output. If there are any 2527219089Spjd * problems just use the hex string. 2528219089Spjd */ 2529219089Spjd 2530219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2531219089Spjd L_NO_CORRECTION, NULL) == -1) { 2532219089Spjd m_label_free(new_sl); 2533219089Spjd break; 2534219089Spjd } 2535219089Spjd 2536219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2537219089Spjd DEF_NAMES) != 0) { 2538219089Spjd if (ascii) 2539219089Spjd free(ascii); 2540219089Spjd m_label_free(new_sl); 2541219089Spjd break; 2542219089Spjd } 2543219089Spjd m_label_free(new_sl); 2544219089Spjd 2545219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2546219089Spjd free(ascii); 2547277300Ssmh#else /* !illumos */ 2548219089Spjd propbuf[0] = '\0'; 2549277300Ssmh#endif /* illumos */ 2550219089Spjd } 2551219089Spjd break; 2552219089Spjd 2553236705Smm case ZFS_PROP_GUID: 2554236705Smm /* 2555236705Smm * GUIDs are stored as numbers, but they are identifiers. 2556236705Smm * We don't want them to be pretty printed, because pretty 2557236705Smm * printing mangles the ID into a truncated and useless value. 2558236705Smm */ 2559236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2560236705Smm return (-1); 2561236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2562236705Smm break; 2563236705Smm 2564168404Spjd default: 2565185029Spjd switch (zfs_prop_get_type(prop)) { 2566185029Spjd case PROP_TYPE_NUMBER: 2567185029Spjd if (get_numeric_property(zhp, prop, src, 2568185029Spjd &source, &val) != 0) 2569185029Spjd return (-1); 2570185029Spjd if (literal) 2571185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2572185029Spjd (u_longlong_t)val); 2573185029Spjd else 2574185029Spjd zfs_nicenum(val, propbuf, proplen); 2575185029Spjd break; 2576185029Spjd 2577185029Spjd case PROP_TYPE_STRING: 2578289362Smav str = getprop_string(zhp, prop, &source); 2579289362Smav if (str == NULL) 2580289362Smav return (-1); 2581289362Smav (void) strlcpy(propbuf, str, proplen); 2582185029Spjd break; 2583185029Spjd 2584185029Spjd case PROP_TYPE_INDEX: 2585185029Spjd if (get_numeric_property(zhp, prop, src, 2586185029Spjd &source, &val) != 0) 2587185029Spjd return (-1); 2588185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2589185029Spjd return (-1); 2590185029Spjd (void) strlcpy(propbuf, strval, proplen); 2591185029Spjd break; 2592185029Spjd 2593185029Spjd default: 2594185029Spjd abort(); 2595185029Spjd } 2596168404Spjd } 2597168404Spjd 2598168404Spjd get_source(zhp, src, source, statbuf, statlen); 2599168404Spjd 2600168404Spjd return (0); 2601168404Spjd} 2602168404Spjd 2603168404Spjd/* 2604168404Spjd * Utility function to get the given numeric property. Does no validation that 2605168404Spjd * the given property is the appropriate type; should only be used with 2606168404Spjd * hard-coded property types. 2607168404Spjd */ 2608168404Spjduint64_t 2609168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2610168404Spjd{ 2611168404Spjd char *source; 2612168404Spjd uint64_t val; 2613168404Spjd 2614185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2615168404Spjd 2616168404Spjd return (val); 2617168404Spjd} 2618168404Spjd 2619185029Spjdint 2620185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2621185029Spjd{ 2622185029Spjd char buf[64]; 2623185029Spjd 2624209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2625185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2626185029Spjd} 2627185029Spjd 2628168404Spjd/* 2629168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2630168404Spjd */ 2631168404Spjdint 2632168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2633185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2634168404Spjd{ 2635168404Spjd char *source; 2636168404Spjd 2637168404Spjd /* 2638168404Spjd * Check to see if this property applies to our object 2639168404Spjd */ 2640185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2641168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2642168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2643168404Spjd zfs_prop_to_name(prop))); 2644185029Spjd } 2645168404Spjd 2646168404Spjd if (src) 2647185029Spjd *src = ZPROP_SRC_NONE; 2648168404Spjd 2649168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2650168404Spjd return (-1); 2651168404Spjd 2652168404Spjd get_source(zhp, src, source, statbuf, statlen); 2653168404Spjd 2654168404Spjd return (0); 2655168404Spjd} 2656168404Spjd 2657209962Smmstatic int 2658209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2659209962Smm char **domainp, idmap_rid_t *ridp) 2660209962Smm{ 2661277300Ssmh#ifdef illumos 2662209962Smm idmap_get_handle_t *get_hdl = NULL; 2663209962Smm idmap_stat status; 2664209962Smm int err = EINVAL; 2665209962Smm 2666219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2667209962Smm goto out; 2668209962Smm 2669209962Smm if (isuser) { 2670209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2671209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2672209962Smm } else { 2673209962Smm err = idmap_get_sidbygid(get_hdl, id, 2674209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2675209962Smm } 2676209962Smm if (err == IDMAP_SUCCESS && 2677209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2678209962Smm status == IDMAP_SUCCESS) 2679209962Smm err = 0; 2680209962Smm else 2681209962Smm err = EINVAL; 2682209962Smmout: 2683209962Smm if (get_hdl) 2684209962Smm idmap_get_destroy(get_hdl); 2685209962Smm return (err); 2686277300Ssmh#else /* !illumos */ 2687209962Smm assert(!"invalid code path"); 2688264852Ssmh return (EINVAL); // silence compiler warning 2689277300Ssmh#endif /* illumos */ 2690209962Smm} 2691209962Smm 2692168404Spjd/* 2693209962Smm * convert the propname into parameters needed by kernel 2694209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2695209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2696209962Smm */ 2697209962Smmstatic int 2698209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2699209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2700209962Smm{ 2701209962Smm zfs_userquota_prop_t type; 2702209962Smm char *cp, *end; 2703209962Smm char *numericsid = NULL; 2704209962Smm boolean_t isuser; 2705209962Smm 2706209962Smm domain[0] = '\0'; 2707275579Sdelphij *ridp = 0; 2708209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2709209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2710209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2711209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2712209962Smm break; 2713209962Smm } 2714209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2715209962Smm return (EINVAL); 2716209962Smm *typep = type; 2717209962Smm 2718209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2719209962Smm type == ZFS_PROP_USERUSED); 2720209962Smm 2721209962Smm cp = strchr(propname, '@') + 1; 2722209962Smm 2723209962Smm if (strchr(cp, '@')) { 2724277300Ssmh#ifdef illumos 2725209962Smm /* 2726209962Smm * It's a SID name (eg "user@domain") that needs to be 2727209962Smm * turned into S-1-domainID-RID. 2728209962Smm */ 2729275579Sdelphij int flag = 0; 2730275579Sdelphij idmap_stat stat, map_stat; 2731275579Sdelphij uid_t pid; 2732275579Sdelphij idmap_rid_t rid; 2733275579Sdelphij idmap_get_handle_t *gh = NULL; 2734275579Sdelphij 2735275579Sdelphij stat = idmap_get_create(&gh); 2736275579Sdelphij if (stat != IDMAP_SUCCESS) { 2737275579Sdelphij idmap_get_destroy(gh); 2738275579Sdelphij return (ENOMEM); 2739275579Sdelphij } 2740209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2741209962Smm return (ENOENT); 2742209962Smm if (isuser) { 2743275579Sdelphij stat = idmap_getuidbywinname(cp, NULL, flag, &pid); 2744275579Sdelphij if (stat < 0) 2745275579Sdelphij return (ENOENT); 2746275579Sdelphij stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid, 2747275579Sdelphij &rid, &map_stat); 2748209962Smm } else { 2749275579Sdelphij stat = idmap_getgidbywinname(cp, NULL, flag, &pid); 2750275579Sdelphij if (stat < 0) 2751275579Sdelphij return (ENOENT); 2752275579Sdelphij stat = idmap_get_sidbygid(gh, pid, flag, &numericsid, 2753275579Sdelphij &rid, &map_stat); 2754209962Smm } 2755275579Sdelphij if (stat < 0) { 2756275579Sdelphij idmap_get_destroy(gh); 2757209962Smm return (ENOENT); 2758209962Smm } 2759275579Sdelphij stat = idmap_get_mappings(gh); 2760275579Sdelphij idmap_get_destroy(gh); 2761275579Sdelphij 2762275579Sdelphij if (stat < 0) { 2763275579Sdelphij return (ENOENT); 2764275579Sdelphij } 2765209962Smm if (numericsid == NULL) 2766209962Smm return (ENOENT); 2767209962Smm cp = numericsid; 2768275579Sdelphij *ridp = rid; 2769209962Smm /* will be further decoded below */ 2770277300Ssmh#else /* !illumos */ 2771219089Spjd return (ENOENT); 2772277300Ssmh#endif /* illumos */ 2773209962Smm } 2774209962Smm 2775209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2776209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2777209962Smm (void) strlcpy(domain, cp, domainlen); 2778209962Smm errno = 0; 2779275579Sdelphij if (*ridp == 0) { 2780275579Sdelphij cp = strrchr(domain, '-'); 2781275579Sdelphij *cp = '\0'; 2782275579Sdelphij cp++; 2783275579Sdelphij *ridp = strtoull(cp, &end, 10); 2784275579Sdelphij } else { 2785275579Sdelphij end = ""; 2786275579Sdelphij } 2787209962Smm if (numericsid) { 2788209962Smm free(numericsid); 2789209962Smm numericsid = NULL; 2790209962Smm } 2791209962Smm if (errno != 0 || *end != '\0') 2792209962Smm return (EINVAL); 2793209962Smm } else if (!isdigit(*cp)) { 2794209962Smm /* 2795209962Smm * It's a user/group name (eg "user") that needs to be 2796209962Smm * turned into a uid/gid 2797209962Smm */ 2798209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2799209962Smm return (ENOENT); 2800209962Smm if (isuser) { 2801209962Smm struct passwd *pw; 2802209962Smm pw = getpwnam(cp); 2803209962Smm if (pw == NULL) 2804209962Smm return (ENOENT); 2805209962Smm *ridp = pw->pw_uid; 2806209962Smm } else { 2807209962Smm struct group *gr; 2808209962Smm gr = getgrnam(cp); 2809209962Smm if (gr == NULL) 2810209962Smm return (ENOENT); 2811209962Smm *ridp = gr->gr_gid; 2812209962Smm } 2813209962Smm } else { 2814209962Smm /* It's a user/group ID (eg "12345"). */ 2815209962Smm uid_t id = strtoul(cp, &end, 10); 2816209962Smm idmap_rid_t rid; 2817209962Smm char *mapdomain; 2818209962Smm 2819209962Smm if (*end != '\0') 2820209962Smm return (EINVAL); 2821209962Smm if (id > MAXUID) { 2822209962Smm /* It's an ephemeral ID. */ 2823209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2824209962Smm &mapdomain, &rid) != 0) 2825209962Smm return (ENOENT); 2826209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2827209962Smm *ridp = rid; 2828209962Smm } else { 2829209962Smm *ridp = id; 2830209962Smm } 2831209962Smm } 2832209962Smm 2833209962Smm ASSERT3P(numericsid, ==, NULL); 2834209962Smm return (0); 2835209962Smm} 2836209962Smm 2837209962Smmstatic int 2838209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2839209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2840209962Smm{ 2841209962Smm int err; 2842209962Smm zfs_cmd_t zc = { 0 }; 2843209962Smm 2844228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2845209962Smm 2846209962Smm err = userquota_propname_decode(propname, 2847209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2848209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2849209962Smm zc.zc_objset_type = *typep; 2850209962Smm if (err) 2851209962Smm return (err); 2852209962Smm 2853209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2854209962Smm if (err) 2855209962Smm return (err); 2856209962Smm 2857209962Smm *propvalue = zc.zc_cookie; 2858209962Smm return (0); 2859209962Smm} 2860209962Smm 2861209962Smmint 2862209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2863209962Smm uint64_t *propvalue) 2864209962Smm{ 2865209962Smm zfs_userquota_prop_t type; 2866209962Smm 2867209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2868209962Smm &type)); 2869209962Smm} 2870209962Smm 2871209962Smmint 2872209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2873209962Smm char *propbuf, int proplen, boolean_t literal) 2874209962Smm{ 2875209962Smm int err; 2876209962Smm uint64_t propvalue; 2877209962Smm zfs_userquota_prop_t type; 2878209962Smm 2879209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2880209962Smm &type); 2881209962Smm 2882209962Smm if (err) 2883209962Smm return (err); 2884209962Smm 2885209962Smm if (literal) { 2886209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2887209962Smm } else if (propvalue == 0 && 2888209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2889209962Smm (void) strlcpy(propbuf, "none", proplen); 2890209962Smm } else { 2891209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2892209962Smm } 2893209962Smm return (0); 2894209962Smm} 2895209962Smm 2896228103Smmint 2897228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 2898228103Smm uint64_t *propvalue) 2899168404Spjd{ 2900228103Smm int err; 2901228103Smm zfs_cmd_t zc = { 0 }; 2902228103Smm const char *snapname; 2903168404Spjd 2904228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2905168404Spjd 2906228103Smm snapname = strchr(propname, '@') + 1; 2907228103Smm if (strchr(snapname, '@')) { 2908228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2909228103Smm } else { 2910228103Smm /* snapname is the short name, append it to zhp's fsname */ 2911228103Smm char *cp; 2912209962Smm 2913228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 2914228103Smm sizeof (zc.zc_value)); 2915228103Smm cp = strchr(zc.zc_value, '@'); 2916228103Smm if (cp != NULL) 2917228103Smm *cp = '\0'; 2918228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 2919228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 2920228103Smm } 2921209962Smm 2922228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 2923228103Smm if (err) 2924228103Smm return (err); 2925228103Smm 2926228103Smm *propvalue = zc.zc_cookie; 2927228103Smm return (0); 2928209962Smm} 2929209962Smm 2930168404Spjdint 2931228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 2932228103Smm char *propbuf, int proplen, boolean_t literal) 2933168404Spjd{ 2934228103Smm int err; 2935228103Smm uint64_t propvalue; 2936168404Spjd 2937228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 2938185029Spjd 2939228103Smm if (err) 2940228103Smm return (err); 2941209962Smm 2942228103Smm if (literal) { 2943228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2944228103Smm } else { 2945228103Smm zfs_nicenum(propvalue, propbuf, proplen); 2946168404Spjd } 2947228103Smm return (0); 2948168404Spjd} 2949168404Spjd 2950168404Spjd/* 2951228103Smm * Returns the name of the given zfs handle. 2952168404Spjd */ 2953228103Smmconst char * 2954228103Smmzfs_get_name(const zfs_handle_t *zhp) 2955168404Spjd{ 2956228103Smm return (zhp->zfs_name); 2957228103Smm} 2958168404Spjd 2959228103Smm/* 2960228103Smm * Returns the type of the given zfs handle. 2961228103Smm */ 2962228103Smmzfs_type_t 2963228103Smmzfs_get_type(const zfs_handle_t *zhp) 2964228103Smm{ 2965228103Smm return (zhp->zfs_type); 2966168404Spjd} 2967168404Spjd 2968168404Spjd/* 2969219089Spjd * Is one dataset name a child dataset of another? 2970219089Spjd * 2971219089Spjd * Needs to handle these cases: 2972219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2973219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2974219089Spjd * Descendant? No. No. No. Yes. 2975219089Spjd */ 2976219089Spjdstatic boolean_t 2977219089Spjdis_descendant(const char *ds1, const char *ds2) 2978219089Spjd{ 2979219089Spjd size_t d1len = strlen(ds1); 2980219089Spjd 2981219089Spjd /* ds2 can't be a descendant if it's smaller */ 2982219089Spjd if (strlen(ds2) < d1len) 2983219089Spjd return (B_FALSE); 2984219089Spjd 2985219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2986219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2987219089Spjd} 2988219089Spjd 2989219089Spjd/* 2990168404Spjd * Given a complete name, return just the portion that refers to the parent. 2991228103Smm * Will return -1 if there is no parent (path is just the name of the 2992228103Smm * pool). 2993168404Spjd */ 2994168404Spjdstatic int 2995168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2996168404Spjd{ 2997228103Smm char *slashp; 2998168404Spjd 2999228103Smm (void) strlcpy(buf, path, buflen); 3000228103Smm 3001228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 3002168404Spjd return (-1); 3003228103Smm *slashp = '\0'; 3004168404Spjd 3005168404Spjd return (0); 3006168404Spjd} 3007168404Spjd 3008168404Spjd/* 3009185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 3010185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 3011185029Spjd * closest existing ancestor for the given path. In prefixlen return the 3012185029Spjd * length of already existing prefix of the given path. We also fetch the 3013185029Spjd * 'zoned' property, which is used to validate property settings when creating 3014185029Spjd * new datasets. 3015168404Spjd */ 3016168404Spjdstatic int 3017185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 3018185029Spjd boolean_t accept_ancestor, int *prefixlen) 3019168404Spjd{ 3020168404Spjd zfs_cmd_t zc = { 0 }; 3021168404Spjd char parent[ZFS_MAXNAMELEN]; 3022168404Spjd char *slash; 3023168404Spjd zfs_handle_t *zhp; 3024168404Spjd char errbuf[1024]; 3025219089Spjd uint64_t is_zoned; 3026168404Spjd 3027209962Smm (void) snprintf(errbuf, sizeof (errbuf), 3028209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 3029168404Spjd 3030168404Spjd /* get parent, and check to see if this is just a pool */ 3031168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 3032168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3033168404Spjd "missing dataset name")); 3034168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3035168404Spjd } 3036168404Spjd 3037168404Spjd /* check to see if the pool exists */ 3038168404Spjd if ((slash = strchr(parent, '/')) == NULL) 3039168404Spjd slash = parent + strlen(parent); 3040168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 3041168404Spjd zc.zc_name[slash - parent] = '\0'; 3042168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 3043168404Spjd errno == ENOENT) { 3044168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3045168404Spjd "no such pool '%s'"), zc.zc_name); 3046168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3047168404Spjd } 3048168404Spjd 3049168404Spjd /* check to see if the parent dataset exists */ 3050185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 3051185029Spjd if (errno == ENOENT && accept_ancestor) { 3052185029Spjd /* 3053185029Spjd * Go deeper to find an ancestor, give up on top level. 3054185029Spjd */ 3055185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 3056185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3057185029Spjd "no such pool '%s'"), zc.zc_name); 3058185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3059185029Spjd } 3060185029Spjd } else if (errno == ENOENT) { 3061168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3062168404Spjd "parent does not exist")); 3063168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3064185029Spjd } else 3065168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3066168404Spjd } 3067168404Spjd 3068219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 3069219089Spjd if (zoned != NULL) 3070219089Spjd *zoned = is_zoned; 3071219089Spjd 3072168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 3073219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 3074168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 3075168404Spjd zfs_close(zhp); 3076168404Spjd return (-1); 3077168404Spjd } 3078168404Spjd 3079168404Spjd /* make sure parent is a filesystem */ 3080168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 3081168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3082168404Spjd "parent is not a filesystem")); 3083168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3084168404Spjd zfs_close(zhp); 3085168404Spjd return (-1); 3086168404Spjd } 3087168404Spjd 3088168404Spjd zfs_close(zhp); 3089185029Spjd if (prefixlen != NULL) 3090185029Spjd *prefixlen = strlen(parent); 3091168404Spjd return (0); 3092168404Spjd} 3093168404Spjd 3094168404Spjd/* 3095185029Spjd * Finds whether the dataset of the given type(s) exists. 3096185029Spjd */ 3097185029Spjdboolean_t 3098185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 3099185029Spjd{ 3100185029Spjd zfs_handle_t *zhp; 3101185029Spjd 3102185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 3103185029Spjd return (B_FALSE); 3104185029Spjd 3105185029Spjd /* 3106185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 3107185029Spjd */ 3108185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 3109185029Spjd int ds_type = zhp->zfs_type; 3110185029Spjd 3111185029Spjd zfs_close(zhp); 3112185029Spjd if (types & ds_type) 3113185029Spjd return (B_TRUE); 3114185029Spjd } 3115185029Spjd return (B_FALSE); 3116185029Spjd} 3117185029Spjd 3118185029Spjd/* 3119185029Spjd * Given a path to 'target', create all the ancestors between 3120185029Spjd * the prefixlen portion of the path, and the target itself. 3121185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 3122185029Spjd */ 3123185029Spjdint 3124185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 3125185029Spjd{ 3126185029Spjd zfs_handle_t *h; 3127185029Spjd char *cp; 3128185029Spjd const char *opname; 3129185029Spjd 3130185029Spjd /* make sure prefix exists */ 3131185029Spjd cp = target + prefixlen; 3132185029Spjd if (*cp != '/') { 3133185029Spjd assert(strchr(cp, '/') == NULL); 3134185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3135185029Spjd } else { 3136185029Spjd *cp = '\0'; 3137185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3138185029Spjd *cp = '/'; 3139185029Spjd } 3140185029Spjd if (h == NULL) 3141185029Spjd return (-1); 3142185029Spjd zfs_close(h); 3143185029Spjd 3144185029Spjd /* 3145185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 3146185029Spjd * up to the prefixlen-long one. 3147185029Spjd */ 3148185029Spjd for (cp = target + prefixlen + 1; 3149185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 3150185029Spjd 3151185029Spjd *cp = '\0'; 3152185029Spjd 3153185029Spjd h = make_dataset_handle(hdl, target); 3154185029Spjd if (h) { 3155185029Spjd /* it already exists, nothing to do here */ 3156185029Spjd zfs_close(h); 3157185029Spjd continue; 3158185029Spjd } 3159185029Spjd 3160185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 3161185029Spjd NULL) != 0) { 3162185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 3163185029Spjd goto ancestorerr; 3164185029Spjd } 3165185029Spjd 3166185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 3167185029Spjd if (h == NULL) { 3168185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 3169185029Spjd goto ancestorerr; 3170185029Spjd } 3171185029Spjd 3172185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 3173185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 3174185029Spjd goto ancestorerr; 3175185029Spjd } 3176185029Spjd 3177185029Spjd if (zfs_share(h) != 0) { 3178185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 3179185029Spjd goto ancestorerr; 3180185029Spjd } 3181185029Spjd 3182185029Spjd zfs_close(h); 3183185029Spjd } 3184185029Spjd 3185185029Spjd return (0); 3186185029Spjd 3187185029Spjdancestorerr: 3188185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3189185029Spjd "failed to %s ancestor '%s'"), opname, target); 3190185029Spjd return (-1); 3191185029Spjd} 3192185029Spjd 3193185029Spjd/* 3194185029Spjd * Creates non-existing ancestors of the given path. 3195185029Spjd */ 3196185029Spjdint 3197185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3198185029Spjd{ 3199185029Spjd int prefix; 3200185029Spjd char *path_copy; 3201185029Spjd int rc; 3202185029Spjd 3203219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3204185029Spjd return (-1); 3205185029Spjd 3206185029Spjd if ((path_copy = strdup(path)) != NULL) { 3207185029Spjd rc = create_parents(hdl, path_copy, prefix); 3208185029Spjd free(path_copy); 3209185029Spjd } 3210185029Spjd if (path_copy == NULL || rc != 0) 3211185029Spjd return (-1); 3212185029Spjd 3213185029Spjd return (0); 3214185029Spjd} 3215185029Spjd 3216185029Spjd/* 3217168404Spjd * Create a new filesystem or volume. 3218168404Spjd */ 3219168404Spjdint 3220168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3221168404Spjd nvlist_t *props) 3222168404Spjd{ 3223168404Spjd int ret; 3224168404Spjd uint64_t size = 0; 3225168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3226168404Spjd char errbuf[1024]; 3227168404Spjd uint64_t zoned; 3228248571Smm dmu_objset_type_t ost; 3229168404Spjd 3230168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3231168404Spjd "cannot create '%s'"), path); 3232168404Spjd 3233168404Spjd /* validate the path, taking care to note the extended error message */ 3234185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3235168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3236168404Spjd 3237168404Spjd /* validate parents exist */ 3238185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3239168404Spjd return (-1); 3240168404Spjd 3241168404Spjd /* 3242168404Spjd * The failure modes when creating a dataset of a different type over 3243168404Spjd * one that already exists is a little strange. In particular, if you 3244168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3245168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3246168404Spjd * first try to see if the dataset exists. 3247168404Spjd */ 3248248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3249168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3250168404Spjd "dataset already exists")); 3251168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3252168404Spjd } 3253168404Spjd 3254168404Spjd if (type == ZFS_TYPE_VOLUME) 3255248571Smm ost = DMU_OST_ZVOL; 3256168404Spjd else 3257248571Smm ost = DMU_OST_ZFS; 3258168404Spjd 3259289500Smav /* open zpool handle for prop validation */ 3260289500Smav char pool_path[MAXNAMELEN]; 3261289500Smav (void) strlcpy(pool_path, path, sizeof (pool_path)); 3262289500Smav 3263289500Smav /* truncate pool_path at first slash */ 3264289500Smav char *p = strchr(pool_path, '/'); 3265289500Smav if (p != NULL) 3266289500Smav *p = '\0'; 3267289500Smav 3268289500Smav zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path); 3269289500Smav 3270185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3271289500Smav zoned, NULL, zpool_handle, errbuf)) == 0) { 3272289500Smav zpool_close(zpool_handle); 3273168404Spjd return (-1); 3274289500Smav } 3275289500Smav zpool_close(zpool_handle); 3276168404Spjd 3277168404Spjd if (type == ZFS_TYPE_VOLUME) { 3278168404Spjd /* 3279168404Spjd * If we are creating a volume, the size and block size must 3280168404Spjd * satisfy a few restraints. First, the blocksize must be a 3281168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3282168404Spjd * volsize must be a multiple of the block size, and cannot be 3283168404Spjd * zero. 3284168404Spjd */ 3285168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3286168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3287168404Spjd nvlist_free(props); 3288168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3289168404Spjd "missing volume size")); 3290168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3291168404Spjd } 3292168404Spjd 3293168404Spjd if ((ret = nvlist_lookup_uint64(props, 3294168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3295168404Spjd &blocksize)) != 0) { 3296168404Spjd if (ret == ENOENT) { 3297168404Spjd blocksize = zfs_prop_default_numeric( 3298168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3299168404Spjd } else { 3300168404Spjd nvlist_free(props); 3301168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3302168404Spjd "missing volume block size")); 3303168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3304168404Spjd } 3305168404Spjd } 3306168404Spjd 3307168404Spjd if (size == 0) { 3308168404Spjd nvlist_free(props); 3309168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3310168404Spjd "volume size cannot be zero")); 3311168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3312168404Spjd } 3313168404Spjd 3314168404Spjd if (size % blocksize != 0) { 3315168404Spjd nvlist_free(props); 3316168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3317168404Spjd "volume size must be a multiple of volume block " 3318168404Spjd "size")); 3319168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3320168404Spjd } 3321168404Spjd } 3322168404Spjd 3323248571Smm /* create the dataset */ 3324248571Smm ret = lzc_create(path, ost, props); 3325168404Spjd nvlist_free(props); 3326168404Spjd 3327168404Spjd /* check for failure */ 3328168404Spjd if (ret != 0) { 3329168404Spjd char parent[ZFS_MAXNAMELEN]; 3330168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3331168404Spjd 3332168404Spjd switch (errno) { 3333168404Spjd case ENOENT: 3334168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3335168404Spjd "no such parent '%s'"), parent); 3336168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3337168404Spjd 3338168404Spjd case EINVAL: 3339168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3340168404Spjd "parent '%s' is not a filesystem"), parent); 3341168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3342168404Spjd 3343185029Spjd case ENOTSUP: 3344185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3345185029Spjd "pool must be upgraded to set this " 3346185029Spjd "property or value")); 3347185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3348168404Spjd#ifdef _ILP32 3349168404Spjd case EOVERFLOW: 3350168404Spjd /* 3351168404Spjd * This platform can't address a volume this big. 3352168404Spjd */ 3353168404Spjd if (type == ZFS_TYPE_VOLUME) 3354168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3355168404Spjd errbuf)); 3356168404Spjd#endif 3357168404Spjd /* FALLTHROUGH */ 3358168404Spjd default: 3359168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3360168404Spjd } 3361168404Spjd } 3362168404Spjd 3363168404Spjd return (0); 3364168404Spjd} 3365168404Spjd 3366168404Spjd/* 3367168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3368238422Smm * isn't mounted, and that there are no active dependents. If the file system 3369238422Smm * does not exist this function does nothing. 3370168404Spjd */ 3371168404Spjdint 3372219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3373168404Spjd{ 3374168404Spjd zfs_cmd_t zc = { 0 }; 3375168404Spjd 3376260183Sdelphij if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3377260183Sdelphij nvlist_t *nv = fnvlist_alloc(); 3378260183Sdelphij fnvlist_add_boolean(nv, zhp->zfs_name); 3379260183Sdelphij int error = lzc_destroy_bookmarks(nv, NULL); 3380260183Sdelphij fnvlist_free(nv); 3381260183Sdelphij if (error != 0) { 3382260183Sdelphij return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3383260183Sdelphij dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3384260183Sdelphij zhp->zfs_name)); 3385260183Sdelphij } 3386260183Sdelphij return (0); 3387260183Sdelphij } 3388260183Sdelphij 3389168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3390168404Spjd 3391168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3392168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3393168404Spjd } else { 3394168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3395168404Spjd } 3396168404Spjd 3397219089Spjd zc.zc_defer_destroy = defer; 3398238422Smm if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && 3399238422Smm errno != ENOENT) { 3400168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3401168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3402168404Spjd zhp->zfs_name)); 3403168404Spjd } 3404168404Spjd 3405168404Spjd remove_mountpoint(zhp); 3406168404Spjd 3407168404Spjd return (0); 3408168404Spjd} 3409168404Spjd 3410168404Spjdstruct destroydata { 3411228103Smm nvlist_t *nvl; 3412228103Smm const char *snapname; 3413168404Spjd}; 3414168404Spjd 3415168404Spjdstatic int 3416219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3417168404Spjd{ 3418168404Spjd struct destroydata *dd = arg; 3419168404Spjd char name[ZFS_MAXNAMELEN]; 3420219089Spjd int rv = 0; 3421168404Spjd 3422228103Smm (void) snprintf(name, sizeof (name), 3423228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3424168404Spjd 3425251646Sdelphij if (lzc_exists(name)) 3426228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3427168404Spjd 3428228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3429228103Smm zfs_close(zhp); 3430168404Spjd return (rv); 3431168404Spjd} 3432168404Spjd 3433168404Spjd/* 3434168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3435168404Spjd */ 3436168404Spjdint 3437219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3438168404Spjd{ 3439168404Spjd int ret; 3440168404Spjd struct destroydata dd = { 0 }; 3441168404Spjd 3442168404Spjd dd.snapname = snapname; 3443228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3444228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3445168404Spjd 3446251646Sdelphij if (nvlist_empty(dd.nvl)) { 3447228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3448168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3449228103Smm zhp->zfs_name, snapname); 3450228103Smm } else { 3451248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3452168404Spjd } 3453228103Smm nvlist_free(dd.nvl); 3454228103Smm return (ret); 3455228103Smm} 3456168404Spjd 3457228103Smm/* 3458248571Smm * Destroys all the snapshots named in the nvlist. 3459228103Smm */ 3460228103Smmint 3461248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3462228103Smm{ 3463228103Smm int ret; 3464248571Smm nvlist_t *errlist; 3465228103Smm 3466248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3467168404Spjd 3468248571Smm if (ret == 0) 3469248571Smm return (0); 3470248571Smm 3471251646Sdelphij if (nvlist_empty(errlist)) { 3472168404Spjd char errbuf[1024]; 3473248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3474248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3475168404Spjd 3476248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3477248571Smm } 3478248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3479248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3480248571Smm char errbuf[1024]; 3481248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3482248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3483248571Smm nvpair_name(pair)); 3484168404Spjd 3485248571Smm switch (fnvpair_value_int32(pair)) { 3486168404Spjd case EEXIST: 3487248571Smm zfs_error_aux(hdl, 3488248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3489248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3490248571Smm break; 3491168404Spjd default: 3492248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3493248571Smm break; 3494168404Spjd } 3495168404Spjd } 3496168404Spjd 3497248571Smm return (ret); 3498168404Spjd} 3499168404Spjd 3500168404Spjd/* 3501168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3502168404Spjd */ 3503168404Spjdint 3504168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3505168404Spjd{ 3506168404Spjd char parent[ZFS_MAXNAMELEN]; 3507168404Spjd int ret; 3508168404Spjd char errbuf[1024]; 3509168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3510168404Spjd uint64_t zoned; 3511168404Spjd 3512168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3513168404Spjd 3514168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3515168404Spjd "cannot create '%s'"), target); 3516168404Spjd 3517228103Smm /* validate the target/clone name */ 3518185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3519168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3520168404Spjd 3521168404Spjd /* validate parents exist */ 3522185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3523168404Spjd return (-1); 3524168404Spjd 3525168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3526168404Spjd 3527168404Spjd /* do the clone */ 3528168404Spjd 3529168404Spjd if (props) { 3530248571Smm zfs_type_t type; 3531248571Smm if (ZFS_IS_VOLUME(zhp)) { 3532248571Smm type = ZFS_TYPE_VOLUME; 3533248571Smm } else { 3534248571Smm type = ZFS_TYPE_FILESYSTEM; 3535248571Smm } 3536185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3537289500Smav zhp, zhp->zpool_hdl, errbuf)) == NULL) 3538168404Spjd return (-1); 3539168404Spjd } 3540168404Spjd 3541248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3542248571Smm nvlist_free(props); 3543168404Spjd 3544168404Spjd if (ret != 0) { 3545168404Spjd switch (errno) { 3546168404Spjd 3547168404Spjd case ENOENT: 3548168404Spjd /* 3549168404Spjd * The parent doesn't exist. We should have caught this 3550168404Spjd * above, but there may a race condition that has since 3551168404Spjd * destroyed the parent. 3552168404Spjd * 3553168404Spjd * At this point, we don't know whether it's the source 3554168404Spjd * that doesn't exist anymore, or whether the target 3555168404Spjd * dataset doesn't exist. 3556168404Spjd */ 3557168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3558168404Spjd "no such parent '%s'"), parent); 3559168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3560168404Spjd 3561168404Spjd case EXDEV: 3562168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3563168404Spjd "source and target pools differ")); 3564168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3565168404Spjd errbuf)); 3566168404Spjd 3567168404Spjd default: 3568168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3569168404Spjd errbuf)); 3570168404Spjd } 3571168404Spjd } 3572168404Spjd 3573168404Spjd return (ret); 3574168404Spjd} 3575168404Spjd 3576168404Spjd/* 3577168404Spjd * Promotes the given clone fs to be the clone parent. 3578168404Spjd */ 3579168404Spjdint 3580168404Spjdzfs_promote(zfs_handle_t *zhp) 3581168404Spjd{ 3582168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3583168404Spjd zfs_cmd_t zc = { 0 }; 3584168404Spjd char parent[MAXPATHLEN]; 3585168404Spjd int ret; 3586168404Spjd char errbuf[1024]; 3587168404Spjd 3588168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3589168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3590168404Spjd 3591168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3592168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3593168404Spjd "snapshots can not be promoted")); 3594168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3595168404Spjd } 3596168404Spjd 3597185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3598168404Spjd if (parent[0] == '\0') { 3599168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3600168404Spjd "not a cloned filesystem")); 3601168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3602168404Spjd } 3603168404Spjd 3604185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3605168404Spjd sizeof (zc.zc_value)); 3606168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3607185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3608168404Spjd 3609168404Spjd if (ret != 0) { 3610168404Spjd int save_errno = errno; 3611168404Spjd 3612168404Spjd switch (save_errno) { 3613168404Spjd case EEXIST: 3614219089Spjd /* There is a conflicting snapshot name. */ 3615168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3616219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3617219089Spjd zc.zc_string, parent); 3618168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3619168404Spjd 3620168404Spjd default: 3621168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3622168404Spjd } 3623168404Spjd } 3624168404Spjd return (ret); 3625168404Spjd} 3626168404Spjd 3627248571Smmtypedef struct snapdata { 3628248571Smm nvlist_t *sd_nvl; 3629248571Smm const char *sd_snapname; 3630248571Smm} snapdata_t; 3631248571Smm 3632248571Smmstatic int 3633248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3634248571Smm{ 3635248571Smm snapdata_t *sd = arg; 3636248571Smm char name[ZFS_MAXNAMELEN]; 3637248571Smm int rv = 0; 3638248571Smm 3639253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3640253819Sdelphij (void) snprintf(name, sizeof (name), 3641253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3642248571Smm 3643253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3644248571Smm 3645253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3646253819Sdelphij } 3647248571Smm zfs_close(zhp); 3648253819Sdelphij 3649248571Smm return (rv); 3650248571Smm} 3651248571Smm 3652168404Spjd/* 3653248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3654248571Smm * created. 3655168404Spjd */ 3656168404Spjdint 3657248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3658168404Spjd{ 3659168404Spjd int ret; 3660168404Spjd char errbuf[1024]; 3661248571Smm nvpair_t *elem; 3662248571Smm nvlist_t *errors; 3663168404Spjd 3664168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3665248571Smm "cannot create snapshots ")); 3666168404Spjd 3667248571Smm elem = NULL; 3668248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3669248571Smm const char *snapname = nvpair_name(elem); 3670168404Spjd 3671248571Smm /* validate the target name */ 3672248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3673248571Smm B_TRUE)) { 3674248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3675248571Smm dgettext(TEXT_DOMAIN, 3676248571Smm "cannot create snapshot '%s'"), snapname); 3677248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3678248571Smm } 3679248571Smm } 3680185029Spjd 3681289500Smav /* 3682289500Smav * get pool handle for prop validation. assumes all snaps are in the 3683289500Smav * same pool, as does lzc_snapshot (below). 3684289500Smav */ 3685289500Smav char pool[MAXNAMELEN]; 3686289500Smav elem = nvlist_next_nvpair(snaps, NULL); 3687289500Smav (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); 3688289500Smav pool[strcspn(pool, "/@")] = '\0'; 3689289500Smav zpool_handle_t *zpool_hdl = zpool_open(hdl, pool); 3690289500Smav 3691248571Smm if (props != NULL && 3692248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3693289500Smav props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) { 3694289500Smav zpool_close(zpool_hdl); 3695248571Smm return (-1); 3696248571Smm } 3697289500Smav zpool_close(zpool_hdl); 3698248571Smm 3699248571Smm ret = lzc_snapshot(snaps, props, &errors); 3700248571Smm 3701248571Smm if (ret != 0) { 3702248571Smm boolean_t printed = B_FALSE; 3703248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 3704248571Smm elem != NULL; 3705248571Smm elem = nvlist_next_nvpair(errors, elem)) { 3706248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3707248571Smm dgettext(TEXT_DOMAIN, 3708248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 3709248571Smm (void) zfs_standard_error(hdl, 3710248571Smm fnvpair_value_int32(elem), errbuf); 3711248571Smm printed = B_TRUE; 3712185029Spjd } 3713248571Smm if (!printed) { 3714248571Smm switch (ret) { 3715248571Smm case EXDEV: 3716248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3717248571Smm "multiple snapshots of same " 3718248571Smm "fs not allowed")); 3719248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3720185029Spjd 3721248571Smm break; 3722248571Smm default: 3723248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 3724248571Smm } 3725248571Smm } 3726185029Spjd } 3727185029Spjd 3728248571Smm nvlist_free(props); 3729248571Smm nvlist_free(errors); 3730248571Smm return (ret); 3731248571Smm} 3732168404Spjd 3733248571Smmint 3734248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3735248571Smm nvlist_t *props) 3736248571Smm{ 3737248571Smm int ret; 3738248571Smm snapdata_t sd = { 0 }; 3739248571Smm char fsname[ZFS_MAXNAMELEN]; 3740248571Smm char *cp; 3741248571Smm zfs_handle_t *zhp; 3742248571Smm char errbuf[1024]; 3743248571Smm 3744248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3745248571Smm "cannot snapshot %s"), path); 3746248571Smm 3747248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3748248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3749248571Smm 3750248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 3751248571Smm cp = strchr(fsname, '@'); 3752248571Smm *cp = '\0'; 3753248571Smm sd.sd_snapname = cp + 1; 3754248571Smm 3755248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 3756168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3757168404Spjd return (-1); 3758168404Spjd } 3759168404Spjd 3760248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 3761248571Smm if (recursive) { 3762248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 3763248571Smm } else { 3764248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 3765168404Spjd } 3766168404Spjd 3767248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 3768248571Smm nvlist_free(sd.sd_nvl); 3769168404Spjd zfs_close(zhp); 3770168404Spjd return (ret); 3771168404Spjd} 3772168404Spjd 3773168404Spjd/* 3774168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3775168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3776168404Spjd * is a dependent and we should just destroy it without checking the transaction 3777168404Spjd * group. 3778168404Spjd */ 3779168404Spjdtypedef struct rollback_data { 3780168404Spjd const char *cb_target; /* the snapshot */ 3781168404Spjd uint64_t cb_create; /* creation time reference */ 3782185029Spjd boolean_t cb_error; 3783185029Spjd boolean_t cb_force; 3784168404Spjd} rollback_data_t; 3785168404Spjd 3786168404Spjdstatic int 3787260183Sdelphijrollback_destroy_dependent(zfs_handle_t *zhp, void *data) 3788168404Spjd{ 3789168404Spjd rollback_data_t *cbp = data; 3790260183Sdelphij prop_changelist_t *clp; 3791168404Spjd 3792260183Sdelphij /* We must destroy this clone; first unmount it */ 3793260183Sdelphij clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3794260183Sdelphij cbp->cb_force ? MS_FORCE: 0); 3795260183Sdelphij if (clp == NULL || changelist_prefix(clp) != 0) { 3796260183Sdelphij cbp->cb_error = B_TRUE; 3797260183Sdelphij zfs_close(zhp); 3798260183Sdelphij return (0); 3799260183Sdelphij } 3800260183Sdelphij if (zfs_destroy(zhp, B_FALSE) != 0) 3801260183Sdelphij cbp->cb_error = B_TRUE; 3802260183Sdelphij else 3803260183Sdelphij changelist_remove(clp, zhp->zfs_name); 3804260183Sdelphij (void) changelist_postfix(clp); 3805260183Sdelphij changelist_free(clp); 3806168404Spjd 3807260183Sdelphij zfs_close(zhp); 3808260183Sdelphij return (0); 3809260183Sdelphij} 3810168404Spjd 3811260183Sdelphijstatic int 3812260183Sdelphijrollback_destroy(zfs_handle_t *zhp, void *data) 3813260183Sdelphij{ 3814260183Sdelphij rollback_data_t *cbp = data; 3815185029Spjd 3816260183Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 3817260183Sdelphij cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3818260183Sdelphij rollback_destroy_dependent, cbp); 3819260183Sdelphij 3820260183Sdelphij cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3821168404Spjd } 3822168404Spjd 3823168404Spjd zfs_close(zhp); 3824168404Spjd return (0); 3825168404Spjd} 3826168404Spjd 3827168404Spjd/* 3828168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3829168404Spjd * data changes since then and making it the active dataset. 3830168404Spjd * 3831260183Sdelphij * Any snapshots and bookmarks more recent than the target are 3832260183Sdelphij * destroyed, along with their dependents (i.e. clones). 3833168404Spjd */ 3834168404Spjdint 3835185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3836168404Spjd{ 3837168404Spjd rollback_data_t cb = { 0 }; 3838185029Spjd int err; 3839185029Spjd boolean_t restore_resv = 0; 3840185029Spjd uint64_t old_volsize, new_volsize; 3841185029Spjd zfs_prop_t resv_prop; 3842168404Spjd 3843185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3844185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3845168404Spjd 3846168404Spjd /* 3847239774Smm * Destroy all recent snapshots and their dependents. 3848168404Spjd */ 3849185029Spjd cb.cb_force = force; 3850168404Spjd cb.cb_target = snap->zfs_name; 3851168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3852260183Sdelphij (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb); 3853260183Sdelphij (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); 3854168404Spjd 3855185029Spjd if (cb.cb_error) 3856185029Spjd return (-1); 3857168404Spjd 3858168404Spjd /* 3859168404Spjd * Now that we have verified that the snapshot is the latest, 3860168404Spjd * rollback to the given snapshot. 3861168404Spjd */ 3862168404Spjd 3863185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3864185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3865185029Spjd return (-1); 3866185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3867185029Spjd restore_resv = 3868185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3869168404Spjd } 3870168404Spjd 3871168404Spjd /* 3872185029Spjd * We rely on zfs_iter_children() to verify that there are no 3873185029Spjd * newer snapshots for the given dataset. Therefore, we can 3874185029Spjd * simply pass the name on to the ioctl() call. There is still 3875185029Spjd * an unlikely race condition where the user has taken a 3876185029Spjd * snapshot since we verified that this was the most recent. 3877168404Spjd */ 3878254587Sdelphij err = lzc_rollback(zhp->zfs_name, NULL, 0); 3879254587Sdelphij if (err != 0) { 3880185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3881185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3882185029Spjd zhp->zfs_name); 3883185029Spjd return (err); 3884185029Spjd } 3885168404Spjd 3886185029Spjd /* 3887185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3888185029Spjd * rollback reservation and the volsize has changed then set 3889185029Spjd * the reservation property to the post-rollback volsize. 3890185029Spjd * Make a new handle since the rollback closed the dataset. 3891185029Spjd */ 3892185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3893185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3894185029Spjd if (restore_resv) { 3895185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3896185029Spjd if (old_volsize != new_volsize) 3897185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3898185029Spjd new_volsize); 3899185029Spjd } 3900185029Spjd zfs_close(zhp); 3901185029Spjd } 3902185029Spjd return (err); 3903168404Spjd} 3904168404Spjd 3905168404Spjd/* 3906168404Spjd * Renames the given dataset. 3907168404Spjd */ 3908168404Spjdint 3909240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 3910240870Spjd renameflags_t flags) 3911168404Spjd{ 3912168404Spjd int ret; 3913168404Spjd zfs_cmd_t zc = { 0 }; 3914168404Spjd char *delim; 3915168676Spjd prop_changelist_t *cl = NULL; 3916168676Spjd zfs_handle_t *zhrp = NULL; 3917168676Spjd char *parentname = NULL; 3918168404Spjd char parent[ZFS_MAXNAMELEN]; 3919226676Spjd char property[ZFS_MAXPROPLEN]; 3920168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3921168404Spjd char errbuf[1024]; 3922168404Spjd 3923168404Spjd /* if we have the same exact name, just return success */ 3924168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3925168404Spjd return (0); 3926168404Spjd 3927168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3928168404Spjd "cannot rename to '%s'"), target); 3929168404Spjd 3930240870Spjd if (source != NULL) { 3931240870Spjd /* 3932240870Spjd * This is recursive snapshots rename, put snapshot name 3933240870Spjd * (that might not exist) into zfs_name. 3934240870Spjd */ 3935240870Spjd assert(flags.recurse); 3936240870Spjd 3937240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 3938240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 3939240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 3940240870Spjd } 3941240870Spjd 3942168404Spjd /* 3943168404Spjd * Make sure the target name is valid 3944168404Spjd */ 3945168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3946168404Spjd if ((strchr(target, '@') == NULL) || 3947168404Spjd *target == '@') { 3948168404Spjd /* 3949168404Spjd * Snapshot target name is abbreviated, 3950168404Spjd * reconstruct full dataset name 3951168404Spjd */ 3952168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3953168404Spjd sizeof (parent)); 3954168404Spjd delim = strchr(parent, '@'); 3955168404Spjd if (strchr(target, '@') == NULL) 3956168404Spjd *(++delim) = '\0'; 3957168404Spjd else 3958168404Spjd *delim = '\0'; 3959168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3960168404Spjd target = parent; 3961168404Spjd } else { 3962168404Spjd /* 3963168404Spjd * Make sure we're renaming within the same dataset. 3964168404Spjd */ 3965168404Spjd delim = strchr(target, '@'); 3966168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3967168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3968168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3969168404Spjd "snapshots must be part of same " 3970168404Spjd "dataset")); 3971168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3972168404Spjd errbuf)); 3973168404Spjd } 3974168404Spjd } 3975185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3976168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3977168404Spjd } else { 3978226705Spjd if (flags.recurse) { 3979168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3980168676Spjd "recursive rename must be a snapshot")); 3981168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3982168676Spjd } 3983168676Spjd 3984185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3985168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3986168404Spjd 3987168404Spjd /* validate parents */ 3988219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3989168404Spjd return (-1); 3990168404Spjd 3991168404Spjd /* make sure we're in the same pool */ 3992168404Spjd verify((delim = strchr(target, '/')) != NULL); 3993168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3994168404Spjd zhp->zfs_name[delim - target] != '/') { 3995168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3996168404Spjd "datasets must be within same pool")); 3997168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3998168404Spjd } 3999168404Spjd 4000168404Spjd /* new name cannot be a child of the current dataset name */ 4001219089Spjd if (is_descendant(zhp->zfs_name, target)) { 4002168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4003219089Spjd "New dataset name cannot be a descendant of " 4004168404Spjd "current dataset name")); 4005168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 4006168404Spjd } 4007168404Spjd } 4008168404Spjd 4009168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4010168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 4011168404Spjd 4012168404Spjd if (getzoneid() == GLOBAL_ZONEID && 4013168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 4014168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4015168404Spjd "dataset is used in a non-global zone")); 4016168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 4017168404Spjd } 4018168404Spjd 4019226705Spjd /* 4020226705Spjd * Avoid unmounting file systems with mountpoint property set to 4021226705Spjd * 'legacy' or 'none' even if -u option is not given. 4022226705Spjd */ 4023226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 4024226705Spjd !flags.recurse && !flags.nounmount && 4025226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 4026226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 4027226705Spjd (strcmp(property, "legacy") == 0 || 4028226705Spjd strcmp(property, "none") == 0)) { 4029226705Spjd flags.nounmount = B_TRUE; 4030226705Spjd } 4031226705Spjd if (flags.recurse) { 4032226705Spjd 4033185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 4034185029Spjd if (parentname == NULL) { 4035185029Spjd ret = -1; 4036185029Spjd goto error; 4037185029Spjd } 4038168676Spjd delim = strchr(parentname, '@'); 4039168676Spjd *delim = '\0'; 4040185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 4041168676Spjd if (zhrp == NULL) { 4042185029Spjd ret = -1; 4043185029Spjd goto error; 4044168676Spjd } 4045268469Sdelphij } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { 4046226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 4047235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 4048235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 4049168676Spjd return (-1); 4050226676Spjd } 4051168676Spjd 4052168676Spjd if (changelist_haszonedchild(cl)) { 4053168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4054168676Spjd "child dataset with inherited mountpoint is used " 4055168676Spjd "in a non-global zone")); 4056168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 4057168676Spjd goto error; 4058168676Spjd } 4059168676Spjd 4060168676Spjd if ((ret = changelist_prefix(cl)) != 0) 4061168676Spjd goto error; 4062168404Spjd } 4063168404Spjd 4064168404Spjd if (ZFS_IS_VOLUME(zhp)) 4065168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 4066168404Spjd else 4067168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4068168404Spjd 4069168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4070168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 4071168404Spjd 4072226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 4073226705Spjd if (flags.nounmount) 4074226676Spjd zc.zc_cookie |= 2; 4075168676Spjd 4076185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 4077168676Spjd /* 4078168676Spjd * if it was recursive, the one that actually failed will 4079168676Spjd * be in zc.zc_name 4080168676Spjd */ 4081168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4082185029Spjd "cannot rename '%s'"), zc.zc_name); 4083168404Spjd 4084226705Spjd if (flags.recurse && errno == EEXIST) { 4085168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4086168676Spjd "a child dataset already has a snapshot " 4087168676Spjd "with the new name")); 4088185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 4089168676Spjd } else { 4090168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 4091168676Spjd } 4092168676Spjd 4093168404Spjd /* 4094168404Spjd * On failure, we still want to remount any filesystems that 4095168404Spjd * were previously mounted, so we don't alter the system state. 4096168404Spjd */ 4097268469Sdelphij if (cl != NULL) 4098168676Spjd (void) changelist_postfix(cl); 4099168404Spjd } else { 4100268469Sdelphij if (cl != NULL) { 4101168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 4102168676Spjd ret = changelist_postfix(cl); 4103168676Spjd } 4104168404Spjd } 4105168404Spjd 4106168404Spjderror: 4107268469Sdelphij if (parentname != NULL) { 4108168676Spjd free(parentname); 4109168676Spjd } 4110268469Sdelphij if (zhrp != NULL) { 4111168676Spjd zfs_close(zhrp); 4112168676Spjd } 4113268469Sdelphij if (cl != NULL) { 4114168676Spjd changelist_free(cl); 4115168676Spjd } 4116168404Spjd return (ret); 4117168404Spjd} 4118168404Spjd 4119219089Spjdnvlist_t * 4120219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 4121168404Spjd{ 4122219089Spjd return (zhp->zfs_user_props); 4123168676Spjd} 4124168676Spjd 4125168404Spjdnvlist_t * 4126219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 4127168404Spjd{ 4128219089Spjd if (zhp->zfs_recvd_props == NULL) 4129219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 4130219089Spjd return (NULL); 4131219089Spjd return (zhp->zfs_recvd_props); 4132168404Spjd} 4133168404Spjd 4134168404Spjd/* 4135168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 4136168404Spjd * display, and their maximum widths. This does two main things: 4137168404Spjd * 4138168404Spjd * - If this is a list of all properties, then expand the list to include 4139168404Spjd * all native properties, and set a flag so that for each dataset we look 4140168404Spjd * for new unique user properties and add them to the list. 4141168404Spjd * 4142168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 4143219089Spjd * so that we can size the column appropriately. If the user has 4144219089Spjd * requested received property values, we also need to compute the width 4145219089Spjd * of the RECEIVED column. 4146168404Spjd */ 4147168404Spjdint 4148259850Sdelphijzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 4149259850Sdelphij boolean_t literal) 4150168404Spjd{ 4151168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4152185029Spjd zprop_list_t *entry; 4153185029Spjd zprop_list_t **last, **start; 4154168404Spjd nvlist_t *userprops, *propval; 4155168404Spjd nvpair_t *elem; 4156168404Spjd char *strval; 4157168404Spjd char buf[ZFS_MAXPROPLEN]; 4158168404Spjd 4159185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 4160168404Spjd return (-1); 4161168404Spjd 4162168404Spjd userprops = zfs_get_user_props(zhp); 4163168404Spjd 4164168404Spjd entry = *plp; 4165168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4166168404Spjd /* 4167168404Spjd * Go through and add any user properties as necessary. We 4168168404Spjd * start by incrementing our list pointer to the first 4169168404Spjd * non-native property. 4170168404Spjd */ 4171168404Spjd start = plp; 4172168404Spjd while (*start != NULL) { 4173185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 4174168404Spjd break; 4175168404Spjd start = &(*start)->pl_next; 4176168404Spjd } 4177168404Spjd 4178168404Spjd elem = NULL; 4179168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4180168404Spjd /* 4181168404Spjd * See if we've already found this property in our list. 4182168404Spjd */ 4183168404Spjd for (last = start; *last != NULL; 4184168404Spjd last = &(*last)->pl_next) { 4185168404Spjd if (strcmp((*last)->pl_user_prop, 4186168404Spjd nvpair_name(elem)) == 0) 4187168404Spjd break; 4188168404Spjd } 4189168404Spjd 4190168404Spjd if (*last == NULL) { 4191168404Spjd if ((entry = zfs_alloc(hdl, 4192185029Spjd sizeof (zprop_list_t))) == NULL || 4193168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 4194168404Spjd nvpair_name(elem)))) == NULL) { 4195168404Spjd free(entry); 4196168404Spjd return (-1); 4197168404Spjd } 4198168404Spjd 4199185029Spjd entry->pl_prop = ZPROP_INVAL; 4200168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 4201168404Spjd entry->pl_all = B_TRUE; 4202168404Spjd *last = entry; 4203168404Spjd } 4204168404Spjd } 4205168404Spjd } 4206168404Spjd 4207168404Spjd /* 4208168404Spjd * Now go through and check the width of any non-fixed columns 4209168404Spjd */ 4210168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4211259850Sdelphij if (entry->pl_fixed && !literal) 4212168404Spjd continue; 4213168404Spjd 4214185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 4215168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 4216259850Sdelphij buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4217168404Spjd if (strlen(buf) > entry->pl_width) 4218168404Spjd entry->pl_width = strlen(buf); 4219168404Spjd } 4220219089Spjd if (received && zfs_prop_get_recvd(zhp, 4221219089Spjd zfs_prop_to_name(entry->pl_prop), 4222259850Sdelphij buf, sizeof (buf), literal) == 0) 4223219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4224219089Spjd entry->pl_recvd_width = strlen(buf); 4225219089Spjd } else { 4226219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4227219089Spjd &propval) == 0) { 4228219089Spjd verify(nvlist_lookup_string(propval, 4229219089Spjd ZPROP_VALUE, &strval) == 0); 4230219089Spjd if (strlen(strval) > entry->pl_width) 4231219089Spjd entry->pl_width = strlen(strval); 4232219089Spjd } 4233219089Spjd if (received && zfs_prop_get_recvd(zhp, 4234219089Spjd entry->pl_user_prop, 4235259850Sdelphij buf, sizeof (buf), literal) == 0) 4236219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4237219089Spjd entry->pl_recvd_width = strlen(buf); 4238168404Spjd } 4239168404Spjd } 4240168404Spjd 4241168404Spjd return (0); 4242168404Spjd} 4243168404Spjd 4244185029Spjdint 4245185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4246209962Smm char *resource, void *export, void *sharetab, 4247209962Smm int sharemax, zfs_share_op_t operation) 4248185029Spjd{ 4249185029Spjd zfs_cmd_t zc = { 0 }; 4250185029Spjd int error; 4251185029Spjd 4252185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4253185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4254209962Smm if (resource) 4255209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4256185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4257185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4258185029Spjd zc.zc_share.z_sharetype = operation; 4259185029Spjd zc.zc_share.z_sharemax = sharemax; 4260185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4261185029Spjd return (error); 4262185029Spjd} 4263185029Spjd 4264205198Sdelphijvoid 4265205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4266205198Sdelphij{ 4267205198Sdelphij nvpair_t *curr; 4268205198Sdelphij 4269205198Sdelphij /* 4270205198Sdelphij * Keep a reference to the props-table against which we prune the 4271205198Sdelphij * properties. 4272205198Sdelphij */ 4273205198Sdelphij zhp->zfs_props_table = props; 4274205198Sdelphij 4275205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4276205198Sdelphij 4277205198Sdelphij while (curr) { 4278205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4279205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4280205198Sdelphij 4281206199Sdelphij /* 4282219089Spjd * User properties will result in ZPROP_INVAL, and since we 4283219089Spjd * only know how to prune standard ZFS properties, we always 4284219089Spjd * leave these in the list. This can also happen if we 4285219089Spjd * encounter an unknown DSL property (when running older 4286219089Spjd * software, for example). 4287206199Sdelphij */ 4288206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4289205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4290205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4291205198Sdelphij curr = next; 4292205198Sdelphij } 4293205198Sdelphij} 4294205198Sdelphij 4295277300Ssmh#ifdef illumos 4296209962Smmstatic int 4297209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4298209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4299209962Smm{ 4300209962Smm zfs_cmd_t zc = { 0 }; 4301209962Smm nvlist_t *nvlist = NULL; 4302209962Smm int error; 4303209962Smm 4304209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4305209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4306209962Smm zc.zc_cookie = (uint64_t)cmd; 4307209962Smm 4308209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4309209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4310209962Smm (void) no_memory(hdl); 4311289497Smav return (0); 4312209962Smm } 4313209962Smm } 4314209962Smm 4315209962Smm switch (cmd) { 4316209962Smm case ZFS_SMB_ACL_ADD: 4317209962Smm case ZFS_SMB_ACL_REMOVE: 4318209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4319209962Smm break; 4320209962Smm case ZFS_SMB_ACL_RENAME: 4321209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4322209962Smm resource1) != 0) { 4323209962Smm (void) no_memory(hdl); 4324209962Smm return (-1); 4325209962Smm } 4326209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4327209962Smm resource2) != 0) { 4328209962Smm (void) no_memory(hdl); 4329209962Smm return (-1); 4330209962Smm } 4331209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4332209962Smm nvlist_free(nvlist); 4333209962Smm return (-1); 4334209962Smm } 4335209962Smm break; 4336209962Smm case ZFS_SMB_ACL_PURGE: 4337209962Smm break; 4338209962Smm default: 4339209962Smm return (-1); 4340209962Smm } 4341209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4342296528Smav nvlist_free(nvlist); 4343209962Smm return (error); 4344209962Smm} 4345209962Smm 4346209962Smmint 4347209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4348209962Smm char *path, char *resource) 4349209962Smm{ 4350209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4351209962Smm resource, NULL)); 4352209962Smm} 4353209962Smm 4354209962Smmint 4355209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4356209962Smm char *path, char *resource) 4357209962Smm{ 4358209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4359209962Smm resource, NULL)); 4360209962Smm} 4361209962Smm 4362209962Smmint 4363209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4364209962Smm{ 4365209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4366209962Smm NULL, NULL)); 4367209962Smm} 4368209962Smm 4369209962Smmint 4370209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4371209962Smm char *oldname, char *newname) 4372209962Smm{ 4373209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4374209962Smm oldname, newname)); 4375209962Smm} 4376277300Ssmh#endif /* illumos */ 4377209962Smm 4378209962Smmint 4379209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4380209962Smm zfs_userspace_cb_t func, void *arg) 4381209962Smm{ 4382209962Smm zfs_cmd_t zc = { 0 }; 4383209962Smm zfs_useracct_t buf[100]; 4384240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4385240415Smm int ret; 4386209962Smm 4387228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4388209962Smm 4389209962Smm zc.zc_objset_type = type; 4390209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4391209962Smm 4392240415Smm for (;;) { 4393209962Smm zfs_useracct_t *zua = buf; 4394209962Smm 4395209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4396240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4397248571Smm char errbuf[1024]; 4398240415Smm 4399240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4400240415Smm dgettext(TEXT_DOMAIN, 4401240415Smm "cannot get used/quota for %s"), zc.zc_name); 4402240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4403240415Smm } 4404240415Smm if (zc.zc_nvlist_dst_size == 0) 4405209962Smm break; 4406209962Smm 4407209962Smm while (zc.zc_nvlist_dst_size > 0) { 4408240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4409240415Smm zua->zu_space)) != 0) 4410240415Smm return (ret); 4411209962Smm zua++; 4412209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4413209962Smm } 4414209962Smm } 4415209962Smm 4416240415Smm return (0); 4417209962Smm} 4418209962Smm 4419248571Smmstruct holdarg { 4420248571Smm nvlist_t *nvl; 4421248571Smm const char *snapname; 4422248571Smm const char *tag; 4423248571Smm boolean_t recursive; 4424252219Sdelphij int error; 4425248571Smm}; 4426248571Smm 4427248571Smmstatic int 4428248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4429248571Smm{ 4430248571Smm struct holdarg *ha = arg; 4431248571Smm char name[ZFS_MAXNAMELEN]; 4432248571Smm int rv = 0; 4433248571Smm 4434248571Smm (void) snprintf(name, sizeof (name), 4435248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4436248571Smm 4437251646Sdelphij if (lzc_exists(name)) 4438248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4439248571Smm 4440248571Smm if (ha->recursive) 4441248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4442248571Smm zfs_close(zhp); 4443248571Smm return (rv); 4444248571Smm} 4445248571Smm 4446219089Spjdint 4447219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4448251646Sdelphij boolean_t recursive, int cleanup_fd) 4449219089Spjd{ 4450248571Smm int ret; 4451248571Smm struct holdarg ha; 4452219089Spjd 4453248571Smm ha.nvl = fnvlist_alloc(); 4454248571Smm ha.snapname = snapname; 4455248571Smm ha.tag = tag; 4456248571Smm ha.recursive = recursive; 4457248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4458249357Smm 4459251646Sdelphij if (nvlist_empty(ha.nvl)) { 4460251646Sdelphij char errbuf[1024]; 4461251646Sdelphij 4462249357Smm fnvlist_free(ha.nvl); 4463249357Smm ret = ENOENT; 4464251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4465251646Sdelphij dgettext(TEXT_DOMAIN, 4466251646Sdelphij "cannot hold snapshot '%s@%s'"), 4467251646Sdelphij zhp->zfs_name, snapname); 4468251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4469249357Smm return (ret); 4470249357Smm } 4471249357Smm 4472251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4473248571Smm fnvlist_free(ha.nvl); 4474219089Spjd 4475251646Sdelphij return (ret); 4476251646Sdelphij} 4477251646Sdelphij 4478251646Sdelphijint 4479251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4480251646Sdelphij{ 4481251646Sdelphij int ret; 4482251646Sdelphij nvlist_t *errors; 4483251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4484251646Sdelphij char errbuf[1024]; 4485251646Sdelphij nvpair_t *elem; 4486251646Sdelphij 4487251646Sdelphij errors = NULL; 4488251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4489251646Sdelphij 4490251646Sdelphij if (ret == 0) { 4491251646Sdelphij /* There may be errors even in the success case. */ 4492251646Sdelphij fnvlist_free(errors); 4493248571Smm return (0); 4494251646Sdelphij } 4495219089Spjd 4496251646Sdelphij if (nvlist_empty(errors)) { 4497248571Smm /* no hold-specific errors */ 4498248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4499248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4500248571Smm switch (ret) { 4501248571Smm case ENOTSUP: 4502248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4503248571Smm "pool must be upgraded")); 4504248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4505248571Smm break; 4506248571Smm case EINVAL: 4507248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4508248571Smm break; 4509248571Smm default: 4510248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4511248571Smm } 4512248571Smm } 4513219089Spjd 4514248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4515248571Smm elem != NULL; 4516248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4517248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4518248571Smm dgettext(TEXT_DOMAIN, 4519248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4520248571Smm switch (fnvpair_value_int32(elem)) { 4521219089Spjd case E2BIG: 4522219089Spjd /* 4523219089Spjd * Temporary tags wind up having the ds object id 4524219089Spjd * prepended. So even if we passed the length check 4525219089Spjd * above, it's still possible for the tag to wind 4526219089Spjd * up being slightly too long. 4527219089Spjd */ 4528248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4529248571Smm break; 4530219089Spjd case EINVAL: 4531248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4532248571Smm break; 4533219089Spjd case EEXIST: 4534248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4535248571Smm break; 4536219089Spjd default: 4537248571Smm (void) zfs_standard_error(hdl, 4538248571Smm fnvpair_value_int32(elem), errbuf); 4539219089Spjd } 4540219089Spjd } 4541219089Spjd 4542248571Smm fnvlist_free(errors); 4543248571Smm return (ret); 4544219089Spjd} 4545219089Spjd 4546248571Smmstatic int 4547248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4548248571Smm{ 4549248571Smm struct holdarg *ha = arg; 4550248571Smm char name[ZFS_MAXNAMELEN]; 4551248571Smm int rv = 0; 4552252219Sdelphij nvlist_t *existing_holds; 4553248571Smm 4554248571Smm (void) snprintf(name, sizeof (name), 4555248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4556248571Smm 4557252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4558252219Sdelphij ha->error = ENOENT; 4559252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4560252219Sdelphij ha->error = ESRCH; 4561252219Sdelphij } else { 4562252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4563252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4564252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4565252219Sdelphij fnvlist_free(torelease); 4566248571Smm } 4567248571Smm 4568248571Smm if (ha->recursive) 4569248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4570248571Smm zfs_close(zhp); 4571248571Smm return (rv); 4572248571Smm} 4573248571Smm 4574219089Spjdint 4575219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4576219089Spjd boolean_t recursive) 4577219089Spjd{ 4578248571Smm int ret; 4579248571Smm struct holdarg ha; 4580251646Sdelphij nvlist_t *errors = NULL; 4581248571Smm nvpair_t *elem; 4582219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4583249357Smm char errbuf[1024]; 4584219089Spjd 4585248571Smm ha.nvl = fnvlist_alloc(); 4586248571Smm ha.snapname = snapname; 4587248571Smm ha.tag = tag; 4588248571Smm ha.recursive = recursive; 4589252219Sdelphij ha.error = 0; 4590248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4591249357Smm 4592251646Sdelphij if (nvlist_empty(ha.nvl)) { 4593249357Smm fnvlist_free(ha.nvl); 4594252219Sdelphij ret = ha.error; 4595249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4596249357Smm dgettext(TEXT_DOMAIN, 4597249357Smm "cannot release hold from snapshot '%s@%s'"), 4598249357Smm zhp->zfs_name, snapname); 4599252219Sdelphij if (ret == ESRCH) { 4600252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4601252219Sdelphij } else { 4602252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4603252219Sdelphij } 4604249357Smm return (ret); 4605249357Smm } 4606249357Smm 4607248571Smm ret = lzc_release(ha.nvl, &errors); 4608248571Smm fnvlist_free(ha.nvl); 4609219089Spjd 4610251646Sdelphij if (ret == 0) { 4611251646Sdelphij /* There may be errors even in the success case. */ 4612251646Sdelphij fnvlist_free(errors); 4613248571Smm return (0); 4614251646Sdelphij } 4615219089Spjd 4616251646Sdelphij if (nvlist_empty(errors)) { 4617248571Smm /* no hold-specific errors */ 4618219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4619248571Smm "cannot release")); 4620219089Spjd switch (errno) { 4621219089Spjd case ENOTSUP: 4622219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4623219089Spjd "pool must be upgraded")); 4624248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4625248571Smm break; 4626248571Smm default: 4627248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4628248571Smm } 4629248571Smm } 4630248571Smm 4631248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4632248571Smm elem != NULL; 4633248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4634248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4635248571Smm dgettext(TEXT_DOMAIN, 4636248571Smm "cannot release hold from snapshot '%s'"), 4637248571Smm nvpair_name(elem)); 4638248571Smm switch (fnvpair_value_int32(elem)) { 4639248571Smm case ESRCH: 4640248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4641248571Smm break; 4642219089Spjd case EINVAL: 4643248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4644248571Smm break; 4645219089Spjd default: 4646248571Smm (void) zfs_standard_error_fmt(hdl, 4647248571Smm fnvpair_value_int32(elem), errbuf); 4648219089Spjd } 4649219089Spjd } 4650219089Spjd 4651248571Smm fnvlist_free(errors); 4652248571Smm return (ret); 4653219089Spjd} 4654219089Spjd 4655219089Spjdint 4656219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4657219089Spjd{ 4658219089Spjd zfs_cmd_t zc = { 0 }; 4659219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4660219089Spjd int nvsz = 2048; 4661219089Spjd void *nvbuf; 4662219089Spjd int err = 0; 4663248571Smm char errbuf[1024]; 4664219089Spjd 4665219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4666219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4667219089Spjd 4668219089Spjdtryagain: 4669219089Spjd 4670219089Spjd nvbuf = malloc(nvsz); 4671219089Spjd if (nvbuf == NULL) { 4672219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4673219089Spjd goto out; 4674219089Spjd } 4675219089Spjd 4676219089Spjd zc.zc_nvlist_dst_size = nvsz; 4677219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4678219089Spjd 4679219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4680219089Spjd 4681230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 4682219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4683219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4684219089Spjd zc.zc_name); 4685219089Spjd switch (errno) { 4686219089Spjd case ENOMEM: 4687219089Spjd free(nvbuf); 4688219089Spjd nvsz = zc.zc_nvlist_dst_size; 4689219089Spjd goto tryagain; 4690219089Spjd 4691219089Spjd case ENOTSUP: 4692219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4693219089Spjd "pool must be upgraded")); 4694219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4695219089Spjd break; 4696219089Spjd case EINVAL: 4697219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4698219089Spjd break; 4699219089Spjd case ENOENT: 4700219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4701219089Spjd break; 4702219089Spjd default: 4703219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4704219089Spjd break; 4705219089Spjd } 4706219089Spjd } else { 4707219089Spjd /* success */ 4708219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4709219089Spjd if (rc) { 4710219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4711219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4712219089Spjd zc.zc_name); 4713219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4714219089Spjd } 4715219089Spjd } 4716219089Spjd 4717219089Spjd free(nvbuf); 4718219089Spjdout: 4719219089Spjd return (err); 4720219089Spjd} 4721219089Spjd 4722219089Spjdint 4723219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4724219089Spjd{ 4725219089Spjd zfs_cmd_t zc = { 0 }; 4726219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4727219089Spjd char *nvbuf; 4728248571Smm char errbuf[1024]; 4729219089Spjd size_t nvsz; 4730219089Spjd int err; 4731219089Spjd 4732219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4733219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4734219089Spjd 4735219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4736219089Spjd assert(err == 0); 4737219089Spjd 4738219089Spjd nvbuf = malloc(nvsz); 4739219089Spjd 4740219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4741219089Spjd assert(err == 0); 4742219089Spjd 4743219089Spjd zc.zc_nvlist_src_size = nvsz; 4744219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4745219089Spjd zc.zc_perm_action = un; 4746219089Spjd 4747219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4748219089Spjd 4749219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4750219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4751219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4752219089Spjd zc.zc_name); 4753219089Spjd switch (errno) { 4754219089Spjd case ENOTSUP: 4755219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4756219089Spjd "pool must be upgraded")); 4757219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4758219089Spjd break; 4759219089Spjd case EINVAL: 4760219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4761219089Spjd break; 4762219089Spjd case ENOENT: 4763219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4764219089Spjd break; 4765219089Spjd default: 4766219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4767219089Spjd break; 4768219089Spjd } 4769219089Spjd } 4770219089Spjd 4771219089Spjd free(nvbuf); 4772219089Spjd 4773219089Spjd return (err); 4774219089Spjd} 4775219089Spjd 4776219089Spjdint 4777219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4778219089Spjd{ 4779248571Smm int err; 4780248571Smm char errbuf[1024]; 4781219089Spjd 4782248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 4783219089Spjd 4784248571Smm if (err != 0) { 4785248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4786219089Spjd 4787219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4788219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4789248571Smm zhp->zfs_name); 4790248571Smm switch (err) { 4791219089Spjd case ENOTSUP: 4792219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4793219089Spjd "pool must be upgraded")); 4794219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4795219089Spjd break; 4796219089Spjd case EINVAL: 4797219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4798219089Spjd break; 4799219089Spjd case ENOENT: 4800219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4801219089Spjd break; 4802219089Spjd default: 4803219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4804219089Spjd break; 4805219089Spjd } 4806219089Spjd } 4807219089Spjd 4808219089Spjd return (err); 4809219089Spjd} 4810219089Spjd 4811251629Sdelphij/* 4812251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 4813251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 4814251629Sdelphij * suite's shell version in reservation.kshlib. 4815251629Sdelphij */ 4816219089Spjduint64_t 4817219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4818219089Spjd{ 4819219089Spjd uint64_t numdb; 4820219089Spjd uint64_t nblocks, volblocksize; 4821219089Spjd int ncopies; 4822219089Spjd char *strval; 4823219089Spjd 4824219089Spjd if (nvlist_lookup_string(props, 4825219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4826219089Spjd ncopies = atoi(strval); 4827219089Spjd else 4828219089Spjd ncopies = 1; 4829219089Spjd if (nvlist_lookup_uint64(props, 4830219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4831219089Spjd &volblocksize) != 0) 4832219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4833219089Spjd nblocks = volsize/volblocksize; 4834219089Spjd /* start with metadnode L0-L6 */ 4835219089Spjd numdb = 7; 4836219089Spjd /* calculate number of indirects */ 4837219089Spjd while (nblocks > 1) { 4838219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4839219089Spjd nblocks /= DNODES_PER_LEVEL; 4840219089Spjd numdb += nblocks; 4841219089Spjd } 4842219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4843219089Spjd volsize *= ncopies; 4844219089Spjd /* 4845219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4846219089Spjd * compressed, but in practice they compress down to about 4847219089Spjd * 1100 bytes 4848219089Spjd */ 4849219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4850219089Spjd volsize += numdb; 4851219089Spjd return (volsize); 4852219089Spjd} 4853219089Spjd 4854168404Spjd/* 4855168404Spjd * Attach/detach the given filesystem to/from the given jail. 4856168404Spjd */ 4857168404Spjdint 4858168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4859168404Spjd{ 4860168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4861168404Spjd zfs_cmd_t zc = { 0 }; 4862168404Spjd char errbuf[1024]; 4863224525Smm unsigned long cmd; 4864224525Smm int ret; 4865168404Spjd 4866168404Spjd if (attach) { 4867168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4868168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4869168404Spjd } else { 4870168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4871249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 4872168404Spjd } 4873168404Spjd 4874168404Spjd switch (zhp->zfs_type) { 4875168404Spjd case ZFS_TYPE_VOLUME: 4876168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4877168404Spjd "volumes can not be jailed")); 4878168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4879168404Spjd case ZFS_TYPE_SNAPSHOT: 4880168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4881168404Spjd "snapshots can not be jailed")); 4882168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4883168404Spjd } 4884168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4885168404Spjd 4886168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4887168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4888168404Spjd zc.zc_jailid = jailid; 4889168404Spjd 4890168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4891168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4892168404Spjd zfs_standard_error(hdl, errno, errbuf); 4893168404Spjd 4894168404Spjd return (ret); 4895168404Spjd} 4896