libzfs_dataset.c revision 253819
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. 24252219Sdelphij * Copyright (c) 2013 by Delphix. All rights reserved. 25252219Sdelphij * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 26240415Smm * Copyright 2012 Nexenta 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. 31168404Spjd */ 32168404Spjd 33168404Spjd#include <ctype.h> 34168404Spjd#include <errno.h> 35168404Spjd#include <libintl.h> 36168404Spjd#include <math.h> 37168404Spjd#include <stdio.h> 38168404Spjd#include <stdlib.h> 39168404Spjd#include <strings.h> 40168404Spjd#include <unistd.h> 41185029Spjd#include <stddef.h> 42168404Spjd#include <zone.h> 43168404Spjd#include <fcntl.h> 44168404Spjd#include <sys/mntent.h> 45168404Spjd#include <sys/mount.h> 46185029Spjd#include <priv.h> 47185029Spjd#include <pwd.h> 48185029Spjd#include <grp.h> 49185029Spjd#include <stddef.h> 50209962Smm#include <idmap.h> 51168404Spjd 52219089Spjd#include <sys/dnode.h> 53168404Spjd#include <sys/spa.h> 54168404Spjd#include <sys/zap.h> 55209962Smm#include <sys/misc.h> 56168404Spjd#include <libzfs.h> 57168404Spjd 58168404Spjd#include "zfs_namecheck.h" 59168404Spjd#include "zfs_prop.h" 60168404Spjd#include "libzfs_impl.h" 61185029Spjd#include "zfs_deleg.h" 62168404Spjd 63209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 64209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 65168676Spjd 66168404Spjd/* 67168404Spjd * Given a single type (not a mask of types), return the type in a human 68168404Spjd * readable form. 69168404Spjd */ 70168404Spjdconst char * 71168404Spjdzfs_type_to_name(zfs_type_t type) 72168404Spjd{ 73168404Spjd switch (type) { 74168404Spjd case ZFS_TYPE_FILESYSTEM: 75168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 76168404Spjd case ZFS_TYPE_SNAPSHOT: 77168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 78168404Spjd case ZFS_TYPE_VOLUME: 79168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 80168404Spjd } 81168404Spjd 82168404Spjd return (NULL); 83168404Spjd} 84168404Spjd 85168404Spjd/* 86168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 87168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 88168404Spjd * We guess what the type would have been based on the path and the mask of 89168404Spjd * acceptable types. 90168404Spjd */ 91168404Spjdstatic const char * 92168404Spjdpath_to_str(const char *path, int types) 93168404Spjd{ 94168404Spjd /* 95168404Spjd * When given a single type, always report the exact type. 96168404Spjd */ 97168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 98168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 99168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 100168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 101168404Spjd if (types == ZFS_TYPE_VOLUME) 102168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 103168404Spjd 104168404Spjd /* 105168404Spjd * The user is requesting more than one type of dataset. If this is the 106168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 107168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 108168404Spjd * snapshot attribute and try again. 109168404Spjd */ 110168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 111168404Spjd if (strchr(path, '@') != NULL) 112168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 113168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 114168404Spjd } 115168404Spjd 116168404Spjd /* 117168404Spjd * The user has requested either filesystems or volumes. 118168404Spjd * We have no way of knowing a priori what type this would be, so always 119168404Spjd * report it as "filesystem" or "volume", our two primitive types. 120168404Spjd */ 121168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 122168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 123168404Spjd 124168404Spjd assert(types & ZFS_TYPE_VOLUME); 125168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 126168404Spjd} 127168404Spjd 128168404Spjd/* 129168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 130209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 131209962Smm * explain exactly why the name was not valid. 132168404Spjd */ 133219089Spjdint 134185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 135185029Spjd boolean_t modifying) 136168404Spjd{ 137168404Spjd namecheck_err_t why; 138168404Spjd char what; 139168404Spjd 140219089Spjd (void) zfs_prop_get_table(); 141168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 142168404Spjd if (hdl != NULL) { 143168404Spjd switch (why) { 144168404Spjd case NAME_ERR_TOOLONG: 145168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 146168404Spjd "name is too long")); 147168404Spjd break; 148168404Spjd 149168404Spjd case NAME_ERR_LEADING_SLASH: 150168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 151168404Spjd "leading slash in name")); 152168404Spjd break; 153168404Spjd 154168404Spjd case NAME_ERR_EMPTY_COMPONENT: 155168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 156168404Spjd "empty component in name")); 157168404Spjd break; 158168404Spjd 159168404Spjd case NAME_ERR_TRAILING_SLASH: 160168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 161168404Spjd "trailing slash in name")); 162168404Spjd break; 163168404Spjd 164168404Spjd case NAME_ERR_INVALCHAR: 165168404Spjd zfs_error_aux(hdl, 166168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 167168404Spjd "'%c' in name"), what); 168168404Spjd break; 169168404Spjd 170168404Spjd case NAME_ERR_MULTIPLE_AT: 171168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 172168404Spjd "multiple '@' delimiters in name")); 173168404Spjd break; 174168404Spjd 175168404Spjd case NAME_ERR_NOLETTER: 176168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 177168404Spjd "pool doesn't begin with a letter")); 178168404Spjd break; 179168404Spjd 180168404Spjd case NAME_ERR_RESERVED: 181168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 182168404Spjd "name is reserved")); 183168404Spjd break; 184168404Spjd 185168404Spjd case NAME_ERR_DISKLIKE: 186168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 187168404Spjd "reserved disk name")); 188168404Spjd break; 189168404Spjd } 190168404Spjd } 191168404Spjd 192168404Spjd return (0); 193168404Spjd } 194168404Spjd 195168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 196168404Spjd if (hdl != NULL) 197168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 198168404Spjd "snapshot delimiter '@' in filesystem name")); 199168404Spjd return (0); 200168404Spjd } 201168404Spjd 202168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 203168404Spjd if (hdl != NULL) 204168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 205168404Spjd "missing '@' delimiter in snapshot name")); 206168404Spjd return (0); 207168404Spjd } 208168404Spjd 209185029Spjd if (modifying && strchr(path, '%') != NULL) { 210185029Spjd if (hdl != NULL) 211185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 212185029Spjd "invalid character %c in name"), '%'); 213185029Spjd return (0); 214185029Spjd } 215185029Spjd 216168404Spjd return (-1); 217168404Spjd} 218168404Spjd 219168404Spjdint 220168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 221168404Spjd{ 222185029Spjd if (type == ZFS_TYPE_POOL) 223185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 224185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 225168404Spjd} 226168404Spjd 227168404Spjd/* 228168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 229168404Spjd * properties into a separate nvlist. 230168404Spjd */ 231185029Spjdstatic nvlist_t * 232185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 233168404Spjd{ 234168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 235168404Spjd nvpair_t *elem; 236168404Spjd nvlist_t *propval; 237185029Spjd nvlist_t *nvl; 238168404Spjd 239185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 240185029Spjd (void) no_memory(hdl); 241185029Spjd return (NULL); 242185029Spjd } 243168404Spjd 244168404Spjd elem = NULL; 245185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 246168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 247168404Spjd continue; 248168404Spjd 249168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 250185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 251185029Spjd nvlist_free(nvl); 252185029Spjd (void) no_memory(hdl); 253185029Spjd return (NULL); 254185029Spjd } 255168404Spjd } 256168404Spjd 257185029Spjd return (nvl); 258168404Spjd} 259168404Spjd 260185029Spjdstatic zpool_handle_t * 261185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 262185029Spjd{ 263185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 264185029Spjd zpool_handle_t *zph; 265185029Spjd 266185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 267185029Spjd if (hdl->libzfs_pool_handles != NULL) 268185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 269185029Spjd hdl->libzfs_pool_handles = zph; 270185029Spjd } 271185029Spjd return (zph); 272185029Spjd} 273185029Spjd 274185029Spjdstatic zpool_handle_t * 275185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 276185029Spjd{ 277185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 278185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 279185029Spjd 280185029Spjd while ((zph != NULL) && 281185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 282185029Spjd zph = zph->zpool_next; 283185029Spjd return (zph); 284185029Spjd} 285185029Spjd 286168404Spjd/* 287185029Spjd * Returns a handle to the pool that contains the provided dataset. 288185029Spjd * If a handle to that pool already exists then that handle is returned. 289185029Spjd * Otherwise, a new handle is created and added to the list of handles. 290185029Spjd */ 291185029Spjdstatic zpool_handle_t * 292185029Spjdzpool_handle(zfs_handle_t *zhp) 293185029Spjd{ 294185029Spjd char *pool_name; 295185029Spjd int len; 296185029Spjd zpool_handle_t *zph; 297185029Spjd 298185029Spjd len = strcspn(zhp->zfs_name, "/@") + 1; 299185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 300185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 301185029Spjd 302185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 303185029Spjd if (zph == NULL) 304185029Spjd zph = zpool_add_handle(zhp, pool_name); 305185029Spjd 306185029Spjd free(pool_name); 307185029Spjd return (zph); 308185029Spjd} 309185029Spjd 310185029Spjdvoid 311185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 312185029Spjd{ 313185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 314185029Spjd 315185029Spjd while (zph != NULL) { 316185029Spjd next = zph->zpool_next; 317185029Spjd zpool_close(zph); 318185029Spjd zph = next; 319185029Spjd } 320185029Spjd hdl->libzfs_pool_handles = NULL; 321185029Spjd} 322185029Spjd 323185029Spjd/* 324168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 325168404Spjd */ 326219089Spjdstatic int 327209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 328168404Spjd{ 329168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 330168404Spjd 331209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 332168404Spjd 333209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 334168404Spjd if (errno == ENOMEM) { 335209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 336168404Spjd return (-1); 337168404Spjd } 338168404Spjd } else { 339168404Spjd return (-1); 340168404Spjd } 341168404Spjd } 342209962Smm return (0); 343209962Smm} 344168404Spjd 345219089Spjd/* 346219089Spjd * Utility function to get the received properties of the given object. 347219089Spjd */ 348209962Smmstatic int 349219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 350219089Spjd{ 351219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 352219089Spjd nvlist_t *recvdprops; 353219089Spjd zfs_cmd_t zc = { 0 }; 354219089Spjd int err; 355219089Spjd 356219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 357219089Spjd return (-1); 358219089Spjd 359219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 360219089Spjd 361219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 362219089Spjd if (errno == ENOMEM) { 363219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 364219089Spjd return (-1); 365219089Spjd } 366219089Spjd } else { 367219089Spjd zcmd_free_nvlists(&zc); 368219089Spjd return (-1); 369219089Spjd } 370219089Spjd } 371219089Spjd 372219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 373219089Spjd zcmd_free_nvlists(&zc); 374219089Spjd if (err != 0) 375219089Spjd return (-1); 376219089Spjd 377219089Spjd nvlist_free(zhp->zfs_recvd_props); 378219089Spjd zhp->zfs_recvd_props = recvdprops; 379219089Spjd 380219089Spjd return (0); 381219089Spjd} 382219089Spjd 383219089Spjdstatic int 384209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 385209962Smm{ 386209962Smm nvlist_t *allprops, *userprops; 387168404Spjd 388209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 389209962Smm 390209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 391168404Spjd return (-1); 392168404Spjd } 393168404Spjd 394209962Smm /* 395209962Smm * XXX Why do we store the user props separately, in addition to 396209962Smm * storing them in zfs_props? 397209962Smm */ 398185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 399185029Spjd nvlist_free(allprops); 400168404Spjd return (-1); 401185029Spjd } 402168404Spjd 403185029Spjd nvlist_free(zhp->zfs_props); 404185029Spjd nvlist_free(zhp->zfs_user_props); 405185029Spjd 406185029Spjd zhp->zfs_props = allprops; 407185029Spjd zhp->zfs_user_props = userprops; 408185029Spjd 409168404Spjd return (0); 410168404Spjd} 411168404Spjd 412209962Smmstatic int 413209962Smmget_stats(zfs_handle_t *zhp) 414209962Smm{ 415209962Smm int rc = 0; 416209962Smm zfs_cmd_t zc = { 0 }; 417209962Smm 418209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 419209962Smm return (-1); 420209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 421209962Smm rc = -1; 422209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 423209962Smm rc = -1; 424209962Smm zcmd_free_nvlists(&zc); 425209962Smm return (rc); 426209962Smm} 427209962Smm 428168404Spjd/* 429168404Spjd * Refresh the properties currently stored in the handle. 430168404Spjd */ 431168404Spjdvoid 432168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 433168404Spjd{ 434168404Spjd (void) get_stats(zhp); 435168404Spjd} 436168404Spjd 437168404Spjd/* 438168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 439168404Spjd * zfs_iter_* to create child handles on the fly. 440168404Spjd */ 441209962Smmstatic int 442209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 443168404Spjd{ 444219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 445209962Smm return (-1); 446168404Spjd 447168404Spjd /* 448168404Spjd * We've managed to open the dataset and gather statistics. Determine 449168404Spjd * the high-level type. 450168404Spjd */ 451168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 452168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 453168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 454168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 455168404Spjd else 456168404Spjd abort(); 457168404Spjd 458168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 459168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 460168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 461168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 462168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 463168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 464168404Spjd else 465168404Spjd abort(); /* we should never see any other types */ 466168404Spjd 467219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 468219089Spjd return (-1); 469219089Spjd 470209962Smm return (0); 471209962Smm} 472209962Smm 473209962Smmzfs_handle_t * 474209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 475209962Smm{ 476209962Smm zfs_cmd_t zc = { 0 }; 477209962Smm 478209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 479209962Smm 480209962Smm if (zhp == NULL) 481209962Smm return (NULL); 482209962Smm 483209962Smm zhp->zfs_hdl = hdl; 484209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 485209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 486209962Smm free(zhp); 487209962Smm return (NULL); 488209962Smm } 489209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 490209962Smm zcmd_free_nvlists(&zc); 491209962Smm free(zhp); 492209962Smm return (NULL); 493209962Smm } 494209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 495209962Smm free(zhp); 496209962Smm zhp = NULL; 497209962Smm } 498209962Smm zcmd_free_nvlists(&zc); 499168404Spjd return (zhp); 500168404Spjd} 501168404Spjd 502228103Smmzfs_handle_t * 503209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 504209962Smm{ 505209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 506209962Smm 507209962Smm if (zhp == NULL) 508209962Smm return (NULL); 509209962Smm 510209962Smm zhp->zfs_hdl = hdl; 511209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 512209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 513209962Smm free(zhp); 514209962Smm return (NULL); 515209962Smm } 516209962Smm return (zhp); 517209962Smm} 518209962Smm 519228103Smmzfs_handle_t * 520230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 521230438Spjd{ 522230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 523230438Spjd 524230438Spjd if (zhp == NULL) 525230438Spjd return (NULL); 526230438Spjd 527230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 528230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 529230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 530230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 531230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 532230438Spjd return (zhp); 533230438Spjd} 534230438Spjd 535230438Spjdzfs_handle_t * 536228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 537228103Smm{ 538228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 539228103Smm 540228103Smm if (zhp == NULL) 541228103Smm return (NULL); 542228103Smm 543228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 544228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 545228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 546228103Smm sizeof (zhp->zfs_name)); 547228103Smm zhp->zfs_type = zhp_orig->zfs_type; 548228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 549228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 550228103Smm if (zhp_orig->zfs_props != NULL) { 551228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 552228103Smm (void) no_memory(zhp->zfs_hdl); 553228103Smm zfs_close(zhp); 554228103Smm return (NULL); 555228103Smm } 556228103Smm } 557228103Smm if (zhp_orig->zfs_user_props != NULL) { 558228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 559228103Smm &zhp->zfs_user_props, 0) != 0) { 560228103Smm (void) no_memory(zhp->zfs_hdl); 561228103Smm zfs_close(zhp); 562228103Smm return (NULL); 563228103Smm } 564228103Smm } 565228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 566228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 567228103Smm &zhp->zfs_recvd_props, 0)) { 568228103Smm (void) no_memory(zhp->zfs_hdl); 569228103Smm zfs_close(zhp); 570228103Smm return (NULL); 571228103Smm } 572228103Smm } 573228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 574228103Smm if (zhp_orig->zfs_mntopts != NULL) { 575228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 576228103Smm zhp_orig->zfs_mntopts); 577228103Smm } 578228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 579228103Smm return (zhp); 580228103Smm} 581228103Smm 582168404Spjd/* 583168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 584168404Spjd * argument is a mask of acceptable types. The function will print an 585168404Spjd * appropriate error message and return NULL if it can't be opened. 586168404Spjd */ 587168404Spjdzfs_handle_t * 588168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 589168404Spjd{ 590168404Spjd zfs_handle_t *zhp; 591168404Spjd char errbuf[1024]; 592168404Spjd 593168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 594168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 595168404Spjd 596168404Spjd /* 597168404Spjd * Validate the name before we even try to open it. 598168404Spjd */ 599185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 600168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 601168404Spjd "invalid dataset name")); 602168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 603168404Spjd return (NULL); 604168404Spjd } 605168404Spjd 606168404Spjd /* 607168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 608168404Spjd */ 609168404Spjd errno = 0; 610168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 611168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 612168404Spjd return (NULL); 613168404Spjd } 614168404Spjd 615240870Spjd if (zhp == NULL) { 616240870Spjd char *at = strchr(path, '@'); 617240870Spjd 618240870Spjd if (at != NULL) 619240870Spjd *at = '\0'; 620240870Spjd errno = 0; 621240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 622240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 623240870Spjd return (NULL); 624240870Spjd } 625240870Spjd if (at != NULL) 626240870Spjd *at = '@'; 627240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 628240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 629240870Spjd } 630240870Spjd 631168404Spjd if (!(types & zhp->zfs_type)) { 632168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 633168404Spjd zfs_close(zhp); 634168404Spjd return (NULL); 635168404Spjd } 636168404Spjd 637168404Spjd return (zhp); 638168404Spjd} 639168404Spjd 640168404Spjd/* 641168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 642168404Spjd */ 643168404Spjdvoid 644168404Spjdzfs_close(zfs_handle_t *zhp) 645168404Spjd{ 646168404Spjd if (zhp->zfs_mntopts) 647168404Spjd free(zhp->zfs_mntopts); 648168404Spjd nvlist_free(zhp->zfs_props); 649168404Spjd nvlist_free(zhp->zfs_user_props); 650219089Spjd nvlist_free(zhp->zfs_recvd_props); 651168404Spjd free(zhp); 652168404Spjd} 653168404Spjd 654209962Smmtypedef struct mnttab_node { 655209962Smm struct mnttab mtn_mt; 656209962Smm avl_node_t mtn_node; 657209962Smm} mnttab_node_t; 658209962Smm 659209962Smmstatic int 660209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 661209962Smm{ 662209962Smm const mnttab_node_t *mtn1 = arg1; 663209962Smm const mnttab_node_t *mtn2 = arg2; 664209962Smm int rv; 665209962Smm 666209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 667209962Smm 668209962Smm if (rv == 0) 669209962Smm return (0); 670209962Smm return (rv > 0 ? 1 : -1); 671209962Smm} 672209962Smm 673209962Smmvoid 674209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 675209962Smm{ 676209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 677209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 678209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 679209962Smm} 680209962Smm 681209962Smmvoid 682209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 683209962Smm{ 684209962Smm struct mnttab entry; 685209962Smm 686209962Smm rewind(hdl->libzfs_mnttab); 687209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 688209962Smm mnttab_node_t *mtn; 689209962Smm 690209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 691209962Smm continue; 692209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 693209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 694209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 695209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 696209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 697209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 698209962Smm } 699209962Smm} 700209962Smm 701209962Smmvoid 702209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 703209962Smm{ 704209962Smm void *cookie = NULL; 705209962Smm mnttab_node_t *mtn; 706209962Smm 707209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 708209962Smm free(mtn->mtn_mt.mnt_special); 709209962Smm free(mtn->mtn_mt.mnt_mountp); 710209962Smm free(mtn->mtn_mt.mnt_fstype); 711209962Smm free(mtn->mtn_mt.mnt_mntopts); 712209962Smm free(mtn); 713209962Smm } 714209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 715209962Smm} 716209962Smm 717209962Smmvoid 718209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 719209962Smm{ 720209962Smm hdl->libzfs_mnttab_enable = enable; 721209962Smm} 722209962Smm 723185029Spjdint 724209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 725209962Smm struct mnttab *entry) 726209962Smm{ 727209962Smm mnttab_node_t find; 728209962Smm mnttab_node_t *mtn; 729209962Smm 730209962Smm if (!hdl->libzfs_mnttab_enable) { 731209962Smm struct mnttab srch = { 0 }; 732209962Smm 733209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 734209962Smm libzfs_mnttab_fini(hdl); 735209962Smm rewind(hdl->libzfs_mnttab); 736209962Smm srch.mnt_special = (char *)fsname; 737209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 738209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 739209962Smm return (0); 740209962Smm else 741209962Smm return (ENOENT); 742209962Smm } 743209962Smm 744209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 745209962Smm libzfs_mnttab_update(hdl); 746209962Smm 747209962Smm find.mtn_mt.mnt_special = (char *)fsname; 748209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 749209962Smm if (mtn) { 750209962Smm *entry = mtn->mtn_mt; 751209962Smm return (0); 752209962Smm } 753209962Smm return (ENOENT); 754209962Smm} 755209962Smm 756209962Smmvoid 757209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 758209962Smm const char *mountp, const char *mntopts) 759209962Smm{ 760209962Smm mnttab_node_t *mtn; 761209962Smm 762209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 763209962Smm return; 764209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 765209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 766209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 767209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 768209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 769209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 770209962Smm} 771209962Smm 772209962Smmvoid 773209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 774209962Smm{ 775209962Smm mnttab_node_t find; 776209962Smm mnttab_node_t *ret; 777209962Smm 778209962Smm find.mtn_mt.mnt_special = (char *)fsname; 779209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 780209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 781209962Smm free(ret->mtn_mt.mnt_special); 782209962Smm free(ret->mtn_mt.mnt_mountp); 783209962Smm free(ret->mtn_mt.mnt_fstype); 784209962Smm free(ret->mtn_mt.mnt_mntopts); 785209962Smm free(ret); 786209962Smm } 787209962Smm} 788209962Smm 789209962Smmint 790185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 791168404Spjd{ 792185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 793168404Spjd 794185029Spjd if (zpool_handle == NULL) 795168404Spjd return (-1); 796168404Spjd 797185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 798185029Spjd ZPOOL_PROP_VERSION, NULL); 799168404Spjd return (0); 800168404Spjd} 801168404Spjd 802168404Spjd/* 803185029Spjd * The choice of reservation property depends on the SPA version. 804168404Spjd */ 805168404Spjdstatic int 806185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 807168404Spjd{ 808185029Spjd int spa_version; 809168404Spjd 810185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 811168404Spjd return (-1); 812168404Spjd 813185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 814185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 815185029Spjd else 816185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 817168404Spjd 818168404Spjd return (0); 819168404Spjd} 820168404Spjd 821168404Spjd/* 822168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 823168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 824168404Spjd * strings. 825168404Spjd */ 826168404Spjdnvlist_t * 827185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 828185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 829168404Spjd{ 830168404Spjd nvpair_t *elem; 831168404Spjd uint64_t intval; 832168404Spjd char *strval; 833185029Spjd zfs_prop_t prop; 834168404Spjd nvlist_t *ret; 835185029Spjd int chosen_normal = -1; 836185029Spjd int chosen_utf = -1; 837168404Spjd 838168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 839168404Spjd (void) no_memory(hdl); 840168404Spjd return (NULL); 841168404Spjd } 842168404Spjd 843209962Smm /* 844209962Smm * Make sure this property is valid and applies to this type. 845209962Smm */ 846209962Smm 847168404Spjd elem = NULL; 848168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 849185029Spjd const char *propname = nvpair_name(elem); 850168404Spjd 851209962Smm prop = zfs_name_to_prop(propname); 852209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 853185029Spjd /* 854209962Smm * This is a user property: make sure it's a 855185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 856185029Spjd */ 857185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 858185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 859185029Spjd "'%s' must be a string"), propname); 860185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 861185029Spjd goto error; 862168404Spjd } 863168404Spjd 864185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 865185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 866185029Spjd "property name '%s' is too long"), 867185029Spjd propname); 868185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 869185029Spjd goto error; 870185029Spjd } 871185029Spjd 872168404Spjd (void) nvpair_value_string(elem, &strval); 873168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 874168404Spjd (void) no_memory(hdl); 875168404Spjd goto error; 876168404Spjd } 877168404Spjd continue; 878168404Spjd } 879168404Spjd 880209962Smm /* 881209962Smm * Currently, only user properties can be modified on 882209962Smm * snapshots. 883209962Smm */ 884185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 885185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 886185029Spjd "this property can not be modified for snapshots")); 887185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 888185029Spjd goto error; 889185029Spjd } 890168404Spjd 891209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 892209962Smm zfs_userquota_prop_t uqtype; 893209962Smm char newpropname[128]; 894209962Smm char domain[128]; 895209962Smm uint64_t rid; 896209962Smm uint64_t valary[3]; 897209962Smm 898209962Smm if (userquota_propname_decode(propname, zoned, 899209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 900209962Smm zfs_error_aux(hdl, 901209962Smm dgettext(TEXT_DOMAIN, 902209962Smm "'%s' has an invalid user/group name"), 903209962Smm propname); 904209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 905209962Smm goto error; 906209962Smm } 907209962Smm 908209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 909209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 910209962Smm zfs_error_aux(hdl, 911209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 912209962Smm propname); 913209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 914209962Smm errbuf); 915209962Smm goto error; 916209962Smm } 917209962Smm 918209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 919209962Smm (void) nvpair_value_string(elem, &strval); 920209962Smm if (strcmp(strval, "none") == 0) { 921209962Smm intval = 0; 922209962Smm } else if (zfs_nicestrtonum(hdl, 923209962Smm strval, &intval) != 0) { 924209962Smm (void) zfs_error(hdl, 925209962Smm EZFS_BADPROP, errbuf); 926209962Smm goto error; 927209962Smm } 928209962Smm } else if (nvpair_type(elem) == 929209962Smm DATA_TYPE_UINT64) { 930209962Smm (void) nvpair_value_uint64(elem, &intval); 931209962Smm if (intval == 0) { 932209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 933209962Smm "use 'none' to disable " 934209962Smm "userquota/groupquota")); 935209962Smm goto error; 936209962Smm } 937209962Smm } else { 938209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 939209962Smm "'%s' must be a number"), propname); 940209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 941209962Smm goto error; 942209962Smm } 943209962Smm 944219089Spjd /* 945219089Spjd * Encode the prop name as 946219089Spjd * userquota@<hex-rid>-domain, to make it easy 947219089Spjd * for the kernel to decode. 948219089Spjd */ 949209962Smm (void) snprintf(newpropname, sizeof (newpropname), 950219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 951219089Spjd (longlong_t)rid, domain); 952209962Smm valary[0] = uqtype; 953209962Smm valary[1] = rid; 954209962Smm valary[2] = intval; 955209962Smm if (nvlist_add_uint64_array(ret, newpropname, 956209962Smm valary, 3) != 0) { 957209962Smm (void) no_memory(hdl); 958209962Smm goto error; 959209962Smm } 960209962Smm continue; 961228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 962228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 963228103Smm "'%s' is readonly"), 964228103Smm propname); 965228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 966228103Smm goto error; 967209962Smm } 968209962Smm 969209962Smm if (prop == ZPROP_INVAL) { 970209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 971209962Smm "invalid property '%s'"), propname); 972209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 973209962Smm goto error; 974209962Smm } 975209962Smm 976168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 977168404Spjd zfs_error_aux(hdl, 978168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 979168404Spjd "apply to datasets of this type"), propname); 980168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 981168404Spjd goto error; 982168404Spjd } 983168404Spjd 984168404Spjd if (zfs_prop_readonly(prop) && 985185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 986168404Spjd zfs_error_aux(hdl, 987168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 988168404Spjd propname); 989168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 990168404Spjd goto error; 991168404Spjd } 992168404Spjd 993185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 994185029Spjd &strval, &intval, errbuf) != 0) 995185029Spjd goto error; 996185029Spjd 997168404Spjd /* 998185029Spjd * Perform some additional checks for specific properties. 999168404Spjd */ 1000185029Spjd switch (prop) { 1001185029Spjd case ZFS_PROP_VERSION: 1002185029Spjd { 1003185029Spjd int version; 1004168404Spjd 1005185029Spjd if (zhp == NULL) 1006185029Spjd break; 1007185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1008185029Spjd if (intval < version) { 1009168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1010185029Spjd "Can not downgrade; already at version %u"), 1011185029Spjd version); 1012168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1013168404Spjd goto error; 1014168404Spjd } 1015168404Spjd break; 1016168404Spjd } 1017168404Spjd 1018168404Spjd case ZFS_PROP_RECORDSIZE: 1019168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 1020168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 1021168404Spjd if (intval < SPA_MINBLOCKSIZE || 1022168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 1023168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1024168404Spjd "'%s' must be power of 2 from %u " 1025168404Spjd "to %uk"), propname, 1026168404Spjd (uint_t)SPA_MINBLOCKSIZE, 1027168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 1028168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1029168404Spjd goto error; 1030168404Spjd } 1031168404Spjd break; 1032168404Spjd 1033219089Spjd case ZFS_PROP_MLSLABEL: 1034219089Spjd { 1035219089Spjd#ifdef sun 1036219089Spjd /* 1037219089Spjd * Verify the mlslabel string and convert to 1038219089Spjd * internal hex label string. 1039219089Spjd */ 1040219089Spjd 1041219089Spjd m_label_t *new_sl; 1042219089Spjd char *hex = NULL; /* internal label string */ 1043219089Spjd 1044219089Spjd /* Default value is already OK. */ 1045219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1046219089Spjd break; 1047219089Spjd 1048219089Spjd /* Verify the label can be converted to binary form */ 1049219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1050219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1051219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1052219089Spjd goto badlabel; 1053168404Spjd } 1054168404Spjd 1055219089Spjd /* Now translate to hex internal label string */ 1056219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1057219089Spjd DEF_NAMES) != 0) { 1058219089Spjd if (hex) 1059219089Spjd free(hex); 1060219089Spjd goto badlabel; 1061219089Spjd } 1062219089Spjd m_label_free(new_sl); 1063219089Spjd 1064219089Spjd /* If string is already in internal form, we're done. */ 1065219089Spjd if (strcmp(strval, hex) == 0) { 1066219089Spjd free(hex); 1067219089Spjd break; 1068219089Spjd } 1069219089Spjd 1070219089Spjd /* Replace the label string with the internal form. */ 1071219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1072219089Spjd DATA_TYPE_STRING); 1073219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1074219089Spjd hex) == 0); 1075219089Spjd free(hex); 1076219089Spjd 1077168404Spjd break; 1078168404Spjd 1079219089Spjdbadlabel: 1080219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1081219089Spjd "invalid mlslabel '%s'"), strval); 1082219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1083219089Spjd m_label_free(new_sl); /* OK if null */ 1084219089Spjd#else /* !sun */ 1085219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1086219089Spjd "mlslabel is not supported on FreeBSD")); 1087219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1088219089Spjd#endif /* !sun */ 1089219089Spjd goto error; 1090219089Spjd 1091219089Spjd } 1092219089Spjd 1093168404Spjd case ZFS_PROP_MOUNTPOINT: 1094185029Spjd { 1095185029Spjd namecheck_err_t why; 1096185029Spjd 1097168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1098168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1099168404Spjd break; 1100168404Spjd 1101185029Spjd if (mountpoint_namecheck(strval, &why)) { 1102185029Spjd switch (why) { 1103185029Spjd case NAME_ERR_LEADING_SLASH: 1104185029Spjd zfs_error_aux(hdl, 1105185029Spjd dgettext(TEXT_DOMAIN, 1106185029Spjd "'%s' must be an absolute path, " 1107185029Spjd "'none', or 'legacy'"), propname); 1108185029Spjd break; 1109185029Spjd case NAME_ERR_TOOLONG: 1110185029Spjd zfs_error_aux(hdl, 1111185029Spjd dgettext(TEXT_DOMAIN, 1112185029Spjd "component of '%s' is too long"), 1113185029Spjd propname); 1114185029Spjd break; 1115185029Spjd } 1116168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1117168404Spjd goto error; 1118168404Spjd } 1119185029Spjd } 1120185029Spjd 1121168404Spjd /*FALLTHRU*/ 1122168404Spjd 1123185029Spjd case ZFS_PROP_SHARESMB: 1124168404Spjd case ZFS_PROP_SHARENFS: 1125168404Spjd /* 1126185029Spjd * For the mountpoint and sharenfs or sharesmb 1127185029Spjd * properties, check if it can be set in a 1128185029Spjd * global/non-global zone based on 1129168404Spjd * the zoned property value: 1130168404Spjd * 1131168404Spjd * global zone non-global zone 1132168404Spjd * -------------------------------------------------- 1133168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1134168404Spjd * sharenfs (no) sharenfs (no) 1135185029Spjd * sharesmb (no) sharesmb (no) 1136168404Spjd * 1137168404Spjd * zoned=off mountpoint (yes) N/A 1138168404Spjd * sharenfs (yes) 1139185029Spjd * sharesmb (yes) 1140168404Spjd */ 1141168404Spjd if (zoned) { 1142168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1143168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1144168404Spjd "'%s' cannot be set on " 1145168404Spjd "dataset in a non-global zone"), 1146168404Spjd propname); 1147168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1148168404Spjd errbuf); 1149168404Spjd goto error; 1150185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1151185029Spjd prop == ZFS_PROP_SHARESMB) { 1152168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1153168404Spjd "'%s' cannot be set in " 1154168404Spjd "a non-global zone"), propname); 1155168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1156168404Spjd errbuf); 1157168404Spjd goto error; 1158168404Spjd } 1159168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1160168404Spjd /* 1161168404Spjd * If zoned property is 'off', this must be in 1162209962Smm * a global zone. If not, something is wrong. 1163168404Spjd */ 1164168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1165168404Spjd "'%s' cannot be set while dataset " 1166168404Spjd "'zoned' property is set"), propname); 1167168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1168168404Spjd goto error; 1169168404Spjd } 1170168404Spjd 1171168404Spjd /* 1172185029Spjd * At this point, it is legitimate to set the 1173185029Spjd * property. Now we want to make sure that the 1174185029Spjd * property value is valid if it is sharenfs. 1175168404Spjd */ 1176185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1177185029Spjd prop == ZFS_PROP_SHARESMB) && 1178185029Spjd strcmp(strval, "on") != 0 && 1179185029Spjd strcmp(strval, "off") != 0) { 1180185029Spjd zfs_share_proto_t proto; 1181168404Spjd 1182185029Spjd if (prop == ZFS_PROP_SHARESMB) 1183185029Spjd proto = PROTO_SMB; 1184185029Spjd else 1185185029Spjd proto = PROTO_NFS; 1186185029Spjd 1187185029Spjd /* 1188185029Spjd * Must be an valid sharing protocol 1189185029Spjd * option string so init the libshare 1190185029Spjd * in order to enable the parser and 1191185029Spjd * then parse the options. We use the 1192185029Spjd * control API since we don't care about 1193185029Spjd * the current configuration and don't 1194185029Spjd * want the overhead of loading it 1195185029Spjd * until we actually do something. 1196185029Spjd */ 1197185029Spjd 1198185029Spjd if (zfs_init_libshare(hdl, 1199185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1200185029Spjd /* 1201185029Spjd * An error occurred so we can't do 1202185029Spjd * anything 1203185029Spjd */ 1204185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1205185029Spjd "'%s' cannot be set: problem " 1206185029Spjd "in share initialization"), 1207185029Spjd propname); 1208185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1209185029Spjd errbuf); 1210185029Spjd goto error; 1211185029Spjd } 1212185029Spjd 1213185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1214185029Spjd /* 1215185029Spjd * There was an error in parsing so 1216185029Spjd * deal with it by issuing an error 1217185029Spjd * message and leaving after 1218185029Spjd * uninitializing the the libshare 1219185029Spjd * interface. 1220185029Spjd */ 1221185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1222185029Spjd "'%s' cannot be set to invalid " 1223185029Spjd "options"), propname); 1224185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1225185029Spjd errbuf); 1226185029Spjd zfs_uninit_libshare(hdl); 1227185029Spjd goto error; 1228185029Spjd } 1229185029Spjd zfs_uninit_libshare(hdl); 1230168404Spjd } 1231185029Spjd 1232168404Spjd break; 1233185029Spjd case ZFS_PROP_UTF8ONLY: 1234185029Spjd chosen_utf = (int)intval; 1235185029Spjd break; 1236185029Spjd case ZFS_PROP_NORMALIZE: 1237185029Spjd chosen_normal = (int)intval; 1238185029Spjd break; 1239168404Spjd } 1240168404Spjd 1241168404Spjd /* 1242168404Spjd * For changes to existing volumes, we have some additional 1243168404Spjd * checks to enforce. 1244168404Spjd */ 1245168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1246168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1247168404Spjd ZFS_PROP_VOLSIZE); 1248168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1249168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1250168404Spjd char buf[64]; 1251168404Spjd 1252168404Spjd switch (prop) { 1253168404Spjd case ZFS_PROP_RESERVATION: 1254185029Spjd case ZFS_PROP_REFRESERVATION: 1255168404Spjd if (intval > volsize) { 1256168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1257168404Spjd "'%s' is greater than current " 1258168404Spjd "volume size"), propname); 1259168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1260168404Spjd errbuf); 1261168404Spjd goto error; 1262168404Spjd } 1263168404Spjd break; 1264168404Spjd 1265168404Spjd case ZFS_PROP_VOLSIZE: 1266168404Spjd if (intval % blocksize != 0) { 1267168404Spjd zfs_nicenum(blocksize, buf, 1268168404Spjd sizeof (buf)); 1269168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1270168404Spjd "'%s' must be a multiple of " 1271168404Spjd "volume block size (%s)"), 1272168404Spjd propname, buf); 1273168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1274168404Spjd errbuf); 1275168404Spjd goto error; 1276168404Spjd } 1277168404Spjd 1278168404Spjd if (intval == 0) { 1279168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1280168404Spjd "'%s' cannot be zero"), 1281168404Spjd propname); 1282168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1283168404Spjd errbuf); 1284168404Spjd goto error; 1285168404Spjd } 1286168404Spjd break; 1287168404Spjd } 1288168404Spjd } 1289168404Spjd } 1290168404Spjd 1291168404Spjd /* 1292185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1293185029Spjd * enforce rejection of non-UTF8 names. 1294185029Spjd * 1295185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1296185029Spjd * was explicitly not chosen, it is an error. 1297185029Spjd */ 1298185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1299185029Spjd if (nvlist_add_uint64(ret, 1300185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1301185029Spjd (void) no_memory(hdl); 1302185029Spjd goto error; 1303185029Spjd } 1304185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1305185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1306185029Spjd "'%s' must be set 'on' if normalization chosen"), 1307185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1308185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1309185029Spjd goto error; 1310185029Spjd } 1311219089Spjd return (ret); 1312185029Spjd 1313219089Spjderror: 1314219089Spjd nvlist_free(ret); 1315219089Spjd return (NULL); 1316219089Spjd} 1317219089Spjd 1318219089Spjdint 1319219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1320219089Spjd{ 1321219089Spjd uint64_t old_volsize; 1322219089Spjd uint64_t new_volsize; 1323219089Spjd uint64_t old_reservation; 1324219089Spjd uint64_t new_reservation; 1325219089Spjd zfs_prop_t resv_prop; 1326219089Spjd 1327185029Spjd /* 1328168404Spjd * If this is an existing volume, and someone is setting the volsize, 1329168404Spjd * make sure that it matches the reservation, or add it if necessary. 1330168404Spjd */ 1331219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1332219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1333219089Spjd return (-1); 1334219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1335219089Spjd if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != 1336219089Spjd old_reservation) || nvlist_lookup_uint64(nvl, 1337219089Spjd zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { 1338219089Spjd return (0); 1339219089Spjd } 1340219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1341219089Spjd &new_volsize) != 0) 1342219089Spjd return (-1); 1343219089Spjd new_reservation = zvol_volsize_to_reservation(new_volsize, 1344219089Spjd zhp->zfs_props); 1345219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1346219089Spjd new_reservation) != 0) { 1347219089Spjd (void) no_memory(zhp->zfs_hdl); 1348219089Spjd return (-1); 1349219089Spjd } 1350219089Spjd return (1); 1351219089Spjd} 1352168404Spjd 1353219089Spjdvoid 1354219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1355219089Spjd char *errbuf) 1356219089Spjd{ 1357219089Spjd switch (err) { 1358185029Spjd 1359219089Spjd case ENOSPC: 1360219089Spjd /* 1361219089Spjd * For quotas and reservations, ENOSPC indicates 1362219089Spjd * something different; setting a quota or reservation 1363219089Spjd * doesn't use any disk space. 1364219089Spjd */ 1365219089Spjd switch (prop) { 1366219089Spjd case ZFS_PROP_QUOTA: 1367219089Spjd case ZFS_PROP_REFQUOTA: 1368219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1369219089Spjd "size is less than current used or " 1370219089Spjd "reserved space")); 1371219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1372219089Spjd break; 1373219089Spjd 1374219089Spjd case ZFS_PROP_RESERVATION: 1375219089Spjd case ZFS_PROP_REFRESERVATION: 1376219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1377219089Spjd "size is greater than available space")); 1378219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1379219089Spjd break; 1380219089Spjd 1381219089Spjd default: 1382219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1383219089Spjd break; 1384168404Spjd } 1385219089Spjd break; 1386219089Spjd 1387219089Spjd case EBUSY: 1388219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1389219089Spjd break; 1390219089Spjd 1391219089Spjd case EROFS: 1392219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1393219089Spjd break; 1394219089Spjd 1395219089Spjd case ENOTSUP: 1396219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1397219089Spjd "pool and or dataset must be upgraded to set this " 1398219089Spjd "property or value")); 1399219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1400219089Spjd break; 1401219089Spjd 1402219089Spjd case ERANGE: 1403219089Spjd if (prop == ZFS_PROP_COMPRESSION) { 1404219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1405219089Spjd "property setting is not allowed on " 1406219089Spjd "bootable datasets")); 1407219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1408219089Spjd } else { 1409219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1410219089Spjd } 1411219089Spjd break; 1412219089Spjd 1413219089Spjd case EINVAL: 1414219089Spjd if (prop == ZPROP_INVAL) { 1415219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1416219089Spjd } else { 1417219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1418219089Spjd } 1419219089Spjd break; 1420219089Spjd 1421219089Spjd case EOVERFLOW: 1422219089Spjd /* 1423219089Spjd * This platform can't address a volume this big. 1424219089Spjd */ 1425219089Spjd#ifdef _ILP32 1426219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1427219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1428219089Spjd break; 1429219089Spjd } 1430219089Spjd#endif 1431219089Spjd /* FALLTHROUGH */ 1432219089Spjd default: 1433219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1434168404Spjd } 1435168404Spjd} 1436168404Spjd 1437168404Spjd/* 1438168404Spjd * Given a property name and value, set the property for the given dataset. 1439168404Spjd */ 1440168404Spjdint 1441168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1442168404Spjd{ 1443168404Spjd zfs_cmd_t zc = { 0 }; 1444168404Spjd int ret = -1; 1445168404Spjd prop_changelist_t *cl = NULL; 1446168404Spjd char errbuf[1024]; 1447168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1448168404Spjd nvlist_t *nvl = NULL, *realprops; 1449168404Spjd zfs_prop_t prop; 1450241655Smm boolean_t do_prefix = B_TRUE; 1451219089Spjd int added_resv; 1452168404Spjd 1453168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1454168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1455168404Spjd zhp->zfs_name); 1456168404Spjd 1457168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1458168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1459168404Spjd (void) no_memory(hdl); 1460168404Spjd goto error; 1461168404Spjd } 1462168404Spjd 1463185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1464168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1465168404Spjd goto error; 1466185029Spjd 1467168404Spjd nvlist_free(nvl); 1468168404Spjd nvl = realprops; 1469168404Spjd 1470168404Spjd prop = zfs_name_to_prop(propname); 1471168404Spjd 1472168404Spjd /* We don't support those properties on FreeBSD. */ 1473168404Spjd switch (prop) { 1474197867Strasz case ZFS_PROP_DEVICES: 1475168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1476197867Strasz case ZFS_PROP_XATTR: 1477197867Strasz case ZFS_PROP_VSCAN: 1478197867Strasz case ZFS_PROP_NBMAND: 1479219089Spjd case ZFS_PROP_MLSLABEL: 1480168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1481168404Spjd "property '%s' not supported on FreeBSD", propname); 1482168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1483168404Spjd goto error; 1484168404Spjd } 1485168404Spjd 1486219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1487219089Spjd if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) 1488219089Spjd goto error; 1489219089Spjd } 1490219089Spjd 1491185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1492168404Spjd goto error; 1493168404Spjd 1494168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1495168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1496168404Spjd "child dataset with inherited mountpoint is used " 1497168404Spjd "in a non-global zone")); 1498168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1499168404Spjd goto error; 1500168404Spjd } 1501168404Spjd 1502185029Spjd /* 1503238391Smm * We don't want to unmount & remount the dataset when changing 1504238391Smm * its canmount property to 'on' or 'noauto'. We only use 1505238391Smm * the changelist logic to unmount when setting canmount=off. 1506185029Spjd */ 1507238391Smm if (prop == ZFS_PROP_CANMOUNT) { 1508238391Smm uint64_t idx; 1509238391Smm int err = zprop_string_to_index(prop, propval, &idx, 1510238391Smm ZFS_TYPE_DATASET); 1511238391Smm if (err == 0 && idx != ZFS_CANMOUNT_OFF) 1512238391Smm do_prefix = B_FALSE; 1513238391Smm } 1514185029Spjd 1515185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1516168404Spjd goto error; 1517168404Spjd 1518168404Spjd /* 1519168404Spjd * Execute the corresponding ioctl() to set this property. 1520168404Spjd */ 1521168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1522168404Spjd 1523185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1524168404Spjd goto error; 1525168404Spjd 1526185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1527209962Smm 1528168404Spjd if (ret != 0) { 1529219089Spjd zfs_setprop_error(hdl, prop, errno, errbuf); 1530219089Spjd if (added_resv && errno == ENOSPC) { 1531219089Spjd /* clean up the volsize property we tried to set */ 1532219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1533219089Spjd ZFS_PROP_VOLSIZE); 1534219089Spjd nvlist_free(nvl); 1535219089Spjd zcmd_free_nvlists(&zc); 1536219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1537219089Spjd goto error; 1538219089Spjd if (nvlist_add_uint64(nvl, 1539219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1540219089Spjd old_volsize) != 0) 1541219089Spjd goto error; 1542219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1543219089Spjd goto error; 1544219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1545168404Spjd } 1546168404Spjd } else { 1547185029Spjd if (do_prefix) 1548185029Spjd ret = changelist_postfix(cl); 1549185029Spjd 1550168404Spjd /* 1551168404Spjd * Refresh the statistics so the new property value 1552168404Spjd * is reflected. 1553168404Spjd */ 1554185029Spjd if (ret == 0) 1555168404Spjd (void) get_stats(zhp); 1556168404Spjd } 1557168404Spjd 1558168404Spjderror: 1559168404Spjd nvlist_free(nvl); 1560168404Spjd zcmd_free_nvlists(&zc); 1561168404Spjd if (cl) 1562168404Spjd changelist_free(cl); 1563168404Spjd return (ret); 1564168404Spjd} 1565168404Spjd 1566168404Spjd/* 1567219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1568219089Spjd * is TRUE, revert to the received value, if any. 1569168404Spjd */ 1570168404Spjdint 1571219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1572168404Spjd{ 1573168404Spjd zfs_cmd_t zc = { 0 }; 1574168404Spjd int ret; 1575168404Spjd prop_changelist_t *cl; 1576168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1577168404Spjd char errbuf[1024]; 1578168404Spjd zfs_prop_t prop; 1579168404Spjd 1580168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1581168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1582168404Spjd 1583219089Spjd zc.zc_cookie = received; 1584185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1585168404Spjd /* 1586168404Spjd * For user properties, the amount of work we have to do is very 1587168404Spjd * small, so just do it here. 1588168404Spjd */ 1589168404Spjd if (!zfs_prop_user(propname)) { 1590168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1591168404Spjd "invalid property")); 1592168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1593168404Spjd } 1594168404Spjd 1595168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1596168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1597168404Spjd 1598185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1599168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1600168404Spjd 1601168404Spjd return (0); 1602168404Spjd } 1603168404Spjd 1604168404Spjd /* 1605168404Spjd * Verify that this property is inheritable. 1606168404Spjd */ 1607168404Spjd if (zfs_prop_readonly(prop)) 1608168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1609168404Spjd 1610219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1611168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1612168404Spjd 1613168404Spjd /* 1614168404Spjd * Check to see if the value applies to this type 1615168404Spjd */ 1616168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1617168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1618168404Spjd 1619168404Spjd /* 1620219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1621168404Spjd */ 1622168404Spjd propname = zfs_prop_to_name(prop); 1623168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1624168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1625168404Spjd 1626168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1627168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1628168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1629168404Spjd "dataset is used in a non-global zone")); 1630168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1631168404Spjd } 1632168404Spjd 1633168404Spjd /* 1634168404Spjd * Determine datasets which will be affected by this change, if any. 1635168404Spjd */ 1636185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1637168404Spjd return (-1); 1638168404Spjd 1639168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1640168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1641168404Spjd "child dataset with inherited mountpoint is used " 1642168404Spjd "in a non-global zone")); 1643168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1644168404Spjd goto error; 1645168404Spjd } 1646168404Spjd 1647168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1648168404Spjd goto error; 1649168404Spjd 1650185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1651168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1652168404Spjd } else { 1653168404Spjd 1654168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1655168404Spjd goto error; 1656168404Spjd 1657168404Spjd /* 1658168404Spjd * Refresh the statistics so the new property is reflected. 1659168404Spjd */ 1660168404Spjd (void) get_stats(zhp); 1661168404Spjd } 1662168404Spjd 1663168404Spjderror: 1664168404Spjd changelist_free(cl); 1665168404Spjd return (ret); 1666168404Spjd} 1667168404Spjd 1668168404Spjd/* 1669168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1670168404Spjd * extract them appropriately. 1671168404Spjd */ 1672168404Spjdstatic uint64_t 1673168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1674168404Spjd{ 1675168404Spjd nvlist_t *nv; 1676168404Spjd uint64_t value; 1677168404Spjd 1678168404Spjd *source = NULL; 1679168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1680168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1681185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1682185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1683168404Spjd } else { 1684205198Sdelphij verify(!zhp->zfs_props_table || 1685205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1686168404Spjd value = zfs_prop_default_numeric(prop); 1687168404Spjd *source = ""; 1688168404Spjd } 1689168404Spjd 1690168404Spjd return (value); 1691168404Spjd} 1692168404Spjd 1693168404Spjdstatic char * 1694168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1695168404Spjd{ 1696168404Spjd nvlist_t *nv; 1697168404Spjd char *value; 1698168404Spjd 1699168404Spjd *source = NULL; 1700168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1701168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1702185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1703185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1704168404Spjd } else { 1705205198Sdelphij verify(!zhp->zfs_props_table || 1706205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1707168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1708168404Spjd value = ""; 1709168404Spjd *source = ""; 1710168404Spjd } 1711168404Spjd 1712168404Spjd return (value); 1713168404Spjd} 1714168404Spjd 1715219089Spjdstatic boolean_t 1716219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1717219089Spjd{ 1718219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1719219089Spjd} 1720219089Spjd 1721219089Spjdstatic void 1722219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1723219089Spjd{ 1724219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1725219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1726219089Spjd} 1727219089Spjd 1728219089Spjdstatic void 1729219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1730219089Spjd{ 1731219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1732219089Spjd *cookie = 0; 1733219089Spjd} 1734219089Spjd 1735168404Spjd/* 1736168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1737168404Spjd * zfs_prop_get_int() are built using this interface. 1738168404Spjd * 1739168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1740168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1741168404Spjd * If they differ from the on-disk values, report the current values and mark 1742168404Spjd * the source "temporary". 1743168404Spjd */ 1744168404Spjdstatic int 1745185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1746168404Spjd char **source, uint64_t *val) 1747168404Spjd{ 1748185029Spjd zfs_cmd_t zc = { 0 }; 1749185029Spjd nvlist_t *zplprops = NULL; 1750168404Spjd struct mnttab mnt; 1751168404Spjd char *mntopt_on = NULL; 1752168404Spjd char *mntopt_off = NULL; 1753219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1754168404Spjd 1755168404Spjd *source = NULL; 1756168404Spjd 1757168404Spjd switch (prop) { 1758168404Spjd case ZFS_PROP_ATIME: 1759168404Spjd mntopt_on = MNTOPT_ATIME; 1760168404Spjd mntopt_off = MNTOPT_NOATIME; 1761168404Spjd break; 1762168404Spjd 1763168404Spjd case ZFS_PROP_DEVICES: 1764168404Spjd mntopt_on = MNTOPT_DEVICES; 1765168404Spjd mntopt_off = MNTOPT_NODEVICES; 1766168404Spjd break; 1767168404Spjd 1768168404Spjd case ZFS_PROP_EXEC: 1769168404Spjd mntopt_on = MNTOPT_EXEC; 1770168404Spjd mntopt_off = MNTOPT_NOEXEC; 1771168404Spjd break; 1772168404Spjd 1773168404Spjd case ZFS_PROP_READONLY: 1774168404Spjd mntopt_on = MNTOPT_RO; 1775168404Spjd mntopt_off = MNTOPT_RW; 1776168404Spjd break; 1777168404Spjd 1778168404Spjd case ZFS_PROP_SETUID: 1779168404Spjd mntopt_on = MNTOPT_SETUID; 1780168404Spjd mntopt_off = MNTOPT_NOSETUID; 1781168404Spjd break; 1782168404Spjd 1783168404Spjd case ZFS_PROP_XATTR: 1784168404Spjd mntopt_on = MNTOPT_XATTR; 1785168404Spjd mntopt_off = MNTOPT_NOXATTR; 1786168404Spjd break; 1787185029Spjd 1788185029Spjd case ZFS_PROP_NBMAND: 1789185029Spjd mntopt_on = MNTOPT_NBMAND; 1790185029Spjd mntopt_off = MNTOPT_NONBMAND; 1791185029Spjd break; 1792168404Spjd } 1793168404Spjd 1794168404Spjd /* 1795168404Spjd * Because looking up the mount options is potentially expensive 1796168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1797168404Spjd * we're looking up a property which requires its presence. 1798168404Spjd */ 1799168404Spjd if (!zhp->zfs_mntcheck && 1800168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1801209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1802209962Smm struct mnttab entry; 1803168404Spjd 1804209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1805209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1806168404Spjd entry.mnt_mntopts); 1807168404Spjd if (zhp->zfs_mntopts == NULL) 1808168404Spjd return (-1); 1809168404Spjd } 1810168404Spjd 1811168404Spjd zhp->zfs_mntcheck = B_TRUE; 1812168404Spjd } 1813168404Spjd 1814168404Spjd if (zhp->zfs_mntopts == NULL) 1815168404Spjd mnt.mnt_mntopts = ""; 1816168404Spjd else 1817168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1818168404Spjd 1819168404Spjd switch (prop) { 1820168404Spjd case ZFS_PROP_ATIME: 1821168404Spjd case ZFS_PROP_DEVICES: 1822168404Spjd case ZFS_PROP_EXEC: 1823168404Spjd case ZFS_PROP_READONLY: 1824168404Spjd case ZFS_PROP_SETUID: 1825168404Spjd case ZFS_PROP_XATTR: 1826185029Spjd case ZFS_PROP_NBMAND: 1827168404Spjd *val = getprop_uint64(zhp, prop, source); 1828168404Spjd 1829219089Spjd if (received) 1830219089Spjd break; 1831219089Spjd 1832168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1833168404Spjd *val = B_TRUE; 1834168404Spjd if (src) 1835185029Spjd *src = ZPROP_SRC_TEMPORARY; 1836168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1837168404Spjd *val = B_FALSE; 1838168404Spjd if (src) 1839185029Spjd *src = ZPROP_SRC_TEMPORARY; 1840168404Spjd } 1841168404Spjd break; 1842168404Spjd 1843168404Spjd case ZFS_PROP_CANMOUNT: 1844219089Spjd case ZFS_PROP_VOLSIZE: 1845168404Spjd case ZFS_PROP_QUOTA: 1846185029Spjd case ZFS_PROP_REFQUOTA: 1847168404Spjd case ZFS_PROP_RESERVATION: 1848185029Spjd case ZFS_PROP_REFRESERVATION: 1849168404Spjd *val = getprop_uint64(zhp, prop, source); 1850219089Spjd 1851219089Spjd if (*source == NULL) { 1852219089Spjd /* not default, must be local */ 1853168404Spjd *source = zhp->zfs_name; 1854219089Spjd } 1855168404Spjd break; 1856168404Spjd 1857168404Spjd case ZFS_PROP_MOUNTED: 1858168404Spjd *val = (zhp->zfs_mntopts != NULL); 1859168404Spjd break; 1860168404Spjd 1861168404Spjd case ZFS_PROP_NUMCLONES: 1862168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1863168404Spjd break; 1864168404Spjd 1865185029Spjd case ZFS_PROP_VERSION: 1866185029Spjd case ZFS_PROP_NORMALIZE: 1867185029Spjd case ZFS_PROP_UTF8ONLY: 1868185029Spjd case ZFS_PROP_CASE: 1869185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1870185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1871185029Spjd return (-1); 1872185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1873185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1874185029Spjd zcmd_free_nvlists(&zc); 1875219089Spjd return (-1); 1876185029Spjd } 1877185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1878185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1879185029Spjd val) != 0) { 1880185029Spjd zcmd_free_nvlists(&zc); 1881219089Spjd return (-1); 1882185029Spjd } 1883185029Spjd if (zplprops) 1884185029Spjd nvlist_free(zplprops); 1885185029Spjd zcmd_free_nvlists(&zc); 1886185029Spjd break; 1887185029Spjd 1888253819Sdelphij case ZFS_PROP_INCONSISTENT: 1889253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 1890253819Sdelphij break; 1891253819Sdelphij 1892168404Spjd default: 1893185029Spjd switch (zfs_prop_get_type(prop)) { 1894185029Spjd case PROP_TYPE_NUMBER: 1895185029Spjd case PROP_TYPE_INDEX: 1896185029Spjd *val = getprop_uint64(zhp, prop, source); 1897185029Spjd /* 1898209962Smm * If we tried to use a default value for a 1899185029Spjd * readonly property, it means that it was not 1900219089Spjd * present. 1901185029Spjd */ 1902185029Spjd if (zfs_prop_readonly(prop) && 1903219089Spjd *source != NULL && (*source)[0] == '\0') { 1904219089Spjd *source = NULL; 1905185029Spjd } 1906185029Spjd break; 1907185029Spjd 1908185029Spjd case PROP_TYPE_STRING: 1909185029Spjd default: 1910185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1911185029Spjd "cannot get non-numeric property")); 1912185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1913185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1914185029Spjd } 1915168404Spjd } 1916168404Spjd 1917168404Spjd return (0); 1918168404Spjd} 1919168404Spjd 1920168404Spjd/* 1921168404Spjd * Calculate the source type, given the raw source string. 1922168404Spjd */ 1923168404Spjdstatic void 1924185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1925168404Spjd char *statbuf, size_t statlen) 1926168404Spjd{ 1927185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1928168404Spjd return; 1929168404Spjd 1930168404Spjd if (source == NULL) { 1931185029Spjd *srctype = ZPROP_SRC_NONE; 1932168404Spjd } else if (source[0] == '\0') { 1933185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1934219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 1935219089Spjd *srctype = ZPROP_SRC_RECEIVED; 1936168404Spjd } else { 1937168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1938185029Spjd *srctype = ZPROP_SRC_LOCAL; 1939168404Spjd } else { 1940168404Spjd (void) strlcpy(statbuf, source, statlen); 1941185029Spjd *srctype = ZPROP_SRC_INHERITED; 1942168404Spjd } 1943168404Spjd } 1944168404Spjd 1945168404Spjd} 1946168404Spjd 1947219089Spjdint 1948219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 1949219089Spjd size_t proplen, boolean_t literal) 1950219089Spjd{ 1951219089Spjd zfs_prop_t prop; 1952219089Spjd int err = 0; 1953219089Spjd 1954219089Spjd if (zhp->zfs_recvd_props == NULL) 1955219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 1956219089Spjd return (-1); 1957219089Spjd 1958219089Spjd prop = zfs_name_to_prop(propname); 1959219089Spjd 1960219089Spjd if (prop != ZPROP_INVAL) { 1961219089Spjd uint64_t cookie; 1962219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 1963219089Spjd return (-1); 1964219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 1965219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 1966219089Spjd NULL, NULL, 0, literal); 1967219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 1968219089Spjd } else { 1969219089Spjd nvlist_t *propval; 1970219089Spjd char *recvdval; 1971219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 1972219089Spjd propname, &propval) != 0) 1973219089Spjd return (-1); 1974219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 1975219089Spjd &recvdval) == 0); 1976219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 1977219089Spjd } 1978219089Spjd 1979219089Spjd return (err == 0 ? 0 : -1); 1980219089Spjd} 1981219089Spjd 1982228103Smmstatic int 1983228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 1984228103Smm{ 1985228103Smm nvlist_t *value; 1986228103Smm nvpair_t *pair; 1987228103Smm 1988228103Smm value = zfs_get_clones_nvl(zhp); 1989228103Smm if (value == NULL) 1990228103Smm return (-1); 1991228103Smm 1992228103Smm propbuf[0] = '\0'; 1993228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 1994228103Smm pair = nvlist_next_nvpair(value, pair)) { 1995228103Smm if (propbuf[0] != '\0') 1996228103Smm (void) strlcat(propbuf, ",", proplen); 1997228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 1998228103Smm } 1999228103Smm 2000228103Smm return (0); 2001228103Smm} 2002228103Smm 2003228103Smmstruct get_clones_arg { 2004228103Smm uint64_t numclones; 2005228103Smm nvlist_t *value; 2006228103Smm const char *origin; 2007228103Smm char buf[ZFS_MAXNAMELEN]; 2008228103Smm}; 2009228103Smm 2010228103Smmint 2011228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2012228103Smm{ 2013228103Smm struct get_clones_arg *gca = arg; 2014228103Smm 2015228103Smm if (gca->numclones == 0) { 2016228103Smm zfs_close(zhp); 2017228103Smm return (0); 2018228103Smm } 2019228103Smm 2020228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2021228103Smm NULL, NULL, 0, B_TRUE) != 0) 2022228103Smm goto out; 2023228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2024248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2025228103Smm gca->numclones--; 2026228103Smm } 2027228103Smm 2028228103Smmout: 2029228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2030228103Smm zfs_close(zhp); 2031228103Smm return (0); 2032228103Smm} 2033228103Smm 2034228103Smmnvlist_t * 2035228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2036228103Smm{ 2037228103Smm nvlist_t *nv, *value; 2038228103Smm 2039228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2040228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2041228103Smm struct get_clones_arg gca; 2042228103Smm 2043228103Smm /* 2044228103Smm * if this is a snapshot, then the kernel wasn't able 2045228103Smm * to get the clones. Do it by slowly iterating. 2046228103Smm */ 2047228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2048228103Smm return (NULL); 2049228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2050228103Smm return (NULL); 2051228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2052228103Smm nvlist_free(nv); 2053228103Smm return (NULL); 2054228103Smm } 2055228103Smm 2056228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2057228103Smm gca.value = value; 2058228103Smm gca.origin = zhp->zfs_name; 2059228103Smm 2060228103Smm if (gca.numclones != 0) { 2061228103Smm zfs_handle_t *root; 2062228103Smm char pool[ZFS_MAXNAMELEN]; 2063228103Smm char *cp = pool; 2064228103Smm 2065228103Smm /* get the pool name */ 2066228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2067228103Smm (void) strsep(&cp, "/@"); 2068228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2069228103Smm ZFS_TYPE_FILESYSTEM); 2070228103Smm 2071228103Smm (void) get_clones_cb(root, &gca); 2072228103Smm } 2073228103Smm 2074228103Smm if (gca.numclones != 0 || 2075228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2076228103Smm nvlist_add_nvlist(zhp->zfs_props, 2077228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2078228103Smm nvlist_free(nv); 2079228103Smm nvlist_free(value); 2080228103Smm return (NULL); 2081228103Smm } 2082228103Smm nvlist_free(nv); 2083228103Smm nvlist_free(value); 2084228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2085228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2086228103Smm } 2087228103Smm 2088228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2089228103Smm 2090228103Smm return (value); 2091228103Smm} 2092228103Smm 2093168404Spjd/* 2094168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2095168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2096168404Spjd * human-readable form. 2097168404Spjd * 2098168404Spjd * Returns 0 on success, or -1 on error. 2099168404Spjd */ 2100168404Spjdint 2101168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2102185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2103168404Spjd{ 2104168404Spjd char *source = NULL; 2105168404Spjd uint64_t val; 2106168404Spjd char *str; 2107168404Spjd const char *strval; 2108219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2109168404Spjd 2110168404Spjd /* 2111168404Spjd * Check to see if this property applies to our object 2112168404Spjd */ 2113168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2114168404Spjd return (-1); 2115168404Spjd 2116219089Spjd if (received && zfs_prop_readonly(prop)) 2117219089Spjd return (-1); 2118219089Spjd 2119168404Spjd if (src) 2120185029Spjd *src = ZPROP_SRC_NONE; 2121168404Spjd 2122168404Spjd switch (prop) { 2123168404Spjd case ZFS_PROP_CREATION: 2124168404Spjd /* 2125168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2126168404Spjd * this into a string unless 'literal' is specified. 2127168404Spjd */ 2128168404Spjd { 2129168404Spjd val = getprop_uint64(zhp, prop, &source); 2130168404Spjd time_t time = (time_t)val; 2131168404Spjd struct tm t; 2132168404Spjd 2133168404Spjd if (literal || 2134168404Spjd localtime_r(&time, &t) == NULL || 2135168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2136168404Spjd &t) == 0) 2137168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2138168404Spjd } 2139168404Spjd break; 2140168404Spjd 2141168404Spjd case ZFS_PROP_MOUNTPOINT: 2142168404Spjd /* 2143168404Spjd * Getting the precise mountpoint can be tricky. 2144168404Spjd * 2145168404Spjd * - for 'none' or 'legacy', return those values. 2146168404Spjd * - for inherited mountpoints, we want to take everything 2147168404Spjd * after our ancestor and append it to the inherited value. 2148168404Spjd * 2149168404Spjd * If the pool has an alternate root, we want to prepend that 2150168404Spjd * root to any values we return. 2151168404Spjd */ 2152185029Spjd 2153168404Spjd str = getprop_string(zhp, prop, &source); 2154168404Spjd 2155185029Spjd if (str[0] == '/') { 2156185029Spjd char buf[MAXPATHLEN]; 2157185029Spjd char *root = buf; 2158219089Spjd const char *relpath; 2159168404Spjd 2160219089Spjd /* 2161219089Spjd * If we inherit the mountpoint, even from a dataset 2162219089Spjd * with a received value, the source will be the path of 2163219089Spjd * the dataset we inherit from. If source is 2164219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2165219089Spjd * inherited. 2166219089Spjd */ 2167219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2168219089Spjd relpath = ""; 2169219089Spjd } else { 2170219089Spjd relpath = zhp->zfs_name + strlen(source); 2171219089Spjd if (relpath[0] == '/') 2172219089Spjd relpath++; 2173219089Spjd } 2174185029Spjd 2175185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2176185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 2177185029Spjd (strcmp(root, "-") == 0)) 2178185029Spjd root[0] = '\0'; 2179185029Spjd /* 2180185029Spjd * Special case an alternate root of '/'. This will 2181185029Spjd * avoid having multiple leading slashes in the 2182185029Spjd * mountpoint path. 2183185029Spjd */ 2184185029Spjd if (strcmp(root, "/") == 0) 2185185029Spjd root++; 2186185029Spjd 2187185029Spjd /* 2188185029Spjd * If the mountpoint is '/' then skip over this 2189185029Spjd * if we are obtaining either an alternate root or 2190185029Spjd * an inherited mountpoint. 2191185029Spjd */ 2192185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2193185029Spjd relpath[0] != '\0')) 2194168404Spjd str++; 2195168404Spjd 2196168404Spjd if (relpath[0] == '\0') 2197168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2198168404Spjd root, str); 2199168404Spjd else 2200168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2201168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2202168404Spjd relpath); 2203168404Spjd } else { 2204168404Spjd /* 'legacy' or 'none' */ 2205168404Spjd (void) strlcpy(propbuf, str, proplen); 2206168404Spjd } 2207168404Spjd 2208168404Spjd break; 2209168404Spjd 2210168404Spjd case ZFS_PROP_ORIGIN: 2211168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2212168404Spjd proplen); 2213168404Spjd /* 2214168404Spjd * If there is no parent at all, return failure to indicate that 2215168404Spjd * it doesn't apply to this dataset. 2216168404Spjd */ 2217168404Spjd if (propbuf[0] == '\0') 2218168404Spjd return (-1); 2219168404Spjd break; 2220168404Spjd 2221228103Smm case ZFS_PROP_CLONES: 2222228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2223228103Smm return (-1); 2224228103Smm break; 2225228103Smm 2226168404Spjd case ZFS_PROP_QUOTA: 2227185029Spjd case ZFS_PROP_REFQUOTA: 2228168404Spjd case ZFS_PROP_RESERVATION: 2229185029Spjd case ZFS_PROP_REFRESERVATION: 2230185029Spjd 2231168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2232168404Spjd return (-1); 2233168404Spjd 2234168404Spjd /* 2235168404Spjd * If quota or reservation is 0, we translate this into 'none' 2236168404Spjd * (unless literal is set), and indicate that it's the default 2237168404Spjd * value. Otherwise, we print the number nicely and indicate 2238168404Spjd * that its set locally. 2239168404Spjd */ 2240168404Spjd if (val == 0) { 2241168404Spjd if (literal) 2242168404Spjd (void) strlcpy(propbuf, "0", proplen); 2243168404Spjd else 2244168404Spjd (void) strlcpy(propbuf, "none", proplen); 2245168404Spjd } else { 2246168404Spjd if (literal) 2247168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2248168404Spjd (u_longlong_t)val); 2249168404Spjd else 2250168404Spjd zfs_nicenum(val, propbuf, proplen); 2251168404Spjd } 2252168404Spjd break; 2253168404Spjd 2254223623Smm case ZFS_PROP_REFRATIO: 2255168404Spjd case ZFS_PROP_COMPRESSRATIO: 2256168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2257168404Spjd return (-1); 2258219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2259219089Spjd (u_longlong_t)(val / 100), 2260219089Spjd (u_longlong_t)(val % 100)); 2261168404Spjd break; 2262168404Spjd 2263168404Spjd case ZFS_PROP_TYPE: 2264168404Spjd switch (zhp->zfs_type) { 2265168404Spjd case ZFS_TYPE_FILESYSTEM: 2266168404Spjd str = "filesystem"; 2267168404Spjd break; 2268168404Spjd case ZFS_TYPE_VOLUME: 2269168404Spjd str = "volume"; 2270168404Spjd break; 2271168404Spjd case ZFS_TYPE_SNAPSHOT: 2272168404Spjd str = "snapshot"; 2273168404Spjd break; 2274168404Spjd default: 2275168404Spjd abort(); 2276168404Spjd } 2277168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2278168404Spjd break; 2279168404Spjd 2280168404Spjd case ZFS_PROP_MOUNTED: 2281168404Spjd /* 2282168404Spjd * The 'mounted' property is a pseudo-property that described 2283168404Spjd * whether the filesystem is currently mounted. Even though 2284168404Spjd * it's a boolean value, the typical values of "on" and "off" 2285168404Spjd * don't make sense, so we translate to "yes" and "no". 2286168404Spjd */ 2287168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2288168404Spjd src, &source, &val) != 0) 2289168404Spjd return (-1); 2290168404Spjd if (val) 2291168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2292168404Spjd else 2293168404Spjd (void) strlcpy(propbuf, "no", proplen); 2294168404Spjd break; 2295168404Spjd 2296168404Spjd case ZFS_PROP_NAME: 2297168404Spjd /* 2298168404Spjd * The 'name' property is a pseudo-property derived from the 2299168404Spjd * dataset name. It is presented as a real property to simplify 2300168404Spjd * consumers. 2301168404Spjd */ 2302168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2303168404Spjd break; 2304168404Spjd 2305219089Spjd case ZFS_PROP_MLSLABEL: 2306219089Spjd { 2307219089Spjd#ifdef sun 2308219089Spjd m_label_t *new_sl = NULL; 2309219089Spjd char *ascii = NULL; /* human readable label */ 2310219089Spjd 2311219089Spjd (void) strlcpy(propbuf, 2312219089Spjd getprop_string(zhp, prop, &source), proplen); 2313219089Spjd 2314219089Spjd if (literal || (strcasecmp(propbuf, 2315219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2316219089Spjd break; 2317219089Spjd 2318219089Spjd /* 2319219089Spjd * Try to translate the internal hex string to 2320219089Spjd * human-readable output. If there are any 2321219089Spjd * problems just use the hex string. 2322219089Spjd */ 2323219089Spjd 2324219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2325219089Spjd L_NO_CORRECTION, NULL) == -1) { 2326219089Spjd m_label_free(new_sl); 2327219089Spjd break; 2328219089Spjd } 2329219089Spjd 2330219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2331219089Spjd DEF_NAMES) != 0) { 2332219089Spjd if (ascii) 2333219089Spjd free(ascii); 2334219089Spjd m_label_free(new_sl); 2335219089Spjd break; 2336219089Spjd } 2337219089Spjd m_label_free(new_sl); 2338219089Spjd 2339219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2340219089Spjd free(ascii); 2341219089Spjd#else /* !sun */ 2342219089Spjd propbuf[0] = '\0'; 2343219089Spjd#endif /* !sun */ 2344219089Spjd } 2345219089Spjd break; 2346219089Spjd 2347236705Smm case ZFS_PROP_GUID: 2348236705Smm /* 2349236705Smm * GUIDs are stored as numbers, but they are identifiers. 2350236705Smm * We don't want them to be pretty printed, because pretty 2351236705Smm * printing mangles the ID into a truncated and useless value. 2352236705Smm */ 2353236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2354236705Smm return (-1); 2355236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2356236705Smm break; 2357236705Smm 2358168404Spjd default: 2359185029Spjd switch (zfs_prop_get_type(prop)) { 2360185029Spjd case PROP_TYPE_NUMBER: 2361185029Spjd if (get_numeric_property(zhp, prop, src, 2362185029Spjd &source, &val) != 0) 2363185029Spjd return (-1); 2364185029Spjd if (literal) 2365185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2366185029Spjd (u_longlong_t)val); 2367185029Spjd else 2368185029Spjd zfs_nicenum(val, propbuf, proplen); 2369185029Spjd break; 2370185029Spjd 2371185029Spjd case PROP_TYPE_STRING: 2372185029Spjd (void) strlcpy(propbuf, 2373185029Spjd getprop_string(zhp, prop, &source), proplen); 2374185029Spjd break; 2375185029Spjd 2376185029Spjd case PROP_TYPE_INDEX: 2377185029Spjd if (get_numeric_property(zhp, prop, src, 2378185029Spjd &source, &val) != 0) 2379185029Spjd return (-1); 2380185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2381185029Spjd return (-1); 2382185029Spjd (void) strlcpy(propbuf, strval, proplen); 2383185029Spjd break; 2384185029Spjd 2385185029Spjd default: 2386185029Spjd abort(); 2387185029Spjd } 2388168404Spjd } 2389168404Spjd 2390168404Spjd get_source(zhp, src, source, statbuf, statlen); 2391168404Spjd 2392168404Spjd return (0); 2393168404Spjd} 2394168404Spjd 2395168404Spjd/* 2396168404Spjd * Utility function to get the given numeric property. Does no validation that 2397168404Spjd * the given property is the appropriate type; should only be used with 2398168404Spjd * hard-coded property types. 2399168404Spjd */ 2400168404Spjduint64_t 2401168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2402168404Spjd{ 2403168404Spjd char *source; 2404168404Spjd uint64_t val; 2405168404Spjd 2406185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2407168404Spjd 2408168404Spjd return (val); 2409168404Spjd} 2410168404Spjd 2411185029Spjdint 2412185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2413185029Spjd{ 2414185029Spjd char buf[64]; 2415185029Spjd 2416209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2417185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2418185029Spjd} 2419185029Spjd 2420168404Spjd/* 2421168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2422168404Spjd */ 2423168404Spjdint 2424168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2425185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2426168404Spjd{ 2427168404Spjd char *source; 2428168404Spjd 2429168404Spjd /* 2430168404Spjd * Check to see if this property applies to our object 2431168404Spjd */ 2432185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2433168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2434168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2435168404Spjd zfs_prop_to_name(prop))); 2436185029Spjd } 2437168404Spjd 2438168404Spjd if (src) 2439185029Spjd *src = ZPROP_SRC_NONE; 2440168404Spjd 2441168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2442168404Spjd return (-1); 2443168404Spjd 2444168404Spjd get_source(zhp, src, source, statbuf, statlen); 2445168404Spjd 2446168404Spjd return (0); 2447168404Spjd} 2448168404Spjd 2449209962Smmstatic int 2450209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2451209962Smm char **domainp, idmap_rid_t *ridp) 2452209962Smm{ 2453209962Smm#ifdef sun 2454209962Smm idmap_get_handle_t *get_hdl = NULL; 2455209962Smm idmap_stat status; 2456209962Smm int err = EINVAL; 2457209962Smm 2458219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2459209962Smm goto out; 2460209962Smm 2461209962Smm if (isuser) { 2462209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2463209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2464209962Smm } else { 2465209962Smm err = idmap_get_sidbygid(get_hdl, id, 2466209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2467209962Smm } 2468209962Smm if (err == IDMAP_SUCCESS && 2469209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2470209962Smm status == IDMAP_SUCCESS) 2471209962Smm err = 0; 2472209962Smm else 2473209962Smm err = EINVAL; 2474209962Smmout: 2475209962Smm if (get_hdl) 2476209962Smm idmap_get_destroy(get_hdl); 2477209962Smm return (err); 2478209962Smm#else /* !sun */ 2479209962Smm assert(!"invalid code path"); 2480209962Smm#endif /* !sun */ 2481209962Smm} 2482209962Smm 2483168404Spjd/* 2484209962Smm * convert the propname into parameters needed by kernel 2485209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2486209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2487209962Smm */ 2488209962Smmstatic int 2489209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2490209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2491209962Smm{ 2492209962Smm zfs_userquota_prop_t type; 2493209962Smm char *cp, *end; 2494209962Smm char *numericsid = NULL; 2495209962Smm boolean_t isuser; 2496209962Smm 2497209962Smm domain[0] = '\0'; 2498209962Smm 2499209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2500209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2501209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2502209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2503209962Smm break; 2504209962Smm } 2505209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2506209962Smm return (EINVAL); 2507209962Smm *typep = type; 2508209962Smm 2509209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2510209962Smm type == ZFS_PROP_USERUSED); 2511209962Smm 2512209962Smm cp = strchr(propname, '@') + 1; 2513209962Smm 2514209962Smm if (strchr(cp, '@')) { 2515209962Smm#ifdef sun 2516209962Smm /* 2517209962Smm * It's a SID name (eg "user@domain") that needs to be 2518209962Smm * turned into S-1-domainID-RID. 2519209962Smm */ 2520209962Smm directory_error_t e; 2521209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2522209962Smm return (ENOENT); 2523209962Smm if (isuser) { 2524209962Smm e = directory_sid_from_user_name(NULL, 2525209962Smm cp, &numericsid); 2526209962Smm } else { 2527209962Smm e = directory_sid_from_group_name(NULL, 2528209962Smm cp, &numericsid); 2529209962Smm } 2530209962Smm if (e != NULL) { 2531209962Smm directory_error_free(e); 2532209962Smm return (ENOENT); 2533209962Smm } 2534209962Smm if (numericsid == NULL) 2535209962Smm return (ENOENT); 2536209962Smm cp = numericsid; 2537209962Smm /* will be further decoded below */ 2538209962Smm#else /* !sun */ 2539219089Spjd return (ENOENT); 2540209962Smm#endif /* !sun */ 2541209962Smm } 2542209962Smm 2543209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2544209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2545209962Smm (void) strlcpy(domain, cp, domainlen); 2546209962Smm cp = strrchr(domain, '-'); 2547209962Smm *cp = '\0'; 2548209962Smm cp++; 2549209962Smm 2550209962Smm errno = 0; 2551209962Smm *ridp = strtoull(cp, &end, 10); 2552209962Smm if (numericsid) { 2553209962Smm free(numericsid); 2554209962Smm numericsid = NULL; 2555209962Smm } 2556209962Smm if (errno != 0 || *end != '\0') 2557209962Smm return (EINVAL); 2558209962Smm } else if (!isdigit(*cp)) { 2559209962Smm /* 2560209962Smm * It's a user/group name (eg "user") that needs to be 2561209962Smm * turned into a uid/gid 2562209962Smm */ 2563209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2564209962Smm return (ENOENT); 2565209962Smm if (isuser) { 2566209962Smm struct passwd *pw; 2567209962Smm pw = getpwnam(cp); 2568209962Smm if (pw == NULL) 2569209962Smm return (ENOENT); 2570209962Smm *ridp = pw->pw_uid; 2571209962Smm } else { 2572209962Smm struct group *gr; 2573209962Smm gr = getgrnam(cp); 2574209962Smm if (gr == NULL) 2575209962Smm return (ENOENT); 2576209962Smm *ridp = gr->gr_gid; 2577209962Smm } 2578209962Smm } else { 2579209962Smm /* It's a user/group ID (eg "12345"). */ 2580209962Smm uid_t id = strtoul(cp, &end, 10); 2581209962Smm idmap_rid_t rid; 2582209962Smm char *mapdomain; 2583209962Smm 2584209962Smm if (*end != '\0') 2585209962Smm return (EINVAL); 2586209962Smm if (id > MAXUID) { 2587209962Smm /* It's an ephemeral ID. */ 2588209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2589209962Smm &mapdomain, &rid) != 0) 2590209962Smm return (ENOENT); 2591209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2592209962Smm *ridp = rid; 2593209962Smm } else { 2594209962Smm *ridp = id; 2595209962Smm } 2596209962Smm } 2597209962Smm 2598209962Smm ASSERT3P(numericsid, ==, NULL); 2599209962Smm return (0); 2600209962Smm} 2601209962Smm 2602209962Smmstatic int 2603209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2604209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2605209962Smm{ 2606209962Smm int err; 2607209962Smm zfs_cmd_t zc = { 0 }; 2608209962Smm 2609228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2610209962Smm 2611209962Smm err = userquota_propname_decode(propname, 2612209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2613209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2614209962Smm zc.zc_objset_type = *typep; 2615209962Smm if (err) 2616209962Smm return (err); 2617209962Smm 2618209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2619209962Smm if (err) 2620209962Smm return (err); 2621209962Smm 2622209962Smm *propvalue = zc.zc_cookie; 2623209962Smm return (0); 2624209962Smm} 2625209962Smm 2626209962Smmint 2627209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2628209962Smm uint64_t *propvalue) 2629209962Smm{ 2630209962Smm zfs_userquota_prop_t type; 2631209962Smm 2632209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2633209962Smm &type)); 2634209962Smm} 2635209962Smm 2636209962Smmint 2637209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2638209962Smm char *propbuf, int proplen, boolean_t literal) 2639209962Smm{ 2640209962Smm int err; 2641209962Smm uint64_t propvalue; 2642209962Smm zfs_userquota_prop_t type; 2643209962Smm 2644209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2645209962Smm &type); 2646209962Smm 2647209962Smm if (err) 2648209962Smm return (err); 2649209962Smm 2650209962Smm if (literal) { 2651209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2652209962Smm } else if (propvalue == 0 && 2653209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2654209962Smm (void) strlcpy(propbuf, "none", proplen); 2655209962Smm } else { 2656209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2657209962Smm } 2658209962Smm return (0); 2659209962Smm} 2660209962Smm 2661228103Smmint 2662228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 2663228103Smm uint64_t *propvalue) 2664168404Spjd{ 2665228103Smm int err; 2666228103Smm zfs_cmd_t zc = { 0 }; 2667228103Smm const char *snapname; 2668168404Spjd 2669228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2670168404Spjd 2671228103Smm snapname = strchr(propname, '@') + 1; 2672228103Smm if (strchr(snapname, '@')) { 2673228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2674228103Smm } else { 2675228103Smm /* snapname is the short name, append it to zhp's fsname */ 2676228103Smm char *cp; 2677209962Smm 2678228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 2679228103Smm sizeof (zc.zc_value)); 2680228103Smm cp = strchr(zc.zc_value, '@'); 2681228103Smm if (cp != NULL) 2682228103Smm *cp = '\0'; 2683228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 2684228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 2685228103Smm } 2686209962Smm 2687228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 2688228103Smm if (err) 2689228103Smm return (err); 2690228103Smm 2691228103Smm *propvalue = zc.zc_cookie; 2692228103Smm return (0); 2693209962Smm} 2694209962Smm 2695168404Spjdint 2696228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 2697228103Smm char *propbuf, int proplen, boolean_t literal) 2698168404Spjd{ 2699228103Smm int err; 2700228103Smm uint64_t propvalue; 2701168404Spjd 2702228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 2703185029Spjd 2704228103Smm if (err) 2705228103Smm return (err); 2706209962Smm 2707228103Smm if (literal) { 2708228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2709228103Smm } else { 2710228103Smm zfs_nicenum(propvalue, propbuf, proplen); 2711168404Spjd } 2712228103Smm return (0); 2713168404Spjd} 2714168404Spjd 2715168404Spjd/* 2716228103Smm * Returns the name of the given zfs handle. 2717168404Spjd */ 2718228103Smmconst char * 2719228103Smmzfs_get_name(const zfs_handle_t *zhp) 2720168404Spjd{ 2721228103Smm return (zhp->zfs_name); 2722228103Smm} 2723168404Spjd 2724228103Smm/* 2725228103Smm * Returns the type of the given zfs handle. 2726228103Smm */ 2727228103Smmzfs_type_t 2728228103Smmzfs_get_type(const zfs_handle_t *zhp) 2729228103Smm{ 2730228103Smm return (zhp->zfs_type); 2731168404Spjd} 2732168404Spjd 2733168404Spjd/* 2734219089Spjd * Is one dataset name a child dataset of another? 2735219089Spjd * 2736219089Spjd * Needs to handle these cases: 2737219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2738219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2739219089Spjd * Descendant? No. No. No. Yes. 2740219089Spjd */ 2741219089Spjdstatic boolean_t 2742219089Spjdis_descendant(const char *ds1, const char *ds2) 2743219089Spjd{ 2744219089Spjd size_t d1len = strlen(ds1); 2745219089Spjd 2746219089Spjd /* ds2 can't be a descendant if it's smaller */ 2747219089Spjd if (strlen(ds2) < d1len) 2748219089Spjd return (B_FALSE); 2749219089Spjd 2750219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2751219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2752219089Spjd} 2753219089Spjd 2754219089Spjd/* 2755168404Spjd * Given a complete name, return just the portion that refers to the parent. 2756228103Smm * Will return -1 if there is no parent (path is just the name of the 2757228103Smm * pool). 2758168404Spjd */ 2759168404Spjdstatic int 2760168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2761168404Spjd{ 2762228103Smm char *slashp; 2763168404Spjd 2764228103Smm (void) strlcpy(buf, path, buflen); 2765228103Smm 2766228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 2767168404Spjd return (-1); 2768228103Smm *slashp = '\0'; 2769168404Spjd 2770168404Spjd return (0); 2771168404Spjd} 2772168404Spjd 2773168404Spjd/* 2774185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2775185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2776185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2777185029Spjd * length of already existing prefix of the given path. We also fetch the 2778185029Spjd * 'zoned' property, which is used to validate property settings when creating 2779185029Spjd * new datasets. 2780168404Spjd */ 2781168404Spjdstatic int 2782185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2783185029Spjd boolean_t accept_ancestor, int *prefixlen) 2784168404Spjd{ 2785168404Spjd zfs_cmd_t zc = { 0 }; 2786168404Spjd char parent[ZFS_MAXNAMELEN]; 2787168404Spjd char *slash; 2788168404Spjd zfs_handle_t *zhp; 2789168404Spjd char errbuf[1024]; 2790219089Spjd uint64_t is_zoned; 2791168404Spjd 2792209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2793209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2794168404Spjd 2795168404Spjd /* get parent, and check to see if this is just a pool */ 2796168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2797168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2798168404Spjd "missing dataset name")); 2799168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2800168404Spjd } 2801168404Spjd 2802168404Spjd /* check to see if the pool exists */ 2803168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2804168404Spjd slash = parent + strlen(parent); 2805168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2806168404Spjd zc.zc_name[slash - parent] = '\0'; 2807168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2808168404Spjd errno == ENOENT) { 2809168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2810168404Spjd "no such pool '%s'"), zc.zc_name); 2811168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2812168404Spjd } 2813168404Spjd 2814168404Spjd /* check to see if the parent dataset exists */ 2815185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2816185029Spjd if (errno == ENOENT && accept_ancestor) { 2817185029Spjd /* 2818185029Spjd * Go deeper to find an ancestor, give up on top level. 2819185029Spjd */ 2820185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2821185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2822185029Spjd "no such pool '%s'"), zc.zc_name); 2823185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2824185029Spjd } 2825185029Spjd } else if (errno == ENOENT) { 2826168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2827168404Spjd "parent does not exist")); 2828168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2829185029Spjd } else 2830168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2831168404Spjd } 2832168404Spjd 2833219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2834219089Spjd if (zoned != NULL) 2835219089Spjd *zoned = is_zoned; 2836219089Spjd 2837168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2838219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 2839168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2840168404Spjd zfs_close(zhp); 2841168404Spjd return (-1); 2842168404Spjd } 2843168404Spjd 2844168404Spjd /* make sure parent is a filesystem */ 2845168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2846168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2847168404Spjd "parent is not a filesystem")); 2848168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2849168404Spjd zfs_close(zhp); 2850168404Spjd return (-1); 2851168404Spjd } 2852168404Spjd 2853168404Spjd zfs_close(zhp); 2854185029Spjd if (prefixlen != NULL) 2855185029Spjd *prefixlen = strlen(parent); 2856168404Spjd return (0); 2857168404Spjd} 2858168404Spjd 2859168404Spjd/* 2860185029Spjd * Finds whether the dataset of the given type(s) exists. 2861185029Spjd */ 2862185029Spjdboolean_t 2863185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2864185029Spjd{ 2865185029Spjd zfs_handle_t *zhp; 2866185029Spjd 2867185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2868185029Spjd return (B_FALSE); 2869185029Spjd 2870185029Spjd /* 2871185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2872185029Spjd */ 2873185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2874185029Spjd int ds_type = zhp->zfs_type; 2875185029Spjd 2876185029Spjd zfs_close(zhp); 2877185029Spjd if (types & ds_type) 2878185029Spjd return (B_TRUE); 2879185029Spjd } 2880185029Spjd return (B_FALSE); 2881185029Spjd} 2882185029Spjd 2883185029Spjd/* 2884185029Spjd * Given a path to 'target', create all the ancestors between 2885185029Spjd * the prefixlen portion of the path, and the target itself. 2886185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2887185029Spjd */ 2888185029Spjdint 2889185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2890185029Spjd{ 2891185029Spjd zfs_handle_t *h; 2892185029Spjd char *cp; 2893185029Spjd const char *opname; 2894185029Spjd 2895185029Spjd /* make sure prefix exists */ 2896185029Spjd cp = target + prefixlen; 2897185029Spjd if (*cp != '/') { 2898185029Spjd assert(strchr(cp, '/') == NULL); 2899185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2900185029Spjd } else { 2901185029Spjd *cp = '\0'; 2902185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2903185029Spjd *cp = '/'; 2904185029Spjd } 2905185029Spjd if (h == NULL) 2906185029Spjd return (-1); 2907185029Spjd zfs_close(h); 2908185029Spjd 2909185029Spjd /* 2910185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2911185029Spjd * up to the prefixlen-long one. 2912185029Spjd */ 2913185029Spjd for (cp = target + prefixlen + 1; 2914185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2915185029Spjd 2916185029Spjd *cp = '\0'; 2917185029Spjd 2918185029Spjd h = make_dataset_handle(hdl, target); 2919185029Spjd if (h) { 2920185029Spjd /* it already exists, nothing to do here */ 2921185029Spjd zfs_close(h); 2922185029Spjd continue; 2923185029Spjd } 2924185029Spjd 2925185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2926185029Spjd NULL) != 0) { 2927185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2928185029Spjd goto ancestorerr; 2929185029Spjd } 2930185029Spjd 2931185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2932185029Spjd if (h == NULL) { 2933185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2934185029Spjd goto ancestorerr; 2935185029Spjd } 2936185029Spjd 2937185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 2938185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2939185029Spjd goto ancestorerr; 2940185029Spjd } 2941185029Spjd 2942185029Spjd if (zfs_share(h) != 0) { 2943185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2944185029Spjd goto ancestorerr; 2945185029Spjd } 2946185029Spjd 2947185029Spjd zfs_close(h); 2948185029Spjd } 2949185029Spjd 2950185029Spjd return (0); 2951185029Spjd 2952185029Spjdancestorerr: 2953185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2954185029Spjd "failed to %s ancestor '%s'"), opname, target); 2955185029Spjd return (-1); 2956185029Spjd} 2957185029Spjd 2958185029Spjd/* 2959185029Spjd * Creates non-existing ancestors of the given path. 2960185029Spjd */ 2961185029Spjdint 2962185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2963185029Spjd{ 2964185029Spjd int prefix; 2965185029Spjd char *path_copy; 2966185029Spjd int rc; 2967185029Spjd 2968219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 2969185029Spjd return (-1); 2970185029Spjd 2971185029Spjd if ((path_copy = strdup(path)) != NULL) { 2972185029Spjd rc = create_parents(hdl, path_copy, prefix); 2973185029Spjd free(path_copy); 2974185029Spjd } 2975185029Spjd if (path_copy == NULL || rc != 0) 2976185029Spjd return (-1); 2977185029Spjd 2978185029Spjd return (0); 2979185029Spjd} 2980185029Spjd 2981185029Spjd/* 2982168404Spjd * Create a new filesystem or volume. 2983168404Spjd */ 2984168404Spjdint 2985168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2986168404Spjd nvlist_t *props) 2987168404Spjd{ 2988168404Spjd int ret; 2989168404Spjd uint64_t size = 0; 2990168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2991168404Spjd char errbuf[1024]; 2992168404Spjd uint64_t zoned; 2993248571Smm dmu_objset_type_t ost; 2994168404Spjd 2995168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2996168404Spjd "cannot create '%s'"), path); 2997168404Spjd 2998168404Spjd /* validate the path, taking care to note the extended error message */ 2999185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3000168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3001168404Spjd 3002168404Spjd /* validate parents exist */ 3003185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3004168404Spjd return (-1); 3005168404Spjd 3006168404Spjd /* 3007168404Spjd * The failure modes when creating a dataset of a different type over 3008168404Spjd * one that already exists is a little strange. In particular, if you 3009168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3010168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3011168404Spjd * first try to see if the dataset exists. 3012168404Spjd */ 3013248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3014168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3015168404Spjd "dataset already exists")); 3016168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3017168404Spjd } 3018168404Spjd 3019168404Spjd if (type == ZFS_TYPE_VOLUME) 3020248571Smm ost = DMU_OST_ZVOL; 3021168404Spjd else 3022248571Smm ost = DMU_OST_ZFS; 3023168404Spjd 3024185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3025168404Spjd zoned, NULL, errbuf)) == 0) 3026168404Spjd return (-1); 3027168404Spjd 3028168404Spjd if (type == ZFS_TYPE_VOLUME) { 3029168404Spjd /* 3030168404Spjd * If we are creating a volume, the size and block size must 3031168404Spjd * satisfy a few restraints. First, the blocksize must be a 3032168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3033168404Spjd * volsize must be a multiple of the block size, and cannot be 3034168404Spjd * zero. 3035168404Spjd */ 3036168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3037168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3038168404Spjd nvlist_free(props); 3039168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3040168404Spjd "missing volume size")); 3041168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3042168404Spjd } 3043168404Spjd 3044168404Spjd if ((ret = nvlist_lookup_uint64(props, 3045168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3046168404Spjd &blocksize)) != 0) { 3047168404Spjd if (ret == ENOENT) { 3048168404Spjd blocksize = zfs_prop_default_numeric( 3049168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3050168404Spjd } else { 3051168404Spjd nvlist_free(props); 3052168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3053168404Spjd "missing volume block size")); 3054168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3055168404Spjd } 3056168404Spjd } 3057168404Spjd 3058168404Spjd if (size == 0) { 3059168404Spjd nvlist_free(props); 3060168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3061168404Spjd "volume size cannot be zero")); 3062168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3063168404Spjd } 3064168404Spjd 3065168404Spjd if (size % blocksize != 0) { 3066168404Spjd nvlist_free(props); 3067168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3068168404Spjd "volume size must be a multiple of volume block " 3069168404Spjd "size")); 3070168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3071168404Spjd } 3072168404Spjd } 3073168404Spjd 3074248571Smm /* create the dataset */ 3075248571Smm ret = lzc_create(path, ost, props); 3076168404Spjd nvlist_free(props); 3077168404Spjd 3078168404Spjd /* check for failure */ 3079168404Spjd if (ret != 0) { 3080168404Spjd char parent[ZFS_MAXNAMELEN]; 3081168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3082168404Spjd 3083168404Spjd switch (errno) { 3084168404Spjd case ENOENT: 3085168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3086168404Spjd "no such parent '%s'"), parent); 3087168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3088168404Spjd 3089168404Spjd case EINVAL: 3090168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3091168404Spjd "parent '%s' is not a filesystem"), parent); 3092168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3093168404Spjd 3094168404Spjd case EDOM: 3095168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3096168404Spjd "volume block size must be power of 2 from " 3097168404Spjd "%u to %uk"), 3098168404Spjd (uint_t)SPA_MINBLOCKSIZE, 3099168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 3100168404Spjd 3101168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3102168404Spjd 3103185029Spjd case ENOTSUP: 3104185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3105185029Spjd "pool must be upgraded to set this " 3106185029Spjd "property or value")); 3107185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3108168404Spjd#ifdef _ILP32 3109168404Spjd case EOVERFLOW: 3110168404Spjd /* 3111168404Spjd * This platform can't address a volume this big. 3112168404Spjd */ 3113168404Spjd if (type == ZFS_TYPE_VOLUME) 3114168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3115168404Spjd errbuf)); 3116168404Spjd#endif 3117168404Spjd /* FALLTHROUGH */ 3118168404Spjd default: 3119168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3120168404Spjd } 3121168404Spjd } 3122168404Spjd 3123168404Spjd return (0); 3124168404Spjd} 3125168404Spjd 3126168404Spjd/* 3127168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3128238422Smm * isn't mounted, and that there are no active dependents. If the file system 3129238422Smm * does not exist this function does nothing. 3130168404Spjd */ 3131168404Spjdint 3132219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3133168404Spjd{ 3134168404Spjd zfs_cmd_t zc = { 0 }; 3135168404Spjd 3136168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3137168404Spjd 3138168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3139168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3140168404Spjd } else { 3141168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3142168404Spjd } 3143168404Spjd 3144219089Spjd zc.zc_defer_destroy = defer; 3145238422Smm if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && 3146238422Smm errno != ENOENT) { 3147168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3148168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3149168404Spjd zhp->zfs_name)); 3150168404Spjd } 3151168404Spjd 3152168404Spjd remove_mountpoint(zhp); 3153168404Spjd 3154168404Spjd return (0); 3155168404Spjd} 3156168404Spjd 3157168404Spjdstruct destroydata { 3158228103Smm nvlist_t *nvl; 3159228103Smm const char *snapname; 3160168404Spjd}; 3161168404Spjd 3162168404Spjdstatic int 3163219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3164168404Spjd{ 3165168404Spjd struct destroydata *dd = arg; 3166168404Spjd char name[ZFS_MAXNAMELEN]; 3167219089Spjd int rv = 0; 3168168404Spjd 3169228103Smm (void) snprintf(name, sizeof (name), 3170228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3171168404Spjd 3172251646Sdelphij if (lzc_exists(name)) 3173228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3174168404Spjd 3175228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3176228103Smm zfs_close(zhp); 3177168404Spjd return (rv); 3178168404Spjd} 3179168404Spjd 3180168404Spjd/* 3181168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3182168404Spjd */ 3183168404Spjdint 3184219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3185168404Spjd{ 3186168404Spjd int ret; 3187168404Spjd struct destroydata dd = { 0 }; 3188168404Spjd 3189168404Spjd dd.snapname = snapname; 3190228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3191228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3192168404Spjd 3193251646Sdelphij if (nvlist_empty(dd.nvl)) { 3194228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3195168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3196228103Smm zhp->zfs_name, snapname); 3197228103Smm } else { 3198248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3199168404Spjd } 3200228103Smm nvlist_free(dd.nvl); 3201228103Smm return (ret); 3202228103Smm} 3203168404Spjd 3204228103Smm/* 3205248571Smm * Destroys all the snapshots named in the nvlist. 3206228103Smm */ 3207228103Smmint 3208248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3209228103Smm{ 3210228103Smm int ret; 3211248571Smm nvlist_t *errlist; 3212228103Smm 3213248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3214168404Spjd 3215248571Smm if (ret == 0) 3216248571Smm return (0); 3217248571Smm 3218251646Sdelphij if (nvlist_empty(errlist)) { 3219168404Spjd char errbuf[1024]; 3220248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3221248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3222168404Spjd 3223248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3224248571Smm } 3225248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3226248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3227248571Smm char errbuf[1024]; 3228248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3229248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3230248571Smm nvpair_name(pair)); 3231168404Spjd 3232248571Smm switch (fnvpair_value_int32(pair)) { 3233168404Spjd case EEXIST: 3234248571Smm zfs_error_aux(hdl, 3235248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3236248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3237248571Smm break; 3238168404Spjd default: 3239248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3240248571Smm break; 3241168404Spjd } 3242168404Spjd } 3243168404Spjd 3244248571Smm return (ret); 3245168404Spjd} 3246168404Spjd 3247168404Spjd/* 3248168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3249168404Spjd */ 3250168404Spjdint 3251168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3252168404Spjd{ 3253168404Spjd char parent[ZFS_MAXNAMELEN]; 3254168404Spjd int ret; 3255168404Spjd char errbuf[1024]; 3256168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3257168404Spjd uint64_t zoned; 3258168404Spjd 3259168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3260168404Spjd 3261168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3262168404Spjd "cannot create '%s'"), target); 3263168404Spjd 3264228103Smm /* validate the target/clone name */ 3265185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3266168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3267168404Spjd 3268168404Spjd /* validate parents exist */ 3269185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3270168404Spjd return (-1); 3271168404Spjd 3272168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3273168404Spjd 3274168404Spjd /* do the clone */ 3275168404Spjd 3276168404Spjd if (props) { 3277248571Smm zfs_type_t type; 3278248571Smm if (ZFS_IS_VOLUME(zhp)) { 3279248571Smm type = ZFS_TYPE_VOLUME; 3280248571Smm } else { 3281248571Smm type = ZFS_TYPE_FILESYSTEM; 3282248571Smm } 3283185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3284185029Spjd zhp, errbuf)) == NULL) 3285168404Spjd return (-1); 3286168404Spjd } 3287168404Spjd 3288248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3289248571Smm nvlist_free(props); 3290168404Spjd 3291168404Spjd if (ret != 0) { 3292168404Spjd switch (errno) { 3293168404Spjd 3294168404Spjd case ENOENT: 3295168404Spjd /* 3296168404Spjd * The parent doesn't exist. We should have caught this 3297168404Spjd * above, but there may a race condition that has since 3298168404Spjd * destroyed the parent. 3299168404Spjd * 3300168404Spjd * At this point, we don't know whether it's the source 3301168404Spjd * that doesn't exist anymore, or whether the target 3302168404Spjd * dataset doesn't exist. 3303168404Spjd */ 3304168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3305168404Spjd "no such parent '%s'"), parent); 3306168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3307168404Spjd 3308168404Spjd case EXDEV: 3309168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3310168404Spjd "source and target pools differ")); 3311168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3312168404Spjd errbuf)); 3313168404Spjd 3314168404Spjd default: 3315168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3316168404Spjd errbuf)); 3317168404Spjd } 3318168404Spjd } 3319168404Spjd 3320168404Spjd return (ret); 3321168404Spjd} 3322168404Spjd 3323168404Spjd/* 3324168404Spjd * Promotes the given clone fs to be the clone parent. 3325168404Spjd */ 3326168404Spjdint 3327168404Spjdzfs_promote(zfs_handle_t *zhp) 3328168404Spjd{ 3329168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3330168404Spjd zfs_cmd_t zc = { 0 }; 3331168404Spjd char parent[MAXPATHLEN]; 3332168404Spjd int ret; 3333168404Spjd char errbuf[1024]; 3334168404Spjd 3335168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3336168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3337168404Spjd 3338168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3339168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3340168404Spjd "snapshots can not be promoted")); 3341168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3342168404Spjd } 3343168404Spjd 3344185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3345168404Spjd if (parent[0] == '\0') { 3346168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3347168404Spjd "not a cloned filesystem")); 3348168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3349168404Spjd } 3350168404Spjd 3351185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3352168404Spjd sizeof (zc.zc_value)); 3353168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3354185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3355168404Spjd 3356168404Spjd if (ret != 0) { 3357168404Spjd int save_errno = errno; 3358168404Spjd 3359168404Spjd switch (save_errno) { 3360168404Spjd case EEXIST: 3361219089Spjd /* There is a conflicting snapshot name. */ 3362168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3363219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3364219089Spjd zc.zc_string, parent); 3365168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3366168404Spjd 3367168404Spjd default: 3368168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3369168404Spjd } 3370168404Spjd } 3371168404Spjd return (ret); 3372168404Spjd} 3373168404Spjd 3374248571Smmtypedef struct snapdata { 3375248571Smm nvlist_t *sd_nvl; 3376248571Smm const char *sd_snapname; 3377248571Smm} snapdata_t; 3378248571Smm 3379248571Smmstatic int 3380248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3381248571Smm{ 3382248571Smm snapdata_t *sd = arg; 3383248571Smm char name[ZFS_MAXNAMELEN]; 3384248571Smm int rv = 0; 3385248571Smm 3386253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3387253819Sdelphij (void) snprintf(name, sizeof (name), 3388253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3389248571Smm 3390253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3391248571Smm 3392253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3393253819Sdelphij } 3394248571Smm zfs_close(zhp); 3395253819Sdelphij 3396248571Smm return (rv); 3397248571Smm} 3398248571Smm 3399168404Spjd/* 3400248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3401248571Smm * created. 3402168404Spjd */ 3403168404Spjdint 3404248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3405168404Spjd{ 3406168404Spjd int ret; 3407168404Spjd char errbuf[1024]; 3408248571Smm nvpair_t *elem; 3409248571Smm nvlist_t *errors; 3410168404Spjd 3411168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3412248571Smm "cannot create snapshots ")); 3413168404Spjd 3414248571Smm elem = NULL; 3415248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3416248571Smm const char *snapname = nvpair_name(elem); 3417168404Spjd 3418248571Smm /* validate the target name */ 3419248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3420248571Smm B_TRUE)) { 3421248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3422248571Smm dgettext(TEXT_DOMAIN, 3423248571Smm "cannot create snapshot '%s'"), snapname); 3424248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3425248571Smm } 3426248571Smm } 3427185029Spjd 3428248571Smm if (props != NULL && 3429248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3430248571Smm props, B_FALSE, NULL, errbuf)) == NULL) { 3431248571Smm return (-1); 3432248571Smm } 3433248571Smm 3434248571Smm ret = lzc_snapshot(snaps, props, &errors); 3435248571Smm 3436248571Smm if (ret != 0) { 3437248571Smm boolean_t printed = B_FALSE; 3438248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 3439248571Smm elem != NULL; 3440248571Smm elem = nvlist_next_nvpair(errors, elem)) { 3441248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3442248571Smm dgettext(TEXT_DOMAIN, 3443248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 3444248571Smm (void) zfs_standard_error(hdl, 3445248571Smm fnvpair_value_int32(elem), errbuf); 3446248571Smm printed = B_TRUE; 3447185029Spjd } 3448248571Smm if (!printed) { 3449248571Smm switch (ret) { 3450248571Smm case EXDEV: 3451248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3452248571Smm "multiple snapshots of same " 3453248571Smm "fs not allowed")); 3454248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3455185029Spjd 3456248571Smm break; 3457248571Smm default: 3458248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 3459248571Smm } 3460248571Smm } 3461185029Spjd } 3462185029Spjd 3463248571Smm nvlist_free(props); 3464248571Smm nvlist_free(errors); 3465248571Smm return (ret); 3466248571Smm} 3467168404Spjd 3468248571Smmint 3469248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3470248571Smm nvlist_t *props) 3471248571Smm{ 3472248571Smm int ret; 3473248571Smm snapdata_t sd = { 0 }; 3474248571Smm char fsname[ZFS_MAXNAMELEN]; 3475248571Smm char *cp; 3476248571Smm zfs_handle_t *zhp; 3477248571Smm char errbuf[1024]; 3478248571Smm 3479248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3480248571Smm "cannot snapshot %s"), path); 3481248571Smm 3482248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3483248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3484248571Smm 3485248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 3486248571Smm cp = strchr(fsname, '@'); 3487248571Smm *cp = '\0'; 3488248571Smm sd.sd_snapname = cp + 1; 3489248571Smm 3490248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 3491168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3492168404Spjd return (-1); 3493168404Spjd } 3494168404Spjd 3495248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 3496248571Smm if (recursive) { 3497248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 3498248571Smm } else { 3499248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 3500168404Spjd } 3501168404Spjd 3502248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 3503248571Smm nvlist_free(sd.sd_nvl); 3504168404Spjd zfs_close(zhp); 3505168404Spjd return (ret); 3506168404Spjd} 3507168404Spjd 3508168404Spjd/* 3509168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3510168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3511168404Spjd * is a dependent and we should just destroy it without checking the transaction 3512168404Spjd * group. 3513168404Spjd */ 3514168404Spjdtypedef struct rollback_data { 3515168404Spjd const char *cb_target; /* the snapshot */ 3516168404Spjd uint64_t cb_create; /* creation time reference */ 3517185029Spjd boolean_t cb_error; 3518168404Spjd boolean_t cb_dependent; 3519185029Spjd boolean_t cb_force; 3520168404Spjd} rollback_data_t; 3521168404Spjd 3522168404Spjdstatic int 3523168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3524168404Spjd{ 3525168404Spjd rollback_data_t *cbp = data; 3526168404Spjd 3527168404Spjd if (!cbp->cb_dependent) { 3528168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3529168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3530168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3531168404Spjd cbp->cb_create) { 3532168404Spjd 3533168404Spjd cbp->cb_dependent = B_TRUE; 3534185029Spjd cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3535185029Spjd rollback_destroy, cbp); 3536168404Spjd cbp->cb_dependent = B_FALSE; 3537168404Spjd 3538219089Spjd cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3539168404Spjd } 3540168404Spjd } else { 3541185029Spjd /* We must destroy this clone; first unmount it */ 3542185029Spjd prop_changelist_t *clp; 3543185029Spjd 3544185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3545185029Spjd cbp->cb_force ? MS_FORCE: 0); 3546185029Spjd if (clp == NULL || changelist_prefix(clp) != 0) { 3547185029Spjd cbp->cb_error = B_TRUE; 3548185029Spjd zfs_close(zhp); 3549185029Spjd return (0); 3550185029Spjd } 3551219089Spjd if (zfs_destroy(zhp, B_FALSE) != 0) 3552185029Spjd cbp->cb_error = B_TRUE; 3553168404Spjd else 3554185029Spjd changelist_remove(clp, zhp->zfs_name); 3555185029Spjd (void) changelist_postfix(clp); 3556185029Spjd changelist_free(clp); 3557168404Spjd } 3558168404Spjd 3559168404Spjd zfs_close(zhp); 3560168404Spjd return (0); 3561168404Spjd} 3562168404Spjd 3563168404Spjd/* 3564168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3565168404Spjd * data changes since then and making it the active dataset. 3566168404Spjd * 3567168404Spjd * Any snapshots more recent than the target are destroyed, along with 3568168404Spjd * their dependents. 3569168404Spjd */ 3570168404Spjdint 3571185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3572168404Spjd{ 3573168404Spjd rollback_data_t cb = { 0 }; 3574185029Spjd int err; 3575185029Spjd zfs_cmd_t zc = { 0 }; 3576185029Spjd boolean_t restore_resv = 0; 3577185029Spjd uint64_t old_volsize, new_volsize; 3578185029Spjd zfs_prop_t resv_prop; 3579168404Spjd 3580185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3581185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3582168404Spjd 3583168404Spjd /* 3584239774Smm * Destroy all recent snapshots and their dependents. 3585168404Spjd */ 3586185029Spjd cb.cb_force = force; 3587168404Spjd cb.cb_target = snap->zfs_name; 3588168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3589168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3590168404Spjd 3591185029Spjd if (cb.cb_error) 3592185029Spjd return (-1); 3593168404Spjd 3594168404Spjd /* 3595168404Spjd * Now that we have verified that the snapshot is the latest, 3596168404Spjd * rollback to the given snapshot. 3597168404Spjd */ 3598168404Spjd 3599185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3600185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3601185029Spjd return (-1); 3602185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3603185029Spjd restore_resv = 3604185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3605168404Spjd } 3606168404Spjd 3607185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3608185029Spjd 3609185029Spjd if (ZFS_IS_VOLUME(zhp)) 3610185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3611185029Spjd else 3612185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3613185029Spjd 3614168404Spjd /* 3615185029Spjd * We rely on zfs_iter_children() to verify that there are no 3616185029Spjd * newer snapshots for the given dataset. Therefore, we can 3617185029Spjd * simply pass the name on to the ioctl() call. There is still 3618185029Spjd * an unlikely race condition where the user has taken a 3619185029Spjd * snapshot since we verified that this was the most recent. 3620185029Spjd * 3621168404Spjd */ 3622185029Spjd if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3623185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3624185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3625185029Spjd zhp->zfs_name); 3626185029Spjd return (err); 3627185029Spjd } 3628168404Spjd 3629185029Spjd /* 3630185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3631185029Spjd * rollback reservation and the volsize has changed then set 3632185029Spjd * the reservation property to the post-rollback volsize. 3633185029Spjd * Make a new handle since the rollback closed the dataset. 3634185029Spjd */ 3635185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3636185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3637185029Spjd if (restore_resv) { 3638185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3639185029Spjd if (old_volsize != new_volsize) 3640185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3641185029Spjd new_volsize); 3642185029Spjd } 3643185029Spjd zfs_close(zhp); 3644185029Spjd } 3645185029Spjd return (err); 3646168404Spjd} 3647168404Spjd 3648168404Spjd/* 3649168404Spjd * Renames the given dataset. 3650168404Spjd */ 3651168404Spjdint 3652240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 3653240870Spjd renameflags_t flags) 3654168404Spjd{ 3655168404Spjd int ret; 3656168404Spjd zfs_cmd_t zc = { 0 }; 3657168404Spjd char *delim; 3658168676Spjd prop_changelist_t *cl = NULL; 3659168676Spjd zfs_handle_t *zhrp = NULL; 3660168676Spjd char *parentname = NULL; 3661168404Spjd char parent[ZFS_MAXNAMELEN]; 3662226676Spjd char property[ZFS_MAXPROPLEN]; 3663168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3664168404Spjd char errbuf[1024]; 3665168404Spjd 3666168404Spjd /* if we have the same exact name, just return success */ 3667168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3668168404Spjd return (0); 3669168404Spjd 3670168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3671168404Spjd "cannot rename to '%s'"), target); 3672168404Spjd 3673240870Spjd if (source != NULL) { 3674240870Spjd /* 3675240870Spjd * This is recursive snapshots rename, put snapshot name 3676240870Spjd * (that might not exist) into zfs_name. 3677240870Spjd */ 3678240870Spjd assert(flags.recurse); 3679240870Spjd 3680240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 3681240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 3682240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 3683240870Spjd } 3684240870Spjd 3685168404Spjd /* 3686168404Spjd * Make sure the target name is valid 3687168404Spjd */ 3688168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3689168404Spjd if ((strchr(target, '@') == NULL) || 3690168404Spjd *target == '@') { 3691168404Spjd /* 3692168404Spjd * Snapshot target name is abbreviated, 3693168404Spjd * reconstruct full dataset name 3694168404Spjd */ 3695168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3696168404Spjd sizeof (parent)); 3697168404Spjd delim = strchr(parent, '@'); 3698168404Spjd if (strchr(target, '@') == NULL) 3699168404Spjd *(++delim) = '\0'; 3700168404Spjd else 3701168404Spjd *delim = '\0'; 3702168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3703168404Spjd target = parent; 3704168404Spjd } else { 3705168404Spjd /* 3706168404Spjd * Make sure we're renaming within the same dataset. 3707168404Spjd */ 3708168404Spjd delim = strchr(target, '@'); 3709168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3710168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3711168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3712168404Spjd "snapshots must be part of same " 3713168404Spjd "dataset")); 3714168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3715168404Spjd errbuf)); 3716168404Spjd } 3717168404Spjd } 3718185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3719168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3720168404Spjd } else { 3721226705Spjd if (flags.recurse) { 3722168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3723168676Spjd "recursive rename must be a snapshot")); 3724168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3725168676Spjd } 3726168676Spjd 3727185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3728168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3729168404Spjd 3730168404Spjd /* validate parents */ 3731219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3732168404Spjd return (-1); 3733168404Spjd 3734168404Spjd /* make sure we're in the same pool */ 3735168404Spjd verify((delim = strchr(target, '/')) != NULL); 3736168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3737168404Spjd zhp->zfs_name[delim - target] != '/') { 3738168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3739168404Spjd "datasets must be within same pool")); 3740168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3741168404Spjd } 3742168404Spjd 3743168404Spjd /* new name cannot be a child of the current dataset name */ 3744219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3745168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3746219089Spjd "New dataset name cannot be a descendant of " 3747168404Spjd "current dataset name")); 3748168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3749168404Spjd } 3750168404Spjd } 3751168404Spjd 3752168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3753168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3754168404Spjd 3755168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3756168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3757168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3758168404Spjd "dataset is used in a non-global zone")); 3759168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3760168404Spjd } 3761168404Spjd 3762226705Spjd /* 3763226705Spjd * Avoid unmounting file systems with mountpoint property set to 3764226705Spjd * 'legacy' or 'none' even if -u option is not given. 3765226705Spjd */ 3766226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 3767226705Spjd !flags.recurse && !flags.nounmount && 3768226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 3769226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 3770226705Spjd (strcmp(property, "legacy") == 0 || 3771226705Spjd strcmp(property, "none") == 0)) { 3772226705Spjd flags.nounmount = B_TRUE; 3773226705Spjd } 3774168404Spjd 3775226705Spjd if (flags.recurse) { 3776226705Spjd 3777185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3778185029Spjd if (parentname == NULL) { 3779185029Spjd ret = -1; 3780185029Spjd goto error; 3781185029Spjd } 3782168676Spjd delim = strchr(parentname, '@'); 3783168676Spjd *delim = '\0'; 3784185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3785168676Spjd if (zhrp == NULL) { 3786185029Spjd ret = -1; 3787185029Spjd goto error; 3788168676Spjd } 3789168676Spjd 3790168676Spjd } else { 3791226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 3792235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 3793235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 3794168676Spjd return (-1); 3795226676Spjd } 3796168676Spjd 3797168676Spjd if (changelist_haszonedchild(cl)) { 3798168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3799168676Spjd "child dataset with inherited mountpoint is used " 3800168676Spjd "in a non-global zone")); 3801168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3802168676Spjd goto error; 3803168676Spjd } 3804168676Spjd 3805168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3806168676Spjd goto error; 3807168404Spjd } 3808168404Spjd 3809168404Spjd if (ZFS_IS_VOLUME(zhp)) 3810168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3811168404Spjd else 3812168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3813168404Spjd 3814168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3815168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3816168404Spjd 3817226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 3818226705Spjd if (flags.nounmount) 3819226676Spjd zc.zc_cookie |= 2; 3820168676Spjd 3821185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3822168676Spjd /* 3823168676Spjd * if it was recursive, the one that actually failed will 3824168676Spjd * be in zc.zc_name 3825168676Spjd */ 3826168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3827185029Spjd "cannot rename '%s'"), zc.zc_name); 3828168404Spjd 3829226705Spjd if (flags.recurse && errno == EEXIST) { 3830168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3831168676Spjd "a child dataset already has a snapshot " 3832168676Spjd "with the new name")); 3833185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3834168676Spjd } else { 3835168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3836168676Spjd } 3837168676Spjd 3838168404Spjd /* 3839168404Spjd * On failure, we still want to remount any filesystems that 3840168404Spjd * were previously mounted, so we don't alter the system state. 3841168404Spjd */ 3842226705Spjd if (!flags.recurse) 3843168676Spjd (void) changelist_postfix(cl); 3844168404Spjd } else { 3845226705Spjd if (!flags.recurse) { 3846168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3847168676Spjd ret = changelist_postfix(cl); 3848168676Spjd } 3849168404Spjd } 3850168404Spjd 3851168404Spjderror: 3852168676Spjd if (parentname) { 3853168676Spjd free(parentname); 3854168676Spjd } 3855168676Spjd if (zhrp) { 3856168676Spjd zfs_close(zhrp); 3857168676Spjd } 3858168676Spjd if (cl) { 3859168676Spjd changelist_free(cl); 3860168676Spjd } 3861168404Spjd return (ret); 3862168404Spjd} 3863168404Spjd 3864219089Spjdnvlist_t * 3865219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 3866168404Spjd{ 3867219089Spjd return (zhp->zfs_user_props); 3868168676Spjd} 3869168676Spjd 3870168404Spjdnvlist_t * 3871219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 3872168404Spjd{ 3873219089Spjd if (zhp->zfs_recvd_props == NULL) 3874219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 3875219089Spjd return (NULL); 3876219089Spjd return (zhp->zfs_recvd_props); 3877168404Spjd} 3878168404Spjd 3879168404Spjd/* 3880168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3881168404Spjd * display, and their maximum widths. This does two main things: 3882168404Spjd * 3883168404Spjd * - If this is a list of all properties, then expand the list to include 3884168404Spjd * all native properties, and set a flag so that for each dataset we look 3885168404Spjd * for new unique user properties and add them to the list. 3886168404Spjd * 3887168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3888219089Spjd * so that we can size the column appropriately. If the user has 3889219089Spjd * requested received property values, we also need to compute the width 3890219089Spjd * of the RECEIVED column. 3891168404Spjd */ 3892168404Spjdint 3893219089Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) 3894168404Spjd{ 3895168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3896185029Spjd zprop_list_t *entry; 3897185029Spjd zprop_list_t **last, **start; 3898168404Spjd nvlist_t *userprops, *propval; 3899168404Spjd nvpair_t *elem; 3900168404Spjd char *strval; 3901168404Spjd char buf[ZFS_MAXPROPLEN]; 3902168404Spjd 3903185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3904168404Spjd return (-1); 3905168404Spjd 3906168404Spjd userprops = zfs_get_user_props(zhp); 3907168404Spjd 3908168404Spjd entry = *plp; 3909168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3910168404Spjd /* 3911168404Spjd * Go through and add any user properties as necessary. We 3912168404Spjd * start by incrementing our list pointer to the first 3913168404Spjd * non-native property. 3914168404Spjd */ 3915168404Spjd start = plp; 3916168404Spjd while (*start != NULL) { 3917185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3918168404Spjd break; 3919168404Spjd start = &(*start)->pl_next; 3920168404Spjd } 3921168404Spjd 3922168404Spjd elem = NULL; 3923168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3924168404Spjd /* 3925168404Spjd * See if we've already found this property in our list. 3926168404Spjd */ 3927168404Spjd for (last = start; *last != NULL; 3928168404Spjd last = &(*last)->pl_next) { 3929168404Spjd if (strcmp((*last)->pl_user_prop, 3930168404Spjd nvpair_name(elem)) == 0) 3931168404Spjd break; 3932168404Spjd } 3933168404Spjd 3934168404Spjd if (*last == NULL) { 3935168404Spjd if ((entry = zfs_alloc(hdl, 3936185029Spjd sizeof (zprop_list_t))) == NULL || 3937168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3938168404Spjd nvpair_name(elem)))) == NULL) { 3939168404Spjd free(entry); 3940168404Spjd return (-1); 3941168404Spjd } 3942168404Spjd 3943185029Spjd entry->pl_prop = ZPROP_INVAL; 3944168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3945168404Spjd entry->pl_all = B_TRUE; 3946168404Spjd *last = entry; 3947168404Spjd } 3948168404Spjd } 3949168404Spjd } 3950168404Spjd 3951168404Spjd /* 3952168404Spjd * Now go through and check the width of any non-fixed columns 3953168404Spjd */ 3954168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3955168404Spjd if (entry->pl_fixed) 3956168404Spjd continue; 3957168404Spjd 3958185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 3959168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3960168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3961168404Spjd if (strlen(buf) > entry->pl_width) 3962168404Spjd entry->pl_width = strlen(buf); 3963168404Spjd } 3964219089Spjd if (received && zfs_prop_get_recvd(zhp, 3965219089Spjd zfs_prop_to_name(entry->pl_prop), 3966219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3967219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3968219089Spjd entry->pl_recvd_width = strlen(buf); 3969219089Spjd } else { 3970219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 3971219089Spjd &propval) == 0) { 3972219089Spjd verify(nvlist_lookup_string(propval, 3973219089Spjd ZPROP_VALUE, &strval) == 0); 3974219089Spjd if (strlen(strval) > entry->pl_width) 3975219089Spjd entry->pl_width = strlen(strval); 3976219089Spjd } 3977219089Spjd if (received && zfs_prop_get_recvd(zhp, 3978219089Spjd entry->pl_user_prop, 3979219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3980219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3981219089Spjd entry->pl_recvd_width = strlen(buf); 3982168404Spjd } 3983168404Spjd } 3984168404Spjd 3985168404Spjd return (0); 3986168404Spjd} 3987168404Spjd 3988185029Spjdint 3989185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 3990209962Smm char *resource, void *export, void *sharetab, 3991209962Smm int sharemax, zfs_share_op_t operation) 3992185029Spjd{ 3993185029Spjd zfs_cmd_t zc = { 0 }; 3994185029Spjd int error; 3995185029Spjd 3996185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3997185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3998209962Smm if (resource) 3999209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4000185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4001185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4002185029Spjd zc.zc_share.z_sharetype = operation; 4003185029Spjd zc.zc_share.z_sharemax = sharemax; 4004185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4005185029Spjd return (error); 4006185029Spjd} 4007185029Spjd 4008205198Sdelphijvoid 4009205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4010205198Sdelphij{ 4011205198Sdelphij nvpair_t *curr; 4012205198Sdelphij 4013205198Sdelphij /* 4014205198Sdelphij * Keep a reference to the props-table against which we prune the 4015205198Sdelphij * properties. 4016205198Sdelphij */ 4017205198Sdelphij zhp->zfs_props_table = props; 4018205198Sdelphij 4019205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4020205198Sdelphij 4021205198Sdelphij while (curr) { 4022205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4023205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4024205198Sdelphij 4025206199Sdelphij /* 4026219089Spjd * User properties will result in ZPROP_INVAL, and since we 4027219089Spjd * only know how to prune standard ZFS properties, we always 4028219089Spjd * leave these in the list. This can also happen if we 4029219089Spjd * encounter an unknown DSL property (when running older 4030219089Spjd * software, for example). 4031206199Sdelphij */ 4032206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4033205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4034205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4035205198Sdelphij curr = next; 4036205198Sdelphij } 4037205198Sdelphij} 4038205198Sdelphij 4039209962Smm#ifdef sun 4040209962Smmstatic int 4041209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4042209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4043209962Smm{ 4044209962Smm zfs_cmd_t zc = { 0 }; 4045209962Smm nvlist_t *nvlist = NULL; 4046209962Smm int error; 4047209962Smm 4048209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4049209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4050209962Smm zc.zc_cookie = (uint64_t)cmd; 4051209962Smm 4052209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4053209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4054209962Smm (void) no_memory(hdl); 4055209962Smm return (NULL); 4056209962Smm } 4057209962Smm } 4058209962Smm 4059209962Smm switch (cmd) { 4060209962Smm case ZFS_SMB_ACL_ADD: 4061209962Smm case ZFS_SMB_ACL_REMOVE: 4062209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4063209962Smm break; 4064209962Smm case ZFS_SMB_ACL_RENAME: 4065209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4066209962Smm resource1) != 0) { 4067209962Smm (void) no_memory(hdl); 4068209962Smm return (-1); 4069209962Smm } 4070209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4071209962Smm resource2) != 0) { 4072209962Smm (void) no_memory(hdl); 4073209962Smm return (-1); 4074209962Smm } 4075209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4076209962Smm nvlist_free(nvlist); 4077209962Smm return (-1); 4078209962Smm } 4079209962Smm break; 4080209962Smm case ZFS_SMB_ACL_PURGE: 4081209962Smm break; 4082209962Smm default: 4083209962Smm return (-1); 4084209962Smm } 4085209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4086209962Smm if (nvlist) 4087209962Smm nvlist_free(nvlist); 4088209962Smm return (error); 4089209962Smm} 4090209962Smm 4091209962Smmint 4092209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4093209962Smm char *path, char *resource) 4094209962Smm{ 4095209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4096209962Smm resource, NULL)); 4097209962Smm} 4098209962Smm 4099209962Smmint 4100209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4101209962Smm char *path, char *resource) 4102209962Smm{ 4103209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4104209962Smm resource, NULL)); 4105209962Smm} 4106209962Smm 4107209962Smmint 4108209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4109209962Smm{ 4110209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4111209962Smm NULL, NULL)); 4112209962Smm} 4113209962Smm 4114209962Smmint 4115209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4116209962Smm char *oldname, char *newname) 4117209962Smm{ 4118209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4119209962Smm oldname, newname)); 4120209962Smm} 4121209962Smm#endif /* sun */ 4122209962Smm 4123209962Smmint 4124209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4125209962Smm zfs_userspace_cb_t func, void *arg) 4126209962Smm{ 4127209962Smm zfs_cmd_t zc = { 0 }; 4128209962Smm zfs_useracct_t buf[100]; 4129240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4130240415Smm int ret; 4131209962Smm 4132228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4133209962Smm 4134209962Smm zc.zc_objset_type = type; 4135209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4136209962Smm 4137240415Smm for (;;) { 4138209962Smm zfs_useracct_t *zua = buf; 4139209962Smm 4140209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4141240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4142248571Smm char errbuf[1024]; 4143240415Smm 4144240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4145240415Smm dgettext(TEXT_DOMAIN, 4146240415Smm "cannot get used/quota for %s"), zc.zc_name); 4147240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4148240415Smm } 4149240415Smm if (zc.zc_nvlist_dst_size == 0) 4150209962Smm break; 4151209962Smm 4152209962Smm while (zc.zc_nvlist_dst_size > 0) { 4153240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4154240415Smm zua->zu_space)) != 0) 4155240415Smm return (ret); 4156209962Smm zua++; 4157209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4158209962Smm } 4159209962Smm } 4160209962Smm 4161240415Smm return (0); 4162209962Smm} 4163209962Smm 4164248571Smmstruct holdarg { 4165248571Smm nvlist_t *nvl; 4166248571Smm const char *snapname; 4167248571Smm const char *tag; 4168248571Smm boolean_t recursive; 4169252219Sdelphij int error; 4170248571Smm}; 4171248571Smm 4172248571Smmstatic int 4173248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4174248571Smm{ 4175248571Smm struct holdarg *ha = arg; 4176248571Smm char name[ZFS_MAXNAMELEN]; 4177248571Smm int rv = 0; 4178248571Smm 4179248571Smm (void) snprintf(name, sizeof (name), 4180248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4181248571Smm 4182251646Sdelphij if (lzc_exists(name)) 4183248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4184248571Smm 4185248571Smm if (ha->recursive) 4186248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4187248571Smm zfs_close(zhp); 4188248571Smm return (rv); 4189248571Smm} 4190248571Smm 4191219089Spjdint 4192219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4193251646Sdelphij boolean_t recursive, int cleanup_fd) 4194219089Spjd{ 4195248571Smm int ret; 4196248571Smm struct holdarg ha; 4197219089Spjd 4198248571Smm ha.nvl = fnvlist_alloc(); 4199248571Smm ha.snapname = snapname; 4200248571Smm ha.tag = tag; 4201248571Smm ha.recursive = recursive; 4202248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4203249357Smm 4204251646Sdelphij if (nvlist_empty(ha.nvl)) { 4205251646Sdelphij char errbuf[1024]; 4206251646Sdelphij 4207249357Smm fnvlist_free(ha.nvl); 4208249357Smm ret = ENOENT; 4209251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4210251646Sdelphij dgettext(TEXT_DOMAIN, 4211251646Sdelphij "cannot hold snapshot '%s@%s'"), 4212251646Sdelphij zhp->zfs_name, snapname); 4213251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4214249357Smm return (ret); 4215249357Smm } 4216249357Smm 4217251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4218248571Smm fnvlist_free(ha.nvl); 4219219089Spjd 4220251646Sdelphij return (ret); 4221251646Sdelphij} 4222251646Sdelphij 4223251646Sdelphijint 4224251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4225251646Sdelphij{ 4226251646Sdelphij int ret; 4227251646Sdelphij nvlist_t *errors; 4228251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4229251646Sdelphij char errbuf[1024]; 4230251646Sdelphij nvpair_t *elem; 4231251646Sdelphij 4232251646Sdelphij errors = NULL; 4233251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4234251646Sdelphij 4235251646Sdelphij if (ret == 0) { 4236251646Sdelphij /* There may be errors even in the success case. */ 4237251646Sdelphij fnvlist_free(errors); 4238248571Smm return (0); 4239251646Sdelphij } 4240219089Spjd 4241251646Sdelphij if (nvlist_empty(errors)) { 4242248571Smm /* no hold-specific errors */ 4243248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4244248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4245248571Smm switch (ret) { 4246248571Smm case ENOTSUP: 4247248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4248248571Smm "pool must be upgraded")); 4249248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4250248571Smm break; 4251248571Smm case EINVAL: 4252248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4253248571Smm break; 4254248571Smm default: 4255248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4256248571Smm } 4257248571Smm } 4258219089Spjd 4259248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4260248571Smm elem != NULL; 4261248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4262248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4263248571Smm dgettext(TEXT_DOMAIN, 4264248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4265248571Smm switch (fnvpair_value_int32(elem)) { 4266219089Spjd case E2BIG: 4267219089Spjd /* 4268219089Spjd * Temporary tags wind up having the ds object id 4269219089Spjd * prepended. So even if we passed the length check 4270219089Spjd * above, it's still possible for the tag to wind 4271219089Spjd * up being slightly too long. 4272219089Spjd */ 4273248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4274248571Smm break; 4275219089Spjd case EINVAL: 4276248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4277248571Smm break; 4278219089Spjd case EEXIST: 4279248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4280248571Smm break; 4281219089Spjd default: 4282248571Smm (void) zfs_standard_error(hdl, 4283248571Smm fnvpair_value_int32(elem), errbuf); 4284219089Spjd } 4285219089Spjd } 4286219089Spjd 4287248571Smm fnvlist_free(errors); 4288248571Smm return (ret); 4289219089Spjd} 4290219089Spjd 4291248571Smmstatic int 4292248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4293248571Smm{ 4294248571Smm struct holdarg *ha = arg; 4295248571Smm char name[ZFS_MAXNAMELEN]; 4296248571Smm int rv = 0; 4297252219Sdelphij nvlist_t *existing_holds; 4298248571Smm 4299248571Smm (void) snprintf(name, sizeof (name), 4300248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4301248571Smm 4302252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4303252219Sdelphij ha->error = ENOENT; 4304252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4305252219Sdelphij ha->error = ESRCH; 4306252219Sdelphij } else { 4307252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4308252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4309252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4310252219Sdelphij fnvlist_free(torelease); 4311248571Smm } 4312248571Smm 4313248571Smm if (ha->recursive) 4314248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4315248571Smm zfs_close(zhp); 4316248571Smm return (rv); 4317248571Smm} 4318248571Smm 4319219089Spjdint 4320219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4321219089Spjd boolean_t recursive) 4322219089Spjd{ 4323248571Smm int ret; 4324248571Smm struct holdarg ha; 4325251646Sdelphij nvlist_t *errors = NULL; 4326248571Smm nvpair_t *elem; 4327219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4328249357Smm char errbuf[1024]; 4329219089Spjd 4330248571Smm ha.nvl = fnvlist_alloc(); 4331248571Smm ha.snapname = snapname; 4332248571Smm ha.tag = tag; 4333248571Smm ha.recursive = recursive; 4334252219Sdelphij ha.error = 0; 4335248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4336249357Smm 4337251646Sdelphij if (nvlist_empty(ha.nvl)) { 4338249357Smm fnvlist_free(ha.nvl); 4339252219Sdelphij ret = ha.error; 4340249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4341249357Smm dgettext(TEXT_DOMAIN, 4342249357Smm "cannot release hold from snapshot '%s@%s'"), 4343249357Smm zhp->zfs_name, snapname); 4344252219Sdelphij if (ret == ESRCH) { 4345252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4346252219Sdelphij } else { 4347252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4348252219Sdelphij } 4349249357Smm return (ret); 4350249357Smm } 4351249357Smm 4352248571Smm ret = lzc_release(ha.nvl, &errors); 4353248571Smm fnvlist_free(ha.nvl); 4354219089Spjd 4355251646Sdelphij if (ret == 0) { 4356251646Sdelphij /* There may be errors even in the success case. */ 4357251646Sdelphij fnvlist_free(errors); 4358248571Smm return (0); 4359251646Sdelphij } 4360219089Spjd 4361251646Sdelphij if (nvlist_empty(errors)) { 4362248571Smm /* no hold-specific errors */ 4363219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4364248571Smm "cannot release")); 4365219089Spjd switch (errno) { 4366219089Spjd case ENOTSUP: 4367219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4368219089Spjd "pool must be upgraded")); 4369248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4370248571Smm break; 4371248571Smm default: 4372248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4373248571Smm } 4374248571Smm } 4375248571Smm 4376248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4377248571Smm elem != NULL; 4378248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4379248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4380248571Smm dgettext(TEXT_DOMAIN, 4381248571Smm "cannot release hold from snapshot '%s'"), 4382248571Smm nvpair_name(elem)); 4383248571Smm switch (fnvpair_value_int32(elem)) { 4384248571Smm case ESRCH: 4385248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4386248571Smm break; 4387219089Spjd case EINVAL: 4388248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4389248571Smm break; 4390219089Spjd default: 4391248571Smm (void) zfs_standard_error_fmt(hdl, 4392248571Smm fnvpair_value_int32(elem), errbuf); 4393219089Spjd } 4394219089Spjd } 4395219089Spjd 4396248571Smm fnvlist_free(errors); 4397248571Smm return (ret); 4398219089Spjd} 4399219089Spjd 4400219089Spjdint 4401219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4402219089Spjd{ 4403219089Spjd zfs_cmd_t zc = { 0 }; 4404219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4405219089Spjd int nvsz = 2048; 4406219089Spjd void *nvbuf; 4407219089Spjd int err = 0; 4408248571Smm char errbuf[1024]; 4409219089Spjd 4410219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4411219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4412219089Spjd 4413219089Spjdtryagain: 4414219089Spjd 4415219089Spjd nvbuf = malloc(nvsz); 4416219089Spjd if (nvbuf == NULL) { 4417219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4418219089Spjd goto out; 4419219089Spjd } 4420219089Spjd 4421219089Spjd zc.zc_nvlist_dst_size = nvsz; 4422219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4423219089Spjd 4424219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4425219089Spjd 4426230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 4427219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4428219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4429219089Spjd zc.zc_name); 4430219089Spjd switch (errno) { 4431219089Spjd case ENOMEM: 4432219089Spjd free(nvbuf); 4433219089Spjd nvsz = zc.zc_nvlist_dst_size; 4434219089Spjd goto tryagain; 4435219089Spjd 4436219089Spjd case ENOTSUP: 4437219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4438219089Spjd "pool must be upgraded")); 4439219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4440219089Spjd break; 4441219089Spjd case EINVAL: 4442219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4443219089Spjd break; 4444219089Spjd case ENOENT: 4445219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4446219089Spjd break; 4447219089Spjd default: 4448219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4449219089Spjd break; 4450219089Spjd } 4451219089Spjd } else { 4452219089Spjd /* success */ 4453219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4454219089Spjd if (rc) { 4455219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4456219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4457219089Spjd zc.zc_name); 4458219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4459219089Spjd } 4460219089Spjd } 4461219089Spjd 4462219089Spjd free(nvbuf); 4463219089Spjdout: 4464219089Spjd return (err); 4465219089Spjd} 4466219089Spjd 4467219089Spjdint 4468219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4469219089Spjd{ 4470219089Spjd zfs_cmd_t zc = { 0 }; 4471219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4472219089Spjd char *nvbuf; 4473248571Smm char errbuf[1024]; 4474219089Spjd size_t nvsz; 4475219089Spjd int err; 4476219089Spjd 4477219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4478219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4479219089Spjd 4480219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4481219089Spjd assert(err == 0); 4482219089Spjd 4483219089Spjd nvbuf = malloc(nvsz); 4484219089Spjd 4485219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4486219089Spjd assert(err == 0); 4487219089Spjd 4488219089Spjd zc.zc_nvlist_src_size = nvsz; 4489219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4490219089Spjd zc.zc_perm_action = un; 4491219089Spjd 4492219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4493219089Spjd 4494219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4495219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4496219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4497219089Spjd zc.zc_name); 4498219089Spjd switch (errno) { 4499219089Spjd case ENOTSUP: 4500219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4501219089Spjd "pool must be upgraded")); 4502219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4503219089Spjd break; 4504219089Spjd case EINVAL: 4505219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4506219089Spjd break; 4507219089Spjd case ENOENT: 4508219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4509219089Spjd break; 4510219089Spjd default: 4511219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4512219089Spjd break; 4513219089Spjd } 4514219089Spjd } 4515219089Spjd 4516219089Spjd free(nvbuf); 4517219089Spjd 4518219089Spjd return (err); 4519219089Spjd} 4520219089Spjd 4521219089Spjdint 4522219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4523219089Spjd{ 4524248571Smm int err; 4525248571Smm char errbuf[1024]; 4526219089Spjd 4527248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 4528219089Spjd 4529248571Smm if (err != 0) { 4530248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4531219089Spjd 4532219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4533219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4534248571Smm zhp->zfs_name); 4535248571Smm switch (err) { 4536219089Spjd case ENOTSUP: 4537219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4538219089Spjd "pool must be upgraded")); 4539219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4540219089Spjd break; 4541219089Spjd case EINVAL: 4542219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4543219089Spjd break; 4544219089Spjd case ENOENT: 4545219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4546219089Spjd break; 4547219089Spjd default: 4548219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4549219089Spjd break; 4550219089Spjd } 4551219089Spjd } 4552219089Spjd 4553219089Spjd return (err); 4554219089Spjd} 4555219089Spjd 4556251629Sdelphij/* 4557251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 4558251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 4559251629Sdelphij * suite's shell version in reservation.kshlib. 4560251629Sdelphij */ 4561219089Spjduint64_t 4562219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4563219089Spjd{ 4564219089Spjd uint64_t numdb; 4565219089Spjd uint64_t nblocks, volblocksize; 4566219089Spjd int ncopies; 4567219089Spjd char *strval; 4568219089Spjd 4569219089Spjd if (nvlist_lookup_string(props, 4570219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4571219089Spjd ncopies = atoi(strval); 4572219089Spjd else 4573219089Spjd ncopies = 1; 4574219089Spjd if (nvlist_lookup_uint64(props, 4575219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4576219089Spjd &volblocksize) != 0) 4577219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4578219089Spjd nblocks = volsize/volblocksize; 4579219089Spjd /* start with metadnode L0-L6 */ 4580219089Spjd numdb = 7; 4581219089Spjd /* calculate number of indirects */ 4582219089Spjd while (nblocks > 1) { 4583219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4584219089Spjd nblocks /= DNODES_PER_LEVEL; 4585219089Spjd numdb += nblocks; 4586219089Spjd } 4587219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4588219089Spjd volsize *= ncopies; 4589219089Spjd /* 4590219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4591219089Spjd * compressed, but in practice they compress down to about 4592219089Spjd * 1100 bytes 4593219089Spjd */ 4594219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4595219089Spjd volsize += numdb; 4596219089Spjd return (volsize); 4597219089Spjd} 4598219089Spjd 4599168404Spjd/* 4600168404Spjd * Attach/detach the given filesystem to/from the given jail. 4601168404Spjd */ 4602168404Spjdint 4603168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4604168404Spjd{ 4605168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4606168404Spjd zfs_cmd_t zc = { 0 }; 4607168404Spjd char errbuf[1024]; 4608224525Smm unsigned long cmd; 4609224525Smm int ret; 4610168404Spjd 4611168404Spjd if (attach) { 4612168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4613168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4614168404Spjd } else { 4615168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4616249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 4617168404Spjd } 4618168404Spjd 4619168404Spjd switch (zhp->zfs_type) { 4620168404Spjd case ZFS_TYPE_VOLUME: 4621168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4622168404Spjd "volumes can not be jailed")); 4623168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4624168404Spjd case ZFS_TYPE_SNAPSHOT: 4625168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4626168404Spjd "snapshots can not be jailed")); 4627168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4628168404Spjd } 4629168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4630168404Spjd 4631168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4632168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4633168404Spjd zc.zc_jailid = jailid; 4634168404Spjd 4635168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4636168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4637168404Spjd zfs_standard_error(hdl, errno, errbuf); 4638168404Spjd 4639168404Spjd return (ret); 4640168404Spjd} 4641