libzfs_dataset.c revision 226706
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. 24219089Spjd * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 25223623Smm * Copyright (c) 2011 by Delphix. All rights reserved. 26226706Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>. 27226706Spjd * All rights reserved. 28168404Spjd */ 29168404Spjd 30168404Spjd#include <ctype.h> 31168404Spjd#include <errno.h> 32168404Spjd#include <libintl.h> 33168404Spjd#include <math.h> 34168404Spjd#include <stdio.h> 35168404Spjd#include <stdlib.h> 36168404Spjd#include <strings.h> 37168404Spjd#include <unistd.h> 38185029Spjd#include <stddef.h> 39168404Spjd#include <zone.h> 40168404Spjd#include <fcntl.h> 41168404Spjd#include <sys/mntent.h> 42168404Spjd#include <sys/mount.h> 43185029Spjd#include <priv.h> 44185029Spjd#include <pwd.h> 45185029Spjd#include <grp.h> 46185029Spjd#include <stddef.h> 47209962Smm#include <idmap.h> 48168404Spjd 49219089Spjd#include <sys/dnode.h> 50168404Spjd#include <sys/spa.h> 51168404Spjd#include <sys/zap.h> 52209962Smm#include <sys/misc.h> 53168404Spjd#include <libzfs.h> 54168404Spjd 55168404Spjd#include "zfs_namecheck.h" 56168404Spjd#include "zfs_prop.h" 57168404Spjd#include "libzfs_impl.h" 58185029Spjd#include "zfs_deleg.h" 59168404Spjd 60209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 61209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 62168676Spjd 63168404Spjd/* 64168404Spjd * Given a single type (not a mask of types), return the type in a human 65168404Spjd * readable form. 66168404Spjd */ 67168404Spjdconst char * 68168404Spjdzfs_type_to_name(zfs_type_t type) 69168404Spjd{ 70168404Spjd switch (type) { 71168404Spjd case ZFS_TYPE_FILESYSTEM: 72168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 73168404Spjd case ZFS_TYPE_SNAPSHOT: 74168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 75168404Spjd case ZFS_TYPE_VOLUME: 76168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 77168404Spjd } 78168404Spjd 79168404Spjd return (NULL); 80168404Spjd} 81168404Spjd 82168404Spjd/* 83168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 84168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 85168404Spjd * We guess what the type would have been based on the path and the mask of 86168404Spjd * acceptable types. 87168404Spjd */ 88168404Spjdstatic const char * 89168404Spjdpath_to_str(const char *path, int types) 90168404Spjd{ 91168404Spjd /* 92168404Spjd * When given a single type, always report the exact type. 93168404Spjd */ 94168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 95168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 96168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 97168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 98168404Spjd if (types == ZFS_TYPE_VOLUME) 99168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 100168404Spjd 101168404Spjd /* 102168404Spjd * The user is requesting more than one type of dataset. If this is the 103168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 104168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 105168404Spjd * snapshot attribute and try again. 106168404Spjd */ 107168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 108168404Spjd if (strchr(path, '@') != NULL) 109168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 110168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 111168404Spjd } 112168404Spjd 113168404Spjd /* 114168404Spjd * The user has requested either filesystems or volumes. 115168404Spjd * We have no way of knowing a priori what type this would be, so always 116168404Spjd * report it as "filesystem" or "volume", our two primitive types. 117168404Spjd */ 118168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 119168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 120168404Spjd 121168404Spjd assert(types & ZFS_TYPE_VOLUME); 122168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 123168404Spjd} 124168404Spjd 125168404Spjd/* 126168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 127209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 128209962Smm * explain exactly why the name was not valid. 129168404Spjd */ 130219089Spjdint 131185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 132185029Spjd boolean_t modifying) 133168404Spjd{ 134168404Spjd namecheck_err_t why; 135168404Spjd char what; 136168404Spjd 137219089Spjd (void) zfs_prop_get_table(); 138168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 139168404Spjd if (hdl != NULL) { 140168404Spjd switch (why) { 141168404Spjd case NAME_ERR_TOOLONG: 142168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 143168404Spjd "name is too long")); 144168404Spjd break; 145168404Spjd 146168404Spjd case NAME_ERR_LEADING_SLASH: 147168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 148168404Spjd "leading slash in name")); 149168404Spjd break; 150168404Spjd 151168404Spjd case NAME_ERR_EMPTY_COMPONENT: 152168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 153168404Spjd "empty component in name")); 154168404Spjd break; 155168404Spjd 156168404Spjd case NAME_ERR_TRAILING_SLASH: 157168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 158168404Spjd "trailing slash in name")); 159168404Spjd break; 160168404Spjd 161168404Spjd case NAME_ERR_INVALCHAR: 162168404Spjd zfs_error_aux(hdl, 163168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 164168404Spjd "'%c' in name"), what); 165168404Spjd break; 166168404Spjd 167168404Spjd case NAME_ERR_MULTIPLE_AT: 168168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 169168404Spjd "multiple '@' delimiters in name")); 170168404Spjd break; 171168404Spjd 172168404Spjd case NAME_ERR_NOLETTER: 173168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 174168404Spjd "pool doesn't begin with a letter")); 175168404Spjd break; 176168404Spjd 177168404Spjd case NAME_ERR_RESERVED: 178168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 179168404Spjd "name is reserved")); 180168404Spjd break; 181168404Spjd 182168404Spjd case NAME_ERR_DISKLIKE: 183168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 184168404Spjd "reserved disk name")); 185168404Spjd break; 186168404Spjd } 187168404Spjd } 188168404Spjd 189168404Spjd return (0); 190168404Spjd } 191168404Spjd 192168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 193168404Spjd if (hdl != NULL) 194168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 195168404Spjd "snapshot delimiter '@' in filesystem name")); 196168404Spjd return (0); 197168404Spjd } 198168404Spjd 199168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 200168404Spjd if (hdl != NULL) 201168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 202168404Spjd "missing '@' delimiter in snapshot name")); 203168404Spjd return (0); 204168404Spjd } 205168404Spjd 206185029Spjd if (modifying && strchr(path, '%') != NULL) { 207185029Spjd if (hdl != NULL) 208185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 209185029Spjd "invalid character %c in name"), '%'); 210185029Spjd return (0); 211185029Spjd } 212185029Spjd 213168404Spjd return (-1); 214168404Spjd} 215168404Spjd 216168404Spjdint 217168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 218168404Spjd{ 219185029Spjd if (type == ZFS_TYPE_POOL) 220185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 221185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 222168404Spjd} 223168404Spjd 224168404Spjd/* 225168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 226168404Spjd * properties into a separate nvlist. 227168404Spjd */ 228185029Spjdstatic nvlist_t * 229185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 230168404Spjd{ 231168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 232168404Spjd nvpair_t *elem; 233168404Spjd nvlist_t *propval; 234185029Spjd nvlist_t *nvl; 235168404Spjd 236185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 237185029Spjd (void) no_memory(hdl); 238185029Spjd return (NULL); 239185029Spjd } 240168404Spjd 241168404Spjd elem = NULL; 242185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 243168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 244168404Spjd continue; 245168404Spjd 246168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 247185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 248185029Spjd nvlist_free(nvl); 249185029Spjd (void) no_memory(hdl); 250185029Spjd return (NULL); 251185029Spjd } 252168404Spjd } 253168404Spjd 254185029Spjd return (nvl); 255168404Spjd} 256168404Spjd 257185029Spjdstatic zpool_handle_t * 258185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 259185029Spjd{ 260185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 261185029Spjd zpool_handle_t *zph; 262185029Spjd 263185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 264185029Spjd if (hdl->libzfs_pool_handles != NULL) 265185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 266185029Spjd hdl->libzfs_pool_handles = zph; 267185029Spjd } 268185029Spjd return (zph); 269185029Spjd} 270185029Spjd 271185029Spjdstatic zpool_handle_t * 272185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 273185029Spjd{ 274185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 275185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 276185029Spjd 277185029Spjd while ((zph != NULL) && 278185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 279185029Spjd zph = zph->zpool_next; 280185029Spjd return (zph); 281185029Spjd} 282185029Spjd 283168404Spjd/* 284185029Spjd * Returns a handle to the pool that contains the provided dataset. 285185029Spjd * If a handle to that pool already exists then that handle is returned. 286185029Spjd * Otherwise, a new handle is created and added to the list of handles. 287185029Spjd */ 288185029Spjdstatic zpool_handle_t * 289185029Spjdzpool_handle(zfs_handle_t *zhp) 290185029Spjd{ 291185029Spjd char *pool_name; 292185029Spjd int len; 293185029Spjd zpool_handle_t *zph; 294185029Spjd 295185029Spjd len = strcspn(zhp->zfs_name, "/@") + 1; 296185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 297185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 298185029Spjd 299185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 300185029Spjd if (zph == NULL) 301185029Spjd zph = zpool_add_handle(zhp, pool_name); 302185029Spjd 303185029Spjd free(pool_name); 304185029Spjd return (zph); 305185029Spjd} 306185029Spjd 307185029Spjdvoid 308185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 309185029Spjd{ 310185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 311185029Spjd 312185029Spjd while (zph != NULL) { 313185029Spjd next = zph->zpool_next; 314185029Spjd zpool_close(zph); 315185029Spjd zph = next; 316185029Spjd } 317185029Spjd hdl->libzfs_pool_handles = NULL; 318185029Spjd} 319185029Spjd 320185029Spjd/* 321168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 322168404Spjd */ 323219089Spjdstatic int 324209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 325168404Spjd{ 326168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 327168404Spjd 328209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 329168404Spjd 330209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 331168404Spjd if (errno == ENOMEM) { 332209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 333168404Spjd return (-1); 334168404Spjd } 335168404Spjd } else { 336168404Spjd return (-1); 337168404Spjd } 338168404Spjd } 339209962Smm return (0); 340209962Smm} 341168404Spjd 342219089Spjd/* 343219089Spjd * Utility function to get the received properties of the given object. 344219089Spjd */ 345209962Smmstatic int 346219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 347219089Spjd{ 348219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 349219089Spjd nvlist_t *recvdprops; 350219089Spjd zfs_cmd_t zc = { 0 }; 351219089Spjd int err; 352219089Spjd 353219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 354219089Spjd return (-1); 355219089Spjd 356219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 357219089Spjd 358219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 359219089Spjd if (errno == ENOMEM) { 360219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 361219089Spjd return (-1); 362219089Spjd } 363219089Spjd } else { 364219089Spjd zcmd_free_nvlists(&zc); 365219089Spjd return (-1); 366219089Spjd } 367219089Spjd } 368219089Spjd 369219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 370219089Spjd zcmd_free_nvlists(&zc); 371219089Spjd if (err != 0) 372219089Spjd return (-1); 373219089Spjd 374219089Spjd nvlist_free(zhp->zfs_recvd_props); 375219089Spjd zhp->zfs_recvd_props = recvdprops; 376219089Spjd 377219089Spjd return (0); 378219089Spjd} 379219089Spjd 380219089Spjdstatic int 381209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 382209962Smm{ 383209962Smm nvlist_t *allprops, *userprops; 384168404Spjd 385209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 386209962Smm 387209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 388168404Spjd return (-1); 389168404Spjd } 390168404Spjd 391209962Smm /* 392209962Smm * XXX Why do we store the user props separately, in addition to 393209962Smm * storing them in zfs_props? 394209962Smm */ 395185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 396185029Spjd nvlist_free(allprops); 397168404Spjd return (-1); 398185029Spjd } 399168404Spjd 400185029Spjd nvlist_free(zhp->zfs_props); 401185029Spjd nvlist_free(zhp->zfs_user_props); 402185029Spjd 403185029Spjd zhp->zfs_props = allprops; 404185029Spjd zhp->zfs_user_props = userprops; 405185029Spjd 406168404Spjd return (0); 407168404Spjd} 408168404Spjd 409209962Smmstatic int 410209962Smmget_stats(zfs_handle_t *zhp) 411209962Smm{ 412209962Smm int rc = 0; 413209962Smm zfs_cmd_t zc = { 0 }; 414209962Smm 415209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 416209962Smm return (-1); 417209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 418209962Smm rc = -1; 419209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 420209962Smm rc = -1; 421209962Smm zcmd_free_nvlists(&zc); 422209962Smm return (rc); 423209962Smm} 424209962Smm 425168404Spjd/* 426168404Spjd * Refresh the properties currently stored in the handle. 427168404Spjd */ 428168404Spjdvoid 429168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 430168404Spjd{ 431168404Spjd (void) get_stats(zhp); 432168404Spjd} 433168404Spjd 434168404Spjd/* 435168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 436168404Spjd * zfs_iter_* to create child handles on the fly. 437168404Spjd */ 438209962Smmstatic int 439209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 440168404Spjd{ 441219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 442209962Smm return (-1); 443168404Spjd 444168404Spjd /* 445168404Spjd * We've managed to open the dataset and gather statistics. Determine 446168404Spjd * the high-level type. 447168404Spjd */ 448168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 449168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 450168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 451168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 452168404Spjd else 453168404Spjd abort(); 454168404Spjd 455168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 456168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 457168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 458168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 459168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 460168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 461168404Spjd else 462168404Spjd abort(); /* we should never see any other types */ 463168404Spjd 464219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 465219089Spjd return (-1); 466219089Spjd 467209962Smm return (0); 468209962Smm} 469209962Smm 470209962Smmzfs_handle_t * 471209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 472209962Smm{ 473209962Smm zfs_cmd_t zc = { 0 }; 474209962Smm 475209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 476209962Smm 477209962Smm if (zhp == NULL) 478209962Smm return (NULL); 479209962Smm 480209962Smm zhp->zfs_hdl = hdl; 481209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 482209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 483209962Smm free(zhp); 484209962Smm return (NULL); 485209962Smm } 486209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 487209962Smm zcmd_free_nvlists(&zc); 488209962Smm free(zhp); 489209962Smm return (NULL); 490209962Smm } 491209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 492209962Smm free(zhp); 493209962Smm zhp = NULL; 494209962Smm } 495209962Smm zcmd_free_nvlists(&zc); 496168404Spjd return (zhp); 497168404Spjd} 498168404Spjd 499209962Smmstatic zfs_handle_t * 500209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 501209962Smm{ 502209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 503209962Smm 504209962Smm if (zhp == NULL) 505209962Smm return (NULL); 506209962Smm 507209962Smm zhp->zfs_hdl = hdl; 508209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 509209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 510209962Smm free(zhp); 511209962Smm return (NULL); 512209962Smm } 513209962Smm return (zhp); 514209962Smm} 515209962Smm 516168404Spjd/* 517168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 518168404Spjd * argument is a mask of acceptable types. The function will print an 519168404Spjd * appropriate error message and return NULL if it can't be opened. 520168404Spjd */ 521168404Spjdzfs_handle_t * 522168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 523168404Spjd{ 524168404Spjd zfs_handle_t *zhp; 525168404Spjd char errbuf[1024]; 526168404Spjd 527168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 528168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 529168404Spjd 530168404Spjd /* 531168404Spjd * Validate the name before we even try to open it. 532168404Spjd */ 533185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 534168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 535168404Spjd "invalid dataset name")); 536168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 537168404Spjd return (NULL); 538168404Spjd } 539168404Spjd 540168404Spjd /* 541168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 542168404Spjd */ 543168404Spjd errno = 0; 544168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 545168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 546168404Spjd return (NULL); 547168404Spjd } 548168404Spjd 549168404Spjd if (!(types & zhp->zfs_type)) { 550168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 551168404Spjd zfs_close(zhp); 552168404Spjd return (NULL); 553168404Spjd } 554168404Spjd 555168404Spjd return (zhp); 556168404Spjd} 557168404Spjd 558168404Spjd/* 559168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 560168404Spjd */ 561168404Spjdvoid 562168404Spjdzfs_close(zfs_handle_t *zhp) 563168404Spjd{ 564168404Spjd if (zhp->zfs_mntopts) 565168404Spjd free(zhp->zfs_mntopts); 566168404Spjd nvlist_free(zhp->zfs_props); 567168404Spjd nvlist_free(zhp->zfs_user_props); 568219089Spjd nvlist_free(zhp->zfs_recvd_props); 569168404Spjd free(zhp); 570168404Spjd} 571168404Spjd 572209962Smmtypedef struct mnttab_node { 573209962Smm struct mnttab mtn_mt; 574209962Smm avl_node_t mtn_node; 575209962Smm} mnttab_node_t; 576209962Smm 577209962Smmstatic int 578209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 579209962Smm{ 580209962Smm const mnttab_node_t *mtn1 = arg1; 581209962Smm const mnttab_node_t *mtn2 = arg2; 582209962Smm int rv; 583209962Smm 584209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 585209962Smm 586209962Smm if (rv == 0) 587209962Smm return (0); 588209962Smm return (rv > 0 ? 1 : -1); 589209962Smm} 590209962Smm 591209962Smmvoid 592209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 593209962Smm{ 594209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 595209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 596209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 597209962Smm} 598209962Smm 599209962Smmvoid 600209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 601209962Smm{ 602209962Smm struct mnttab entry; 603209962Smm 604209962Smm rewind(hdl->libzfs_mnttab); 605209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 606209962Smm mnttab_node_t *mtn; 607209962Smm 608209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 609209962Smm continue; 610209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 611209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 612209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 613209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 614209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 615209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 616209962Smm } 617209962Smm} 618209962Smm 619209962Smmvoid 620209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 621209962Smm{ 622209962Smm void *cookie = NULL; 623209962Smm mnttab_node_t *mtn; 624209962Smm 625209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 626209962Smm free(mtn->mtn_mt.mnt_special); 627209962Smm free(mtn->mtn_mt.mnt_mountp); 628209962Smm free(mtn->mtn_mt.mnt_fstype); 629209962Smm free(mtn->mtn_mt.mnt_mntopts); 630209962Smm free(mtn); 631209962Smm } 632209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 633209962Smm} 634209962Smm 635209962Smmvoid 636209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 637209962Smm{ 638209962Smm hdl->libzfs_mnttab_enable = enable; 639209962Smm} 640209962Smm 641185029Spjdint 642209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 643209962Smm struct mnttab *entry) 644209962Smm{ 645209962Smm mnttab_node_t find; 646209962Smm mnttab_node_t *mtn; 647209962Smm 648209962Smm if (!hdl->libzfs_mnttab_enable) { 649209962Smm struct mnttab srch = { 0 }; 650209962Smm 651209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 652209962Smm libzfs_mnttab_fini(hdl); 653209962Smm rewind(hdl->libzfs_mnttab); 654209962Smm srch.mnt_special = (char *)fsname; 655209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 656209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 657209962Smm return (0); 658209962Smm else 659209962Smm return (ENOENT); 660209962Smm } 661209962Smm 662209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 663209962Smm libzfs_mnttab_update(hdl); 664209962Smm 665209962Smm find.mtn_mt.mnt_special = (char *)fsname; 666209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 667209962Smm if (mtn) { 668209962Smm *entry = mtn->mtn_mt; 669209962Smm return (0); 670209962Smm } 671209962Smm return (ENOENT); 672209962Smm} 673209962Smm 674209962Smmvoid 675209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 676209962Smm const char *mountp, const char *mntopts) 677209962Smm{ 678209962Smm mnttab_node_t *mtn; 679209962Smm 680209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 681209962Smm return; 682209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 683209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 684209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 685209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 686209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 687209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 688209962Smm} 689209962Smm 690209962Smmvoid 691209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 692209962Smm{ 693209962Smm mnttab_node_t find; 694209962Smm mnttab_node_t *ret; 695209962Smm 696209962Smm find.mtn_mt.mnt_special = (char *)fsname; 697209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 698209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 699209962Smm free(ret->mtn_mt.mnt_special); 700209962Smm free(ret->mtn_mt.mnt_mountp); 701209962Smm free(ret->mtn_mt.mnt_fstype); 702209962Smm free(ret->mtn_mt.mnt_mntopts); 703209962Smm free(ret); 704209962Smm } 705209962Smm} 706209962Smm 707209962Smmint 708185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 709168404Spjd{ 710185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 711168404Spjd 712185029Spjd if (zpool_handle == NULL) 713168404Spjd return (-1); 714168404Spjd 715185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 716185029Spjd ZPOOL_PROP_VERSION, NULL); 717168404Spjd return (0); 718168404Spjd} 719168404Spjd 720168404Spjd/* 721185029Spjd * The choice of reservation property depends on the SPA version. 722168404Spjd */ 723168404Spjdstatic int 724185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 725168404Spjd{ 726185029Spjd int spa_version; 727168404Spjd 728185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 729168404Spjd return (-1); 730168404Spjd 731185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 732185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 733185029Spjd else 734185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 735168404Spjd 736168404Spjd return (0); 737168404Spjd} 738168404Spjd 739168404Spjd/* 740168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 741168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 742168404Spjd * strings. 743168404Spjd */ 744168404Spjdnvlist_t * 745185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 746185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 747168404Spjd{ 748168404Spjd nvpair_t *elem; 749168404Spjd uint64_t intval; 750168404Spjd char *strval; 751185029Spjd zfs_prop_t prop; 752168404Spjd nvlist_t *ret; 753185029Spjd int chosen_normal = -1; 754185029Spjd int chosen_utf = -1; 755168404Spjd 756168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 757168404Spjd (void) no_memory(hdl); 758168404Spjd return (NULL); 759168404Spjd } 760168404Spjd 761209962Smm /* 762209962Smm * Make sure this property is valid and applies to this type. 763209962Smm */ 764209962Smm 765168404Spjd elem = NULL; 766168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 767185029Spjd const char *propname = nvpair_name(elem); 768168404Spjd 769209962Smm prop = zfs_name_to_prop(propname); 770209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 771185029Spjd /* 772209962Smm * This is a user property: make sure it's a 773185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 774185029Spjd */ 775185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 776185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 777185029Spjd "'%s' must be a string"), propname); 778185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 779185029Spjd goto error; 780168404Spjd } 781168404Spjd 782185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 783185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 784185029Spjd "property name '%s' is too long"), 785185029Spjd propname); 786185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 787185029Spjd goto error; 788185029Spjd } 789185029Spjd 790168404Spjd (void) nvpair_value_string(elem, &strval); 791168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 792168404Spjd (void) no_memory(hdl); 793168404Spjd goto error; 794168404Spjd } 795168404Spjd continue; 796168404Spjd } 797168404Spjd 798209962Smm /* 799209962Smm * Currently, only user properties can be modified on 800209962Smm * snapshots. 801209962Smm */ 802185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 803185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 804185029Spjd "this property can not be modified for snapshots")); 805185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 806185029Spjd goto error; 807185029Spjd } 808168404Spjd 809209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 810209962Smm zfs_userquota_prop_t uqtype; 811209962Smm char newpropname[128]; 812209962Smm char domain[128]; 813209962Smm uint64_t rid; 814209962Smm uint64_t valary[3]; 815209962Smm 816209962Smm if (userquota_propname_decode(propname, zoned, 817209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 818209962Smm zfs_error_aux(hdl, 819209962Smm dgettext(TEXT_DOMAIN, 820209962Smm "'%s' has an invalid user/group name"), 821209962Smm propname); 822209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 823209962Smm goto error; 824209962Smm } 825209962Smm 826209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 827209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 828209962Smm zfs_error_aux(hdl, 829209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 830209962Smm propname); 831209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 832209962Smm errbuf); 833209962Smm goto error; 834209962Smm } 835209962Smm 836209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 837209962Smm (void) nvpair_value_string(elem, &strval); 838209962Smm if (strcmp(strval, "none") == 0) { 839209962Smm intval = 0; 840209962Smm } else if (zfs_nicestrtonum(hdl, 841209962Smm strval, &intval) != 0) { 842209962Smm (void) zfs_error(hdl, 843209962Smm EZFS_BADPROP, errbuf); 844209962Smm goto error; 845209962Smm } 846209962Smm } else if (nvpair_type(elem) == 847209962Smm DATA_TYPE_UINT64) { 848209962Smm (void) nvpair_value_uint64(elem, &intval); 849209962Smm if (intval == 0) { 850209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 851209962Smm "use 'none' to disable " 852209962Smm "userquota/groupquota")); 853209962Smm goto error; 854209962Smm } 855209962Smm } else { 856209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 857209962Smm "'%s' must be a number"), propname); 858209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 859209962Smm goto error; 860209962Smm } 861209962Smm 862219089Spjd /* 863219089Spjd * Encode the prop name as 864219089Spjd * userquota@<hex-rid>-domain, to make it easy 865219089Spjd * for the kernel to decode. 866219089Spjd */ 867209962Smm (void) snprintf(newpropname, sizeof (newpropname), 868219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 869219089Spjd (longlong_t)rid, domain); 870209962Smm valary[0] = uqtype; 871209962Smm valary[1] = rid; 872209962Smm valary[2] = intval; 873209962Smm if (nvlist_add_uint64_array(ret, newpropname, 874209962Smm valary, 3) != 0) { 875209962Smm (void) no_memory(hdl); 876209962Smm goto error; 877209962Smm } 878209962Smm continue; 879209962Smm } 880209962Smm 881209962Smm if (prop == ZPROP_INVAL) { 882209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 883209962Smm "invalid property '%s'"), propname); 884209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 885209962Smm goto error; 886209962Smm } 887209962Smm 888168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 889168404Spjd zfs_error_aux(hdl, 890168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 891168404Spjd "apply to datasets of this type"), propname); 892168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 893168404Spjd goto error; 894168404Spjd } 895168404Spjd 896168404Spjd if (zfs_prop_readonly(prop) && 897185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 898168404Spjd zfs_error_aux(hdl, 899168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 900168404Spjd propname); 901168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 902168404Spjd goto error; 903168404Spjd } 904168404Spjd 905185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 906185029Spjd &strval, &intval, errbuf) != 0) 907185029Spjd goto error; 908185029Spjd 909168404Spjd /* 910185029Spjd * Perform some additional checks for specific properties. 911168404Spjd */ 912185029Spjd switch (prop) { 913185029Spjd case ZFS_PROP_VERSION: 914185029Spjd { 915185029Spjd int version; 916168404Spjd 917185029Spjd if (zhp == NULL) 918185029Spjd break; 919185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 920185029Spjd if (intval < version) { 921168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 922185029Spjd "Can not downgrade; already at version %u"), 923185029Spjd version); 924168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 925168404Spjd goto error; 926168404Spjd } 927168404Spjd break; 928168404Spjd } 929168404Spjd 930168404Spjd case ZFS_PROP_RECORDSIZE: 931168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 932168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 933168404Spjd if (intval < SPA_MINBLOCKSIZE || 934168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 935168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 936168404Spjd "'%s' must be power of 2 from %u " 937168404Spjd "to %uk"), propname, 938168404Spjd (uint_t)SPA_MINBLOCKSIZE, 939168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 940168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 941168404Spjd goto error; 942168404Spjd } 943168404Spjd break; 944168404Spjd 945219089Spjd case ZFS_PROP_MLSLABEL: 946219089Spjd { 947219089Spjd#ifdef sun 948219089Spjd /* 949219089Spjd * Verify the mlslabel string and convert to 950219089Spjd * internal hex label string. 951219089Spjd */ 952219089Spjd 953219089Spjd m_label_t *new_sl; 954219089Spjd char *hex = NULL; /* internal label string */ 955219089Spjd 956219089Spjd /* Default value is already OK. */ 957219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 958219089Spjd break; 959219089Spjd 960219089Spjd /* Verify the label can be converted to binary form */ 961219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 962219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 963219089Spjd L_NO_CORRECTION, NULL) == -1)) { 964219089Spjd goto badlabel; 965168404Spjd } 966168404Spjd 967219089Spjd /* Now translate to hex internal label string */ 968219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 969219089Spjd DEF_NAMES) != 0) { 970219089Spjd if (hex) 971219089Spjd free(hex); 972219089Spjd goto badlabel; 973219089Spjd } 974219089Spjd m_label_free(new_sl); 975219089Spjd 976219089Spjd /* If string is already in internal form, we're done. */ 977219089Spjd if (strcmp(strval, hex) == 0) { 978219089Spjd free(hex); 979219089Spjd break; 980219089Spjd } 981219089Spjd 982219089Spjd /* Replace the label string with the internal form. */ 983219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 984219089Spjd DATA_TYPE_STRING); 985219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 986219089Spjd hex) == 0); 987219089Spjd free(hex); 988219089Spjd 989168404Spjd break; 990168404Spjd 991219089Spjdbadlabel: 992219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 993219089Spjd "invalid mlslabel '%s'"), strval); 994219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 995219089Spjd m_label_free(new_sl); /* OK if null */ 996219089Spjd#else /* !sun */ 997219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 998219089Spjd "mlslabel is not supported on FreeBSD")); 999219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1000219089Spjd#endif /* !sun */ 1001219089Spjd goto error; 1002219089Spjd 1003219089Spjd } 1004219089Spjd 1005168404Spjd case ZFS_PROP_MOUNTPOINT: 1006185029Spjd { 1007185029Spjd namecheck_err_t why; 1008185029Spjd 1009168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1010168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1011168404Spjd break; 1012168404Spjd 1013185029Spjd if (mountpoint_namecheck(strval, &why)) { 1014185029Spjd switch (why) { 1015185029Spjd case NAME_ERR_LEADING_SLASH: 1016185029Spjd zfs_error_aux(hdl, 1017185029Spjd dgettext(TEXT_DOMAIN, 1018185029Spjd "'%s' must be an absolute path, " 1019185029Spjd "'none', or 'legacy'"), propname); 1020185029Spjd break; 1021185029Spjd case NAME_ERR_TOOLONG: 1022185029Spjd zfs_error_aux(hdl, 1023185029Spjd dgettext(TEXT_DOMAIN, 1024185029Spjd "component of '%s' is too long"), 1025185029Spjd propname); 1026185029Spjd break; 1027185029Spjd } 1028168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1029168404Spjd goto error; 1030168404Spjd } 1031185029Spjd } 1032185029Spjd 1033168404Spjd /*FALLTHRU*/ 1034168404Spjd 1035185029Spjd case ZFS_PROP_SHARESMB: 1036168404Spjd case ZFS_PROP_SHARENFS: 1037168404Spjd /* 1038185029Spjd * For the mountpoint and sharenfs or sharesmb 1039185029Spjd * properties, check if it can be set in a 1040185029Spjd * global/non-global zone based on 1041168404Spjd * the zoned property value: 1042168404Spjd * 1043168404Spjd * global zone non-global zone 1044168404Spjd * -------------------------------------------------- 1045168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1046168404Spjd * sharenfs (no) sharenfs (no) 1047185029Spjd * sharesmb (no) sharesmb (no) 1048168404Spjd * 1049168404Spjd * zoned=off mountpoint (yes) N/A 1050168404Spjd * sharenfs (yes) 1051185029Spjd * sharesmb (yes) 1052168404Spjd */ 1053168404Spjd if (zoned) { 1054168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1055168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1056168404Spjd "'%s' cannot be set on " 1057168404Spjd "dataset in a non-global zone"), 1058168404Spjd propname); 1059168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1060168404Spjd errbuf); 1061168404Spjd goto error; 1062185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1063185029Spjd prop == ZFS_PROP_SHARESMB) { 1064168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1065168404Spjd "'%s' cannot be set in " 1066168404Spjd "a non-global zone"), propname); 1067168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1068168404Spjd errbuf); 1069168404Spjd goto error; 1070168404Spjd } 1071168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1072168404Spjd /* 1073168404Spjd * If zoned property is 'off', this must be in 1074209962Smm * a global zone. If not, something is wrong. 1075168404Spjd */ 1076168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1077168404Spjd "'%s' cannot be set while dataset " 1078168404Spjd "'zoned' property is set"), propname); 1079168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1080168404Spjd goto error; 1081168404Spjd } 1082168404Spjd 1083168404Spjd /* 1084185029Spjd * At this point, it is legitimate to set the 1085185029Spjd * property. Now we want to make sure that the 1086185029Spjd * property value is valid if it is sharenfs. 1087168404Spjd */ 1088185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1089185029Spjd prop == ZFS_PROP_SHARESMB) && 1090185029Spjd strcmp(strval, "on") != 0 && 1091185029Spjd strcmp(strval, "off") != 0) { 1092185029Spjd zfs_share_proto_t proto; 1093168404Spjd 1094185029Spjd if (prop == ZFS_PROP_SHARESMB) 1095185029Spjd proto = PROTO_SMB; 1096185029Spjd else 1097185029Spjd proto = PROTO_NFS; 1098185029Spjd 1099185029Spjd /* 1100185029Spjd * Must be an valid sharing protocol 1101185029Spjd * option string so init the libshare 1102185029Spjd * in order to enable the parser and 1103185029Spjd * then parse the options. We use the 1104185029Spjd * control API since we don't care about 1105185029Spjd * the current configuration and don't 1106185029Spjd * want the overhead of loading it 1107185029Spjd * until we actually do something. 1108185029Spjd */ 1109185029Spjd 1110185029Spjd if (zfs_init_libshare(hdl, 1111185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1112185029Spjd /* 1113185029Spjd * An error occurred so we can't do 1114185029Spjd * anything 1115185029Spjd */ 1116185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1117185029Spjd "'%s' cannot be set: problem " 1118185029Spjd "in share initialization"), 1119185029Spjd propname); 1120185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1121185029Spjd errbuf); 1122185029Spjd goto error; 1123185029Spjd } 1124185029Spjd 1125185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1126185029Spjd /* 1127185029Spjd * There was an error in parsing so 1128185029Spjd * deal with it by issuing an error 1129185029Spjd * message and leaving after 1130185029Spjd * uninitializing the the libshare 1131185029Spjd * interface. 1132185029Spjd */ 1133185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1134185029Spjd "'%s' cannot be set to invalid " 1135185029Spjd "options"), propname); 1136185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1137185029Spjd errbuf); 1138185029Spjd zfs_uninit_libshare(hdl); 1139185029Spjd goto error; 1140185029Spjd } 1141185029Spjd zfs_uninit_libshare(hdl); 1142168404Spjd } 1143185029Spjd 1144168404Spjd break; 1145185029Spjd case ZFS_PROP_UTF8ONLY: 1146185029Spjd chosen_utf = (int)intval; 1147185029Spjd break; 1148185029Spjd case ZFS_PROP_NORMALIZE: 1149185029Spjd chosen_normal = (int)intval; 1150185029Spjd break; 1151168404Spjd } 1152168404Spjd 1153168404Spjd /* 1154168404Spjd * For changes to existing volumes, we have some additional 1155168404Spjd * checks to enforce. 1156168404Spjd */ 1157168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1158168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1159168404Spjd ZFS_PROP_VOLSIZE); 1160168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1161168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1162168404Spjd char buf[64]; 1163168404Spjd 1164168404Spjd switch (prop) { 1165168404Spjd case ZFS_PROP_RESERVATION: 1166185029Spjd case ZFS_PROP_REFRESERVATION: 1167168404Spjd if (intval > volsize) { 1168168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1169168404Spjd "'%s' is greater than current " 1170168404Spjd "volume size"), propname); 1171168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1172168404Spjd errbuf); 1173168404Spjd goto error; 1174168404Spjd } 1175168404Spjd break; 1176168404Spjd 1177168404Spjd case ZFS_PROP_VOLSIZE: 1178168404Spjd if (intval % blocksize != 0) { 1179168404Spjd zfs_nicenum(blocksize, buf, 1180168404Spjd sizeof (buf)); 1181168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1182168404Spjd "'%s' must be a multiple of " 1183168404Spjd "volume block size (%s)"), 1184168404Spjd propname, buf); 1185168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1186168404Spjd errbuf); 1187168404Spjd goto error; 1188168404Spjd } 1189168404Spjd 1190168404Spjd if (intval == 0) { 1191168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1192168404Spjd "'%s' cannot be zero"), 1193168404Spjd propname); 1194168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1195168404Spjd errbuf); 1196168404Spjd goto error; 1197168404Spjd } 1198168404Spjd break; 1199168404Spjd } 1200168404Spjd } 1201168404Spjd } 1202168404Spjd 1203168404Spjd /* 1204185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1205185029Spjd * enforce rejection of non-UTF8 names. 1206185029Spjd * 1207185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1208185029Spjd * was explicitly not chosen, it is an error. 1209185029Spjd */ 1210185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1211185029Spjd if (nvlist_add_uint64(ret, 1212185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1213185029Spjd (void) no_memory(hdl); 1214185029Spjd goto error; 1215185029Spjd } 1216185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1217185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1218185029Spjd "'%s' must be set 'on' if normalization chosen"), 1219185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1220185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1221185029Spjd goto error; 1222185029Spjd } 1223219089Spjd return (ret); 1224185029Spjd 1225219089Spjderror: 1226219089Spjd nvlist_free(ret); 1227219089Spjd return (NULL); 1228219089Spjd} 1229219089Spjd 1230219089Spjdint 1231219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1232219089Spjd{ 1233219089Spjd uint64_t old_volsize; 1234219089Spjd uint64_t new_volsize; 1235219089Spjd uint64_t old_reservation; 1236219089Spjd uint64_t new_reservation; 1237219089Spjd zfs_prop_t resv_prop; 1238219089Spjd 1239185029Spjd /* 1240168404Spjd * If this is an existing volume, and someone is setting the volsize, 1241168404Spjd * make sure that it matches the reservation, or add it if necessary. 1242168404Spjd */ 1243219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1244219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1245219089Spjd return (-1); 1246219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1247219089Spjd if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != 1248219089Spjd old_reservation) || nvlist_lookup_uint64(nvl, 1249219089Spjd zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { 1250219089Spjd return (0); 1251219089Spjd } 1252219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1253219089Spjd &new_volsize) != 0) 1254219089Spjd return (-1); 1255219089Spjd new_reservation = zvol_volsize_to_reservation(new_volsize, 1256219089Spjd zhp->zfs_props); 1257219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1258219089Spjd new_reservation) != 0) { 1259219089Spjd (void) no_memory(zhp->zfs_hdl); 1260219089Spjd return (-1); 1261219089Spjd } 1262219089Spjd return (1); 1263219089Spjd} 1264168404Spjd 1265219089Spjdvoid 1266219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1267219089Spjd char *errbuf) 1268219089Spjd{ 1269219089Spjd switch (err) { 1270185029Spjd 1271219089Spjd case ENOSPC: 1272219089Spjd /* 1273219089Spjd * For quotas and reservations, ENOSPC indicates 1274219089Spjd * something different; setting a quota or reservation 1275219089Spjd * doesn't use any disk space. 1276219089Spjd */ 1277219089Spjd switch (prop) { 1278219089Spjd case ZFS_PROP_QUOTA: 1279219089Spjd case ZFS_PROP_REFQUOTA: 1280219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1281219089Spjd "size is less than current used or " 1282219089Spjd "reserved space")); 1283219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1284219089Spjd break; 1285219089Spjd 1286219089Spjd case ZFS_PROP_RESERVATION: 1287219089Spjd case ZFS_PROP_REFRESERVATION: 1288219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1289219089Spjd "size is greater than available space")); 1290219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1291219089Spjd break; 1292219089Spjd 1293219089Spjd default: 1294219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1295219089Spjd break; 1296168404Spjd } 1297219089Spjd break; 1298219089Spjd 1299219089Spjd case EBUSY: 1300219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1301219089Spjd break; 1302219089Spjd 1303219089Spjd case EROFS: 1304219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1305219089Spjd break; 1306219089Spjd 1307219089Spjd case ENOTSUP: 1308219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1309219089Spjd "pool and or dataset must be upgraded to set this " 1310219089Spjd "property or value")); 1311219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1312219089Spjd break; 1313219089Spjd 1314219089Spjd case ERANGE: 1315219089Spjd if (prop == ZFS_PROP_COMPRESSION) { 1316219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1317219089Spjd "property setting is not allowed on " 1318219089Spjd "bootable datasets")); 1319219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1320219089Spjd } else { 1321219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1322219089Spjd } 1323219089Spjd break; 1324219089Spjd 1325219089Spjd case EINVAL: 1326219089Spjd if (prop == ZPROP_INVAL) { 1327219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1328219089Spjd } else { 1329219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1330219089Spjd } 1331219089Spjd break; 1332219089Spjd 1333219089Spjd case EOVERFLOW: 1334219089Spjd /* 1335219089Spjd * This platform can't address a volume this big. 1336219089Spjd */ 1337219089Spjd#ifdef _ILP32 1338219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1339219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1340219089Spjd break; 1341219089Spjd } 1342219089Spjd#endif 1343219089Spjd /* FALLTHROUGH */ 1344219089Spjd default: 1345219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1346168404Spjd } 1347168404Spjd} 1348168404Spjd 1349168404Spjd/* 1350168404Spjd * Given a property name and value, set the property for the given dataset. 1351168404Spjd */ 1352168404Spjdint 1353168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1354168404Spjd{ 1355168404Spjd zfs_cmd_t zc = { 0 }; 1356168404Spjd int ret = -1; 1357168404Spjd prop_changelist_t *cl = NULL; 1358168404Spjd char errbuf[1024]; 1359168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1360168404Spjd nvlist_t *nvl = NULL, *realprops; 1361168404Spjd zfs_prop_t prop; 1362185029Spjd boolean_t do_prefix; 1363185029Spjd uint64_t idx; 1364219089Spjd int added_resv; 1365168404Spjd 1366168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1367168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1368168404Spjd zhp->zfs_name); 1369168404Spjd 1370168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1371168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1372168404Spjd (void) no_memory(hdl); 1373168404Spjd goto error; 1374168404Spjd } 1375168404Spjd 1376185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1377168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1378168404Spjd goto error; 1379185029Spjd 1380168404Spjd nvlist_free(nvl); 1381168404Spjd nvl = realprops; 1382168404Spjd 1383168404Spjd prop = zfs_name_to_prop(propname); 1384168404Spjd 1385168404Spjd /* We don't support those properties on FreeBSD. */ 1386168404Spjd switch (prop) { 1387197867Strasz case ZFS_PROP_DEVICES: 1388168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1389197867Strasz case ZFS_PROP_XATTR: 1390197867Strasz case ZFS_PROP_VSCAN: 1391197867Strasz case ZFS_PROP_NBMAND: 1392219089Spjd case ZFS_PROP_MLSLABEL: 1393168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1394168404Spjd "property '%s' not supported on FreeBSD", propname); 1395168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1396168404Spjd goto error; 1397168404Spjd } 1398168404Spjd 1399219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1400219089Spjd if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) 1401219089Spjd goto error; 1402219089Spjd } 1403219089Spjd 1404185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1405168404Spjd goto error; 1406168404Spjd 1407168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1408168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1409168404Spjd "child dataset with inherited mountpoint is used " 1410168404Spjd "in a non-global zone")); 1411168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1412168404Spjd goto error; 1413168404Spjd } 1414168404Spjd 1415185029Spjd /* 1416185029Spjd * If the dataset's canmount property is being set to noauto, 1417185029Spjd * then we want to prevent unmounting & remounting it. 1418185029Spjd */ 1419185029Spjd do_prefix = !((prop == ZFS_PROP_CANMOUNT) && 1420185029Spjd (zprop_string_to_index(prop, propval, &idx, 1421185029Spjd ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); 1422185029Spjd 1423185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1424168404Spjd goto error; 1425168404Spjd 1426168404Spjd /* 1427168404Spjd * Execute the corresponding ioctl() to set this property. 1428168404Spjd */ 1429168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1430168404Spjd 1431185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1432168404Spjd goto error; 1433168404Spjd 1434185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1435209962Smm 1436168404Spjd if (ret != 0) { 1437219089Spjd zfs_setprop_error(hdl, prop, errno, errbuf); 1438219089Spjd if (added_resv && errno == ENOSPC) { 1439219089Spjd /* clean up the volsize property we tried to set */ 1440219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1441219089Spjd ZFS_PROP_VOLSIZE); 1442219089Spjd nvlist_free(nvl); 1443219089Spjd zcmd_free_nvlists(&zc); 1444219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1445219089Spjd goto error; 1446219089Spjd if (nvlist_add_uint64(nvl, 1447219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1448219089Spjd old_volsize) != 0) 1449219089Spjd goto error; 1450219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1451219089Spjd goto error; 1452219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1453168404Spjd } 1454168404Spjd } else { 1455185029Spjd if (do_prefix) 1456185029Spjd ret = changelist_postfix(cl); 1457185029Spjd 1458168404Spjd /* 1459168404Spjd * Refresh the statistics so the new property value 1460168404Spjd * is reflected. 1461168404Spjd */ 1462185029Spjd if (ret == 0) 1463168404Spjd (void) get_stats(zhp); 1464168404Spjd } 1465168404Spjd 1466168404Spjderror: 1467168404Spjd nvlist_free(nvl); 1468168404Spjd zcmd_free_nvlists(&zc); 1469168404Spjd if (cl) 1470168404Spjd changelist_free(cl); 1471168404Spjd return (ret); 1472168404Spjd} 1473168404Spjd 1474168404Spjd/* 1475219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1476219089Spjd * is TRUE, revert to the received value, if any. 1477168404Spjd */ 1478168404Spjdint 1479219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1480168404Spjd{ 1481168404Spjd zfs_cmd_t zc = { 0 }; 1482168404Spjd int ret; 1483168404Spjd prop_changelist_t *cl; 1484168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1485168404Spjd char errbuf[1024]; 1486168404Spjd zfs_prop_t prop; 1487168404Spjd 1488168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1489168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1490168404Spjd 1491219089Spjd zc.zc_cookie = received; 1492185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1493168404Spjd /* 1494168404Spjd * For user properties, the amount of work we have to do is very 1495168404Spjd * small, so just do it here. 1496168404Spjd */ 1497168404Spjd if (!zfs_prop_user(propname)) { 1498168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1499168404Spjd "invalid property")); 1500168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1501168404Spjd } 1502168404Spjd 1503168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1504168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1505168404Spjd 1506185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1507168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1508168404Spjd 1509168404Spjd return (0); 1510168404Spjd } 1511168404Spjd 1512168404Spjd /* 1513168404Spjd * Verify that this property is inheritable. 1514168404Spjd */ 1515168404Spjd if (zfs_prop_readonly(prop)) 1516168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1517168404Spjd 1518219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1519168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1520168404Spjd 1521168404Spjd /* 1522168404Spjd * Check to see if the value applies to this type 1523168404Spjd */ 1524168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1525168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1526168404Spjd 1527168404Spjd /* 1528219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1529168404Spjd */ 1530168404Spjd propname = zfs_prop_to_name(prop); 1531168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1532168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1533168404Spjd 1534168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1535168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1536168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1537168404Spjd "dataset is used in a non-global zone")); 1538168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1539168404Spjd } 1540168404Spjd 1541168404Spjd /* 1542168404Spjd * Determine datasets which will be affected by this change, if any. 1543168404Spjd */ 1544185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1545168404Spjd return (-1); 1546168404Spjd 1547168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1548168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1549168404Spjd "child dataset with inherited mountpoint is used " 1550168404Spjd "in a non-global zone")); 1551168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1552168404Spjd goto error; 1553168404Spjd } 1554168404Spjd 1555168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1556168404Spjd goto error; 1557168404Spjd 1558185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1559168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1560168404Spjd } else { 1561168404Spjd 1562168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1563168404Spjd goto error; 1564168404Spjd 1565168404Spjd /* 1566168404Spjd * Refresh the statistics so the new property is reflected. 1567168404Spjd */ 1568168404Spjd (void) get_stats(zhp); 1569168404Spjd } 1570168404Spjd 1571168404Spjderror: 1572168404Spjd changelist_free(cl); 1573168404Spjd return (ret); 1574168404Spjd} 1575168404Spjd 1576168404Spjd/* 1577168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1578168404Spjd * extract them appropriately. 1579168404Spjd */ 1580168404Spjdstatic uint64_t 1581168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1582168404Spjd{ 1583168404Spjd nvlist_t *nv; 1584168404Spjd uint64_t value; 1585168404Spjd 1586168404Spjd *source = NULL; 1587168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1588168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1589185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1590185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1591168404Spjd } else { 1592205198Sdelphij verify(!zhp->zfs_props_table || 1593205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1594168404Spjd value = zfs_prop_default_numeric(prop); 1595168404Spjd *source = ""; 1596168404Spjd } 1597168404Spjd 1598168404Spjd return (value); 1599168404Spjd} 1600168404Spjd 1601168404Spjdstatic char * 1602168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1603168404Spjd{ 1604168404Spjd nvlist_t *nv; 1605168404Spjd char *value; 1606168404Spjd 1607168404Spjd *source = NULL; 1608168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1609168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1610185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1611185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1612168404Spjd } else { 1613205198Sdelphij verify(!zhp->zfs_props_table || 1614205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1615168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1616168404Spjd value = ""; 1617168404Spjd *source = ""; 1618168404Spjd } 1619168404Spjd 1620168404Spjd return (value); 1621168404Spjd} 1622168404Spjd 1623219089Spjdstatic boolean_t 1624219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1625219089Spjd{ 1626219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1627219089Spjd} 1628219089Spjd 1629219089Spjdstatic void 1630219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1631219089Spjd{ 1632219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1633219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1634219089Spjd} 1635219089Spjd 1636219089Spjdstatic void 1637219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1638219089Spjd{ 1639219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1640219089Spjd *cookie = 0; 1641219089Spjd} 1642219089Spjd 1643168404Spjd/* 1644168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1645168404Spjd * zfs_prop_get_int() are built using this interface. 1646168404Spjd * 1647168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1648168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1649168404Spjd * If they differ from the on-disk values, report the current values and mark 1650168404Spjd * the source "temporary". 1651168404Spjd */ 1652168404Spjdstatic int 1653185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1654168404Spjd char **source, uint64_t *val) 1655168404Spjd{ 1656185029Spjd zfs_cmd_t zc = { 0 }; 1657185029Spjd nvlist_t *zplprops = NULL; 1658168404Spjd struct mnttab mnt; 1659168404Spjd char *mntopt_on = NULL; 1660168404Spjd char *mntopt_off = NULL; 1661219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1662168404Spjd 1663168404Spjd *source = NULL; 1664168404Spjd 1665168404Spjd switch (prop) { 1666168404Spjd case ZFS_PROP_ATIME: 1667168404Spjd mntopt_on = MNTOPT_ATIME; 1668168404Spjd mntopt_off = MNTOPT_NOATIME; 1669168404Spjd break; 1670168404Spjd 1671168404Spjd case ZFS_PROP_DEVICES: 1672168404Spjd mntopt_on = MNTOPT_DEVICES; 1673168404Spjd mntopt_off = MNTOPT_NODEVICES; 1674168404Spjd break; 1675168404Spjd 1676168404Spjd case ZFS_PROP_EXEC: 1677168404Spjd mntopt_on = MNTOPT_EXEC; 1678168404Spjd mntopt_off = MNTOPT_NOEXEC; 1679168404Spjd break; 1680168404Spjd 1681168404Spjd case ZFS_PROP_READONLY: 1682168404Spjd mntopt_on = MNTOPT_RO; 1683168404Spjd mntopt_off = MNTOPT_RW; 1684168404Spjd break; 1685168404Spjd 1686168404Spjd case ZFS_PROP_SETUID: 1687168404Spjd mntopt_on = MNTOPT_SETUID; 1688168404Spjd mntopt_off = MNTOPT_NOSETUID; 1689168404Spjd break; 1690168404Spjd 1691168404Spjd case ZFS_PROP_XATTR: 1692168404Spjd mntopt_on = MNTOPT_XATTR; 1693168404Spjd mntopt_off = MNTOPT_NOXATTR; 1694168404Spjd break; 1695185029Spjd 1696185029Spjd case ZFS_PROP_NBMAND: 1697185029Spjd mntopt_on = MNTOPT_NBMAND; 1698185029Spjd mntopt_off = MNTOPT_NONBMAND; 1699185029Spjd break; 1700168404Spjd } 1701168404Spjd 1702168404Spjd /* 1703168404Spjd * Because looking up the mount options is potentially expensive 1704168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1705168404Spjd * we're looking up a property which requires its presence. 1706168404Spjd */ 1707168404Spjd if (!zhp->zfs_mntcheck && 1708168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1709209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1710209962Smm struct mnttab entry; 1711168404Spjd 1712209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1713209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1714168404Spjd entry.mnt_mntopts); 1715168404Spjd if (zhp->zfs_mntopts == NULL) 1716168404Spjd return (-1); 1717168404Spjd } 1718168404Spjd 1719168404Spjd zhp->zfs_mntcheck = B_TRUE; 1720168404Spjd } 1721168404Spjd 1722168404Spjd if (zhp->zfs_mntopts == NULL) 1723168404Spjd mnt.mnt_mntopts = ""; 1724168404Spjd else 1725168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1726168404Spjd 1727168404Spjd switch (prop) { 1728168404Spjd case ZFS_PROP_ATIME: 1729168404Spjd case ZFS_PROP_DEVICES: 1730168404Spjd case ZFS_PROP_EXEC: 1731168404Spjd case ZFS_PROP_READONLY: 1732168404Spjd case ZFS_PROP_SETUID: 1733168404Spjd case ZFS_PROP_XATTR: 1734185029Spjd case ZFS_PROP_NBMAND: 1735168404Spjd *val = getprop_uint64(zhp, prop, source); 1736168404Spjd 1737219089Spjd if (received) 1738219089Spjd break; 1739219089Spjd 1740168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1741168404Spjd *val = B_TRUE; 1742168404Spjd if (src) 1743185029Spjd *src = ZPROP_SRC_TEMPORARY; 1744168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1745168404Spjd *val = B_FALSE; 1746168404Spjd if (src) 1747185029Spjd *src = ZPROP_SRC_TEMPORARY; 1748168404Spjd } 1749168404Spjd break; 1750168404Spjd 1751168404Spjd case ZFS_PROP_CANMOUNT: 1752219089Spjd case ZFS_PROP_VOLSIZE: 1753168404Spjd case ZFS_PROP_QUOTA: 1754185029Spjd case ZFS_PROP_REFQUOTA: 1755168404Spjd case ZFS_PROP_RESERVATION: 1756185029Spjd case ZFS_PROP_REFRESERVATION: 1757168404Spjd *val = getprop_uint64(zhp, prop, source); 1758219089Spjd 1759219089Spjd if (*source == NULL) { 1760219089Spjd /* not default, must be local */ 1761168404Spjd *source = zhp->zfs_name; 1762219089Spjd } 1763168404Spjd break; 1764168404Spjd 1765168404Spjd case ZFS_PROP_MOUNTED: 1766168404Spjd *val = (zhp->zfs_mntopts != NULL); 1767168404Spjd break; 1768168404Spjd 1769168404Spjd case ZFS_PROP_NUMCLONES: 1770168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1771168404Spjd break; 1772168404Spjd 1773185029Spjd case ZFS_PROP_VERSION: 1774185029Spjd case ZFS_PROP_NORMALIZE: 1775185029Spjd case ZFS_PROP_UTF8ONLY: 1776185029Spjd case ZFS_PROP_CASE: 1777185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1778185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1779185029Spjd return (-1); 1780185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1781185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1782185029Spjd zcmd_free_nvlists(&zc); 1783219089Spjd return (-1); 1784185029Spjd } 1785185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1786185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1787185029Spjd val) != 0) { 1788185029Spjd zcmd_free_nvlists(&zc); 1789219089Spjd return (-1); 1790185029Spjd } 1791185029Spjd if (zplprops) 1792185029Spjd nvlist_free(zplprops); 1793185029Spjd zcmd_free_nvlists(&zc); 1794185029Spjd break; 1795185029Spjd 1796168404Spjd default: 1797185029Spjd switch (zfs_prop_get_type(prop)) { 1798185029Spjd case PROP_TYPE_NUMBER: 1799185029Spjd case PROP_TYPE_INDEX: 1800185029Spjd *val = getprop_uint64(zhp, prop, source); 1801185029Spjd /* 1802209962Smm * If we tried to use a default value for a 1803185029Spjd * readonly property, it means that it was not 1804219089Spjd * present. 1805185029Spjd */ 1806185029Spjd if (zfs_prop_readonly(prop) && 1807219089Spjd *source != NULL && (*source)[0] == '\0') { 1808219089Spjd *source = NULL; 1809185029Spjd } 1810185029Spjd break; 1811185029Spjd 1812185029Spjd case PROP_TYPE_STRING: 1813185029Spjd default: 1814185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1815185029Spjd "cannot get non-numeric property")); 1816185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1817185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1818185029Spjd } 1819168404Spjd } 1820168404Spjd 1821168404Spjd return (0); 1822168404Spjd} 1823168404Spjd 1824168404Spjd/* 1825168404Spjd * Calculate the source type, given the raw source string. 1826168404Spjd */ 1827168404Spjdstatic void 1828185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1829168404Spjd char *statbuf, size_t statlen) 1830168404Spjd{ 1831185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1832168404Spjd return; 1833168404Spjd 1834168404Spjd if (source == NULL) { 1835185029Spjd *srctype = ZPROP_SRC_NONE; 1836168404Spjd } else if (source[0] == '\0') { 1837185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1838219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 1839219089Spjd *srctype = ZPROP_SRC_RECEIVED; 1840168404Spjd } else { 1841168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1842185029Spjd *srctype = ZPROP_SRC_LOCAL; 1843168404Spjd } else { 1844168404Spjd (void) strlcpy(statbuf, source, statlen); 1845185029Spjd *srctype = ZPROP_SRC_INHERITED; 1846168404Spjd } 1847168404Spjd } 1848168404Spjd 1849168404Spjd} 1850168404Spjd 1851219089Spjdint 1852219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 1853219089Spjd size_t proplen, boolean_t literal) 1854219089Spjd{ 1855219089Spjd zfs_prop_t prop; 1856219089Spjd int err = 0; 1857219089Spjd 1858219089Spjd if (zhp->zfs_recvd_props == NULL) 1859219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 1860219089Spjd return (-1); 1861219089Spjd 1862219089Spjd prop = zfs_name_to_prop(propname); 1863219089Spjd 1864219089Spjd if (prop != ZPROP_INVAL) { 1865219089Spjd uint64_t cookie; 1866219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 1867219089Spjd return (-1); 1868219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 1869219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 1870219089Spjd NULL, NULL, 0, literal); 1871219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 1872219089Spjd } else if (zfs_prop_userquota(propname)) { 1873219089Spjd return (-1); 1874219089Spjd } else { 1875219089Spjd nvlist_t *propval; 1876219089Spjd char *recvdval; 1877219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 1878219089Spjd propname, &propval) != 0) 1879219089Spjd return (-1); 1880219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 1881219089Spjd &recvdval) == 0); 1882219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 1883219089Spjd } 1884219089Spjd 1885219089Spjd return (err == 0 ? 0 : -1); 1886219089Spjd} 1887219089Spjd 1888168404Spjd/* 1889168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 1890168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 1891168404Spjd * human-readable form. 1892168404Spjd * 1893168404Spjd * Returns 0 on success, or -1 on error. 1894168404Spjd */ 1895168404Spjdint 1896168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1897185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1898168404Spjd{ 1899168404Spjd char *source = NULL; 1900168404Spjd uint64_t val; 1901168404Spjd char *str; 1902168404Spjd const char *strval; 1903219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1904168404Spjd 1905168404Spjd /* 1906168404Spjd * Check to see if this property applies to our object 1907168404Spjd */ 1908168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1909168404Spjd return (-1); 1910168404Spjd 1911219089Spjd if (received && zfs_prop_readonly(prop)) 1912219089Spjd return (-1); 1913219089Spjd 1914168404Spjd if (src) 1915185029Spjd *src = ZPROP_SRC_NONE; 1916168404Spjd 1917168404Spjd switch (prop) { 1918168404Spjd case ZFS_PROP_CREATION: 1919168404Spjd /* 1920168404Spjd * 'creation' is a time_t stored in the statistics. We convert 1921168404Spjd * this into a string unless 'literal' is specified. 1922168404Spjd */ 1923168404Spjd { 1924168404Spjd val = getprop_uint64(zhp, prop, &source); 1925168404Spjd time_t time = (time_t)val; 1926168404Spjd struct tm t; 1927168404Spjd 1928168404Spjd if (literal || 1929168404Spjd localtime_r(&time, &t) == NULL || 1930168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1931168404Spjd &t) == 0) 1932168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 1933168404Spjd } 1934168404Spjd break; 1935168404Spjd 1936168404Spjd case ZFS_PROP_MOUNTPOINT: 1937168404Spjd /* 1938168404Spjd * Getting the precise mountpoint can be tricky. 1939168404Spjd * 1940168404Spjd * - for 'none' or 'legacy', return those values. 1941168404Spjd * - for inherited mountpoints, we want to take everything 1942168404Spjd * after our ancestor and append it to the inherited value. 1943168404Spjd * 1944168404Spjd * If the pool has an alternate root, we want to prepend that 1945168404Spjd * root to any values we return. 1946168404Spjd */ 1947185029Spjd 1948168404Spjd str = getprop_string(zhp, prop, &source); 1949168404Spjd 1950185029Spjd if (str[0] == '/') { 1951185029Spjd char buf[MAXPATHLEN]; 1952185029Spjd char *root = buf; 1953219089Spjd const char *relpath; 1954168404Spjd 1955219089Spjd /* 1956219089Spjd * If we inherit the mountpoint, even from a dataset 1957219089Spjd * with a received value, the source will be the path of 1958219089Spjd * the dataset we inherit from. If source is 1959219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 1960219089Spjd * inherited. 1961219089Spjd */ 1962219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 1963219089Spjd relpath = ""; 1964219089Spjd } else { 1965219089Spjd relpath = zhp->zfs_name + strlen(source); 1966219089Spjd if (relpath[0] == '/') 1967219089Spjd relpath++; 1968219089Spjd } 1969185029Spjd 1970185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 1971185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 1972185029Spjd (strcmp(root, "-") == 0)) 1973185029Spjd root[0] = '\0'; 1974185029Spjd /* 1975185029Spjd * Special case an alternate root of '/'. This will 1976185029Spjd * avoid having multiple leading slashes in the 1977185029Spjd * mountpoint path. 1978185029Spjd */ 1979185029Spjd if (strcmp(root, "/") == 0) 1980185029Spjd root++; 1981185029Spjd 1982185029Spjd /* 1983185029Spjd * If the mountpoint is '/' then skip over this 1984185029Spjd * if we are obtaining either an alternate root or 1985185029Spjd * an inherited mountpoint. 1986185029Spjd */ 1987185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 1988185029Spjd relpath[0] != '\0')) 1989168404Spjd str++; 1990168404Spjd 1991168404Spjd if (relpath[0] == '\0') 1992168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 1993168404Spjd root, str); 1994168404Spjd else 1995168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 1996168404Spjd root, str, relpath[0] == '@' ? "" : "/", 1997168404Spjd relpath); 1998168404Spjd } else { 1999168404Spjd /* 'legacy' or 'none' */ 2000168404Spjd (void) strlcpy(propbuf, str, proplen); 2001168404Spjd } 2002168404Spjd 2003168404Spjd break; 2004168404Spjd 2005168404Spjd case ZFS_PROP_ORIGIN: 2006168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2007168404Spjd proplen); 2008168404Spjd /* 2009168404Spjd * If there is no parent at all, return failure to indicate that 2010168404Spjd * it doesn't apply to this dataset. 2011168404Spjd */ 2012168404Spjd if (propbuf[0] == '\0') 2013168404Spjd return (-1); 2014168404Spjd break; 2015168404Spjd 2016168404Spjd case ZFS_PROP_QUOTA: 2017185029Spjd case ZFS_PROP_REFQUOTA: 2018168404Spjd case ZFS_PROP_RESERVATION: 2019185029Spjd case ZFS_PROP_REFRESERVATION: 2020185029Spjd 2021168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2022168404Spjd return (-1); 2023168404Spjd 2024168404Spjd /* 2025168404Spjd * If quota or reservation is 0, we translate this into 'none' 2026168404Spjd * (unless literal is set), and indicate that it's the default 2027168404Spjd * value. Otherwise, we print the number nicely and indicate 2028168404Spjd * that its set locally. 2029168404Spjd */ 2030168404Spjd if (val == 0) { 2031168404Spjd if (literal) 2032168404Spjd (void) strlcpy(propbuf, "0", proplen); 2033168404Spjd else 2034168404Spjd (void) strlcpy(propbuf, "none", proplen); 2035168404Spjd } else { 2036168404Spjd if (literal) 2037168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2038168404Spjd (u_longlong_t)val); 2039168404Spjd else 2040168404Spjd zfs_nicenum(val, propbuf, proplen); 2041168404Spjd } 2042168404Spjd break; 2043168404Spjd 2044223623Smm case ZFS_PROP_REFRATIO: 2045168404Spjd case ZFS_PROP_COMPRESSRATIO: 2046168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2047168404Spjd return (-1); 2048219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2049219089Spjd (u_longlong_t)(val / 100), 2050219089Spjd (u_longlong_t)(val % 100)); 2051168404Spjd break; 2052168404Spjd 2053168404Spjd case ZFS_PROP_TYPE: 2054168404Spjd switch (zhp->zfs_type) { 2055168404Spjd case ZFS_TYPE_FILESYSTEM: 2056168404Spjd str = "filesystem"; 2057168404Spjd break; 2058168404Spjd case ZFS_TYPE_VOLUME: 2059168404Spjd str = "volume"; 2060168404Spjd break; 2061168404Spjd case ZFS_TYPE_SNAPSHOT: 2062168404Spjd str = "snapshot"; 2063168404Spjd break; 2064168404Spjd default: 2065168404Spjd abort(); 2066168404Spjd } 2067168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2068168404Spjd break; 2069168404Spjd 2070168404Spjd case ZFS_PROP_MOUNTED: 2071168404Spjd /* 2072168404Spjd * The 'mounted' property is a pseudo-property that described 2073168404Spjd * whether the filesystem is currently mounted. Even though 2074168404Spjd * it's a boolean value, the typical values of "on" and "off" 2075168404Spjd * don't make sense, so we translate to "yes" and "no". 2076168404Spjd */ 2077168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2078168404Spjd src, &source, &val) != 0) 2079168404Spjd return (-1); 2080168404Spjd if (val) 2081168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2082168404Spjd else 2083168404Spjd (void) strlcpy(propbuf, "no", proplen); 2084168404Spjd break; 2085168404Spjd 2086168404Spjd case ZFS_PROP_NAME: 2087168404Spjd /* 2088168404Spjd * The 'name' property is a pseudo-property derived from the 2089168404Spjd * dataset name. It is presented as a real property to simplify 2090168404Spjd * consumers. 2091168404Spjd */ 2092168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2093168404Spjd break; 2094168404Spjd 2095219089Spjd case ZFS_PROP_MLSLABEL: 2096219089Spjd { 2097219089Spjd#ifdef sun 2098219089Spjd m_label_t *new_sl = NULL; 2099219089Spjd char *ascii = NULL; /* human readable label */ 2100219089Spjd 2101219089Spjd (void) strlcpy(propbuf, 2102219089Spjd getprop_string(zhp, prop, &source), proplen); 2103219089Spjd 2104219089Spjd if (literal || (strcasecmp(propbuf, 2105219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2106219089Spjd break; 2107219089Spjd 2108219089Spjd /* 2109219089Spjd * Try to translate the internal hex string to 2110219089Spjd * human-readable output. If there are any 2111219089Spjd * problems just use the hex string. 2112219089Spjd */ 2113219089Spjd 2114219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2115219089Spjd L_NO_CORRECTION, NULL) == -1) { 2116219089Spjd m_label_free(new_sl); 2117219089Spjd break; 2118219089Spjd } 2119219089Spjd 2120219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2121219089Spjd DEF_NAMES) != 0) { 2122219089Spjd if (ascii) 2123219089Spjd free(ascii); 2124219089Spjd m_label_free(new_sl); 2125219089Spjd break; 2126219089Spjd } 2127219089Spjd m_label_free(new_sl); 2128219089Spjd 2129219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2130219089Spjd free(ascii); 2131219089Spjd#else /* !sun */ 2132219089Spjd propbuf[0] = '\0'; 2133219089Spjd#endif /* !sun */ 2134219089Spjd } 2135219089Spjd break; 2136219089Spjd 2137168404Spjd default: 2138185029Spjd switch (zfs_prop_get_type(prop)) { 2139185029Spjd case PROP_TYPE_NUMBER: 2140185029Spjd if (get_numeric_property(zhp, prop, src, 2141185029Spjd &source, &val) != 0) 2142185029Spjd return (-1); 2143185029Spjd if (literal) 2144185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2145185029Spjd (u_longlong_t)val); 2146185029Spjd else 2147185029Spjd zfs_nicenum(val, propbuf, proplen); 2148185029Spjd break; 2149185029Spjd 2150185029Spjd case PROP_TYPE_STRING: 2151185029Spjd (void) strlcpy(propbuf, 2152185029Spjd getprop_string(zhp, prop, &source), proplen); 2153185029Spjd break; 2154185029Spjd 2155185029Spjd case PROP_TYPE_INDEX: 2156185029Spjd if (get_numeric_property(zhp, prop, src, 2157185029Spjd &source, &val) != 0) 2158185029Spjd return (-1); 2159185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2160185029Spjd return (-1); 2161185029Spjd (void) strlcpy(propbuf, strval, proplen); 2162185029Spjd break; 2163185029Spjd 2164185029Spjd default: 2165185029Spjd abort(); 2166185029Spjd } 2167168404Spjd } 2168168404Spjd 2169168404Spjd get_source(zhp, src, source, statbuf, statlen); 2170168404Spjd 2171168404Spjd return (0); 2172168404Spjd} 2173168404Spjd 2174168404Spjd/* 2175168404Spjd * Utility function to get the given numeric property. Does no validation that 2176168404Spjd * the given property is the appropriate type; should only be used with 2177168404Spjd * hard-coded property types. 2178168404Spjd */ 2179168404Spjduint64_t 2180168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2181168404Spjd{ 2182168404Spjd char *source; 2183168404Spjd uint64_t val; 2184168404Spjd 2185185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2186168404Spjd 2187168404Spjd return (val); 2188168404Spjd} 2189168404Spjd 2190185029Spjdint 2191185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2192185029Spjd{ 2193185029Spjd char buf[64]; 2194185029Spjd 2195209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2196185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2197185029Spjd} 2198185029Spjd 2199168404Spjd/* 2200168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2201168404Spjd */ 2202168404Spjdint 2203168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2204185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2205168404Spjd{ 2206168404Spjd char *source; 2207168404Spjd 2208168404Spjd /* 2209168404Spjd * Check to see if this property applies to our object 2210168404Spjd */ 2211185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2212168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2213168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2214168404Spjd zfs_prop_to_name(prop))); 2215185029Spjd } 2216168404Spjd 2217168404Spjd if (src) 2218185029Spjd *src = ZPROP_SRC_NONE; 2219168404Spjd 2220168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2221168404Spjd return (-1); 2222168404Spjd 2223168404Spjd get_source(zhp, src, source, statbuf, statlen); 2224168404Spjd 2225168404Spjd return (0); 2226168404Spjd} 2227168404Spjd 2228209962Smmstatic int 2229209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2230209962Smm char **domainp, idmap_rid_t *ridp) 2231209962Smm{ 2232209962Smm#ifdef sun 2233209962Smm idmap_get_handle_t *get_hdl = NULL; 2234209962Smm idmap_stat status; 2235209962Smm int err = EINVAL; 2236209962Smm 2237219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2238209962Smm goto out; 2239209962Smm 2240209962Smm if (isuser) { 2241209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2242209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2243209962Smm } else { 2244209962Smm err = idmap_get_sidbygid(get_hdl, id, 2245209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2246209962Smm } 2247209962Smm if (err == IDMAP_SUCCESS && 2248209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2249209962Smm status == IDMAP_SUCCESS) 2250209962Smm err = 0; 2251209962Smm else 2252209962Smm err = EINVAL; 2253209962Smmout: 2254209962Smm if (get_hdl) 2255209962Smm idmap_get_destroy(get_hdl); 2256209962Smm return (err); 2257209962Smm#else /* !sun */ 2258209962Smm assert(!"invalid code path"); 2259209962Smm#endif /* !sun */ 2260209962Smm} 2261209962Smm 2262168404Spjd/* 2263209962Smm * convert the propname into parameters needed by kernel 2264209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2265209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2266209962Smm */ 2267209962Smmstatic int 2268209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2269209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2270209962Smm{ 2271209962Smm zfs_userquota_prop_t type; 2272209962Smm char *cp, *end; 2273209962Smm char *numericsid = NULL; 2274209962Smm boolean_t isuser; 2275209962Smm 2276209962Smm domain[0] = '\0'; 2277209962Smm 2278209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2279209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2280209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2281209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2282209962Smm break; 2283209962Smm } 2284209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2285209962Smm return (EINVAL); 2286209962Smm *typep = type; 2287209962Smm 2288209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2289209962Smm type == ZFS_PROP_USERUSED); 2290209962Smm 2291209962Smm cp = strchr(propname, '@') + 1; 2292209962Smm 2293209962Smm if (strchr(cp, '@')) { 2294209962Smm#ifdef sun 2295209962Smm /* 2296209962Smm * It's a SID name (eg "user@domain") that needs to be 2297209962Smm * turned into S-1-domainID-RID. 2298209962Smm */ 2299209962Smm directory_error_t e; 2300209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2301209962Smm return (ENOENT); 2302209962Smm if (isuser) { 2303209962Smm e = directory_sid_from_user_name(NULL, 2304209962Smm cp, &numericsid); 2305209962Smm } else { 2306209962Smm e = directory_sid_from_group_name(NULL, 2307209962Smm cp, &numericsid); 2308209962Smm } 2309209962Smm if (e != NULL) { 2310209962Smm directory_error_free(e); 2311209962Smm return (ENOENT); 2312209962Smm } 2313209962Smm if (numericsid == NULL) 2314209962Smm return (ENOENT); 2315209962Smm cp = numericsid; 2316209962Smm /* will be further decoded below */ 2317209962Smm#else /* !sun */ 2318219089Spjd return (ENOENT); 2319209962Smm#endif /* !sun */ 2320209962Smm } 2321209962Smm 2322209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2323209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2324209962Smm (void) strlcpy(domain, cp, domainlen); 2325209962Smm cp = strrchr(domain, '-'); 2326209962Smm *cp = '\0'; 2327209962Smm cp++; 2328209962Smm 2329209962Smm errno = 0; 2330209962Smm *ridp = strtoull(cp, &end, 10); 2331209962Smm if (numericsid) { 2332209962Smm free(numericsid); 2333209962Smm numericsid = NULL; 2334209962Smm } 2335209962Smm if (errno != 0 || *end != '\0') 2336209962Smm return (EINVAL); 2337209962Smm } else if (!isdigit(*cp)) { 2338209962Smm /* 2339209962Smm * It's a user/group name (eg "user") that needs to be 2340209962Smm * turned into a uid/gid 2341209962Smm */ 2342209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2343209962Smm return (ENOENT); 2344209962Smm if (isuser) { 2345209962Smm struct passwd *pw; 2346209962Smm pw = getpwnam(cp); 2347209962Smm if (pw == NULL) 2348209962Smm return (ENOENT); 2349209962Smm *ridp = pw->pw_uid; 2350209962Smm } else { 2351209962Smm struct group *gr; 2352209962Smm gr = getgrnam(cp); 2353209962Smm if (gr == NULL) 2354209962Smm return (ENOENT); 2355209962Smm *ridp = gr->gr_gid; 2356209962Smm } 2357209962Smm } else { 2358209962Smm /* It's a user/group ID (eg "12345"). */ 2359209962Smm uid_t id = strtoul(cp, &end, 10); 2360209962Smm idmap_rid_t rid; 2361209962Smm char *mapdomain; 2362209962Smm 2363209962Smm if (*end != '\0') 2364209962Smm return (EINVAL); 2365209962Smm if (id > MAXUID) { 2366209962Smm /* It's an ephemeral ID. */ 2367209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2368209962Smm &mapdomain, &rid) != 0) 2369209962Smm return (ENOENT); 2370209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2371209962Smm *ridp = rid; 2372209962Smm } else { 2373209962Smm *ridp = id; 2374209962Smm } 2375209962Smm } 2376209962Smm 2377209962Smm ASSERT3P(numericsid, ==, NULL); 2378209962Smm return (0); 2379209962Smm} 2380209962Smm 2381209962Smmstatic int 2382209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2383209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2384209962Smm{ 2385209962Smm int err; 2386209962Smm zfs_cmd_t zc = { 0 }; 2387209962Smm 2388209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2389209962Smm 2390209962Smm err = userquota_propname_decode(propname, 2391209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2392209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2393209962Smm zc.zc_objset_type = *typep; 2394209962Smm if (err) 2395209962Smm return (err); 2396209962Smm 2397209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2398209962Smm if (err) 2399209962Smm return (err); 2400209962Smm 2401209962Smm *propvalue = zc.zc_cookie; 2402209962Smm return (0); 2403209962Smm} 2404209962Smm 2405209962Smmint 2406209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2407209962Smm uint64_t *propvalue) 2408209962Smm{ 2409209962Smm zfs_userquota_prop_t type; 2410209962Smm 2411209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2412209962Smm &type)); 2413209962Smm} 2414209962Smm 2415209962Smmint 2416209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2417209962Smm char *propbuf, int proplen, boolean_t literal) 2418209962Smm{ 2419209962Smm int err; 2420209962Smm uint64_t propvalue; 2421209962Smm zfs_userquota_prop_t type; 2422209962Smm 2423209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2424209962Smm &type); 2425209962Smm 2426209962Smm if (err) 2427209962Smm return (err); 2428209962Smm 2429209962Smm if (literal) { 2430209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2431209962Smm } else if (propvalue == 0 && 2432209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2433209962Smm (void) strlcpy(propbuf, "none", proplen); 2434209962Smm } else { 2435209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2436209962Smm } 2437209962Smm return (0); 2438209962Smm} 2439209962Smm 2440209962Smm/* 2441168404Spjd * Returns the name of the given zfs handle. 2442168404Spjd */ 2443168404Spjdconst char * 2444168404Spjdzfs_get_name(const zfs_handle_t *zhp) 2445168404Spjd{ 2446168404Spjd return (zhp->zfs_name); 2447168404Spjd} 2448168404Spjd 2449168404Spjd/* 2450168404Spjd * Returns the type of the given zfs handle. 2451168404Spjd */ 2452168404Spjdzfs_type_t 2453168404Spjdzfs_get_type(const zfs_handle_t *zhp) 2454168404Spjd{ 2455168404Spjd return (zhp->zfs_type); 2456168404Spjd} 2457168404Spjd 2458209962Smmstatic int 2459209962Smmzfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc) 2460209962Smm{ 2461209962Smm int rc; 2462209962Smm uint64_t orig_cookie; 2463209962Smm 2464209962Smm orig_cookie = zc->zc_cookie; 2465209962Smmtop: 2466209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 2467209962Smm rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); 2468209962Smm 2469209962Smm if (rc == -1) { 2470209962Smm switch (errno) { 2471209962Smm case ENOMEM: 2472209962Smm /* expand nvlist memory and try again */ 2473209962Smm if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { 2474209962Smm zcmd_free_nvlists(zc); 2475209962Smm return (-1); 2476209962Smm } 2477209962Smm zc->zc_cookie = orig_cookie; 2478209962Smm goto top; 2479209962Smm /* 2480209962Smm * An errno value of ESRCH indicates normal completion. 2481209962Smm * If ENOENT is returned, then the underlying dataset 2482209962Smm * has been removed since we obtained the handle. 2483209962Smm */ 2484209962Smm case ESRCH: 2485209962Smm case ENOENT: 2486209962Smm rc = 1; 2487209962Smm break; 2488209962Smm default: 2489209962Smm rc = zfs_standard_error(zhp->zfs_hdl, errno, 2490209962Smm dgettext(TEXT_DOMAIN, 2491209962Smm "cannot iterate filesystems")); 2492209962Smm break; 2493209962Smm } 2494209962Smm } 2495209962Smm return (rc); 2496209962Smm} 2497209962Smm 2498168404Spjd/* 2499168404Spjd * Iterate over all child filesystems 2500168404Spjd */ 2501168404Spjdint 2502168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2503168404Spjd{ 2504168404Spjd zfs_cmd_t zc = { 0 }; 2505168404Spjd zfs_handle_t *nzhp; 2506168404Spjd int ret; 2507168404Spjd 2508185029Spjd if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 2509185029Spjd return (0); 2510185029Spjd 2511209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2512209962Smm return (-1); 2513209962Smm 2514209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, 2515209962Smm &zc)) == 0) { 2516168404Spjd /* 2517168404Spjd * Silently ignore errors, as the only plausible explanation is 2518168404Spjd * that the pool has since been removed. 2519168404Spjd */ 2520209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2521209962Smm &zc)) == NULL) { 2522168404Spjd continue; 2523209962Smm } 2524168404Spjd 2525209962Smm if ((ret = func(nzhp, data)) != 0) { 2526209962Smm zcmd_free_nvlists(&zc); 2527168404Spjd return (ret); 2528209962Smm } 2529168404Spjd } 2530209962Smm zcmd_free_nvlists(&zc); 2531209962Smm return ((ret < 0) ? ret : 0); 2532168404Spjd} 2533168404Spjd 2534168404Spjd/* 2535168404Spjd * Iterate over all snapshots 2536168404Spjd */ 2537168404Spjdint 2538168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2539168404Spjd{ 2540168404Spjd zfs_cmd_t zc = { 0 }; 2541168404Spjd zfs_handle_t *nzhp; 2542168404Spjd int ret; 2543168404Spjd 2544185029Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 2545185029Spjd return (0); 2546185029Spjd 2547209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2548209962Smm return (-1); 2549209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, 2550209962Smm &zc)) == 0) { 2551168404Spjd 2552209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2553209962Smm &zc)) == NULL) { 2554209962Smm continue; 2555209962Smm } 2556209962Smm 2557209962Smm if ((ret = func(nzhp, data)) != 0) { 2558209962Smm zcmd_free_nvlists(&zc); 2559168404Spjd return (ret); 2560209962Smm } 2561168404Spjd } 2562209962Smm zcmd_free_nvlists(&zc); 2563209962Smm return ((ret < 0) ? ret : 0); 2564168404Spjd} 2565168404Spjd 2566168404Spjd/* 2567168404Spjd * Iterate over all children, snapshots and filesystems 2568168404Spjd */ 2569168404Spjdint 2570168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2571168404Spjd{ 2572168404Spjd int ret; 2573168404Spjd 2574168404Spjd if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 2575168404Spjd return (ret); 2576168404Spjd 2577168404Spjd return (zfs_iter_snapshots(zhp, func, data)); 2578168404Spjd} 2579168404Spjd 2580168404Spjd/* 2581219089Spjd * Is one dataset name a child dataset of another? 2582219089Spjd * 2583219089Spjd * Needs to handle these cases: 2584219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2585219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2586219089Spjd * Descendant? No. No. No. Yes. 2587219089Spjd */ 2588219089Spjdstatic boolean_t 2589219089Spjdis_descendant(const char *ds1, const char *ds2) 2590219089Spjd{ 2591219089Spjd size_t d1len = strlen(ds1); 2592219089Spjd 2593219089Spjd /* ds2 can't be a descendant if it's smaller */ 2594219089Spjd if (strlen(ds2) < d1len) 2595219089Spjd return (B_FALSE); 2596219089Spjd 2597219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2598219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2599219089Spjd} 2600219089Spjd 2601219089Spjd/* 2602168404Spjd * Given a complete name, return just the portion that refers to the parent. 2603168404Spjd * Can return NULL if this is a pool. 2604168404Spjd */ 2605168404Spjdstatic int 2606168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2607168404Spjd{ 2608168404Spjd char *loc; 2609168404Spjd 2610168404Spjd if ((loc = strrchr(path, '/')) == NULL) 2611168404Spjd return (-1); 2612168404Spjd 2613168404Spjd (void) strncpy(buf, path, MIN(buflen, loc - path)); 2614168404Spjd buf[loc - path] = '\0'; 2615168404Spjd 2616168404Spjd return (0); 2617168404Spjd} 2618168404Spjd 2619168404Spjd/* 2620185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2621185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2622185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2623185029Spjd * length of already existing prefix of the given path. We also fetch the 2624185029Spjd * 'zoned' property, which is used to validate property settings when creating 2625185029Spjd * new datasets. 2626168404Spjd */ 2627168404Spjdstatic int 2628185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2629185029Spjd boolean_t accept_ancestor, int *prefixlen) 2630168404Spjd{ 2631168404Spjd zfs_cmd_t zc = { 0 }; 2632168404Spjd char parent[ZFS_MAXNAMELEN]; 2633168404Spjd char *slash; 2634168404Spjd zfs_handle_t *zhp; 2635168404Spjd char errbuf[1024]; 2636219089Spjd uint64_t is_zoned; 2637168404Spjd 2638209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2639209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2640168404Spjd 2641168404Spjd /* get parent, and check to see if this is just a pool */ 2642168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2643168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2644168404Spjd "missing dataset name")); 2645168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2646168404Spjd } 2647168404Spjd 2648168404Spjd /* check to see if the pool exists */ 2649168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2650168404Spjd slash = parent + strlen(parent); 2651168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2652168404Spjd zc.zc_name[slash - parent] = '\0'; 2653168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2654168404Spjd errno == ENOENT) { 2655168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2656168404Spjd "no such pool '%s'"), zc.zc_name); 2657168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2658168404Spjd } 2659168404Spjd 2660168404Spjd /* check to see if the parent dataset exists */ 2661185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2662185029Spjd if (errno == ENOENT && accept_ancestor) { 2663185029Spjd /* 2664185029Spjd * Go deeper to find an ancestor, give up on top level. 2665185029Spjd */ 2666185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2667185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2668185029Spjd "no such pool '%s'"), zc.zc_name); 2669185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2670185029Spjd } 2671185029Spjd } else if (errno == ENOENT) { 2672168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2673168404Spjd "parent does not exist")); 2674168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2675185029Spjd } else 2676168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2677168404Spjd } 2678168404Spjd 2679219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2680219089Spjd if (zoned != NULL) 2681219089Spjd *zoned = is_zoned; 2682219089Spjd 2683168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2684219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 2685168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2686168404Spjd zfs_close(zhp); 2687168404Spjd return (-1); 2688168404Spjd } 2689168404Spjd 2690168404Spjd /* make sure parent is a filesystem */ 2691168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2692168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2693168404Spjd "parent is not a filesystem")); 2694168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2695168404Spjd zfs_close(zhp); 2696168404Spjd return (-1); 2697168404Spjd } 2698168404Spjd 2699168404Spjd zfs_close(zhp); 2700185029Spjd if (prefixlen != NULL) 2701185029Spjd *prefixlen = strlen(parent); 2702168404Spjd return (0); 2703168404Spjd} 2704168404Spjd 2705168404Spjd/* 2706185029Spjd * Finds whether the dataset of the given type(s) exists. 2707185029Spjd */ 2708185029Spjdboolean_t 2709185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2710185029Spjd{ 2711185029Spjd zfs_handle_t *zhp; 2712185029Spjd 2713185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2714185029Spjd return (B_FALSE); 2715185029Spjd 2716185029Spjd /* 2717185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2718185029Spjd */ 2719185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2720185029Spjd int ds_type = zhp->zfs_type; 2721185029Spjd 2722185029Spjd zfs_close(zhp); 2723185029Spjd if (types & ds_type) 2724185029Spjd return (B_TRUE); 2725185029Spjd } 2726185029Spjd return (B_FALSE); 2727185029Spjd} 2728185029Spjd 2729185029Spjd/* 2730185029Spjd * Given a path to 'target', create all the ancestors between 2731185029Spjd * the prefixlen portion of the path, and the target itself. 2732185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2733185029Spjd */ 2734185029Spjdint 2735185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2736185029Spjd{ 2737185029Spjd zfs_handle_t *h; 2738185029Spjd char *cp; 2739185029Spjd const char *opname; 2740185029Spjd 2741185029Spjd /* make sure prefix exists */ 2742185029Spjd cp = target + prefixlen; 2743185029Spjd if (*cp != '/') { 2744185029Spjd assert(strchr(cp, '/') == NULL); 2745185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2746185029Spjd } else { 2747185029Spjd *cp = '\0'; 2748185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2749185029Spjd *cp = '/'; 2750185029Spjd } 2751185029Spjd if (h == NULL) 2752185029Spjd return (-1); 2753185029Spjd zfs_close(h); 2754185029Spjd 2755185029Spjd /* 2756185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2757185029Spjd * up to the prefixlen-long one. 2758185029Spjd */ 2759185029Spjd for (cp = target + prefixlen + 1; 2760185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2761185029Spjd char *logstr; 2762185029Spjd 2763185029Spjd *cp = '\0'; 2764185029Spjd 2765185029Spjd h = make_dataset_handle(hdl, target); 2766185029Spjd if (h) { 2767185029Spjd /* it already exists, nothing to do here */ 2768185029Spjd zfs_close(h); 2769185029Spjd continue; 2770185029Spjd } 2771185029Spjd 2772185029Spjd logstr = hdl->libzfs_log_str; 2773185029Spjd hdl->libzfs_log_str = NULL; 2774185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2775185029Spjd NULL) != 0) { 2776185029Spjd hdl->libzfs_log_str = logstr; 2777185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2778185029Spjd goto ancestorerr; 2779185029Spjd } 2780185029Spjd 2781185029Spjd hdl->libzfs_log_str = logstr; 2782185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2783185029Spjd if (h == NULL) { 2784185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2785185029Spjd goto ancestorerr; 2786185029Spjd } 2787185029Spjd 2788185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 2789185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2790185029Spjd goto ancestorerr; 2791185029Spjd } 2792185029Spjd 2793185029Spjd if (zfs_share(h) != 0) { 2794185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2795185029Spjd goto ancestorerr; 2796185029Spjd } 2797185029Spjd 2798185029Spjd zfs_close(h); 2799185029Spjd } 2800185029Spjd 2801185029Spjd return (0); 2802185029Spjd 2803185029Spjdancestorerr: 2804185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2805185029Spjd "failed to %s ancestor '%s'"), opname, target); 2806185029Spjd return (-1); 2807185029Spjd} 2808185029Spjd 2809185029Spjd/* 2810185029Spjd * Creates non-existing ancestors of the given path. 2811185029Spjd */ 2812185029Spjdint 2813185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2814185029Spjd{ 2815185029Spjd int prefix; 2816185029Spjd char *path_copy; 2817185029Spjd int rc; 2818185029Spjd 2819219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 2820185029Spjd return (-1); 2821185029Spjd 2822185029Spjd if ((path_copy = strdup(path)) != NULL) { 2823185029Spjd rc = create_parents(hdl, path_copy, prefix); 2824185029Spjd free(path_copy); 2825185029Spjd } 2826185029Spjd if (path_copy == NULL || rc != 0) 2827185029Spjd return (-1); 2828185029Spjd 2829185029Spjd return (0); 2830185029Spjd} 2831185029Spjd 2832185029Spjd/* 2833168404Spjd * Create a new filesystem or volume. 2834168404Spjd */ 2835168404Spjdint 2836168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2837168404Spjd nvlist_t *props) 2838168404Spjd{ 2839168404Spjd zfs_cmd_t zc = { 0 }; 2840168404Spjd int ret; 2841168404Spjd uint64_t size = 0; 2842168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2843168404Spjd char errbuf[1024]; 2844168404Spjd uint64_t zoned; 2845168404Spjd 2846168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2847168404Spjd "cannot create '%s'"), path); 2848168404Spjd 2849168404Spjd /* validate the path, taking care to note the extended error message */ 2850185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 2851168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2852168404Spjd 2853168404Spjd /* validate parents exist */ 2854185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 2855168404Spjd return (-1); 2856168404Spjd 2857168404Spjd /* 2858168404Spjd * The failure modes when creating a dataset of a different type over 2859168404Spjd * one that already exists is a little strange. In particular, if you 2860168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 2861168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 2862168404Spjd * first try to see if the dataset exists. 2863168404Spjd */ 2864168404Spjd (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2865185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 2866168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2867168404Spjd "dataset already exists")); 2868168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2869168404Spjd } 2870168404Spjd 2871168404Spjd if (type == ZFS_TYPE_VOLUME) 2872168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2873168404Spjd else 2874168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2875168404Spjd 2876185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 2877168404Spjd zoned, NULL, errbuf)) == 0) 2878168404Spjd return (-1); 2879168404Spjd 2880168404Spjd if (type == ZFS_TYPE_VOLUME) { 2881168404Spjd /* 2882168404Spjd * If we are creating a volume, the size and block size must 2883168404Spjd * satisfy a few restraints. First, the blocksize must be a 2884168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 2885168404Spjd * volsize must be a multiple of the block size, and cannot be 2886168404Spjd * zero. 2887168404Spjd */ 2888168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 2889168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2890168404Spjd nvlist_free(props); 2891168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2892168404Spjd "missing volume size")); 2893168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2894168404Spjd } 2895168404Spjd 2896168404Spjd if ((ret = nvlist_lookup_uint64(props, 2897168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2898168404Spjd &blocksize)) != 0) { 2899168404Spjd if (ret == ENOENT) { 2900168404Spjd blocksize = zfs_prop_default_numeric( 2901168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2902168404Spjd } else { 2903168404Spjd nvlist_free(props); 2904168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2905168404Spjd "missing volume block size")); 2906168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2907168404Spjd } 2908168404Spjd } 2909168404Spjd 2910168404Spjd if (size == 0) { 2911168404Spjd nvlist_free(props); 2912168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2913168404Spjd "volume size cannot be zero")); 2914168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2915168404Spjd } 2916168404Spjd 2917168404Spjd if (size % blocksize != 0) { 2918168404Spjd nvlist_free(props); 2919168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2920168404Spjd "volume size must be a multiple of volume block " 2921168404Spjd "size")); 2922168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2923168404Spjd } 2924168404Spjd } 2925168404Spjd 2926185029Spjd if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) 2927168404Spjd return (-1); 2928168404Spjd nvlist_free(props); 2929168404Spjd 2930168404Spjd /* create the dataset */ 2931185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); 2932168404Spjd 2933168404Spjd zcmd_free_nvlists(&zc); 2934168404Spjd 2935168404Spjd /* check for failure */ 2936168404Spjd if (ret != 0) { 2937168404Spjd char parent[ZFS_MAXNAMELEN]; 2938168404Spjd (void) parent_name(path, parent, sizeof (parent)); 2939168404Spjd 2940168404Spjd switch (errno) { 2941168404Spjd case ENOENT: 2942168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2943168404Spjd "no such parent '%s'"), parent); 2944168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2945168404Spjd 2946168404Spjd case EINVAL: 2947168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2948168404Spjd "parent '%s' is not a filesystem"), parent); 2949168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2950168404Spjd 2951168404Spjd case EDOM: 2952168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2953168404Spjd "volume block size must be power of 2 from " 2954168404Spjd "%u to %uk"), 2955168404Spjd (uint_t)SPA_MINBLOCKSIZE, 2956168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 2957168404Spjd 2958168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2959168404Spjd 2960185029Spjd case ENOTSUP: 2961185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2962185029Spjd "pool must be upgraded to set this " 2963185029Spjd "property or value")); 2964185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 2965168404Spjd#ifdef _ILP32 2966168404Spjd case EOVERFLOW: 2967168404Spjd /* 2968168404Spjd * This platform can't address a volume this big. 2969168404Spjd */ 2970168404Spjd if (type == ZFS_TYPE_VOLUME) 2971168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 2972168404Spjd errbuf)); 2973168404Spjd#endif 2974168404Spjd /* FALLTHROUGH */ 2975168404Spjd default: 2976168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2977168404Spjd } 2978168404Spjd } 2979168404Spjd 2980168404Spjd return (0); 2981168404Spjd} 2982168404Spjd 2983168404Spjd/* 2984168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 2985168404Spjd * isn't mounted, and that there are no active dependents. 2986168404Spjd */ 2987168404Spjdint 2988219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 2989168404Spjd{ 2990168404Spjd zfs_cmd_t zc = { 0 }; 2991168404Spjd 2992168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2993168404Spjd 2994168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2995168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2996168404Spjd } else { 2997168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2998168404Spjd } 2999168404Spjd 3000219089Spjd zc.zc_defer_destroy = defer; 3001185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { 3002168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3003168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3004168404Spjd zhp->zfs_name)); 3005168404Spjd } 3006168404Spjd 3007168404Spjd remove_mountpoint(zhp); 3008168404Spjd 3009168404Spjd return (0); 3010168404Spjd} 3011168404Spjd 3012168404Spjdstruct destroydata { 3013168404Spjd char *snapname; 3014168404Spjd boolean_t gotone; 3015168404Spjd boolean_t closezhp; 3016168404Spjd}; 3017168404Spjd 3018168404Spjdstatic int 3019219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3020168404Spjd{ 3021168404Spjd struct destroydata *dd = arg; 3022168404Spjd zfs_handle_t *szhp; 3023168404Spjd char name[ZFS_MAXNAMELEN]; 3024168404Spjd boolean_t closezhp = dd->closezhp; 3025219089Spjd int rv = 0; 3026168404Spjd 3027168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 3028168404Spjd (void) strlcat(name, "@", sizeof (name)); 3029168404Spjd (void) strlcat(name, dd->snapname, sizeof (name)); 3030168404Spjd 3031168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, name); 3032168404Spjd if (szhp) { 3033168404Spjd dd->gotone = B_TRUE; 3034168404Spjd zfs_close(szhp); 3035168404Spjd } 3036168404Spjd 3037168404Spjd dd->closezhp = B_TRUE; 3038219089Spjd if (!dd->gotone) 3039219089Spjd rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg); 3040168404Spjd if (closezhp) 3041168404Spjd zfs_close(zhp); 3042168404Spjd return (rv); 3043168404Spjd} 3044168404Spjd 3045168404Spjd/* 3046168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3047168404Spjd */ 3048168404Spjdint 3049219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3050168404Spjd{ 3051168404Spjd zfs_cmd_t zc = { 0 }; 3052168404Spjd int ret; 3053168404Spjd struct destroydata dd = { 0 }; 3054168404Spjd 3055168404Spjd dd.snapname = snapname; 3056219089Spjd (void) zfs_check_snap_cb(zhp, &dd); 3057168404Spjd 3058168404Spjd if (!dd.gotone) { 3059168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3060168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3061168404Spjd zhp->zfs_name, snapname)); 3062168404Spjd } 3063168404Spjd 3064168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3065168404Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3066219089Spjd zc.zc_defer_destroy = defer; 3067168404Spjd 3068185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); 3069168404Spjd if (ret != 0) { 3070168404Spjd char errbuf[1024]; 3071168404Spjd 3072168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3073168404Spjd "cannot destroy '%s@%s'"), zc.zc_name, snapname); 3074168404Spjd 3075168404Spjd switch (errno) { 3076168404Spjd case EEXIST: 3077168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3078168404Spjd "snapshot is cloned")); 3079168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 3080168404Spjd 3081168404Spjd default: 3082168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3083168404Spjd errbuf)); 3084168404Spjd } 3085168404Spjd } 3086168404Spjd 3087168404Spjd return (0); 3088168404Spjd} 3089168404Spjd 3090168404Spjd/* 3091168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3092168404Spjd */ 3093168404Spjdint 3094168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3095168404Spjd{ 3096168404Spjd zfs_cmd_t zc = { 0 }; 3097168404Spjd char parent[ZFS_MAXNAMELEN]; 3098168404Spjd int ret; 3099168404Spjd char errbuf[1024]; 3100168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3101168404Spjd zfs_type_t type; 3102168404Spjd uint64_t zoned; 3103168404Spjd 3104168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3105168404Spjd 3106168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3107168404Spjd "cannot create '%s'"), target); 3108168404Spjd 3109168404Spjd /* validate the target name */ 3110185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3111168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3112168404Spjd 3113168404Spjd /* validate parents exist */ 3114185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3115168404Spjd return (-1); 3116168404Spjd 3117168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3118168404Spjd 3119168404Spjd /* do the clone */ 3120168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3121168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3122168404Spjd type = ZFS_TYPE_VOLUME; 3123168404Spjd } else { 3124168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3125168404Spjd type = ZFS_TYPE_FILESYSTEM; 3126168404Spjd } 3127168404Spjd 3128168404Spjd if (props) { 3129185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3130185029Spjd zhp, errbuf)) == NULL) 3131168404Spjd return (-1); 3132168404Spjd 3133185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3134168404Spjd nvlist_free(props); 3135168404Spjd return (-1); 3136168404Spjd } 3137168404Spjd 3138168404Spjd nvlist_free(props); 3139168404Spjd } 3140168404Spjd 3141168404Spjd (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 3142168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 3143185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); 3144168404Spjd 3145168404Spjd zcmd_free_nvlists(&zc); 3146168404Spjd 3147168404Spjd if (ret != 0) { 3148168404Spjd switch (errno) { 3149168404Spjd 3150168404Spjd case ENOENT: 3151168404Spjd /* 3152168404Spjd * The parent doesn't exist. We should have caught this 3153168404Spjd * above, but there may a race condition that has since 3154168404Spjd * destroyed the parent. 3155168404Spjd * 3156168404Spjd * At this point, we don't know whether it's the source 3157168404Spjd * that doesn't exist anymore, or whether the target 3158168404Spjd * dataset doesn't exist. 3159168404Spjd */ 3160168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3161168404Spjd "no such parent '%s'"), parent); 3162168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3163168404Spjd 3164168404Spjd case EXDEV: 3165168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3166168404Spjd "source and target pools differ")); 3167168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3168168404Spjd errbuf)); 3169168404Spjd 3170168404Spjd default: 3171168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3172168404Spjd errbuf)); 3173168404Spjd } 3174168404Spjd } 3175168404Spjd 3176168404Spjd return (ret); 3177168404Spjd} 3178168404Spjd 3179168404Spjd/* 3180168404Spjd * Promotes the given clone fs to be the clone parent. 3181168404Spjd */ 3182168404Spjdint 3183168404Spjdzfs_promote(zfs_handle_t *zhp) 3184168404Spjd{ 3185168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3186168404Spjd zfs_cmd_t zc = { 0 }; 3187168404Spjd char parent[MAXPATHLEN]; 3188168404Spjd int ret; 3189168404Spjd char errbuf[1024]; 3190168404Spjd 3191168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3192168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3193168404Spjd 3194168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3195168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3196168404Spjd "snapshots can not be promoted")); 3197168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3198168404Spjd } 3199168404Spjd 3200185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3201168404Spjd if (parent[0] == '\0') { 3202168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3203168404Spjd "not a cloned filesystem")); 3204168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3205168404Spjd } 3206168404Spjd 3207185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3208168404Spjd sizeof (zc.zc_value)); 3209168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3210185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3211168404Spjd 3212168404Spjd if (ret != 0) { 3213168404Spjd int save_errno = errno; 3214168404Spjd 3215168404Spjd switch (save_errno) { 3216168404Spjd case EEXIST: 3217219089Spjd /* There is a conflicting snapshot name. */ 3218168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3219219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3220219089Spjd zc.zc_string, parent); 3221168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3222168404Spjd 3223168404Spjd default: 3224168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3225168404Spjd } 3226168404Spjd } 3227168404Spjd return (ret); 3228168404Spjd} 3229168404Spjd 3230168404Spjd/* 3231168404Spjd * Takes a snapshot of the given dataset. 3232168404Spjd */ 3233168404Spjdint 3234185029Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3235185029Spjd nvlist_t *props) 3236168404Spjd{ 3237168404Spjd const char *delim; 3238185029Spjd char parent[ZFS_MAXNAMELEN]; 3239168404Spjd zfs_handle_t *zhp; 3240168404Spjd zfs_cmd_t zc = { 0 }; 3241168404Spjd int ret; 3242168404Spjd char errbuf[1024]; 3243168404Spjd 3244168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3245168404Spjd "cannot snapshot '%s'"), path); 3246168404Spjd 3247168404Spjd /* validate the target name */ 3248185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3249168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3250168404Spjd 3251185029Spjd if (props) { 3252185029Spjd if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3253185029Spjd props, B_FALSE, NULL, errbuf)) == NULL) 3254185029Spjd return (-1); 3255185029Spjd 3256185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3257185029Spjd nvlist_free(props); 3258185029Spjd return (-1); 3259185029Spjd } 3260185029Spjd 3261185029Spjd nvlist_free(props); 3262185029Spjd } 3263185029Spjd 3264168404Spjd /* make sure the parent exists and is of the appropriate type */ 3265168404Spjd delim = strchr(path, '@'); 3266168404Spjd (void) strncpy(parent, path, delim - path); 3267168404Spjd parent[delim - path] = '\0'; 3268168404Spjd 3269168404Spjd if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 3270168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3271185029Spjd zcmd_free_nvlists(&zc); 3272168404Spjd return (-1); 3273168404Spjd } 3274168404Spjd 3275168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3276168404Spjd (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 3277185029Spjd if (ZFS_IS_VOLUME(zhp)) 3278185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3279185029Spjd else 3280185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3281168404Spjd zc.zc_cookie = recursive; 3282185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); 3283168404Spjd 3284185029Spjd zcmd_free_nvlists(&zc); 3285185029Spjd 3286168404Spjd /* 3287168404Spjd * if it was recursive, the one that actually failed will be in 3288168404Spjd * zc.zc_name. 3289168404Spjd */ 3290219089Spjd if (ret != 0) { 3291185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3292185029Spjd "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 3293219089Spjd (void) zfs_standard_error(hdl, errno, errbuf); 3294168404Spjd } 3295168404Spjd 3296168404Spjd zfs_close(zhp); 3297168404Spjd 3298168404Spjd return (ret); 3299168404Spjd} 3300168404Spjd 3301168404Spjd/* 3302168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3303168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3304168404Spjd * is a dependent and we should just destroy it without checking the transaction 3305168404Spjd * group. 3306168404Spjd */ 3307168404Spjdtypedef struct rollback_data { 3308168404Spjd const char *cb_target; /* the snapshot */ 3309168404Spjd uint64_t cb_create; /* creation time reference */ 3310185029Spjd boolean_t cb_error; 3311168404Spjd boolean_t cb_dependent; 3312185029Spjd boolean_t cb_force; 3313168404Spjd} rollback_data_t; 3314168404Spjd 3315168404Spjdstatic int 3316168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3317168404Spjd{ 3318168404Spjd rollback_data_t *cbp = data; 3319168404Spjd 3320168404Spjd if (!cbp->cb_dependent) { 3321168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3322168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3323168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3324168404Spjd cbp->cb_create) { 3325185029Spjd char *logstr; 3326168404Spjd 3327168404Spjd cbp->cb_dependent = B_TRUE; 3328185029Spjd cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3329185029Spjd rollback_destroy, cbp); 3330168404Spjd cbp->cb_dependent = B_FALSE; 3331168404Spjd 3332185029Spjd logstr = zhp->zfs_hdl->libzfs_log_str; 3333185029Spjd zhp->zfs_hdl->libzfs_log_str = NULL; 3334219089Spjd cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3335185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 3336168404Spjd } 3337168404Spjd } else { 3338185029Spjd /* We must destroy this clone; first unmount it */ 3339185029Spjd prop_changelist_t *clp; 3340185029Spjd 3341185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3342185029Spjd cbp->cb_force ? MS_FORCE: 0); 3343185029Spjd if (clp == NULL || changelist_prefix(clp) != 0) { 3344185029Spjd cbp->cb_error = B_TRUE; 3345185029Spjd zfs_close(zhp); 3346185029Spjd return (0); 3347185029Spjd } 3348219089Spjd if (zfs_destroy(zhp, B_FALSE) != 0) 3349185029Spjd cbp->cb_error = B_TRUE; 3350168404Spjd else 3351185029Spjd changelist_remove(clp, zhp->zfs_name); 3352185029Spjd (void) changelist_postfix(clp); 3353185029Spjd changelist_free(clp); 3354168404Spjd } 3355168404Spjd 3356168404Spjd zfs_close(zhp); 3357168404Spjd return (0); 3358168404Spjd} 3359168404Spjd 3360168404Spjd/* 3361168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3362168404Spjd * data changes since then and making it the active dataset. 3363168404Spjd * 3364168404Spjd * Any snapshots more recent than the target are destroyed, along with 3365168404Spjd * their dependents. 3366168404Spjd */ 3367168404Spjdint 3368185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3369168404Spjd{ 3370168404Spjd rollback_data_t cb = { 0 }; 3371185029Spjd int err; 3372185029Spjd zfs_cmd_t zc = { 0 }; 3373185029Spjd boolean_t restore_resv = 0; 3374185029Spjd uint64_t old_volsize, new_volsize; 3375185029Spjd zfs_prop_t resv_prop; 3376168404Spjd 3377185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3378185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3379168404Spjd 3380168404Spjd /* 3381168404Spjd * Destroy all recent snapshots and its dependends. 3382168404Spjd */ 3383185029Spjd cb.cb_force = force; 3384168404Spjd cb.cb_target = snap->zfs_name; 3385168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3386168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3387168404Spjd 3388185029Spjd if (cb.cb_error) 3389185029Spjd return (-1); 3390168404Spjd 3391168404Spjd /* 3392168404Spjd * Now that we have verified that the snapshot is the latest, 3393168404Spjd * rollback to the given snapshot. 3394168404Spjd */ 3395168404Spjd 3396185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3397185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3398185029Spjd return (-1); 3399185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3400185029Spjd restore_resv = 3401185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3402168404Spjd } 3403168404Spjd 3404185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3405185029Spjd 3406185029Spjd if (ZFS_IS_VOLUME(zhp)) 3407185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3408185029Spjd else 3409185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3410185029Spjd 3411168404Spjd /* 3412185029Spjd * We rely on zfs_iter_children() to verify that there are no 3413185029Spjd * newer snapshots for the given dataset. Therefore, we can 3414185029Spjd * simply pass the name on to the ioctl() call. There is still 3415185029Spjd * an unlikely race condition where the user has taken a 3416185029Spjd * snapshot since we verified that this was the most recent. 3417185029Spjd * 3418168404Spjd */ 3419185029Spjd if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3420185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3421185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3422185029Spjd zhp->zfs_name); 3423185029Spjd return (err); 3424185029Spjd } 3425168404Spjd 3426185029Spjd /* 3427185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3428185029Spjd * rollback reservation and the volsize has changed then set 3429185029Spjd * the reservation property to the post-rollback volsize. 3430185029Spjd * Make a new handle since the rollback closed the dataset. 3431185029Spjd */ 3432185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3433185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3434185029Spjd if (restore_resv) { 3435185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3436185029Spjd if (old_volsize != new_volsize) 3437185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3438185029Spjd new_volsize); 3439185029Spjd } 3440185029Spjd zfs_close(zhp); 3441185029Spjd } 3442185029Spjd return (err); 3443168404Spjd} 3444168404Spjd 3445168404Spjd/* 3446168404Spjd * Iterate over all dependents for a given dataset. This includes both 3447168404Spjd * hierarchical dependents (children) and data dependents (snapshots and 3448168404Spjd * clones). The bulk of the processing occurs in get_dependents() in 3449168404Spjd * libzfs_graph.c. 3450168404Spjd */ 3451168404Spjdint 3452168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 3453168404Spjd zfs_iter_f func, void *data) 3454168404Spjd{ 3455168404Spjd char **dependents; 3456168404Spjd size_t count; 3457168404Spjd int i; 3458168404Spjd zfs_handle_t *child; 3459168404Spjd int ret = 0; 3460168404Spjd 3461168404Spjd if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 3462168404Spjd &dependents, &count) != 0) 3463168404Spjd return (-1); 3464168404Spjd 3465168404Spjd for (i = 0; i < count; i++) { 3466168404Spjd if ((child = make_dataset_handle(zhp->zfs_hdl, 3467168404Spjd dependents[i])) == NULL) 3468168404Spjd continue; 3469168404Spjd 3470168404Spjd if ((ret = func(child, data)) != 0) 3471168404Spjd break; 3472168404Spjd } 3473168404Spjd 3474168404Spjd for (i = 0; i < count; i++) 3475168404Spjd free(dependents[i]); 3476168404Spjd free(dependents); 3477168404Spjd 3478168404Spjd return (ret); 3479168404Spjd} 3480168404Spjd 3481168404Spjd/* 3482168404Spjd * Renames the given dataset. 3483168404Spjd */ 3484168404Spjdint 3485226705Spjdzfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags) 3486168404Spjd{ 3487168404Spjd int ret; 3488168404Spjd zfs_cmd_t zc = { 0 }; 3489168404Spjd char *delim; 3490168676Spjd prop_changelist_t *cl = NULL; 3491168676Spjd zfs_handle_t *zhrp = NULL; 3492168676Spjd char *parentname = NULL; 3493168404Spjd char parent[ZFS_MAXNAMELEN]; 3494226676Spjd char property[ZFS_MAXPROPLEN]; 3495168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3496168404Spjd char errbuf[1024]; 3497168404Spjd 3498168404Spjd /* if we have the same exact name, just return success */ 3499168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3500168404Spjd return (0); 3501168404Spjd 3502168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3503168404Spjd "cannot rename to '%s'"), target); 3504168404Spjd 3505168404Spjd /* 3506168404Spjd * Make sure the target name is valid 3507168404Spjd */ 3508168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3509168404Spjd if ((strchr(target, '@') == NULL) || 3510168404Spjd *target == '@') { 3511168404Spjd /* 3512168404Spjd * Snapshot target name is abbreviated, 3513168404Spjd * reconstruct full dataset name 3514168404Spjd */ 3515168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3516168404Spjd sizeof (parent)); 3517168404Spjd delim = strchr(parent, '@'); 3518168404Spjd if (strchr(target, '@') == NULL) 3519168404Spjd *(++delim) = '\0'; 3520168404Spjd else 3521168404Spjd *delim = '\0'; 3522168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3523168404Spjd target = parent; 3524168404Spjd } else { 3525168404Spjd /* 3526168404Spjd * Make sure we're renaming within the same dataset. 3527168404Spjd */ 3528168404Spjd delim = strchr(target, '@'); 3529168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3530168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3531168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3532168404Spjd "snapshots must be part of same " 3533168404Spjd "dataset")); 3534168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3535168404Spjd errbuf)); 3536168404Spjd } 3537168404Spjd } 3538185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3539168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3540168404Spjd } else { 3541226705Spjd if (flags.recurse) { 3542168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3543168676Spjd "recursive rename must be a snapshot")); 3544168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3545168676Spjd } 3546168676Spjd 3547185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3548168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3549168404Spjd 3550168404Spjd /* validate parents */ 3551219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3552168404Spjd return (-1); 3553168404Spjd 3554168404Spjd /* make sure we're in the same pool */ 3555168404Spjd verify((delim = strchr(target, '/')) != NULL); 3556168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3557168404Spjd zhp->zfs_name[delim - target] != '/') { 3558168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3559168404Spjd "datasets must be within same pool")); 3560168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3561168404Spjd } 3562168404Spjd 3563168404Spjd /* new name cannot be a child of the current dataset name */ 3564219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3565168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3566219089Spjd "New dataset name cannot be a descendant of " 3567168404Spjd "current dataset name")); 3568168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3569168404Spjd } 3570168404Spjd } 3571168404Spjd 3572168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3573168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3574168404Spjd 3575168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3576168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3577168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3578168404Spjd "dataset is used in a non-global zone")); 3579168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3580168404Spjd } 3581168404Spjd 3582226705Spjd /* 3583226705Spjd * Avoid unmounting file systems with mountpoint property set to 3584226705Spjd * 'legacy' or 'none' even if -u option is not given. 3585226705Spjd */ 3586226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 3587226705Spjd !flags.recurse && !flags.nounmount && 3588226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 3589226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 3590226705Spjd (strcmp(property, "legacy") == 0 || 3591226705Spjd strcmp(property, "none") == 0)) { 3592226705Spjd flags.nounmount = B_TRUE; 3593226705Spjd } 3594168404Spjd 3595226705Spjd if (flags.recurse) { 3596226705Spjd 3597185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3598185029Spjd if (parentname == NULL) { 3599185029Spjd ret = -1; 3600185029Spjd goto error; 3601185029Spjd } 3602168676Spjd delim = strchr(parentname, '@'); 3603168676Spjd *delim = '\0'; 3604185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3605168676Spjd if (zhrp == NULL) { 3606185029Spjd ret = -1; 3607185029Spjd goto error; 3608168676Spjd } 3609168676Spjd 3610168676Spjd } else { 3611226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 3612226705Spjd flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 0)) == NULL) { 3613168676Spjd return (-1); 3614226676Spjd } 3615168676Spjd 3616168676Spjd if (changelist_haszonedchild(cl)) { 3617168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3618168676Spjd "child dataset with inherited mountpoint is used " 3619168676Spjd "in a non-global zone")); 3620168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3621168676Spjd goto error; 3622168676Spjd } 3623168676Spjd 3624168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3625168676Spjd goto error; 3626168404Spjd } 3627168404Spjd 3628168404Spjd if (ZFS_IS_VOLUME(zhp)) 3629168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3630168404Spjd else 3631168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3632168404Spjd 3633168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3634168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3635168404Spjd 3636226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 3637226705Spjd if (flags.nounmount) 3638226676Spjd zc.zc_cookie |= 2; 3639168676Spjd 3640185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3641168676Spjd /* 3642168676Spjd * if it was recursive, the one that actually failed will 3643168676Spjd * be in zc.zc_name 3644168676Spjd */ 3645168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3646185029Spjd "cannot rename '%s'"), zc.zc_name); 3647168404Spjd 3648226705Spjd if (flags.recurse && errno == EEXIST) { 3649168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3650168676Spjd "a child dataset already has a snapshot " 3651168676Spjd "with the new name")); 3652185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3653168676Spjd } else { 3654168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3655168676Spjd } 3656168676Spjd 3657168404Spjd /* 3658168404Spjd * On failure, we still want to remount any filesystems that 3659168404Spjd * were previously mounted, so we don't alter the system state. 3660168404Spjd */ 3661226705Spjd if (!flags.recurse) 3662168676Spjd (void) changelist_postfix(cl); 3663168404Spjd } else { 3664226705Spjd if (!flags.recurse) { 3665168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3666168676Spjd ret = changelist_postfix(cl); 3667168676Spjd } 3668168404Spjd } 3669168404Spjd 3670168404Spjderror: 3671168676Spjd if (parentname) { 3672168676Spjd free(parentname); 3673168676Spjd } 3674168676Spjd if (zhrp) { 3675168676Spjd zfs_close(zhrp); 3676168676Spjd } 3677168676Spjd if (cl) { 3678168676Spjd changelist_free(cl); 3679168676Spjd } 3680168404Spjd return (ret); 3681168404Spjd} 3682168404Spjd 3683219089Spjdnvlist_t * 3684219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 3685168404Spjd{ 3686219089Spjd return (zhp->zfs_user_props); 3687168676Spjd} 3688168676Spjd 3689168404Spjdnvlist_t * 3690219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 3691168404Spjd{ 3692219089Spjd if (zhp->zfs_recvd_props == NULL) 3693219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 3694219089Spjd return (NULL); 3695219089Spjd return (zhp->zfs_recvd_props); 3696168404Spjd} 3697168404Spjd 3698168404Spjd/* 3699168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3700168404Spjd * display, and their maximum widths. This does two main things: 3701168404Spjd * 3702168404Spjd * - If this is a list of all properties, then expand the list to include 3703168404Spjd * all native properties, and set a flag so that for each dataset we look 3704168404Spjd * for new unique user properties and add them to the list. 3705168404Spjd * 3706168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3707219089Spjd * so that we can size the column appropriately. If the user has 3708219089Spjd * requested received property values, we also need to compute the width 3709219089Spjd * of the RECEIVED column. 3710168404Spjd */ 3711168404Spjdint 3712219089Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) 3713168404Spjd{ 3714168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3715185029Spjd zprop_list_t *entry; 3716185029Spjd zprop_list_t **last, **start; 3717168404Spjd nvlist_t *userprops, *propval; 3718168404Spjd nvpair_t *elem; 3719168404Spjd char *strval; 3720168404Spjd char buf[ZFS_MAXPROPLEN]; 3721168404Spjd 3722185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3723168404Spjd return (-1); 3724168404Spjd 3725168404Spjd userprops = zfs_get_user_props(zhp); 3726168404Spjd 3727168404Spjd entry = *plp; 3728168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3729168404Spjd /* 3730168404Spjd * Go through and add any user properties as necessary. We 3731168404Spjd * start by incrementing our list pointer to the first 3732168404Spjd * non-native property. 3733168404Spjd */ 3734168404Spjd start = plp; 3735168404Spjd while (*start != NULL) { 3736185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3737168404Spjd break; 3738168404Spjd start = &(*start)->pl_next; 3739168404Spjd } 3740168404Spjd 3741168404Spjd elem = NULL; 3742168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3743168404Spjd /* 3744168404Spjd * See if we've already found this property in our list. 3745168404Spjd */ 3746168404Spjd for (last = start; *last != NULL; 3747168404Spjd last = &(*last)->pl_next) { 3748168404Spjd if (strcmp((*last)->pl_user_prop, 3749168404Spjd nvpair_name(elem)) == 0) 3750168404Spjd break; 3751168404Spjd } 3752168404Spjd 3753168404Spjd if (*last == NULL) { 3754168404Spjd if ((entry = zfs_alloc(hdl, 3755185029Spjd sizeof (zprop_list_t))) == NULL || 3756168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3757168404Spjd nvpair_name(elem)))) == NULL) { 3758168404Spjd free(entry); 3759168404Spjd return (-1); 3760168404Spjd } 3761168404Spjd 3762185029Spjd entry->pl_prop = ZPROP_INVAL; 3763168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3764168404Spjd entry->pl_all = B_TRUE; 3765168404Spjd *last = entry; 3766168404Spjd } 3767168404Spjd } 3768168404Spjd } 3769168404Spjd 3770168404Spjd /* 3771168404Spjd * Now go through and check the width of any non-fixed columns 3772168404Spjd */ 3773168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3774168404Spjd if (entry->pl_fixed) 3775168404Spjd continue; 3776168404Spjd 3777185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 3778168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3779168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3780168404Spjd if (strlen(buf) > entry->pl_width) 3781168404Spjd entry->pl_width = strlen(buf); 3782168404Spjd } 3783219089Spjd if (received && zfs_prop_get_recvd(zhp, 3784219089Spjd zfs_prop_to_name(entry->pl_prop), 3785219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3786219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3787219089Spjd entry->pl_recvd_width = strlen(buf); 3788219089Spjd } else { 3789219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 3790219089Spjd &propval) == 0) { 3791219089Spjd verify(nvlist_lookup_string(propval, 3792219089Spjd ZPROP_VALUE, &strval) == 0); 3793219089Spjd if (strlen(strval) > entry->pl_width) 3794219089Spjd entry->pl_width = strlen(strval); 3795219089Spjd } 3796219089Spjd if (received && zfs_prop_get_recvd(zhp, 3797219089Spjd entry->pl_user_prop, 3798219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3799219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3800219089Spjd entry->pl_recvd_width = strlen(buf); 3801168404Spjd } 3802168404Spjd } 3803168404Spjd 3804168404Spjd return (0); 3805168404Spjd} 3806168404Spjd 3807185029Spjdint 3808185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 3809209962Smm char *resource, void *export, void *sharetab, 3810209962Smm int sharemax, zfs_share_op_t operation) 3811185029Spjd{ 3812185029Spjd zfs_cmd_t zc = { 0 }; 3813185029Spjd int error; 3814185029Spjd 3815185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3816185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3817209962Smm if (resource) 3818209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 3819185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 3820185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 3821185029Spjd zc.zc_share.z_sharetype = operation; 3822185029Spjd zc.zc_share.z_sharemax = sharemax; 3823185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 3824185029Spjd return (error); 3825185029Spjd} 3826185029Spjd 3827205198Sdelphijvoid 3828205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 3829205198Sdelphij{ 3830205198Sdelphij nvpair_t *curr; 3831205198Sdelphij 3832205198Sdelphij /* 3833205198Sdelphij * Keep a reference to the props-table against which we prune the 3834205198Sdelphij * properties. 3835205198Sdelphij */ 3836205198Sdelphij zhp->zfs_props_table = props; 3837205198Sdelphij 3838205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 3839205198Sdelphij 3840205198Sdelphij while (curr) { 3841205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 3842205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 3843205198Sdelphij 3844206199Sdelphij /* 3845219089Spjd * User properties will result in ZPROP_INVAL, and since we 3846219089Spjd * only know how to prune standard ZFS properties, we always 3847219089Spjd * leave these in the list. This can also happen if we 3848219089Spjd * encounter an unknown DSL property (when running older 3849219089Spjd * software, for example). 3850206199Sdelphij */ 3851206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 3852205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 3853205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 3854205198Sdelphij curr = next; 3855205198Sdelphij } 3856205198Sdelphij} 3857205198Sdelphij 3858209962Smm#ifdef sun 3859209962Smmstatic int 3860209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 3861209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 3862209962Smm{ 3863209962Smm zfs_cmd_t zc = { 0 }; 3864209962Smm nvlist_t *nvlist = NULL; 3865209962Smm int error; 3866209962Smm 3867209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3868209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3869209962Smm zc.zc_cookie = (uint64_t)cmd; 3870209962Smm 3871209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 3872209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 3873209962Smm (void) no_memory(hdl); 3874209962Smm return (NULL); 3875209962Smm } 3876209962Smm } 3877209962Smm 3878209962Smm switch (cmd) { 3879209962Smm case ZFS_SMB_ACL_ADD: 3880209962Smm case ZFS_SMB_ACL_REMOVE: 3881209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 3882209962Smm break; 3883209962Smm case ZFS_SMB_ACL_RENAME: 3884209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 3885209962Smm resource1) != 0) { 3886209962Smm (void) no_memory(hdl); 3887209962Smm return (-1); 3888209962Smm } 3889209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 3890209962Smm resource2) != 0) { 3891209962Smm (void) no_memory(hdl); 3892209962Smm return (-1); 3893209962Smm } 3894209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 3895209962Smm nvlist_free(nvlist); 3896209962Smm return (-1); 3897209962Smm } 3898209962Smm break; 3899209962Smm case ZFS_SMB_ACL_PURGE: 3900209962Smm break; 3901209962Smm default: 3902209962Smm return (-1); 3903209962Smm } 3904209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 3905209962Smm if (nvlist) 3906209962Smm nvlist_free(nvlist); 3907209962Smm return (error); 3908209962Smm} 3909209962Smm 3910209962Smmint 3911209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 3912209962Smm char *path, char *resource) 3913209962Smm{ 3914209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 3915209962Smm resource, NULL)); 3916209962Smm} 3917209962Smm 3918209962Smmint 3919209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 3920209962Smm char *path, char *resource) 3921209962Smm{ 3922209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 3923209962Smm resource, NULL)); 3924209962Smm} 3925209962Smm 3926209962Smmint 3927209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 3928209962Smm{ 3929209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 3930209962Smm NULL, NULL)); 3931209962Smm} 3932209962Smm 3933209962Smmint 3934209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 3935209962Smm char *oldname, char *newname) 3936209962Smm{ 3937209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 3938209962Smm oldname, newname)); 3939209962Smm} 3940209962Smm#endif /* sun */ 3941209962Smm 3942209962Smmint 3943209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 3944209962Smm zfs_userspace_cb_t func, void *arg) 3945209962Smm{ 3946209962Smm zfs_cmd_t zc = { 0 }; 3947209962Smm int error; 3948209962Smm zfs_useracct_t buf[100]; 3949209962Smm 3950209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3951209962Smm 3952209962Smm zc.zc_objset_type = type; 3953209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 3954209962Smm 3955209962Smm /* CONSTCOND */ 3956209962Smm while (1) { 3957209962Smm zfs_useracct_t *zua = buf; 3958209962Smm 3959209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 3960209962Smm error = ioctl(zhp->zfs_hdl->libzfs_fd, 3961209962Smm ZFS_IOC_USERSPACE_MANY, &zc); 3962209962Smm if (error || zc.zc_nvlist_dst_size == 0) 3963209962Smm break; 3964209962Smm 3965209962Smm while (zc.zc_nvlist_dst_size > 0) { 3966209962Smm error = func(arg, zua->zu_domain, zua->zu_rid, 3967209962Smm zua->zu_space); 3968209962Smm if (error != 0) 3969209962Smm return (error); 3970209962Smm zua++; 3971209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 3972209962Smm } 3973209962Smm } 3974209962Smm 3975209962Smm return (error); 3976209962Smm} 3977209962Smm 3978219089Spjdint 3979219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 3980219089Spjd boolean_t recursive, boolean_t temphold, boolean_t enoent_ok, 3981219089Spjd int cleanup_fd, uint64_t dsobj, uint64_t createtxg) 3982219089Spjd{ 3983219089Spjd zfs_cmd_t zc = { 0 }; 3984219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3985219089Spjd 3986219089Spjd ASSERT(!recursive || dsobj == 0); 3987219089Spjd 3988219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3989219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3990219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 3991219089Spjd >= sizeof (zc.zc_string)) 3992219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 3993219089Spjd zc.zc_cookie = recursive; 3994219089Spjd zc.zc_temphold = temphold; 3995219089Spjd zc.zc_cleanup_fd = cleanup_fd; 3996219089Spjd zc.zc_sendobj = dsobj; 3997219089Spjd zc.zc_createtxg = createtxg; 3998219089Spjd 3999219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) { 4000219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4001219089Spjd 4002219089Spjd /* 4003219089Spjd * if it was recursive, the one that actually failed will be in 4004219089Spjd * zc.zc_name. 4005219089Spjd */ 4006219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4007219089Spjd "cannot hold '%s@%s'"), zc.zc_name, snapname); 4008219089Spjd switch (errno) { 4009219089Spjd case E2BIG: 4010219089Spjd /* 4011219089Spjd * Temporary tags wind up having the ds object id 4012219089Spjd * prepended. So even if we passed the length check 4013219089Spjd * above, it's still possible for the tag to wind 4014219089Spjd * up being slightly too long. 4015219089Spjd */ 4016219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf)); 4017219089Spjd case ENOTSUP: 4018219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4019219089Spjd "pool must be upgraded")); 4020219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 4021219089Spjd case EINVAL: 4022219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4023219089Spjd case EEXIST: 4024219089Spjd return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf)); 4025219089Spjd case ENOENT: 4026219089Spjd if (enoent_ok) 4027219089Spjd return (ENOENT); 4028219089Spjd /* FALLTHROUGH */ 4029219089Spjd default: 4030219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4031219089Spjd } 4032219089Spjd } 4033219089Spjd 4034219089Spjd return (0); 4035219089Spjd} 4036219089Spjd 4037219089Spjdint 4038219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4039219089Spjd boolean_t recursive) 4040219089Spjd{ 4041219089Spjd zfs_cmd_t zc = { 0 }; 4042219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4043219089Spjd 4044219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4045219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 4046219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 4047219089Spjd >= sizeof (zc.zc_string)) 4048219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 4049219089Spjd zc.zc_cookie = recursive; 4050219089Spjd 4051219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) { 4052219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4053219089Spjd 4054219089Spjd /* 4055219089Spjd * if it was recursive, the one that actually failed will be in 4056219089Spjd * zc.zc_name. 4057219089Spjd */ 4058219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4059219089Spjd "cannot release '%s' from '%s@%s'"), tag, zc.zc_name, 4060219089Spjd snapname); 4061219089Spjd switch (errno) { 4062219089Spjd case ESRCH: 4063219089Spjd return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf)); 4064219089Spjd case ENOTSUP: 4065219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4066219089Spjd "pool must be upgraded")); 4067219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 4068219089Spjd case EINVAL: 4069219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4070219089Spjd default: 4071219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4072219089Spjd } 4073219089Spjd } 4074219089Spjd 4075219089Spjd return (0); 4076219089Spjd} 4077219089Spjd 4078219089Spjdint 4079219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4080219089Spjd{ 4081219089Spjd zfs_cmd_t zc = { 0 }; 4082219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4083219089Spjd int nvsz = 2048; 4084219089Spjd void *nvbuf; 4085219089Spjd int err = 0; 4086219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4087219089Spjd 4088219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4089219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4090219089Spjd 4091219089Spjdtryagain: 4092219089Spjd 4093219089Spjd nvbuf = malloc(nvsz); 4094219089Spjd if (nvbuf == NULL) { 4095219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4096219089Spjd goto out; 4097219089Spjd } 4098219089Spjd 4099219089Spjd zc.zc_nvlist_dst_size = nvsz; 4100219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4101219089Spjd 4102219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4103219089Spjd 4104219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { 4105219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4106219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4107219089Spjd zc.zc_name); 4108219089Spjd switch (errno) { 4109219089Spjd case ENOMEM: 4110219089Spjd free(nvbuf); 4111219089Spjd nvsz = zc.zc_nvlist_dst_size; 4112219089Spjd goto tryagain; 4113219089Spjd 4114219089Spjd case ENOTSUP: 4115219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4116219089Spjd "pool must be upgraded")); 4117219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4118219089Spjd break; 4119219089Spjd case EINVAL: 4120219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4121219089Spjd break; 4122219089Spjd case ENOENT: 4123219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4124219089Spjd break; 4125219089Spjd default: 4126219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4127219089Spjd break; 4128219089Spjd } 4129219089Spjd } else { 4130219089Spjd /* success */ 4131219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4132219089Spjd if (rc) { 4133219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4134219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4135219089Spjd zc.zc_name); 4136219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4137219089Spjd } 4138219089Spjd } 4139219089Spjd 4140219089Spjd free(nvbuf); 4141219089Spjdout: 4142219089Spjd return (err); 4143219089Spjd} 4144219089Spjd 4145219089Spjdint 4146219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4147219089Spjd{ 4148219089Spjd zfs_cmd_t zc = { 0 }; 4149219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4150219089Spjd char *nvbuf; 4151219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4152219089Spjd size_t nvsz; 4153219089Spjd int err; 4154219089Spjd 4155219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4156219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4157219089Spjd 4158219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4159219089Spjd assert(err == 0); 4160219089Spjd 4161219089Spjd nvbuf = malloc(nvsz); 4162219089Spjd 4163219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4164219089Spjd assert(err == 0); 4165219089Spjd 4166219089Spjd zc.zc_nvlist_src_size = nvsz; 4167219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4168219089Spjd zc.zc_perm_action = un; 4169219089Spjd 4170219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4171219089Spjd 4172219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4173219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4174219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4175219089Spjd zc.zc_name); 4176219089Spjd switch (errno) { 4177219089Spjd case ENOTSUP: 4178219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4179219089Spjd "pool must be upgraded")); 4180219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4181219089Spjd break; 4182219089Spjd case EINVAL: 4183219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4184219089Spjd break; 4185219089Spjd case ENOENT: 4186219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4187219089Spjd break; 4188219089Spjd default: 4189219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4190219089Spjd break; 4191219089Spjd } 4192219089Spjd } 4193219089Spjd 4194219089Spjd free(nvbuf); 4195219089Spjd 4196219089Spjd return (err); 4197219089Spjd} 4198219089Spjd 4199219089Spjdint 4200219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4201219089Spjd{ 4202219089Spjd zfs_cmd_t zc = { 0 }; 4203219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4204219089Spjd int nvsz = 2048; 4205219089Spjd void *nvbuf; 4206219089Spjd int err = 0; 4207219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4208219089Spjd 4209219089Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 4210219089Spjd 4211219089Spjdtryagain: 4212219089Spjd 4213219089Spjd nvbuf = malloc(nvsz); 4214219089Spjd if (nvbuf == NULL) { 4215219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4216219089Spjd goto out; 4217219089Spjd } 4218219089Spjd 4219219089Spjd zc.zc_nvlist_dst_size = nvsz; 4220219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4221219089Spjd 4222219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4223219089Spjd 4224219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) { 4225219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4226219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4227219089Spjd zc.zc_name); 4228219089Spjd switch (errno) { 4229219089Spjd case ENOMEM: 4230219089Spjd free(nvbuf); 4231219089Spjd nvsz = zc.zc_nvlist_dst_size; 4232219089Spjd goto tryagain; 4233219089Spjd 4234219089Spjd case ENOTSUP: 4235219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4236219089Spjd "pool must be upgraded")); 4237219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4238219089Spjd break; 4239219089Spjd case EINVAL: 4240219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4241219089Spjd break; 4242219089Spjd case ENOENT: 4243219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4244219089Spjd break; 4245219089Spjd default: 4246219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4247219089Spjd break; 4248219089Spjd } 4249219089Spjd } else { 4250219089Spjd /* success */ 4251219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4252219089Spjd if (rc) { 4253219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4254219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4255219089Spjd zc.zc_name); 4256219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4257219089Spjd } 4258219089Spjd } 4259219089Spjd 4260219089Spjd free(nvbuf); 4261219089Spjdout: 4262219089Spjd return (err); 4263219089Spjd} 4264219089Spjd 4265219089Spjduint64_t 4266219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4267219089Spjd{ 4268219089Spjd uint64_t numdb; 4269219089Spjd uint64_t nblocks, volblocksize; 4270219089Spjd int ncopies; 4271219089Spjd char *strval; 4272219089Spjd 4273219089Spjd if (nvlist_lookup_string(props, 4274219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4275219089Spjd ncopies = atoi(strval); 4276219089Spjd else 4277219089Spjd ncopies = 1; 4278219089Spjd if (nvlist_lookup_uint64(props, 4279219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4280219089Spjd &volblocksize) != 0) 4281219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4282219089Spjd nblocks = volsize/volblocksize; 4283219089Spjd /* start with metadnode L0-L6 */ 4284219089Spjd numdb = 7; 4285219089Spjd /* calculate number of indirects */ 4286219089Spjd while (nblocks > 1) { 4287219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4288219089Spjd nblocks /= DNODES_PER_LEVEL; 4289219089Spjd numdb += nblocks; 4290219089Spjd } 4291219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4292219089Spjd volsize *= ncopies; 4293219089Spjd /* 4294219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4295219089Spjd * compressed, but in practice they compress down to about 4296219089Spjd * 1100 bytes 4297219089Spjd */ 4298219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4299219089Spjd volsize += numdb; 4300219089Spjd return (volsize); 4301219089Spjd} 4302219089Spjd 4303168404Spjd/* 4304168404Spjd * Attach/detach the given filesystem to/from the given jail. 4305168404Spjd */ 4306168404Spjdint 4307168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4308168404Spjd{ 4309168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4310168404Spjd zfs_cmd_t zc = { 0 }; 4311168404Spjd char errbuf[1024]; 4312224525Smm unsigned long cmd; 4313224525Smm int ret; 4314168404Spjd 4315168404Spjd if (attach) { 4316168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4317168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4318168404Spjd } else { 4319168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4320168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4321168404Spjd } 4322168404Spjd 4323168404Spjd switch (zhp->zfs_type) { 4324168404Spjd case ZFS_TYPE_VOLUME: 4325168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4326168404Spjd "volumes can not be jailed")); 4327168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4328168404Spjd case ZFS_TYPE_SNAPSHOT: 4329168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4330168404Spjd "snapshots can not be jailed")); 4331168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4332168404Spjd } 4333168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4334168404Spjd 4335168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4336168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4337168404Spjd zc.zc_jailid = jailid; 4338168404Spjd 4339168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4340168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4341168404Spjd zfs_standard_error(hdl, errno, errbuf); 4342168404Spjd 4343168404Spjd return (ret); 4344168404Spjd} 4345