libzfs_dataset.c revision 209962
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/* 23205198Sdelphij * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24168404Spjd * Use is subject to license terms. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <assert.h> 28168404Spjd#include <ctype.h> 29168404Spjd#include <errno.h> 30168404Spjd#include <libintl.h> 31168404Spjd#include <math.h> 32168404Spjd#include <stdio.h> 33168404Spjd#include <stdlib.h> 34168404Spjd#include <strings.h> 35168404Spjd#include <unistd.h> 36185029Spjd#include <stddef.h> 37168404Spjd#include <zone.h> 38168404Spjd#include <fcntl.h> 39168404Spjd#include <sys/mntent.h> 40168404Spjd#include <sys/mount.h> 41185029Spjd#include <sys/avl.h> 42185029Spjd#include <priv.h> 43185029Spjd#include <pwd.h> 44185029Spjd#include <grp.h> 45185029Spjd#include <stddef.h> 46209962Smm#include <idmap.h> 47168404Spjd 48168404Spjd#include <sys/spa.h> 49168404Spjd#include <sys/zap.h> 50209962Smm#include <sys/misc.h> 51168404Spjd#include <libzfs.h> 52168404Spjd 53168404Spjd#include "zfs_namecheck.h" 54168404Spjd#include "zfs_prop.h" 55168404Spjd#include "libzfs_impl.h" 56185029Spjd#include "zfs_deleg.h" 57168404Spjd 58168676Spjdstatic int zvol_create_link_common(libzfs_handle_t *, const char *, int); 59209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 60209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 61168676Spjd 62168404Spjd/* 63168404Spjd * Given a single type (not a mask of types), return the type in a human 64168404Spjd * readable form. 65168404Spjd */ 66168404Spjdconst char * 67168404Spjdzfs_type_to_name(zfs_type_t type) 68168404Spjd{ 69168404Spjd switch (type) { 70168404Spjd case ZFS_TYPE_FILESYSTEM: 71168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 72168404Spjd case ZFS_TYPE_SNAPSHOT: 73168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 74168404Spjd case ZFS_TYPE_VOLUME: 75168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 76168404Spjd } 77168404Spjd 78168404Spjd return (NULL); 79168404Spjd} 80168404Spjd 81168404Spjd/* 82168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 83168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 84168404Spjd * We guess what the type would have been based on the path and the mask of 85168404Spjd * acceptable types. 86168404Spjd */ 87168404Spjdstatic const char * 88168404Spjdpath_to_str(const char *path, int types) 89168404Spjd{ 90168404Spjd /* 91168404Spjd * When given a single type, always report the exact type. 92168404Spjd */ 93168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 94168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 95168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 96168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 97168404Spjd if (types == ZFS_TYPE_VOLUME) 98168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 99168404Spjd 100168404Spjd /* 101168404Spjd * The user is requesting more than one type of dataset. If this is the 102168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 103168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 104168404Spjd * snapshot attribute and try again. 105168404Spjd */ 106168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 107168404Spjd if (strchr(path, '@') != NULL) 108168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 109168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 110168404Spjd } 111168404Spjd 112168404Spjd /* 113168404Spjd * The user has requested either filesystems or volumes. 114168404Spjd * We have no way of knowing a priori what type this would be, so always 115168404Spjd * report it as "filesystem" or "volume", our two primitive types. 116168404Spjd */ 117168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 118168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 119168404Spjd 120168404Spjd assert(types & ZFS_TYPE_VOLUME); 121168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 122168404Spjd} 123168404Spjd 124168404Spjd/* 125168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 126209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 127209962Smm * explain exactly why the name was not valid. 128168404Spjd */ 129168404Spjdstatic int 130185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 131185029Spjd boolean_t modifying) 132168404Spjd{ 133168404Spjd namecheck_err_t why; 134168404Spjd char what; 135168404Spjd 136168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 137168404Spjd if (hdl != NULL) { 138168404Spjd switch (why) { 139168404Spjd case NAME_ERR_TOOLONG: 140168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 141168404Spjd "name is too long")); 142168404Spjd break; 143168404Spjd 144168404Spjd case NAME_ERR_LEADING_SLASH: 145168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 146168404Spjd "leading slash in name")); 147168404Spjd break; 148168404Spjd 149168404Spjd case NAME_ERR_EMPTY_COMPONENT: 150168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 151168404Spjd "empty component in name")); 152168404Spjd break; 153168404Spjd 154168404Spjd case NAME_ERR_TRAILING_SLASH: 155168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 156168404Spjd "trailing slash in name")); 157168404Spjd break; 158168404Spjd 159168404Spjd case NAME_ERR_INVALCHAR: 160168404Spjd zfs_error_aux(hdl, 161168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 162168404Spjd "'%c' in name"), what); 163168404Spjd break; 164168404Spjd 165168404Spjd case NAME_ERR_MULTIPLE_AT: 166168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 167168404Spjd "multiple '@' delimiters in name")); 168168404Spjd break; 169168404Spjd 170168404Spjd case NAME_ERR_NOLETTER: 171168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 172168404Spjd "pool doesn't begin with a letter")); 173168404Spjd break; 174168404Spjd 175168404Spjd case NAME_ERR_RESERVED: 176168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 177168404Spjd "name is reserved")); 178168404Spjd break; 179168404Spjd 180168404Spjd case NAME_ERR_DISKLIKE: 181168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 182168404Spjd "reserved disk name")); 183168404Spjd break; 184168404Spjd } 185168404Spjd } 186168404Spjd 187168404Spjd return (0); 188168404Spjd } 189168404Spjd 190168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 191168404Spjd if (hdl != NULL) 192168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 193168404Spjd "snapshot delimiter '@' in filesystem name")); 194168404Spjd return (0); 195168404Spjd } 196168404Spjd 197168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 198168404Spjd if (hdl != NULL) 199168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 200168404Spjd "missing '@' delimiter in snapshot name")); 201168404Spjd return (0); 202168404Spjd } 203168404Spjd 204185029Spjd if (modifying && strchr(path, '%') != NULL) { 205185029Spjd if (hdl != NULL) 206185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 207185029Spjd "invalid character %c in name"), '%'); 208185029Spjd return (0); 209185029Spjd } 210185029Spjd 211168404Spjd return (-1); 212168404Spjd} 213168404Spjd 214168404Spjdint 215168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 216168404Spjd{ 217185029Spjd if (type == ZFS_TYPE_POOL) 218185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 219185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 220168404Spjd} 221168404Spjd 222168404Spjd/* 223168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 224168404Spjd * properties into a separate nvlist. 225168404Spjd */ 226185029Spjdstatic nvlist_t * 227185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 228168404Spjd{ 229168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 230168404Spjd nvpair_t *elem; 231168404Spjd nvlist_t *propval; 232185029Spjd nvlist_t *nvl; 233168404Spjd 234185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 235185029Spjd (void) no_memory(hdl); 236185029Spjd return (NULL); 237185029Spjd } 238168404Spjd 239168404Spjd elem = NULL; 240185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 241168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 242168404Spjd continue; 243168404Spjd 244168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 245185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 246185029Spjd nvlist_free(nvl); 247185029Spjd (void) no_memory(hdl); 248185029Spjd return (NULL); 249185029Spjd } 250168404Spjd } 251168404Spjd 252185029Spjd return (nvl); 253168404Spjd} 254168404Spjd 255185029Spjdstatic zpool_handle_t * 256185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 257185029Spjd{ 258185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 259185029Spjd zpool_handle_t *zph; 260185029Spjd 261185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 262185029Spjd if (hdl->libzfs_pool_handles != NULL) 263185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 264185029Spjd hdl->libzfs_pool_handles = zph; 265185029Spjd } 266185029Spjd return (zph); 267185029Spjd} 268185029Spjd 269185029Spjdstatic zpool_handle_t * 270185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 271185029Spjd{ 272185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 273185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 274185029Spjd 275185029Spjd while ((zph != NULL) && 276185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 277185029Spjd zph = zph->zpool_next; 278185029Spjd return (zph); 279185029Spjd} 280185029Spjd 281168404Spjd/* 282185029Spjd * Returns a handle to the pool that contains the provided dataset. 283185029Spjd * If a handle to that pool already exists then that handle is returned. 284185029Spjd * Otherwise, a new handle is created and added to the list of handles. 285185029Spjd */ 286185029Spjdstatic zpool_handle_t * 287185029Spjdzpool_handle(zfs_handle_t *zhp) 288185029Spjd{ 289185029Spjd char *pool_name; 290185029Spjd int len; 291185029Spjd zpool_handle_t *zph; 292185029Spjd 293185029Spjd len = strcspn(zhp->zfs_name, "/@") + 1; 294185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 295185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 296185029Spjd 297185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 298185029Spjd if (zph == NULL) 299185029Spjd zph = zpool_add_handle(zhp, pool_name); 300185029Spjd 301185029Spjd free(pool_name); 302185029Spjd return (zph); 303185029Spjd} 304185029Spjd 305185029Spjdvoid 306185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 307185029Spjd{ 308185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 309185029Spjd 310185029Spjd while (zph != NULL) { 311185029Spjd next = zph->zpool_next; 312185029Spjd zpool_close(zph); 313185029Spjd zph = next; 314185029Spjd } 315185029Spjd hdl->libzfs_pool_handles = NULL; 316185029Spjd} 317185029Spjd 318185029Spjd/* 319168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 320168404Spjd */ 321209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 322168404Spjd{ 323168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 324168404Spjd 325209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 326168404Spjd 327209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 328168404Spjd if (errno == ENOMEM) { 329209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 330168404Spjd return (-1); 331168404Spjd } 332168404Spjd } else { 333168404Spjd return (-1); 334168404Spjd } 335168404Spjd } 336209962Smm return (0); 337209962Smm} 338168404Spjd 339209962Smmstatic int 340209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 341209962Smm{ 342209962Smm nvlist_t *allprops, *userprops; 343168404Spjd 344209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 345209962Smm 346209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 347168404Spjd return (-1); 348168404Spjd } 349168404Spjd 350209962Smm /* 351209962Smm * XXX Why do we store the user props separately, in addition to 352209962Smm * storing them in zfs_props? 353209962Smm */ 354185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 355185029Spjd nvlist_free(allprops); 356168404Spjd return (-1); 357185029Spjd } 358168404Spjd 359185029Spjd nvlist_free(zhp->zfs_props); 360185029Spjd nvlist_free(zhp->zfs_user_props); 361185029Spjd 362185029Spjd zhp->zfs_props = allprops; 363185029Spjd zhp->zfs_user_props = userprops; 364185029Spjd 365168404Spjd return (0); 366168404Spjd} 367168404Spjd 368209962Smmstatic int 369209962Smmget_stats(zfs_handle_t *zhp) 370209962Smm{ 371209962Smm int rc = 0; 372209962Smm zfs_cmd_t zc = { 0 }; 373209962Smm 374209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 375209962Smm return (-1); 376209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 377209962Smm rc = -1; 378209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 379209962Smm rc = -1; 380209962Smm zcmd_free_nvlists(&zc); 381209962Smm return (rc); 382209962Smm} 383209962Smm 384168404Spjd/* 385168404Spjd * Refresh the properties currently stored in the handle. 386168404Spjd */ 387168404Spjdvoid 388168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 389168404Spjd{ 390168404Spjd (void) get_stats(zhp); 391168404Spjd} 392168404Spjd 393168404Spjd/* 394168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 395168404Spjd * zfs_iter_* to create child handles on the fly. 396168404Spjd */ 397209962Smmstatic int 398209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 399168404Spjd{ 400185029Spjd char *logstr; 401209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 402168404Spjd 403185029Spjd /* 404185029Spjd * Preserve history log string. 405185029Spjd * any changes performed here will be 406185029Spjd * logged as an internal event. 407185029Spjd */ 408185029Spjd logstr = zhp->zfs_hdl->libzfs_log_str; 409185029Spjd zhp->zfs_hdl->libzfs_log_str = NULL; 410209962Smm 411168404Spjdtop: 412209962Smm if (put_stats_zhdl(zhp, zc) != 0) { 413185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 414209962Smm return (-1); 415168404Spjd } 416168404Spjd 417209962Smm 418168404Spjd if (zhp->zfs_dmustats.dds_inconsistent) { 419209962Smm zfs_cmd_t zc2 = { 0 }; 420168404Spjd 421168404Spjd /* 422168404Spjd * If it is dds_inconsistent, then we've caught it in 423168404Spjd * the middle of a 'zfs receive' or 'zfs destroy', and 424168404Spjd * it is inconsistent from the ZPL's point of view, so 425168404Spjd * can't be mounted. However, it could also be that we 426168404Spjd * have crashed in the middle of one of those 427168404Spjd * operations, in which case we need to get rid of the 428168404Spjd * inconsistent state. We do that by either rolling 429168404Spjd * back to the previous snapshot (which will fail if 430168404Spjd * there is none), or destroying the filesystem. Note 431168404Spjd * that if we are still in the middle of an active 432168404Spjd * 'receive' or 'destroy', then the rollback and destroy 433168404Spjd * will fail with EBUSY and we will drive on as usual. 434168404Spjd */ 435168404Spjd 436209962Smm (void) strlcpy(zc2.zc_name, zhp->zfs_name, 437209962Smm sizeof (zc2.zc_name)); 438168404Spjd 439168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 440168404Spjd (void) zvol_remove_link(hdl, zhp->zfs_name); 441209962Smm zc2.zc_objset_type = DMU_OST_ZVOL; 442168404Spjd } else { 443209962Smm zc2.zc_objset_type = DMU_OST_ZFS; 444168404Spjd } 445168404Spjd 446168404Spjd /* 447185029Spjd * If we can successfully destroy it, pretend that it 448168404Spjd * never existed. 449168404Spjd */ 450209962Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc2) == 0) { 451185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 452168404Spjd errno = ENOENT; 453209962Smm return (-1); 454168404Spjd } 455209962Smm /* If we can successfully roll it back, reset the stats */ 456209962Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc2) == 0) { 457209962Smm if (get_stats_ioctl(zhp, zc) != 0) { 458209962Smm zhp->zfs_hdl->libzfs_log_str = logstr; 459209962Smm return (-1); 460209962Smm } 461185029Spjd goto top; 462209962Smm } 463168404Spjd } 464168404Spjd 465168404Spjd /* 466168404Spjd * We've managed to open the dataset and gather statistics. Determine 467168404Spjd * the high-level type. 468168404Spjd */ 469168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 470168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 471168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 472168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 473168404Spjd else 474168404Spjd abort(); 475168404Spjd 476168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 477168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 478168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 479168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 480168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 481168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 482168404Spjd else 483168404Spjd abort(); /* we should never see any other types */ 484168404Spjd 485185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 486185029Spjd zhp->zpool_hdl = zpool_handle(zhp); 487209962Smm return (0); 488209962Smm} 489209962Smm 490209962Smmzfs_handle_t * 491209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 492209962Smm{ 493209962Smm zfs_cmd_t zc = { 0 }; 494209962Smm 495209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 496209962Smm 497209962Smm if (zhp == NULL) 498209962Smm return (NULL); 499209962Smm 500209962Smm zhp->zfs_hdl = hdl; 501209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 502209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 503209962Smm free(zhp); 504209962Smm return (NULL); 505209962Smm } 506209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 507209962Smm zcmd_free_nvlists(&zc); 508209962Smm free(zhp); 509209962Smm return (NULL); 510209962Smm } 511209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 512209962Smm free(zhp); 513209962Smm zhp = NULL; 514209962Smm } 515209962Smm zcmd_free_nvlists(&zc); 516168404Spjd return (zhp); 517168404Spjd} 518168404Spjd 519209962Smmstatic zfs_handle_t * 520209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 521209962Smm{ 522209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 523209962Smm 524209962Smm if (zhp == NULL) 525209962Smm return (NULL); 526209962Smm 527209962Smm zhp->zfs_hdl = hdl; 528209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 529209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 530209962Smm free(zhp); 531209962Smm return (NULL); 532209962Smm } 533209962Smm return (zhp); 534209962Smm} 535209962Smm 536168404Spjd/* 537168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 538168404Spjd * argument is a mask of acceptable types. The function will print an 539168404Spjd * appropriate error message and return NULL if it can't be opened. 540168404Spjd */ 541168404Spjdzfs_handle_t * 542168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 543168404Spjd{ 544168404Spjd zfs_handle_t *zhp; 545168404Spjd char errbuf[1024]; 546168404Spjd 547168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 548168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 549168404Spjd 550168404Spjd /* 551168404Spjd * Validate the name before we even try to open it. 552168404Spjd */ 553185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 554168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 555168404Spjd "invalid dataset name")); 556168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 557168404Spjd return (NULL); 558168404Spjd } 559168404Spjd 560168404Spjd /* 561168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 562168404Spjd */ 563168404Spjd errno = 0; 564168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 565168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 566168404Spjd return (NULL); 567168404Spjd } 568168404Spjd 569168404Spjd if (!(types & zhp->zfs_type)) { 570168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 571168404Spjd zfs_close(zhp); 572168404Spjd return (NULL); 573168404Spjd } 574168404Spjd 575168404Spjd return (zhp); 576168404Spjd} 577168404Spjd 578168404Spjd/* 579168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 580168404Spjd */ 581168404Spjdvoid 582168404Spjdzfs_close(zfs_handle_t *zhp) 583168404Spjd{ 584168404Spjd if (zhp->zfs_mntopts) 585168404Spjd free(zhp->zfs_mntopts); 586168404Spjd nvlist_free(zhp->zfs_props); 587168404Spjd nvlist_free(zhp->zfs_user_props); 588168404Spjd free(zhp); 589168404Spjd} 590168404Spjd 591209962Smmtypedef struct mnttab_node { 592209962Smm struct mnttab mtn_mt; 593209962Smm avl_node_t mtn_node; 594209962Smm} mnttab_node_t; 595209962Smm 596209962Smmstatic int 597209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 598209962Smm{ 599209962Smm const mnttab_node_t *mtn1 = arg1; 600209962Smm const mnttab_node_t *mtn2 = arg2; 601209962Smm int rv; 602209962Smm 603209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 604209962Smm 605209962Smm if (rv == 0) 606209962Smm return (0); 607209962Smm return (rv > 0 ? 1 : -1); 608209962Smm} 609209962Smm 610209962Smmvoid 611209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 612209962Smm{ 613209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 614209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 615209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 616209962Smm} 617209962Smm 618209962Smmvoid 619209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 620209962Smm{ 621209962Smm struct mnttab entry; 622209962Smm 623209962Smm rewind(hdl->libzfs_mnttab); 624209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 625209962Smm mnttab_node_t *mtn; 626209962Smm 627209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 628209962Smm continue; 629209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 630209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 631209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 632209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 633209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 634209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 635209962Smm } 636209962Smm} 637209962Smm 638209962Smmvoid 639209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 640209962Smm{ 641209962Smm void *cookie = NULL; 642209962Smm mnttab_node_t *mtn; 643209962Smm 644209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 645209962Smm free(mtn->mtn_mt.mnt_special); 646209962Smm free(mtn->mtn_mt.mnt_mountp); 647209962Smm free(mtn->mtn_mt.mnt_fstype); 648209962Smm free(mtn->mtn_mt.mnt_mntopts); 649209962Smm free(mtn); 650209962Smm } 651209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 652209962Smm} 653209962Smm 654209962Smmvoid 655209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 656209962Smm{ 657209962Smm hdl->libzfs_mnttab_enable = enable; 658209962Smm} 659209962Smm 660185029Spjdint 661209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 662209962Smm struct mnttab *entry) 663209962Smm{ 664209962Smm mnttab_node_t find; 665209962Smm mnttab_node_t *mtn; 666209962Smm 667209962Smm if (!hdl->libzfs_mnttab_enable) { 668209962Smm struct mnttab srch = { 0 }; 669209962Smm 670209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 671209962Smm libzfs_mnttab_fini(hdl); 672209962Smm rewind(hdl->libzfs_mnttab); 673209962Smm srch.mnt_special = (char *)fsname; 674209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 675209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 676209962Smm return (0); 677209962Smm else 678209962Smm return (ENOENT); 679209962Smm } 680209962Smm 681209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 682209962Smm libzfs_mnttab_update(hdl); 683209962Smm 684209962Smm find.mtn_mt.mnt_special = (char *)fsname; 685209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 686209962Smm if (mtn) { 687209962Smm *entry = mtn->mtn_mt; 688209962Smm return (0); 689209962Smm } 690209962Smm return (ENOENT); 691209962Smm} 692209962Smm 693209962Smmvoid 694209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 695209962Smm const char *mountp, const char *mntopts) 696209962Smm{ 697209962Smm mnttab_node_t *mtn; 698209962Smm 699209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 700209962Smm return; 701209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 702209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 703209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 704209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 705209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 706209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 707209962Smm} 708209962Smm 709209962Smmvoid 710209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 711209962Smm{ 712209962Smm mnttab_node_t find; 713209962Smm mnttab_node_t *ret; 714209962Smm 715209962Smm find.mtn_mt.mnt_special = (char *)fsname; 716209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 717209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 718209962Smm free(ret->mtn_mt.mnt_special); 719209962Smm free(ret->mtn_mt.mnt_mountp); 720209962Smm free(ret->mtn_mt.mnt_fstype); 721209962Smm free(ret->mtn_mt.mnt_mntopts); 722209962Smm free(ret); 723209962Smm } 724209962Smm} 725209962Smm 726209962Smmint 727185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 728168404Spjd{ 729185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 730168404Spjd 731185029Spjd if (zpool_handle == NULL) 732168404Spjd return (-1); 733168404Spjd 734185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 735185029Spjd ZPOOL_PROP_VERSION, NULL); 736168404Spjd return (0); 737168404Spjd} 738168404Spjd 739168404Spjd/* 740185029Spjd * The choice of reservation property depends on the SPA version. 741168404Spjd */ 742168404Spjdstatic int 743185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 744168404Spjd{ 745185029Spjd int spa_version; 746168404Spjd 747185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 748168404Spjd return (-1); 749168404Spjd 750185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 751185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 752185029Spjd else 753185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 754168404Spjd 755168404Spjd return (0); 756168404Spjd} 757168404Spjd 758168404Spjd/* 759168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 760168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 761168404Spjd * strings. 762168404Spjd */ 763168404Spjdnvlist_t * 764185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 765185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 766168404Spjd{ 767168404Spjd nvpair_t *elem; 768168404Spjd uint64_t intval; 769168404Spjd char *strval; 770185029Spjd zfs_prop_t prop; 771168404Spjd nvlist_t *ret; 772185029Spjd int chosen_normal = -1; 773185029Spjd int chosen_utf = -1; 774168404Spjd 775168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 776168404Spjd (void) no_memory(hdl); 777168404Spjd return (NULL); 778168404Spjd } 779168404Spjd 780209962Smm /* 781209962Smm * Make sure this property is valid and applies to this type. 782209962Smm */ 783209962Smm 784168404Spjd elem = NULL; 785168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 786185029Spjd const char *propname = nvpair_name(elem); 787168404Spjd 788209962Smm prop = zfs_name_to_prop(propname); 789209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 790185029Spjd /* 791209962Smm * This is a user property: make sure it's a 792185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 793185029Spjd */ 794185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 795185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 796185029Spjd "'%s' must be a string"), propname); 797185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 798185029Spjd goto error; 799168404Spjd } 800168404Spjd 801185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 802185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 803185029Spjd "property name '%s' is too long"), 804185029Spjd propname); 805185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 806185029Spjd goto error; 807185029Spjd } 808185029Spjd 809168404Spjd (void) nvpair_value_string(elem, &strval); 810168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 811168404Spjd (void) no_memory(hdl); 812168404Spjd goto error; 813168404Spjd } 814168404Spjd continue; 815168404Spjd } 816168404Spjd 817209962Smm /* 818209962Smm * Currently, only user properties can be modified on 819209962Smm * snapshots. 820209962Smm */ 821185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 822185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 823185029Spjd "this property can not be modified for snapshots")); 824185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 825185029Spjd goto error; 826185029Spjd } 827168404Spjd 828209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 829209962Smm zfs_userquota_prop_t uqtype; 830209962Smm char newpropname[128]; 831209962Smm char domain[128]; 832209962Smm uint64_t rid; 833209962Smm uint64_t valary[3]; 834209962Smm 835209962Smm if (userquota_propname_decode(propname, zoned, 836209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 837209962Smm zfs_error_aux(hdl, 838209962Smm dgettext(TEXT_DOMAIN, 839209962Smm "'%s' has an invalid user/group name"), 840209962Smm propname); 841209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 842209962Smm goto error; 843209962Smm } 844209962Smm 845209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 846209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 847209962Smm zfs_error_aux(hdl, 848209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 849209962Smm propname); 850209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 851209962Smm errbuf); 852209962Smm goto error; 853209962Smm } 854209962Smm 855209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 856209962Smm (void) nvpair_value_string(elem, &strval); 857209962Smm if (strcmp(strval, "none") == 0) { 858209962Smm intval = 0; 859209962Smm } else if (zfs_nicestrtonum(hdl, 860209962Smm strval, &intval) != 0) { 861209962Smm (void) zfs_error(hdl, 862209962Smm EZFS_BADPROP, errbuf); 863209962Smm goto error; 864209962Smm } 865209962Smm } else if (nvpair_type(elem) == 866209962Smm DATA_TYPE_UINT64) { 867209962Smm (void) nvpair_value_uint64(elem, &intval); 868209962Smm if (intval == 0) { 869209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 870209962Smm "use 'none' to disable " 871209962Smm "userquota/groupquota")); 872209962Smm goto error; 873209962Smm } 874209962Smm } else { 875209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 876209962Smm "'%s' must be a number"), propname); 877209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 878209962Smm goto error; 879209962Smm } 880209962Smm 881209962Smm (void) snprintf(newpropname, sizeof (newpropname), 882209962Smm "%s%s", zfs_userquota_prop_prefixes[uqtype], 883209962Smm domain); 884209962Smm valary[0] = uqtype; 885209962Smm valary[1] = rid; 886209962Smm valary[2] = intval; 887209962Smm if (nvlist_add_uint64_array(ret, newpropname, 888209962Smm valary, 3) != 0) { 889209962Smm (void) no_memory(hdl); 890209962Smm goto error; 891209962Smm } 892209962Smm continue; 893209962Smm } 894209962Smm 895209962Smm if (prop == ZPROP_INVAL) { 896209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 897209962Smm "invalid property '%s'"), propname); 898209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 899209962Smm goto error; 900209962Smm } 901209962Smm 902168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 903168404Spjd zfs_error_aux(hdl, 904168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 905168404Spjd "apply to datasets of this type"), propname); 906168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 907168404Spjd goto error; 908168404Spjd } 909168404Spjd 910168404Spjd if (zfs_prop_readonly(prop) && 911185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 912168404Spjd zfs_error_aux(hdl, 913168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 914168404Spjd propname); 915168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 916168404Spjd goto error; 917168404Spjd } 918168404Spjd 919185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 920185029Spjd &strval, &intval, errbuf) != 0) 921185029Spjd goto error; 922185029Spjd 923168404Spjd /* 924185029Spjd * Perform some additional checks for specific properties. 925168404Spjd */ 926185029Spjd switch (prop) { 927185029Spjd case ZFS_PROP_VERSION: 928185029Spjd { 929185029Spjd int version; 930168404Spjd 931185029Spjd if (zhp == NULL) 932185029Spjd break; 933185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 934185029Spjd if (intval < version) { 935168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 936185029Spjd "Can not downgrade; already at version %u"), 937185029Spjd version); 938168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 939168404Spjd goto error; 940168404Spjd } 941168404Spjd break; 942168404Spjd } 943168404Spjd 944168404Spjd case ZFS_PROP_RECORDSIZE: 945168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 946168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 947168404Spjd if (intval < SPA_MINBLOCKSIZE || 948168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 949168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 950168404Spjd "'%s' must be power of 2 from %u " 951168404Spjd "to %uk"), propname, 952168404Spjd (uint_t)SPA_MINBLOCKSIZE, 953168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 954168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 955168404Spjd goto error; 956168404Spjd } 957168404Spjd break; 958168404Spjd 959168404Spjd case ZFS_PROP_SHAREISCSI: 960168404Spjd if (strcmp(strval, "off") != 0 && 961168404Spjd strcmp(strval, "on") != 0 && 962168404Spjd strcmp(strval, "type=disk") != 0) { 963168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 964168404Spjd "'%s' must be 'on', 'off', or 'type=disk'"), 965168404Spjd propname); 966168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 967168404Spjd goto error; 968168404Spjd } 969168404Spjd 970168404Spjd break; 971168404Spjd 972168404Spjd case ZFS_PROP_MOUNTPOINT: 973185029Spjd { 974185029Spjd namecheck_err_t why; 975185029Spjd 976168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 977168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 978168404Spjd break; 979168404Spjd 980185029Spjd if (mountpoint_namecheck(strval, &why)) { 981185029Spjd switch (why) { 982185029Spjd case NAME_ERR_LEADING_SLASH: 983185029Spjd zfs_error_aux(hdl, 984185029Spjd dgettext(TEXT_DOMAIN, 985185029Spjd "'%s' must be an absolute path, " 986185029Spjd "'none', or 'legacy'"), propname); 987185029Spjd break; 988185029Spjd case NAME_ERR_TOOLONG: 989185029Spjd zfs_error_aux(hdl, 990185029Spjd dgettext(TEXT_DOMAIN, 991185029Spjd "component of '%s' is too long"), 992185029Spjd propname); 993185029Spjd break; 994185029Spjd } 995168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 996168404Spjd goto error; 997168404Spjd } 998185029Spjd } 999185029Spjd 1000168404Spjd /*FALLTHRU*/ 1001168404Spjd 1002185029Spjd case ZFS_PROP_SHARESMB: 1003168404Spjd case ZFS_PROP_SHARENFS: 1004168404Spjd /* 1005185029Spjd * For the mountpoint and sharenfs or sharesmb 1006185029Spjd * properties, check if it can be set in a 1007185029Spjd * global/non-global zone based on 1008168404Spjd * the zoned property value: 1009168404Spjd * 1010168404Spjd * global zone non-global zone 1011168404Spjd * -------------------------------------------------- 1012168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1013168404Spjd * sharenfs (no) sharenfs (no) 1014185029Spjd * sharesmb (no) sharesmb (no) 1015168404Spjd * 1016168404Spjd * zoned=off mountpoint (yes) N/A 1017168404Spjd * sharenfs (yes) 1018185029Spjd * sharesmb (yes) 1019168404Spjd */ 1020168404Spjd if (zoned) { 1021168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1022168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1023168404Spjd "'%s' cannot be set on " 1024168404Spjd "dataset in a non-global zone"), 1025168404Spjd propname); 1026168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1027168404Spjd errbuf); 1028168404Spjd goto error; 1029185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1030185029Spjd prop == ZFS_PROP_SHARESMB) { 1031168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1032168404Spjd "'%s' cannot be set in " 1033168404Spjd "a non-global zone"), propname); 1034168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1035168404Spjd errbuf); 1036168404Spjd goto error; 1037168404Spjd } 1038168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1039168404Spjd /* 1040168404Spjd * If zoned property is 'off', this must be in 1041209962Smm * a global zone. If not, something is wrong. 1042168404Spjd */ 1043168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1044168404Spjd "'%s' cannot be set while dataset " 1045168404Spjd "'zoned' property is set"), propname); 1046168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1047168404Spjd goto error; 1048168404Spjd } 1049168404Spjd 1050168404Spjd /* 1051185029Spjd * At this point, it is legitimate to set the 1052185029Spjd * property. Now we want to make sure that the 1053185029Spjd * property value is valid if it is sharenfs. 1054168404Spjd */ 1055185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1056185029Spjd prop == ZFS_PROP_SHARESMB) && 1057185029Spjd strcmp(strval, "on") != 0 && 1058185029Spjd strcmp(strval, "off") != 0) { 1059185029Spjd zfs_share_proto_t proto; 1060168404Spjd 1061185029Spjd if (prop == ZFS_PROP_SHARESMB) 1062185029Spjd proto = PROTO_SMB; 1063185029Spjd else 1064185029Spjd proto = PROTO_NFS; 1065185029Spjd 1066185029Spjd /* 1067185029Spjd * Must be an valid sharing protocol 1068185029Spjd * option string so init the libshare 1069185029Spjd * in order to enable the parser and 1070185029Spjd * then parse the options. We use the 1071185029Spjd * control API since we don't care about 1072185029Spjd * the current configuration and don't 1073185029Spjd * want the overhead of loading it 1074185029Spjd * until we actually do something. 1075185029Spjd */ 1076185029Spjd 1077185029Spjd if (zfs_init_libshare(hdl, 1078185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1079185029Spjd /* 1080185029Spjd * An error occurred so we can't do 1081185029Spjd * anything 1082185029Spjd */ 1083185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1084185029Spjd "'%s' cannot be set: problem " 1085185029Spjd "in share initialization"), 1086185029Spjd propname); 1087185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1088185029Spjd errbuf); 1089185029Spjd goto error; 1090185029Spjd } 1091185029Spjd 1092185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1093185029Spjd /* 1094185029Spjd * There was an error in parsing so 1095185029Spjd * deal with it by issuing an error 1096185029Spjd * message and leaving after 1097185029Spjd * uninitializing the the libshare 1098185029Spjd * interface. 1099185029Spjd */ 1100185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1101185029Spjd "'%s' cannot be set to invalid " 1102185029Spjd "options"), propname); 1103185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1104185029Spjd errbuf); 1105185029Spjd zfs_uninit_libshare(hdl); 1106185029Spjd goto error; 1107185029Spjd } 1108185029Spjd zfs_uninit_libshare(hdl); 1109168404Spjd } 1110185029Spjd 1111168404Spjd break; 1112185029Spjd case ZFS_PROP_UTF8ONLY: 1113185029Spjd chosen_utf = (int)intval; 1114185029Spjd break; 1115185029Spjd case ZFS_PROP_NORMALIZE: 1116185029Spjd chosen_normal = (int)intval; 1117185029Spjd break; 1118168404Spjd } 1119168404Spjd 1120168404Spjd /* 1121168404Spjd * For changes to existing volumes, we have some additional 1122168404Spjd * checks to enforce. 1123168404Spjd */ 1124168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1125168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1126168404Spjd ZFS_PROP_VOLSIZE); 1127168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1128168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1129168404Spjd char buf[64]; 1130168404Spjd 1131168404Spjd switch (prop) { 1132168404Spjd case ZFS_PROP_RESERVATION: 1133185029Spjd case ZFS_PROP_REFRESERVATION: 1134168404Spjd if (intval > volsize) { 1135168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1136168404Spjd "'%s' is greater than current " 1137168404Spjd "volume size"), propname); 1138168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1139168404Spjd errbuf); 1140168404Spjd goto error; 1141168404Spjd } 1142168404Spjd break; 1143168404Spjd 1144168404Spjd case ZFS_PROP_VOLSIZE: 1145168404Spjd if (intval % blocksize != 0) { 1146168404Spjd zfs_nicenum(blocksize, buf, 1147168404Spjd sizeof (buf)); 1148168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1149168404Spjd "'%s' must be a multiple of " 1150168404Spjd "volume block size (%s)"), 1151168404Spjd propname, buf); 1152168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1153168404Spjd errbuf); 1154168404Spjd goto error; 1155168404Spjd } 1156168404Spjd 1157168404Spjd if (intval == 0) { 1158168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1159168404Spjd "'%s' cannot be zero"), 1160168404Spjd propname); 1161168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1162168404Spjd errbuf); 1163168404Spjd goto error; 1164168404Spjd } 1165168404Spjd break; 1166168404Spjd } 1167168404Spjd } 1168168404Spjd } 1169168404Spjd 1170168404Spjd /* 1171185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1172185029Spjd * enforce rejection of non-UTF8 names. 1173185029Spjd * 1174185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1175185029Spjd * was explicitly not chosen, it is an error. 1176185029Spjd */ 1177185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1178185029Spjd if (nvlist_add_uint64(ret, 1179185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1180185029Spjd (void) no_memory(hdl); 1181185029Spjd goto error; 1182185029Spjd } 1183185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1184185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1185185029Spjd "'%s' must be set 'on' if normalization chosen"), 1186185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1187185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1188185029Spjd goto error; 1189185029Spjd } 1190185029Spjd 1191185029Spjd /* 1192168404Spjd * If this is an existing volume, and someone is setting the volsize, 1193168404Spjd * make sure that it matches the reservation, or add it if necessary. 1194168404Spjd */ 1195168404Spjd if (zhp != NULL && type == ZFS_TYPE_VOLUME && 1196168404Spjd nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1197168404Spjd &intval) == 0) { 1198168404Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1199168404Spjd ZFS_PROP_VOLSIZE); 1200185029Spjd uint64_t old_reservation; 1201168404Spjd uint64_t new_reservation; 1202185029Spjd zfs_prop_t resv_prop; 1203168404Spjd 1204185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1205185029Spjd goto error; 1206185029Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1207185029Spjd 1208168404Spjd if (old_volsize == old_reservation && 1209185029Spjd nvlist_lookup_uint64(ret, zfs_prop_to_name(resv_prop), 1210168404Spjd &new_reservation) != 0) { 1211168404Spjd if (nvlist_add_uint64(ret, 1212185029Spjd zfs_prop_to_name(resv_prop), intval) != 0) { 1213168404Spjd (void) no_memory(hdl); 1214168404Spjd goto error; 1215168404Spjd } 1216168404Spjd } 1217168404Spjd } 1218168404Spjd return (ret); 1219168404Spjd 1220168404Spjderror: 1221168404Spjd nvlist_free(ret); 1222168404Spjd return (NULL); 1223168404Spjd} 1224168404Spjd 1225168404Spjd/* 1226168404Spjd * Given a property name and value, set the property for the given dataset. 1227168404Spjd */ 1228168404Spjdint 1229168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1230168404Spjd{ 1231168404Spjd zfs_cmd_t zc = { 0 }; 1232168404Spjd int ret = -1; 1233168404Spjd prop_changelist_t *cl = NULL; 1234168404Spjd char errbuf[1024]; 1235168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1236168404Spjd nvlist_t *nvl = NULL, *realprops; 1237168404Spjd zfs_prop_t prop; 1238185029Spjd boolean_t do_prefix; 1239185029Spjd uint64_t idx; 1240168404Spjd 1241168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1242168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1243168404Spjd zhp->zfs_name); 1244168404Spjd 1245168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1246168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1247168404Spjd (void) no_memory(hdl); 1248168404Spjd goto error; 1249168404Spjd } 1250168404Spjd 1251185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1252168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1253168404Spjd goto error; 1254185029Spjd 1255168404Spjd nvlist_free(nvl); 1256168404Spjd nvl = realprops; 1257168404Spjd 1258168404Spjd prop = zfs_name_to_prop(propname); 1259168404Spjd 1260168404Spjd /* We don't support those properties on FreeBSD. */ 1261168404Spjd switch (prop) { 1262197867Strasz case ZFS_PROP_DEVICES: 1263168404Spjd case ZFS_PROP_SHAREISCSI: 1264168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1265197867Strasz case ZFS_PROP_XATTR: 1266197867Strasz case ZFS_PROP_VSCAN: 1267197867Strasz case ZFS_PROP_NBMAND: 1268197867Strasz case ZFS_PROP_SHARESMB: 1269168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1270168404Spjd "property '%s' not supported on FreeBSD", propname); 1271168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1272168404Spjd goto error; 1273168404Spjd } 1274168404Spjd 1275185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1276168404Spjd goto error; 1277168404Spjd 1278168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1279168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1280168404Spjd "child dataset with inherited mountpoint is used " 1281168404Spjd "in a non-global zone")); 1282168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1283168404Spjd goto error; 1284168404Spjd } 1285168404Spjd 1286185029Spjd /* 1287185029Spjd * If the dataset's canmount property is being set to noauto, 1288185029Spjd * then we want to prevent unmounting & remounting it. 1289185029Spjd */ 1290185029Spjd do_prefix = !((prop == ZFS_PROP_CANMOUNT) && 1291185029Spjd (zprop_string_to_index(prop, propval, &idx, 1292185029Spjd ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); 1293185029Spjd 1294185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1295168404Spjd goto error; 1296168404Spjd 1297168404Spjd /* 1298168404Spjd * Execute the corresponding ioctl() to set this property. 1299168404Spjd */ 1300168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1301168404Spjd 1302185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1303168404Spjd goto error; 1304168404Spjd 1305185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1306209962Smm 1307168404Spjd if (ret != 0) { 1308168404Spjd switch (errno) { 1309168404Spjd 1310168404Spjd case ENOSPC: 1311168404Spjd /* 1312168404Spjd * For quotas and reservations, ENOSPC indicates 1313168404Spjd * something different; setting a quota or reservation 1314168404Spjd * doesn't use any disk space. 1315168404Spjd */ 1316168404Spjd switch (prop) { 1317168404Spjd case ZFS_PROP_QUOTA: 1318185029Spjd case ZFS_PROP_REFQUOTA: 1319168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1320168404Spjd "size is less than current used or " 1321168404Spjd "reserved space")); 1322168404Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1323168404Spjd break; 1324168404Spjd 1325168404Spjd case ZFS_PROP_RESERVATION: 1326185029Spjd case ZFS_PROP_REFRESERVATION: 1327168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1328168404Spjd "size is greater than available space")); 1329168404Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1330168404Spjd break; 1331168404Spjd 1332168404Spjd default: 1333168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 1334168404Spjd break; 1335168404Spjd } 1336168404Spjd break; 1337168404Spjd 1338168404Spjd case EBUSY: 1339168404Spjd if (prop == ZFS_PROP_VOLBLOCKSIZE) 1340168404Spjd (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 1341168404Spjd else 1342168404Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1343168404Spjd break; 1344168404Spjd 1345168404Spjd case EROFS: 1346168404Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1347168404Spjd break; 1348168404Spjd 1349168404Spjd case ENOTSUP: 1350168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1351185029Spjd "pool and or dataset must be upgraded to set this " 1352185029Spjd "property or value")); 1353168404Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1354168404Spjd break; 1355168404Spjd 1356185029Spjd case ERANGE: 1357185029Spjd if (prop == ZFS_PROP_COMPRESSION) { 1358185029Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1359185029Spjd "property setting is not allowed on " 1360185029Spjd "bootable datasets")); 1361185029Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1362185029Spjd } else { 1363185029Spjd (void) zfs_standard_error(hdl, errno, errbuf); 1364185029Spjd } 1365185029Spjd break; 1366185029Spjd 1367168404Spjd case EOVERFLOW: 1368168404Spjd /* 1369168404Spjd * This platform can't address a volume this big. 1370168404Spjd */ 1371168404Spjd#ifdef _ILP32 1372168404Spjd if (prop == ZFS_PROP_VOLSIZE) { 1373168404Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1374168404Spjd break; 1375168404Spjd } 1376168404Spjd#endif 1377168404Spjd /* FALLTHROUGH */ 1378168404Spjd default: 1379168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 1380168404Spjd } 1381168404Spjd } else { 1382185029Spjd if (do_prefix) 1383185029Spjd ret = changelist_postfix(cl); 1384185029Spjd 1385168404Spjd /* 1386168404Spjd * Refresh the statistics so the new property value 1387168404Spjd * is reflected. 1388168404Spjd */ 1389185029Spjd if (ret == 0) 1390168404Spjd (void) get_stats(zhp); 1391168404Spjd } 1392168404Spjd 1393168404Spjderror: 1394168404Spjd nvlist_free(nvl); 1395168404Spjd zcmd_free_nvlists(&zc); 1396168404Spjd if (cl) 1397168404Spjd changelist_free(cl); 1398168404Spjd return (ret); 1399168404Spjd} 1400168404Spjd 1401168404Spjd/* 1402168404Spjd * Given a property, inherit the value from the parent dataset. 1403168404Spjd */ 1404168404Spjdint 1405168404Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1406168404Spjd{ 1407168404Spjd zfs_cmd_t zc = { 0 }; 1408168404Spjd int ret; 1409168404Spjd prop_changelist_t *cl; 1410168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1411168404Spjd char errbuf[1024]; 1412168404Spjd zfs_prop_t prop; 1413168404Spjd 1414168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1415168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1416168404Spjd 1417185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1418168404Spjd /* 1419168404Spjd * For user properties, the amount of work we have to do is very 1420168404Spjd * small, so just do it here. 1421168404Spjd */ 1422168404Spjd if (!zfs_prop_user(propname)) { 1423168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1424168404Spjd "invalid property")); 1425168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1426168404Spjd } 1427168404Spjd 1428168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1429168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1430168404Spjd 1431185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1432168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1433168404Spjd 1434168404Spjd return (0); 1435168404Spjd } 1436168404Spjd 1437168404Spjd /* 1438168404Spjd * Verify that this property is inheritable. 1439168404Spjd */ 1440168404Spjd if (zfs_prop_readonly(prop)) 1441168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1442168404Spjd 1443168404Spjd if (!zfs_prop_inheritable(prop)) 1444168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1445168404Spjd 1446168404Spjd /* 1447168404Spjd * Check to see if the value applies to this type 1448168404Spjd */ 1449168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1450168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1451168404Spjd 1452168404Spjd /* 1453168404Spjd * Normalize the name, to get rid of shorthand abbrevations. 1454168404Spjd */ 1455168404Spjd propname = zfs_prop_to_name(prop); 1456168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1457168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1458168404Spjd 1459168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1460168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1461168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1462168404Spjd "dataset is used in a non-global zone")); 1463168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1464168404Spjd } 1465168404Spjd 1466168404Spjd /* 1467168404Spjd * Determine datasets which will be affected by this change, if any. 1468168404Spjd */ 1469185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1470168404Spjd return (-1); 1471168404Spjd 1472168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1473168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1474168404Spjd "child dataset with inherited mountpoint is used " 1475168404Spjd "in a non-global zone")); 1476168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1477168404Spjd goto error; 1478168404Spjd } 1479168404Spjd 1480168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1481168404Spjd goto error; 1482168404Spjd 1483185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1484168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1485168404Spjd } else { 1486168404Spjd 1487168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1488168404Spjd goto error; 1489168404Spjd 1490168404Spjd /* 1491168404Spjd * Refresh the statistics so the new property is reflected. 1492168404Spjd */ 1493168404Spjd (void) get_stats(zhp); 1494168404Spjd } 1495168404Spjd 1496168404Spjderror: 1497168404Spjd changelist_free(cl); 1498168404Spjd return (ret); 1499168404Spjd} 1500168404Spjd 1501168404Spjd/* 1502168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1503168404Spjd * extract them appropriately. 1504168404Spjd */ 1505168404Spjdstatic uint64_t 1506168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1507168404Spjd{ 1508168404Spjd nvlist_t *nv; 1509168404Spjd uint64_t value; 1510168404Spjd 1511168404Spjd *source = NULL; 1512168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1513168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1514185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1515185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1516168404Spjd } else { 1517205198Sdelphij verify(!zhp->zfs_props_table || 1518205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1519168404Spjd value = zfs_prop_default_numeric(prop); 1520168404Spjd *source = ""; 1521168404Spjd } 1522168404Spjd 1523168404Spjd return (value); 1524168404Spjd} 1525168404Spjd 1526168404Spjdstatic char * 1527168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1528168404Spjd{ 1529168404Spjd nvlist_t *nv; 1530168404Spjd char *value; 1531168404Spjd 1532168404Spjd *source = NULL; 1533168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1534168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1535185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1536185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1537168404Spjd } else { 1538205198Sdelphij verify(!zhp->zfs_props_table || 1539205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1540168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1541168404Spjd value = ""; 1542168404Spjd *source = ""; 1543168404Spjd } 1544168404Spjd 1545168404Spjd return (value); 1546168404Spjd} 1547168404Spjd 1548168404Spjd/* 1549168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1550168404Spjd * zfs_prop_get_int() are built using this interface. 1551168404Spjd * 1552168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1553168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1554168404Spjd * If they differ from the on-disk values, report the current values and mark 1555168404Spjd * the source "temporary". 1556168404Spjd */ 1557168404Spjdstatic int 1558185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1559168404Spjd char **source, uint64_t *val) 1560168404Spjd{ 1561185029Spjd zfs_cmd_t zc = { 0 }; 1562185029Spjd nvlist_t *zplprops = NULL; 1563168404Spjd struct mnttab mnt; 1564168404Spjd char *mntopt_on = NULL; 1565168404Spjd char *mntopt_off = NULL; 1566168404Spjd 1567168404Spjd *source = NULL; 1568168404Spjd 1569168404Spjd switch (prop) { 1570168404Spjd case ZFS_PROP_ATIME: 1571168404Spjd mntopt_on = MNTOPT_ATIME; 1572168404Spjd mntopt_off = MNTOPT_NOATIME; 1573168404Spjd break; 1574168404Spjd 1575168404Spjd case ZFS_PROP_DEVICES: 1576168404Spjd mntopt_on = MNTOPT_DEVICES; 1577168404Spjd mntopt_off = MNTOPT_NODEVICES; 1578168404Spjd break; 1579168404Spjd 1580168404Spjd case ZFS_PROP_EXEC: 1581168404Spjd mntopt_on = MNTOPT_EXEC; 1582168404Spjd mntopt_off = MNTOPT_NOEXEC; 1583168404Spjd break; 1584168404Spjd 1585168404Spjd case ZFS_PROP_READONLY: 1586168404Spjd mntopt_on = MNTOPT_RO; 1587168404Spjd mntopt_off = MNTOPT_RW; 1588168404Spjd break; 1589168404Spjd 1590168404Spjd case ZFS_PROP_SETUID: 1591168404Spjd mntopt_on = MNTOPT_SETUID; 1592168404Spjd mntopt_off = MNTOPT_NOSETUID; 1593168404Spjd break; 1594168404Spjd 1595168404Spjd case ZFS_PROP_XATTR: 1596168404Spjd mntopt_on = MNTOPT_XATTR; 1597168404Spjd mntopt_off = MNTOPT_NOXATTR; 1598168404Spjd break; 1599185029Spjd 1600185029Spjd case ZFS_PROP_NBMAND: 1601185029Spjd mntopt_on = MNTOPT_NBMAND; 1602185029Spjd mntopt_off = MNTOPT_NONBMAND; 1603185029Spjd break; 1604168404Spjd } 1605168404Spjd 1606168404Spjd /* 1607168404Spjd * Because looking up the mount options is potentially expensive 1608168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1609168404Spjd * we're looking up a property which requires its presence. 1610168404Spjd */ 1611168404Spjd if (!zhp->zfs_mntcheck && 1612168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1613209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1614209962Smm struct mnttab entry; 1615168404Spjd 1616209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1617209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1618168404Spjd entry.mnt_mntopts); 1619168404Spjd if (zhp->zfs_mntopts == NULL) 1620168404Spjd return (-1); 1621168404Spjd } 1622168404Spjd 1623168404Spjd zhp->zfs_mntcheck = B_TRUE; 1624168404Spjd } 1625168404Spjd 1626168404Spjd if (zhp->zfs_mntopts == NULL) 1627168404Spjd mnt.mnt_mntopts = ""; 1628168404Spjd else 1629168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1630168404Spjd 1631168404Spjd switch (prop) { 1632168404Spjd case ZFS_PROP_ATIME: 1633168404Spjd case ZFS_PROP_DEVICES: 1634168404Spjd case ZFS_PROP_EXEC: 1635168404Spjd case ZFS_PROP_READONLY: 1636168404Spjd case ZFS_PROP_SETUID: 1637168404Spjd case ZFS_PROP_XATTR: 1638185029Spjd case ZFS_PROP_NBMAND: 1639168404Spjd *val = getprop_uint64(zhp, prop, source); 1640168404Spjd 1641168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1642168404Spjd *val = B_TRUE; 1643168404Spjd if (src) 1644185029Spjd *src = ZPROP_SRC_TEMPORARY; 1645168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1646168404Spjd *val = B_FALSE; 1647168404Spjd if (src) 1648185029Spjd *src = ZPROP_SRC_TEMPORARY; 1649168404Spjd } 1650168404Spjd break; 1651168404Spjd 1652168404Spjd case ZFS_PROP_CANMOUNT: 1653168404Spjd *val = getprop_uint64(zhp, prop, source); 1654185029Spjd if (*val != ZFS_CANMOUNT_ON) 1655168404Spjd *source = zhp->zfs_name; 1656168404Spjd else 1657168404Spjd *source = ""; /* default */ 1658168404Spjd break; 1659168404Spjd 1660168404Spjd case ZFS_PROP_QUOTA: 1661185029Spjd case ZFS_PROP_REFQUOTA: 1662168404Spjd case ZFS_PROP_RESERVATION: 1663185029Spjd case ZFS_PROP_REFRESERVATION: 1664168404Spjd *val = getprop_uint64(zhp, prop, source); 1665168404Spjd if (*val == 0) 1666168404Spjd *source = ""; /* default */ 1667168404Spjd else 1668168404Spjd *source = zhp->zfs_name; 1669168404Spjd break; 1670168404Spjd 1671168404Spjd case ZFS_PROP_MOUNTED: 1672168404Spjd *val = (zhp->zfs_mntopts != NULL); 1673168404Spjd break; 1674168404Spjd 1675168404Spjd case ZFS_PROP_NUMCLONES: 1676168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1677168404Spjd break; 1678168404Spjd 1679185029Spjd case ZFS_PROP_VERSION: 1680185029Spjd case ZFS_PROP_NORMALIZE: 1681185029Spjd case ZFS_PROP_UTF8ONLY: 1682185029Spjd case ZFS_PROP_CASE: 1683185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1684185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1685185029Spjd return (-1); 1686185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1687185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1688185029Spjd zcmd_free_nvlists(&zc); 1689185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1690185029Spjd "unable to get %s property"), 1691185029Spjd zfs_prop_to_name(prop)); 1692185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, 1693185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1694185029Spjd } 1695185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1696185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1697185029Spjd val) != 0) { 1698185029Spjd zcmd_free_nvlists(&zc); 1699185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1700185029Spjd "unable to get %s property"), 1701185029Spjd zfs_prop_to_name(prop)); 1702185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOMEM, 1703185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1704185029Spjd } 1705185029Spjd if (zplprops) 1706185029Spjd nvlist_free(zplprops); 1707185029Spjd zcmd_free_nvlists(&zc); 1708185029Spjd break; 1709185029Spjd 1710168404Spjd default: 1711185029Spjd switch (zfs_prop_get_type(prop)) { 1712185029Spjd case PROP_TYPE_NUMBER: 1713185029Spjd case PROP_TYPE_INDEX: 1714185029Spjd *val = getprop_uint64(zhp, prop, source); 1715185029Spjd /* 1716209962Smm * If we tried to use a default value for a 1717185029Spjd * readonly property, it means that it was not 1718185029Spjd * present; return an error. 1719185029Spjd */ 1720185029Spjd if (zfs_prop_readonly(prop) && 1721185029Spjd *source && (*source)[0] == '\0') { 1722185029Spjd return (-1); 1723185029Spjd } 1724185029Spjd break; 1725185029Spjd 1726185029Spjd case PROP_TYPE_STRING: 1727185029Spjd default: 1728185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1729185029Spjd "cannot get non-numeric property")); 1730185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1731185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1732185029Spjd } 1733168404Spjd } 1734168404Spjd 1735168404Spjd return (0); 1736168404Spjd} 1737168404Spjd 1738168404Spjd/* 1739168404Spjd * Calculate the source type, given the raw source string. 1740168404Spjd */ 1741168404Spjdstatic void 1742185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1743168404Spjd char *statbuf, size_t statlen) 1744168404Spjd{ 1745185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1746168404Spjd return; 1747168404Spjd 1748168404Spjd if (source == NULL) { 1749185029Spjd *srctype = ZPROP_SRC_NONE; 1750168404Spjd } else if (source[0] == '\0') { 1751185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1752168404Spjd } else { 1753168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1754185029Spjd *srctype = ZPROP_SRC_LOCAL; 1755168404Spjd } else { 1756168404Spjd (void) strlcpy(statbuf, source, statlen); 1757185029Spjd *srctype = ZPROP_SRC_INHERITED; 1758168404Spjd } 1759168404Spjd } 1760168404Spjd 1761168404Spjd} 1762168404Spjd 1763168404Spjd/* 1764168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 1765168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 1766168404Spjd * human-readable form. 1767168404Spjd * 1768168404Spjd * Returns 0 on success, or -1 on error. 1769168404Spjd */ 1770168404Spjdint 1771168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1772185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1773168404Spjd{ 1774168404Spjd char *source = NULL; 1775168404Spjd uint64_t val; 1776168404Spjd char *str; 1777168404Spjd const char *strval; 1778168404Spjd 1779168404Spjd /* 1780168404Spjd * Check to see if this property applies to our object 1781168404Spjd */ 1782168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1783168404Spjd return (-1); 1784168404Spjd 1785168404Spjd if (src) 1786185029Spjd *src = ZPROP_SRC_NONE; 1787168404Spjd 1788168404Spjd switch (prop) { 1789168404Spjd case ZFS_PROP_CREATION: 1790168404Spjd /* 1791168404Spjd * 'creation' is a time_t stored in the statistics. We convert 1792168404Spjd * this into a string unless 'literal' is specified. 1793168404Spjd */ 1794168404Spjd { 1795168404Spjd val = getprop_uint64(zhp, prop, &source); 1796168404Spjd time_t time = (time_t)val; 1797168404Spjd struct tm t; 1798168404Spjd 1799168404Spjd if (literal || 1800168404Spjd localtime_r(&time, &t) == NULL || 1801168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1802168404Spjd &t) == 0) 1803168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 1804168404Spjd } 1805168404Spjd break; 1806168404Spjd 1807168404Spjd case ZFS_PROP_MOUNTPOINT: 1808168404Spjd /* 1809168404Spjd * Getting the precise mountpoint can be tricky. 1810168404Spjd * 1811168404Spjd * - for 'none' or 'legacy', return those values. 1812168404Spjd * - for inherited mountpoints, we want to take everything 1813168404Spjd * after our ancestor and append it to the inherited value. 1814168404Spjd * 1815168404Spjd * If the pool has an alternate root, we want to prepend that 1816168404Spjd * root to any values we return. 1817168404Spjd */ 1818185029Spjd 1819168404Spjd str = getprop_string(zhp, prop, &source); 1820168404Spjd 1821185029Spjd if (str[0] == '/') { 1822185029Spjd char buf[MAXPATHLEN]; 1823185029Spjd char *root = buf; 1824168404Spjd const char *relpath = zhp->zfs_name + strlen(source); 1825168404Spjd 1826168404Spjd if (relpath[0] == '/') 1827168404Spjd relpath++; 1828185029Spjd 1829185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 1830185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 1831185029Spjd (strcmp(root, "-") == 0)) 1832185029Spjd root[0] = '\0'; 1833185029Spjd /* 1834185029Spjd * Special case an alternate root of '/'. This will 1835185029Spjd * avoid having multiple leading slashes in the 1836185029Spjd * mountpoint path. 1837185029Spjd */ 1838185029Spjd if (strcmp(root, "/") == 0) 1839185029Spjd root++; 1840185029Spjd 1841185029Spjd /* 1842185029Spjd * If the mountpoint is '/' then skip over this 1843185029Spjd * if we are obtaining either an alternate root or 1844185029Spjd * an inherited mountpoint. 1845185029Spjd */ 1846185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 1847185029Spjd relpath[0] != '\0')) 1848168404Spjd str++; 1849168404Spjd 1850168404Spjd if (relpath[0] == '\0') 1851168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 1852168404Spjd root, str); 1853168404Spjd else 1854168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 1855168404Spjd root, str, relpath[0] == '@' ? "" : "/", 1856168404Spjd relpath); 1857168404Spjd } else { 1858168404Spjd /* 'legacy' or 'none' */ 1859168404Spjd (void) strlcpy(propbuf, str, proplen); 1860168404Spjd } 1861168404Spjd 1862168404Spjd break; 1863168404Spjd 1864168404Spjd case ZFS_PROP_ORIGIN: 1865168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1866168404Spjd proplen); 1867168404Spjd /* 1868168404Spjd * If there is no parent at all, return failure to indicate that 1869168404Spjd * it doesn't apply to this dataset. 1870168404Spjd */ 1871168404Spjd if (propbuf[0] == '\0') 1872168404Spjd return (-1); 1873168404Spjd break; 1874168404Spjd 1875168404Spjd case ZFS_PROP_QUOTA: 1876185029Spjd case ZFS_PROP_REFQUOTA: 1877168404Spjd case ZFS_PROP_RESERVATION: 1878185029Spjd case ZFS_PROP_REFRESERVATION: 1879185029Spjd 1880168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1881168404Spjd return (-1); 1882168404Spjd 1883168404Spjd /* 1884168404Spjd * If quota or reservation is 0, we translate this into 'none' 1885168404Spjd * (unless literal is set), and indicate that it's the default 1886168404Spjd * value. Otherwise, we print the number nicely and indicate 1887168404Spjd * that its set locally. 1888168404Spjd */ 1889168404Spjd if (val == 0) { 1890168404Spjd if (literal) 1891168404Spjd (void) strlcpy(propbuf, "0", proplen); 1892168404Spjd else 1893168404Spjd (void) strlcpy(propbuf, "none", proplen); 1894168404Spjd } else { 1895168404Spjd if (literal) 1896168404Spjd (void) snprintf(propbuf, proplen, "%llu", 1897168404Spjd (u_longlong_t)val); 1898168404Spjd else 1899168404Spjd zfs_nicenum(val, propbuf, proplen); 1900168404Spjd } 1901168404Spjd break; 1902168404Spjd 1903168404Spjd case ZFS_PROP_COMPRESSRATIO: 1904168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1905168404Spjd return (-1); 1906168404Spjd (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 1907168404Spjd val / 100, (longlong_t)val % 100); 1908168404Spjd break; 1909168404Spjd 1910168404Spjd case ZFS_PROP_TYPE: 1911168404Spjd switch (zhp->zfs_type) { 1912168404Spjd case ZFS_TYPE_FILESYSTEM: 1913168404Spjd str = "filesystem"; 1914168404Spjd break; 1915168404Spjd case ZFS_TYPE_VOLUME: 1916168404Spjd str = "volume"; 1917168404Spjd break; 1918168404Spjd case ZFS_TYPE_SNAPSHOT: 1919168404Spjd str = "snapshot"; 1920168404Spjd break; 1921168404Spjd default: 1922168404Spjd abort(); 1923168404Spjd } 1924168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 1925168404Spjd break; 1926168404Spjd 1927168404Spjd case ZFS_PROP_MOUNTED: 1928168404Spjd /* 1929168404Spjd * The 'mounted' property is a pseudo-property that described 1930168404Spjd * whether the filesystem is currently mounted. Even though 1931168404Spjd * it's a boolean value, the typical values of "on" and "off" 1932168404Spjd * don't make sense, so we translate to "yes" and "no". 1933168404Spjd */ 1934168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 1935168404Spjd src, &source, &val) != 0) 1936168404Spjd return (-1); 1937168404Spjd if (val) 1938168404Spjd (void) strlcpy(propbuf, "yes", proplen); 1939168404Spjd else 1940168404Spjd (void) strlcpy(propbuf, "no", proplen); 1941168404Spjd break; 1942168404Spjd 1943168404Spjd case ZFS_PROP_NAME: 1944168404Spjd /* 1945168404Spjd * The 'name' property is a pseudo-property derived from the 1946168404Spjd * dataset name. It is presented as a real property to simplify 1947168404Spjd * consumers. 1948168404Spjd */ 1949168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1950168404Spjd break; 1951168404Spjd 1952168404Spjd default: 1953185029Spjd switch (zfs_prop_get_type(prop)) { 1954185029Spjd case PROP_TYPE_NUMBER: 1955185029Spjd if (get_numeric_property(zhp, prop, src, 1956185029Spjd &source, &val) != 0) 1957185029Spjd return (-1); 1958185029Spjd if (literal) 1959185029Spjd (void) snprintf(propbuf, proplen, "%llu", 1960185029Spjd (u_longlong_t)val); 1961185029Spjd else 1962185029Spjd zfs_nicenum(val, propbuf, proplen); 1963185029Spjd break; 1964185029Spjd 1965185029Spjd case PROP_TYPE_STRING: 1966185029Spjd (void) strlcpy(propbuf, 1967185029Spjd getprop_string(zhp, prop, &source), proplen); 1968185029Spjd break; 1969185029Spjd 1970185029Spjd case PROP_TYPE_INDEX: 1971185029Spjd if (get_numeric_property(zhp, prop, src, 1972185029Spjd &source, &val) != 0) 1973185029Spjd return (-1); 1974185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 1975185029Spjd return (-1); 1976185029Spjd (void) strlcpy(propbuf, strval, proplen); 1977185029Spjd break; 1978185029Spjd 1979185029Spjd default: 1980185029Spjd abort(); 1981185029Spjd } 1982168404Spjd } 1983168404Spjd 1984168404Spjd get_source(zhp, src, source, statbuf, statlen); 1985168404Spjd 1986168404Spjd return (0); 1987168404Spjd} 1988168404Spjd 1989168404Spjd/* 1990168404Spjd * Utility function to get the given numeric property. Does no validation that 1991168404Spjd * the given property is the appropriate type; should only be used with 1992168404Spjd * hard-coded property types. 1993168404Spjd */ 1994168404Spjduint64_t 1995168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1996168404Spjd{ 1997168404Spjd char *source; 1998168404Spjd uint64_t val; 1999168404Spjd 2000185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2001168404Spjd 2002168404Spjd return (val); 2003168404Spjd} 2004168404Spjd 2005185029Spjdint 2006185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2007185029Spjd{ 2008185029Spjd char buf[64]; 2009185029Spjd 2010209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2011185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2012185029Spjd} 2013185029Spjd 2014168404Spjd/* 2015168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2016168404Spjd */ 2017168404Spjdint 2018168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2019185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2020168404Spjd{ 2021168404Spjd char *source; 2022168404Spjd 2023168404Spjd /* 2024168404Spjd * Check to see if this property applies to our object 2025168404Spjd */ 2026185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2027168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2028168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2029168404Spjd zfs_prop_to_name(prop))); 2030185029Spjd } 2031168404Spjd 2032168404Spjd if (src) 2033185029Spjd *src = ZPROP_SRC_NONE; 2034168404Spjd 2035168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2036168404Spjd return (-1); 2037168404Spjd 2038168404Spjd get_source(zhp, src, source, statbuf, statlen); 2039168404Spjd 2040168404Spjd return (0); 2041168404Spjd} 2042168404Spjd 2043209962Smmstatic int 2044209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2045209962Smm char **domainp, idmap_rid_t *ridp) 2046209962Smm{ 2047209962Smm#ifdef sun 2048209962Smm idmap_handle_t *idmap_hdl = NULL; 2049209962Smm idmap_get_handle_t *get_hdl = NULL; 2050209962Smm idmap_stat status; 2051209962Smm int err = EINVAL; 2052209962Smm 2053209962Smm if (idmap_init(&idmap_hdl) != IDMAP_SUCCESS) 2054209962Smm goto out; 2055209962Smm if (idmap_get_create(idmap_hdl, &get_hdl) != IDMAP_SUCCESS) 2056209962Smm goto out; 2057209962Smm 2058209962Smm if (isuser) { 2059209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2060209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2061209962Smm } else { 2062209962Smm err = idmap_get_sidbygid(get_hdl, id, 2063209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2064209962Smm } 2065209962Smm if (err == IDMAP_SUCCESS && 2066209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2067209962Smm status == IDMAP_SUCCESS) 2068209962Smm err = 0; 2069209962Smm else 2070209962Smm err = EINVAL; 2071209962Smmout: 2072209962Smm if (get_hdl) 2073209962Smm idmap_get_destroy(get_hdl); 2074209962Smm if (idmap_hdl) 2075209962Smm (void) idmap_fini(idmap_hdl); 2076209962Smm return (err); 2077209962Smm#else /* !sun */ 2078209962Smm assert(!"invalid code path"); 2079209962Smm#endif /* !sun */ 2080209962Smm} 2081209962Smm 2082209962Smm#ifndef sun 2083209962Smm/* Check if a string contains only digits */ 2084209962Smmstatic int 2085209962Smmstring_is_digits(char *cp) 2086209962Smm{ 2087209962Smm int i; 2088209962Smm 2089209962Smm for(i = 0; i < strlen(cp); i++) 2090209962Smm if(!isdigit(cp[i])) 2091209962Smm return (0); 2092209962Smm return (1); 2093209962Smm} 2094209962Smm 2095209962Smm#endif /* !sun */ 2096209962Smm 2097168404Spjd/* 2098209962Smm * convert the propname into parameters needed by kernel 2099209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2100209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2101209962Smm */ 2102209962Smmstatic int 2103209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2104209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2105209962Smm{ 2106209962Smm zfs_userquota_prop_t type; 2107209962Smm char *cp, *end; 2108209962Smm char *numericsid = NULL; 2109209962Smm boolean_t isuser; 2110209962Smm 2111209962Smm domain[0] = '\0'; 2112209962Smm 2113209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2114209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2115209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2116209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2117209962Smm break; 2118209962Smm } 2119209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2120209962Smm return (EINVAL); 2121209962Smm *typep = type; 2122209962Smm 2123209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2124209962Smm type == ZFS_PROP_USERUSED); 2125209962Smm 2126209962Smm cp = strchr(propname, '@') + 1; 2127209962Smm 2128209962Smm if (strchr(cp, '@')) { 2129209962Smm#ifdef sun 2130209962Smm /* 2131209962Smm * It's a SID name (eg "user@domain") that needs to be 2132209962Smm * turned into S-1-domainID-RID. 2133209962Smm */ 2134209962Smm directory_error_t e; 2135209962Smm 2136209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2137209962Smm return (ENOENT); 2138209962Smm if (isuser) { 2139209962Smm e = directory_sid_from_user_name(NULL, 2140209962Smm cp, &numericsid); 2141209962Smm } else { 2142209962Smm e = directory_sid_from_group_name(NULL, 2143209962Smm cp, &numericsid); 2144209962Smm } 2145209962Smm if (e != NULL) { 2146209962Smm directory_error_free(e); 2147209962Smm return (ENOENT); 2148209962Smm } 2149209962Smm if (numericsid == NULL) 2150209962Smm return (ENOENT); 2151209962Smm cp = numericsid; 2152209962Smm /* will be further decoded below */ 2153209962Smm#else /* !sun */ 2154209962Smm return (ENOENT); 2155209962Smm#endif /* !sun */ 2156209962Smm } 2157209962Smm 2158209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2159209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2160209962Smm (void) strlcpy(domain, cp, domainlen); 2161209962Smm cp = strrchr(domain, '-'); 2162209962Smm *cp = '\0'; 2163209962Smm cp++; 2164209962Smm 2165209962Smm errno = 0; 2166209962Smm *ridp = strtoull(cp, &end, 10); 2167209962Smm if (numericsid) { 2168209962Smm free(numericsid); 2169209962Smm numericsid = NULL; 2170209962Smm } 2171209962Smm if (errno != 0 || *end != '\0') 2172209962Smm return (EINVAL); 2173209962Smm#ifdef sun 2174209962Smm } else if (!isdigit(*cp)) { 2175209962Smm#else /* sun */ 2176209962Smm /* 2177209962Smm * In FreeBSD user and group names can begin with a digit so treat 2178209962Smm * as a uid/gid if string contains digits only 2179209962Smm */ 2180209962Smm } else if (!string_is_digits(cp)) { 2181209962Smm#endif /* sun */ 2182209962Smm /* 2183209962Smm * It's a user/group name (eg "user") that needs to be 2184209962Smm * turned into a uid/gid 2185209962Smm */ 2186209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2187209962Smm return (ENOENT); 2188209962Smm if (isuser) { 2189209962Smm struct passwd *pw; 2190209962Smm pw = getpwnam(cp); 2191209962Smm if (pw == NULL) 2192209962Smm return (ENOENT); 2193209962Smm *ridp = pw->pw_uid; 2194209962Smm } else { 2195209962Smm struct group *gr; 2196209962Smm gr = getgrnam(cp); 2197209962Smm if (gr == NULL) 2198209962Smm return (ENOENT); 2199209962Smm *ridp = gr->gr_gid; 2200209962Smm } 2201209962Smm } else { 2202209962Smm /* It's a user/group ID (eg "12345"). */ 2203209962Smm uid_t id = strtoul(cp, &end, 10); 2204209962Smm idmap_rid_t rid; 2205209962Smm char *mapdomain; 2206209962Smm 2207209962Smm if (*end != '\0') 2208209962Smm return (EINVAL); 2209209962Smm if (id > MAXUID) { 2210209962Smm /* It's an ephemeral ID. */ 2211209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2212209962Smm &mapdomain, &rid) != 0) 2213209962Smm return (ENOENT); 2214209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2215209962Smm *ridp = rid; 2216209962Smm } else { 2217209962Smm *ridp = id; 2218209962Smm } 2219209962Smm } 2220209962Smm 2221209962Smm ASSERT3P(numericsid, ==, NULL); 2222209962Smm return (0); 2223209962Smm} 2224209962Smm 2225209962Smmstatic int 2226209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2227209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2228209962Smm{ 2229209962Smm int err; 2230209962Smm zfs_cmd_t zc = { 0 }; 2231209962Smm 2232209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2233209962Smm 2234209962Smm err = userquota_propname_decode(propname, 2235209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2236209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2237209962Smm zc.zc_objset_type = *typep; 2238209962Smm if (err) 2239209962Smm return (err); 2240209962Smm 2241209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2242209962Smm if (err) 2243209962Smm return (err); 2244209962Smm 2245209962Smm *propvalue = zc.zc_cookie; 2246209962Smm return (0); 2247209962Smm} 2248209962Smm 2249209962Smmint 2250209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2251209962Smm uint64_t *propvalue) 2252209962Smm{ 2253209962Smm zfs_userquota_prop_t type; 2254209962Smm 2255209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2256209962Smm &type)); 2257209962Smm} 2258209962Smm 2259209962Smmint 2260209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2261209962Smm char *propbuf, int proplen, boolean_t literal) 2262209962Smm{ 2263209962Smm int err; 2264209962Smm uint64_t propvalue; 2265209962Smm zfs_userquota_prop_t type; 2266209962Smm 2267209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2268209962Smm &type); 2269209962Smm 2270209962Smm if (err) 2271209962Smm return (err); 2272209962Smm 2273209962Smm if (literal) { 2274209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2275209962Smm } else if (propvalue == 0 && 2276209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2277209962Smm (void) strlcpy(propbuf, "none", proplen); 2278209962Smm } else { 2279209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2280209962Smm } 2281209962Smm return (0); 2282209962Smm} 2283209962Smm 2284209962Smm/* 2285168404Spjd * Returns the name of the given zfs handle. 2286168404Spjd */ 2287168404Spjdconst char * 2288168404Spjdzfs_get_name(const zfs_handle_t *zhp) 2289168404Spjd{ 2290168404Spjd return (zhp->zfs_name); 2291168404Spjd} 2292168404Spjd 2293168404Spjd/* 2294168404Spjd * Returns the type of the given zfs handle. 2295168404Spjd */ 2296168404Spjdzfs_type_t 2297168404Spjdzfs_get_type(const zfs_handle_t *zhp) 2298168404Spjd{ 2299168404Spjd return (zhp->zfs_type); 2300168404Spjd} 2301168404Spjd 2302209962Smmstatic int 2303209962Smmzfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc) 2304209962Smm{ 2305209962Smm int rc; 2306209962Smm uint64_t orig_cookie; 2307209962Smm 2308209962Smm orig_cookie = zc->zc_cookie; 2309209962Smmtop: 2310209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 2311209962Smm rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); 2312209962Smm 2313209962Smm /* 2314209962Smm * FreeBSD compatibility with pre-v15 kernel module. 2315209962Smm * Ignore private dataset names. 2316209962Smm */ 2317209962Smm if (strchr(zc->zc_name, '$') != NULL) 2318209962Smm rc = 0; 2319209962Smm 2320209962Smm if (rc == -1) { 2321209962Smm switch (errno) { 2322209962Smm case ENOMEM: 2323209962Smm /* expand nvlist memory and try again */ 2324209962Smm if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { 2325209962Smm zcmd_free_nvlists(zc); 2326209962Smm return (-1); 2327209962Smm } 2328209962Smm zc->zc_cookie = orig_cookie; 2329209962Smm goto top; 2330209962Smm /* 2331209962Smm * An errno value of ESRCH indicates normal completion. 2332209962Smm * If ENOENT is returned, then the underlying dataset 2333209962Smm * has been removed since we obtained the handle. 2334209962Smm */ 2335209962Smm case ESRCH: 2336209962Smm case ENOENT: 2337209962Smm rc = 1; 2338209962Smm break; 2339209962Smm default: 2340209962Smm rc = zfs_standard_error(zhp->zfs_hdl, errno, 2341209962Smm dgettext(TEXT_DOMAIN, 2342209962Smm "cannot iterate filesystems")); 2343209962Smm break; 2344209962Smm } 2345209962Smm } 2346209962Smm return (rc); 2347209962Smm} 2348209962Smm 2349168404Spjd/* 2350168404Spjd * Iterate over all child filesystems 2351168404Spjd */ 2352168404Spjdint 2353168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2354168404Spjd{ 2355168404Spjd zfs_cmd_t zc = { 0 }; 2356168404Spjd zfs_handle_t *nzhp; 2357168404Spjd int ret; 2358168404Spjd 2359185029Spjd if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 2360185029Spjd return (0); 2361185029Spjd 2362209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2363209962Smm return (-1); 2364209962Smm 2365209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, 2366209962Smm &zc)) == 0) { 2367209962Smm 2368168404Spjd /* 2369209962Smm * FreeBSD compatibility with pre-v15 kernel module. 2370168404Spjd * Ignore private dataset names. 2371168404Spjd */ 2372209962Smm if (strchr(zc.zc_name, '$') != NULL) 2373168404Spjd continue; 2374168404Spjd 2375168404Spjd /* 2376168404Spjd * Silently ignore errors, as the only plausible explanation is 2377168404Spjd * that the pool has since been removed. 2378168404Spjd */ 2379209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2380209962Smm &zc)) == NULL) { 2381168404Spjd continue; 2382209962Smm } 2383168404Spjd 2384209962Smm if ((ret = func(nzhp, data)) != 0) { 2385209962Smm zcmd_free_nvlists(&zc); 2386168404Spjd return (ret); 2387209962Smm } 2388168404Spjd } 2389209962Smm zcmd_free_nvlists(&zc); 2390209962Smm return ((ret < 0) ? ret : 0); 2391168404Spjd} 2392168404Spjd 2393168404Spjd/* 2394168404Spjd * Iterate over all snapshots 2395168404Spjd */ 2396168404Spjdint 2397168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2398168404Spjd{ 2399168404Spjd zfs_cmd_t zc = { 0 }; 2400168404Spjd zfs_handle_t *nzhp; 2401168404Spjd int ret; 2402168404Spjd 2403185029Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 2404185029Spjd return (0); 2405185029Spjd 2406209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2407209962Smm return (-1); 2408209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, 2409209962Smm &zc)) == 0) { 2410168404Spjd 2411209962Smm /* 2412209962Smm * FreeBSD compatibility with pre-v15 kernel module. 2413209962Smm * Ignore private dataset names. 2414209962Smm */ 2415209962Smm if (strchr(zc.zc_name, '$') != NULL) 2416168404Spjd continue; 2417168404Spjd 2418209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2419209962Smm &zc)) == NULL) { 2420209962Smm continue; 2421209962Smm } 2422209962Smm 2423209962Smm if ((ret = func(nzhp, data)) != 0) { 2424209962Smm zcmd_free_nvlists(&zc); 2425168404Spjd return (ret); 2426209962Smm } 2427168404Spjd } 2428209962Smm zcmd_free_nvlists(&zc); 2429209962Smm return ((ret < 0) ? ret : 0); 2430168404Spjd} 2431168404Spjd 2432168404Spjd/* 2433168404Spjd * Iterate over all children, snapshots and filesystems 2434168404Spjd */ 2435168404Spjdint 2436168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2437168404Spjd{ 2438168404Spjd int ret; 2439168404Spjd 2440168404Spjd if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 2441168404Spjd return (ret); 2442168404Spjd 2443168404Spjd return (zfs_iter_snapshots(zhp, func, data)); 2444168404Spjd} 2445168404Spjd 2446168404Spjd/* 2447168404Spjd * Given a complete name, return just the portion that refers to the parent. 2448168404Spjd * Can return NULL if this is a pool. 2449168404Spjd */ 2450168404Spjdstatic int 2451168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2452168404Spjd{ 2453168404Spjd char *loc; 2454168404Spjd 2455168404Spjd if ((loc = strrchr(path, '/')) == NULL) 2456168404Spjd return (-1); 2457168404Spjd 2458168404Spjd (void) strncpy(buf, path, MIN(buflen, loc - path)); 2459168404Spjd buf[loc - path] = '\0'; 2460168404Spjd 2461168404Spjd return (0); 2462168404Spjd} 2463168404Spjd 2464168404Spjd/* 2465185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2466185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2467185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2468185029Spjd * length of already existing prefix of the given path. We also fetch the 2469185029Spjd * 'zoned' property, which is used to validate property settings when creating 2470185029Spjd * new datasets. 2471168404Spjd */ 2472168404Spjdstatic int 2473185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2474185029Spjd boolean_t accept_ancestor, int *prefixlen) 2475168404Spjd{ 2476168404Spjd zfs_cmd_t zc = { 0 }; 2477168404Spjd char parent[ZFS_MAXNAMELEN]; 2478168404Spjd char *slash; 2479168404Spjd zfs_handle_t *zhp; 2480168404Spjd char errbuf[1024]; 2481168404Spjd 2482209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2483209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2484168404Spjd 2485168404Spjd /* get parent, and check to see if this is just a pool */ 2486168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2487168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2488168404Spjd "missing dataset name")); 2489168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2490168404Spjd } 2491168404Spjd 2492168404Spjd /* check to see if the pool exists */ 2493168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2494168404Spjd slash = parent + strlen(parent); 2495168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2496168404Spjd zc.zc_name[slash - parent] = '\0'; 2497168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2498168404Spjd errno == ENOENT) { 2499168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2500168404Spjd "no such pool '%s'"), zc.zc_name); 2501168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2502168404Spjd } 2503168404Spjd 2504168404Spjd /* check to see if the parent dataset exists */ 2505185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2506185029Spjd if (errno == ENOENT && accept_ancestor) { 2507185029Spjd /* 2508185029Spjd * Go deeper to find an ancestor, give up on top level. 2509185029Spjd */ 2510185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2511185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2512185029Spjd "no such pool '%s'"), zc.zc_name); 2513185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2514185029Spjd } 2515185029Spjd } else if (errno == ENOENT) { 2516168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2517168404Spjd "parent does not exist")); 2518168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2519185029Spjd } else 2520168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2521168404Spjd } 2522168404Spjd 2523168404Spjd *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2524168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2525168404Spjd if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 2526168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2527168404Spjd zfs_close(zhp); 2528168404Spjd return (-1); 2529168404Spjd } 2530168404Spjd 2531168404Spjd /* make sure parent is a filesystem */ 2532168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2533168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2534168404Spjd "parent is not a filesystem")); 2535168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2536168404Spjd zfs_close(zhp); 2537168404Spjd return (-1); 2538168404Spjd } 2539168404Spjd 2540168404Spjd zfs_close(zhp); 2541185029Spjd if (prefixlen != NULL) 2542185029Spjd *prefixlen = strlen(parent); 2543168404Spjd return (0); 2544168404Spjd} 2545168404Spjd 2546168404Spjd/* 2547185029Spjd * Finds whether the dataset of the given type(s) exists. 2548185029Spjd */ 2549185029Spjdboolean_t 2550185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2551185029Spjd{ 2552185029Spjd zfs_handle_t *zhp; 2553185029Spjd 2554185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2555185029Spjd return (B_FALSE); 2556185029Spjd 2557185029Spjd /* 2558185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2559185029Spjd */ 2560185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2561185029Spjd int ds_type = zhp->zfs_type; 2562185029Spjd 2563185029Spjd zfs_close(zhp); 2564185029Spjd if (types & ds_type) 2565185029Spjd return (B_TRUE); 2566185029Spjd } 2567185029Spjd return (B_FALSE); 2568185029Spjd} 2569185029Spjd 2570185029Spjd/* 2571185029Spjd * Given a path to 'target', create all the ancestors between 2572185029Spjd * the prefixlen portion of the path, and the target itself. 2573185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2574185029Spjd */ 2575185029Spjdint 2576185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2577185029Spjd{ 2578185029Spjd zfs_handle_t *h; 2579185029Spjd char *cp; 2580185029Spjd const char *opname; 2581185029Spjd 2582185029Spjd /* make sure prefix exists */ 2583185029Spjd cp = target + prefixlen; 2584185029Spjd if (*cp != '/') { 2585185029Spjd assert(strchr(cp, '/') == NULL); 2586185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2587185029Spjd } else { 2588185029Spjd *cp = '\0'; 2589185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2590185029Spjd *cp = '/'; 2591185029Spjd } 2592185029Spjd if (h == NULL) 2593185029Spjd return (-1); 2594185029Spjd zfs_close(h); 2595185029Spjd 2596185029Spjd /* 2597185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2598185029Spjd * up to the prefixlen-long one. 2599185029Spjd */ 2600185029Spjd for (cp = target + prefixlen + 1; 2601185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2602185029Spjd char *logstr; 2603185029Spjd 2604185029Spjd *cp = '\0'; 2605185029Spjd 2606185029Spjd h = make_dataset_handle(hdl, target); 2607185029Spjd if (h) { 2608185029Spjd /* it already exists, nothing to do here */ 2609185029Spjd zfs_close(h); 2610185029Spjd continue; 2611185029Spjd } 2612185029Spjd 2613185029Spjd logstr = hdl->libzfs_log_str; 2614185029Spjd hdl->libzfs_log_str = NULL; 2615185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2616185029Spjd NULL) != 0) { 2617185029Spjd hdl->libzfs_log_str = logstr; 2618185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2619185029Spjd goto ancestorerr; 2620185029Spjd } 2621185029Spjd 2622185029Spjd hdl->libzfs_log_str = logstr; 2623185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2624185029Spjd if (h == NULL) { 2625185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2626185029Spjd goto ancestorerr; 2627185029Spjd } 2628185029Spjd 2629185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 2630185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2631185029Spjd goto ancestorerr; 2632185029Spjd } 2633185029Spjd 2634185029Spjd if (zfs_share(h) != 0) { 2635185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2636185029Spjd goto ancestorerr; 2637185029Spjd } 2638185029Spjd 2639185029Spjd zfs_close(h); 2640185029Spjd } 2641185029Spjd 2642185029Spjd return (0); 2643185029Spjd 2644185029Spjdancestorerr: 2645185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2646185029Spjd "failed to %s ancestor '%s'"), opname, target); 2647185029Spjd return (-1); 2648185029Spjd} 2649185029Spjd 2650185029Spjd/* 2651185029Spjd * Creates non-existing ancestors of the given path. 2652185029Spjd */ 2653185029Spjdint 2654185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2655185029Spjd{ 2656185029Spjd int prefix; 2657185029Spjd uint64_t zoned; 2658185029Spjd char *path_copy; 2659185029Spjd int rc; 2660185029Spjd 2661185029Spjd if (check_parents(hdl, path, &zoned, B_TRUE, &prefix) != 0) 2662185029Spjd return (-1); 2663185029Spjd 2664185029Spjd if ((path_copy = strdup(path)) != NULL) { 2665185029Spjd rc = create_parents(hdl, path_copy, prefix); 2666185029Spjd free(path_copy); 2667185029Spjd } 2668185029Spjd if (path_copy == NULL || rc != 0) 2669185029Spjd return (-1); 2670185029Spjd 2671185029Spjd return (0); 2672185029Spjd} 2673185029Spjd 2674185029Spjd/* 2675168404Spjd * Create a new filesystem or volume. 2676168404Spjd */ 2677168404Spjdint 2678168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2679168404Spjd nvlist_t *props) 2680168404Spjd{ 2681168404Spjd zfs_cmd_t zc = { 0 }; 2682168404Spjd int ret; 2683168404Spjd uint64_t size = 0; 2684168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2685168404Spjd char errbuf[1024]; 2686168404Spjd uint64_t zoned; 2687168404Spjd 2688168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2689168404Spjd "cannot create '%s'"), path); 2690168404Spjd 2691168404Spjd /* validate the path, taking care to note the extended error message */ 2692185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 2693168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2694168404Spjd 2695168404Spjd /* validate parents exist */ 2696185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 2697168404Spjd return (-1); 2698168404Spjd 2699168404Spjd /* 2700168404Spjd * The failure modes when creating a dataset of a different type over 2701168404Spjd * one that already exists is a little strange. In particular, if you 2702168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 2703168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 2704168404Spjd * first try to see if the dataset exists. 2705168404Spjd */ 2706168404Spjd (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2707185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 2708168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2709168404Spjd "dataset already exists")); 2710168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2711168404Spjd } 2712168404Spjd 2713168404Spjd if (type == ZFS_TYPE_VOLUME) 2714168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2715168404Spjd else 2716168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2717168404Spjd 2718185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 2719168404Spjd zoned, NULL, errbuf)) == 0) 2720168404Spjd return (-1); 2721168404Spjd 2722168404Spjd if (type == ZFS_TYPE_VOLUME) { 2723168404Spjd /* 2724168404Spjd * If we are creating a volume, the size and block size must 2725168404Spjd * satisfy a few restraints. First, the blocksize must be a 2726168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 2727168404Spjd * volsize must be a multiple of the block size, and cannot be 2728168404Spjd * zero. 2729168404Spjd */ 2730168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 2731168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2732168404Spjd nvlist_free(props); 2733168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2734168404Spjd "missing volume size")); 2735168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2736168404Spjd } 2737168404Spjd 2738168404Spjd if ((ret = nvlist_lookup_uint64(props, 2739168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2740168404Spjd &blocksize)) != 0) { 2741168404Spjd if (ret == ENOENT) { 2742168404Spjd blocksize = zfs_prop_default_numeric( 2743168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2744168404Spjd } else { 2745168404Spjd nvlist_free(props); 2746168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2747168404Spjd "missing volume block size")); 2748168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2749168404Spjd } 2750168404Spjd } 2751168404Spjd 2752168404Spjd if (size == 0) { 2753168404Spjd nvlist_free(props); 2754168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2755168404Spjd "volume size cannot be zero")); 2756168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2757168404Spjd } 2758168404Spjd 2759168404Spjd if (size % blocksize != 0) { 2760168404Spjd nvlist_free(props); 2761168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2762168404Spjd "volume size must be a multiple of volume block " 2763168404Spjd "size")); 2764168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2765168404Spjd } 2766168404Spjd } 2767168404Spjd 2768185029Spjd if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) 2769168404Spjd return (-1); 2770168404Spjd nvlist_free(props); 2771168404Spjd 2772168404Spjd /* create the dataset */ 2773185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); 2774168404Spjd 2775168404Spjd if (ret == 0 && type == ZFS_TYPE_VOLUME) { 2776168404Spjd ret = zvol_create_link(hdl, path); 2777168404Spjd if (ret) { 2778168404Spjd (void) zfs_standard_error(hdl, errno, 2779168404Spjd dgettext(TEXT_DOMAIN, 2780168404Spjd "Volume successfully created, but device links " 2781168404Spjd "were not created")); 2782168404Spjd zcmd_free_nvlists(&zc); 2783168404Spjd return (-1); 2784168404Spjd } 2785168404Spjd } 2786168404Spjd 2787168404Spjd zcmd_free_nvlists(&zc); 2788168404Spjd 2789168404Spjd /* check for failure */ 2790168404Spjd if (ret != 0) { 2791168404Spjd char parent[ZFS_MAXNAMELEN]; 2792168404Spjd (void) parent_name(path, parent, sizeof (parent)); 2793168404Spjd 2794168404Spjd switch (errno) { 2795168404Spjd case ENOENT: 2796168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2797168404Spjd "no such parent '%s'"), parent); 2798168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2799168404Spjd 2800168404Spjd case EINVAL: 2801168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2802168404Spjd "parent '%s' is not a filesystem"), parent); 2803168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2804168404Spjd 2805168404Spjd case EDOM: 2806168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2807168404Spjd "volume block size must be power of 2 from " 2808168404Spjd "%u to %uk"), 2809168404Spjd (uint_t)SPA_MINBLOCKSIZE, 2810168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 2811168404Spjd 2812168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2813168404Spjd 2814185029Spjd case ENOTSUP: 2815185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2816185029Spjd "pool must be upgraded to set this " 2817185029Spjd "property or value")); 2818185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 2819168404Spjd#ifdef _ILP32 2820168404Spjd case EOVERFLOW: 2821168404Spjd /* 2822168404Spjd * This platform can't address a volume this big. 2823168404Spjd */ 2824168404Spjd if (type == ZFS_TYPE_VOLUME) 2825168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 2826168404Spjd errbuf)); 2827168404Spjd#endif 2828168404Spjd /* FALLTHROUGH */ 2829168404Spjd default: 2830168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2831168404Spjd } 2832168404Spjd } 2833168404Spjd 2834168404Spjd return (0); 2835168404Spjd} 2836168404Spjd 2837168404Spjd/* 2838168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 2839168404Spjd * isn't mounted, and that there are no active dependents. 2840168404Spjd */ 2841168404Spjdint 2842168404Spjdzfs_destroy(zfs_handle_t *zhp) 2843168404Spjd{ 2844168404Spjd zfs_cmd_t zc = { 0 }; 2845168404Spjd 2846168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2847168404Spjd 2848168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2849168404Spjd /* 2850185029Spjd * If user doesn't have permissions to unshare volume, then 2851185029Spjd * abort the request. This would only happen for a 2852185029Spjd * non-privileged user. 2853168404Spjd */ 2854185029Spjd if (zfs_unshare_iscsi(zhp) != 0) { 2855185029Spjd return (-1); 2856185029Spjd } 2857168404Spjd 2858168404Spjd if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2859168404Spjd return (-1); 2860168404Spjd 2861168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2862168404Spjd } else { 2863168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2864168404Spjd } 2865168404Spjd 2866185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { 2867168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 2868168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 2869168404Spjd zhp->zfs_name)); 2870168404Spjd } 2871168404Spjd 2872168404Spjd remove_mountpoint(zhp); 2873168404Spjd 2874168404Spjd return (0); 2875168404Spjd} 2876168404Spjd 2877168404Spjdstruct destroydata { 2878168404Spjd char *snapname; 2879168404Spjd boolean_t gotone; 2880168404Spjd boolean_t closezhp; 2881168404Spjd}; 2882168404Spjd 2883168404Spjdstatic int 2884168404Spjdzfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 2885168404Spjd{ 2886168404Spjd struct destroydata *dd = arg; 2887168404Spjd zfs_handle_t *szhp; 2888168404Spjd char name[ZFS_MAXNAMELEN]; 2889168404Spjd boolean_t closezhp = dd->closezhp; 2890168404Spjd int rv; 2891168404Spjd 2892168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2893168404Spjd (void) strlcat(name, "@", sizeof (name)); 2894168404Spjd (void) strlcat(name, dd->snapname, sizeof (name)); 2895168404Spjd 2896168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, name); 2897168404Spjd if (szhp) { 2898168404Spjd dd->gotone = B_TRUE; 2899168404Spjd zfs_close(szhp); 2900168404Spjd } 2901168404Spjd 2902168404Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2903168404Spjd (void) zvol_remove_link(zhp->zfs_hdl, name); 2904168404Spjd /* 2905168404Spjd * NB: this is simply a best-effort. We don't want to 2906168404Spjd * return an error, because then we wouldn't visit all 2907168404Spjd * the volumes. 2908168404Spjd */ 2909168404Spjd } 2910168404Spjd 2911168404Spjd dd->closezhp = B_TRUE; 2912168404Spjd rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 2913168404Spjd if (closezhp) 2914168404Spjd zfs_close(zhp); 2915168404Spjd return (rv); 2916168404Spjd} 2917168404Spjd 2918168404Spjd/* 2919168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 2920168404Spjd */ 2921168404Spjdint 2922168404Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 2923168404Spjd{ 2924168404Spjd zfs_cmd_t zc = { 0 }; 2925168404Spjd int ret; 2926168404Spjd struct destroydata dd = { 0 }; 2927168404Spjd 2928168404Spjd dd.snapname = snapname; 2929168404Spjd (void) zfs_remove_link_cb(zhp, &dd); 2930168404Spjd 2931168404Spjd if (!dd.gotone) { 2932168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 2933168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 2934168404Spjd zhp->zfs_name, snapname)); 2935168404Spjd } 2936168404Spjd 2937168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2938168404Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2939168404Spjd 2940185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); 2941168404Spjd if (ret != 0) { 2942168404Spjd char errbuf[1024]; 2943168404Spjd 2944168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2945168404Spjd "cannot destroy '%s@%s'"), zc.zc_name, snapname); 2946168404Spjd 2947168404Spjd switch (errno) { 2948168404Spjd case EEXIST: 2949168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2950168404Spjd "snapshot is cloned")); 2951168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 2952168404Spjd 2953168404Spjd default: 2954168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 2955168404Spjd errbuf)); 2956168404Spjd } 2957168404Spjd } 2958168404Spjd 2959168404Spjd return (0); 2960168404Spjd} 2961168404Spjd 2962168404Spjd/* 2963168404Spjd * Clones the given dataset. The target must be of the same type as the source. 2964168404Spjd */ 2965168404Spjdint 2966168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2967168404Spjd{ 2968168404Spjd zfs_cmd_t zc = { 0 }; 2969168404Spjd char parent[ZFS_MAXNAMELEN]; 2970168404Spjd int ret; 2971168404Spjd char errbuf[1024]; 2972168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 2973168404Spjd zfs_type_t type; 2974168404Spjd uint64_t zoned; 2975168404Spjd 2976168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2977168404Spjd 2978168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2979168404Spjd "cannot create '%s'"), target); 2980168404Spjd 2981168404Spjd /* validate the target name */ 2982185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 2983168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2984168404Spjd 2985168404Spjd /* validate parents exist */ 2986185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 2987168404Spjd return (-1); 2988168404Spjd 2989168404Spjd (void) parent_name(target, parent, sizeof (parent)); 2990168404Spjd 2991168404Spjd /* do the clone */ 2992168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2993168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2994168404Spjd type = ZFS_TYPE_VOLUME; 2995168404Spjd } else { 2996168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2997168404Spjd type = ZFS_TYPE_FILESYSTEM; 2998168404Spjd } 2999168404Spjd 3000168404Spjd if (props) { 3001185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3002185029Spjd zhp, errbuf)) == NULL) 3003168404Spjd return (-1); 3004168404Spjd 3005185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3006168404Spjd nvlist_free(props); 3007168404Spjd return (-1); 3008168404Spjd } 3009168404Spjd 3010168404Spjd nvlist_free(props); 3011168404Spjd } 3012168404Spjd 3013168404Spjd (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 3014168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 3015185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); 3016168404Spjd 3017168404Spjd zcmd_free_nvlists(&zc); 3018168404Spjd 3019168404Spjd if (ret != 0) { 3020168404Spjd switch (errno) { 3021168404Spjd 3022168404Spjd case ENOENT: 3023168404Spjd /* 3024168404Spjd * The parent doesn't exist. We should have caught this 3025168404Spjd * above, but there may a race condition that has since 3026168404Spjd * destroyed the parent. 3027168404Spjd * 3028168404Spjd * At this point, we don't know whether it's the source 3029168404Spjd * that doesn't exist anymore, or whether the target 3030168404Spjd * dataset doesn't exist. 3031168404Spjd */ 3032168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3033168404Spjd "no such parent '%s'"), parent); 3034168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3035168404Spjd 3036168404Spjd case EXDEV: 3037168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3038168404Spjd "source and target pools differ")); 3039168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3040168404Spjd errbuf)); 3041168404Spjd 3042168404Spjd default: 3043168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3044168404Spjd errbuf)); 3045168404Spjd } 3046168404Spjd } else if (ZFS_IS_VOLUME(zhp)) { 3047168404Spjd ret = zvol_create_link(zhp->zfs_hdl, target); 3048168404Spjd } 3049168404Spjd 3050168404Spjd return (ret); 3051168404Spjd} 3052168404Spjd 3053168404Spjdtypedef struct promote_data { 3054168404Spjd char cb_mountpoint[MAXPATHLEN]; 3055168404Spjd const char *cb_target; 3056168404Spjd const char *cb_errbuf; 3057168404Spjd uint64_t cb_pivot_txg; 3058168404Spjd} promote_data_t; 3059168404Spjd 3060168404Spjdstatic int 3061168404Spjdpromote_snap_cb(zfs_handle_t *zhp, void *data) 3062168404Spjd{ 3063168404Spjd promote_data_t *pd = data; 3064168404Spjd zfs_handle_t *szhp; 3065168404Spjd char snapname[MAXPATHLEN]; 3066168404Spjd int rv = 0; 3067168404Spjd 3068168404Spjd /* We don't care about snapshots after the pivot point */ 3069168404Spjd if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 3070168404Spjd zfs_close(zhp); 3071168404Spjd return (0); 3072168404Spjd } 3073168404Spjd 3074168404Spjd /* Remove the device link if it's a zvol. */ 3075168404Spjd if (ZFS_IS_VOLUME(zhp)) 3076168404Spjd (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 3077168404Spjd 3078168404Spjd /* Check for conflicting names */ 3079168404Spjd (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 3080168404Spjd (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 3081168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 3082168404Spjd if (szhp != NULL) { 3083168404Spjd zfs_close(szhp); 3084168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3085168404Spjd "snapshot name '%s' from origin \n" 3086168404Spjd "conflicts with '%s' from target"), 3087168404Spjd zhp->zfs_name, snapname); 3088168404Spjd rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 3089168404Spjd } 3090168404Spjd zfs_close(zhp); 3091168404Spjd return (rv); 3092168404Spjd} 3093168404Spjd 3094168404Spjdstatic int 3095168404Spjdpromote_snap_done_cb(zfs_handle_t *zhp, void *data) 3096168404Spjd{ 3097168404Spjd promote_data_t *pd = data; 3098168404Spjd 3099168404Spjd /* We don't care about snapshots after the pivot point */ 3100168404Spjd if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 3101168404Spjd /* Create the device link if it's a zvol. */ 3102168404Spjd if (ZFS_IS_VOLUME(zhp)) 3103168404Spjd (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3104168404Spjd } 3105168404Spjd 3106168404Spjd zfs_close(zhp); 3107168404Spjd return (0); 3108168404Spjd} 3109168404Spjd 3110168404Spjd/* 3111168404Spjd * Promotes the given clone fs to be the clone parent. 3112168404Spjd */ 3113168404Spjdint 3114168404Spjdzfs_promote(zfs_handle_t *zhp) 3115168404Spjd{ 3116168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3117168404Spjd zfs_cmd_t zc = { 0 }; 3118168404Spjd char parent[MAXPATHLEN]; 3119168404Spjd char *cp; 3120168404Spjd int ret; 3121168404Spjd zfs_handle_t *pzhp; 3122168404Spjd promote_data_t pd; 3123168404Spjd char errbuf[1024]; 3124168404Spjd 3125168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3126168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3127168404Spjd 3128168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3129168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3130168404Spjd "snapshots can not be promoted")); 3131168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3132168404Spjd } 3133168404Spjd 3134185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3135168404Spjd if (parent[0] == '\0') { 3136168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3137168404Spjd "not a cloned filesystem")); 3138168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3139168404Spjd } 3140168404Spjd cp = strchr(parent, '@'); 3141168404Spjd *cp = '\0'; 3142168404Spjd 3143168404Spjd /* Walk the snapshots we will be moving */ 3144185029Spjd pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT); 3145168404Spjd if (pzhp == NULL) 3146168404Spjd return (-1); 3147168404Spjd pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 3148168404Spjd zfs_close(pzhp); 3149168404Spjd pd.cb_target = zhp->zfs_name; 3150168404Spjd pd.cb_errbuf = errbuf; 3151185029Spjd pzhp = zfs_open(hdl, parent, ZFS_TYPE_DATASET); 3152168404Spjd if (pzhp == NULL) 3153168404Spjd return (-1); 3154168404Spjd (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 3155168404Spjd sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 3156168404Spjd ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 3157168404Spjd if (ret != 0) { 3158168404Spjd zfs_close(pzhp); 3159168404Spjd return (-1); 3160168404Spjd } 3161168404Spjd 3162168404Spjd /* issue the ioctl */ 3163185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3164168404Spjd sizeof (zc.zc_value)); 3165168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3166185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3167168404Spjd 3168168404Spjd if (ret != 0) { 3169168404Spjd int save_errno = errno; 3170168404Spjd 3171168404Spjd (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 3172168404Spjd zfs_close(pzhp); 3173168404Spjd 3174168404Spjd switch (save_errno) { 3175168404Spjd case EEXIST: 3176168404Spjd /* 3177168404Spjd * There is a conflicting snapshot name. We 3178168404Spjd * should have caught this above, but they could 3179168404Spjd * have renamed something in the mean time. 3180168404Spjd */ 3181168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3182168404Spjd "conflicting snapshot name from parent '%s'"), 3183168404Spjd parent); 3184168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3185168404Spjd 3186168404Spjd default: 3187168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3188168404Spjd } 3189168404Spjd } else { 3190168404Spjd (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 3191168404Spjd } 3192168404Spjd 3193168404Spjd zfs_close(pzhp); 3194168404Spjd return (ret); 3195168404Spjd} 3196168404Spjd 3197168676Spjdstruct createdata { 3198168676Spjd const char *cd_snapname; 3199168676Spjd int cd_ifexists; 3200168676Spjd}; 3201168676Spjd 3202168404Spjdstatic int 3203168404Spjdzfs_create_link_cb(zfs_handle_t *zhp, void *arg) 3204168404Spjd{ 3205168676Spjd struct createdata *cd = arg; 3206168404Spjd int ret; 3207168404Spjd 3208168404Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3209168404Spjd char name[MAXPATHLEN]; 3210168404Spjd 3211168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 3212168404Spjd (void) strlcat(name, "@", sizeof (name)); 3213168676Spjd (void) strlcat(name, cd->cd_snapname, sizeof (name)); 3214168676Spjd (void) zvol_create_link_common(zhp->zfs_hdl, name, 3215168676Spjd cd->cd_ifexists); 3216168404Spjd /* 3217168404Spjd * NB: this is simply a best-effort. We don't want to 3218168404Spjd * return an error, because then we wouldn't visit all 3219168404Spjd * the volumes. 3220168404Spjd */ 3221168404Spjd } 3222168404Spjd 3223168676Spjd ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd); 3224168404Spjd 3225168404Spjd zfs_close(zhp); 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 */ 3290185029Spjd if (ret != 0) 3291185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3292185029Spjd "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 3293185029Spjd 3294168404Spjd if (ret == 0 && recursive) { 3295168676Spjd struct createdata cd; 3296168676Spjd 3297168676Spjd cd.cd_snapname = delim + 1; 3298168676Spjd cd.cd_ifexists = B_FALSE; 3299168676Spjd (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 3300168404Spjd } 3301168404Spjd if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 3302168404Spjd ret = zvol_create_link(zhp->zfs_hdl, path); 3303168404Spjd if (ret != 0) { 3304185029Spjd (void) zfs_standard_error(hdl, errno, 3305185029Spjd dgettext(TEXT_DOMAIN, 3306185029Spjd "Volume successfully snapshotted, but device links " 3307185029Spjd "were not created")); 3308185029Spjd zfs_close(zhp); 3309185029Spjd return (-1); 3310168404Spjd } 3311168404Spjd } 3312168404Spjd 3313168404Spjd if (ret != 0) 3314168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 3315168404Spjd 3316168404Spjd zfs_close(zhp); 3317168404Spjd 3318168404Spjd return (ret); 3319168404Spjd} 3320168404Spjd 3321168404Spjd/* 3322168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3323168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3324168404Spjd * is a dependent and we should just destroy it without checking the transaction 3325168404Spjd * group. 3326168404Spjd */ 3327168404Spjdtypedef struct rollback_data { 3328168404Spjd const char *cb_target; /* the snapshot */ 3329168404Spjd uint64_t cb_create; /* creation time reference */ 3330185029Spjd boolean_t cb_error; 3331168404Spjd boolean_t cb_dependent; 3332185029Spjd boolean_t cb_force; 3333168404Spjd} rollback_data_t; 3334168404Spjd 3335168404Spjdstatic int 3336168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3337168404Spjd{ 3338168404Spjd rollback_data_t *cbp = data; 3339168404Spjd 3340168404Spjd if (!cbp->cb_dependent) { 3341168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3342168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3343168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3344168404Spjd cbp->cb_create) { 3345185029Spjd char *logstr; 3346168404Spjd 3347168404Spjd cbp->cb_dependent = B_TRUE; 3348185029Spjd cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3349185029Spjd rollback_destroy, cbp); 3350168404Spjd cbp->cb_dependent = B_FALSE; 3351168404Spjd 3352185029Spjd logstr = zhp->zfs_hdl->libzfs_log_str; 3353185029Spjd zhp->zfs_hdl->libzfs_log_str = NULL; 3354185029Spjd cbp->cb_error |= zfs_destroy(zhp); 3355185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 3356168404Spjd } 3357168404Spjd } else { 3358185029Spjd /* We must destroy this clone; first unmount it */ 3359185029Spjd prop_changelist_t *clp; 3360185029Spjd 3361185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3362185029Spjd cbp->cb_force ? MS_FORCE: 0); 3363185029Spjd if (clp == NULL || changelist_prefix(clp) != 0) { 3364185029Spjd cbp->cb_error = B_TRUE; 3365185029Spjd zfs_close(zhp); 3366185029Spjd return (0); 3367185029Spjd } 3368168404Spjd if (zfs_destroy(zhp) != 0) 3369185029Spjd cbp->cb_error = B_TRUE; 3370168404Spjd else 3371185029Spjd changelist_remove(clp, zhp->zfs_name); 3372185029Spjd (void) changelist_postfix(clp); 3373185029Spjd changelist_free(clp); 3374168404Spjd } 3375168404Spjd 3376168404Spjd zfs_close(zhp); 3377168404Spjd return (0); 3378168404Spjd} 3379168404Spjd 3380168404Spjd/* 3381168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3382168404Spjd * data changes since then and making it the active dataset. 3383168404Spjd * 3384168404Spjd * Any snapshots more recent than the target are destroyed, along with 3385168404Spjd * their dependents. 3386168404Spjd */ 3387168404Spjdint 3388185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3389168404Spjd{ 3390168404Spjd rollback_data_t cb = { 0 }; 3391185029Spjd int err; 3392185029Spjd zfs_cmd_t zc = { 0 }; 3393185029Spjd boolean_t restore_resv = 0; 3394185029Spjd uint64_t old_volsize, new_volsize; 3395185029Spjd zfs_prop_t resv_prop; 3396168404Spjd 3397185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3398185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3399168404Spjd 3400168404Spjd /* 3401168404Spjd * Destroy all recent snapshots and its dependends. 3402168404Spjd */ 3403185029Spjd cb.cb_force = force; 3404168404Spjd cb.cb_target = snap->zfs_name; 3405168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3406168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3407168404Spjd 3408185029Spjd if (cb.cb_error) 3409185029Spjd return (-1); 3410168404Spjd 3411168404Spjd /* 3412168404Spjd * Now that we have verified that the snapshot is the latest, 3413168404Spjd * rollback to the given snapshot. 3414168404Spjd */ 3415168404Spjd 3416185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3417185029Spjd if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3418185029Spjd return (-1); 3419185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3420185029Spjd return (-1); 3421185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3422185029Spjd restore_resv = 3423185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3424168404Spjd } 3425168404Spjd 3426185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3427185029Spjd 3428185029Spjd if (ZFS_IS_VOLUME(zhp)) 3429185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3430185029Spjd else 3431185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3432185029Spjd 3433168404Spjd /* 3434185029Spjd * We rely on zfs_iter_children() to verify that there are no 3435185029Spjd * newer snapshots for the given dataset. Therefore, we can 3436185029Spjd * simply pass the name on to the ioctl() call. There is still 3437185029Spjd * an unlikely race condition where the user has taken a 3438185029Spjd * snapshot since we verified that this was the most recent. 3439185029Spjd * 3440168404Spjd */ 3441185029Spjd if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3442185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3443185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3444185029Spjd zhp->zfs_name); 3445185029Spjd return (err); 3446185029Spjd } 3447168404Spjd 3448185029Spjd /* 3449185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3450185029Spjd * rollback reservation and the volsize has changed then set 3451185029Spjd * the reservation property to the post-rollback volsize. 3452185029Spjd * Make a new handle since the rollback closed the dataset. 3453185029Spjd */ 3454185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3455185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3456185029Spjd if (err = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name)) { 3457185029Spjd zfs_close(zhp); 3458185029Spjd return (err); 3459185029Spjd } 3460185029Spjd if (restore_resv) { 3461185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3462185029Spjd if (old_volsize != new_volsize) 3463185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3464185029Spjd new_volsize); 3465185029Spjd } 3466185029Spjd zfs_close(zhp); 3467185029Spjd } 3468185029Spjd return (err); 3469168404Spjd} 3470168404Spjd 3471168404Spjd/* 3472168404Spjd * Iterate over all dependents for a given dataset. This includes both 3473168404Spjd * hierarchical dependents (children) and data dependents (snapshots and 3474168404Spjd * clones). The bulk of the processing occurs in get_dependents() in 3475168404Spjd * libzfs_graph.c. 3476168404Spjd */ 3477168404Spjdint 3478168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 3479168404Spjd zfs_iter_f func, void *data) 3480168404Spjd{ 3481168404Spjd char **dependents; 3482168404Spjd size_t count; 3483168404Spjd int i; 3484168404Spjd zfs_handle_t *child; 3485168404Spjd int ret = 0; 3486168404Spjd 3487168404Spjd if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 3488168404Spjd &dependents, &count) != 0) 3489168404Spjd return (-1); 3490168404Spjd 3491168404Spjd for (i = 0; i < count; i++) { 3492168404Spjd if ((child = make_dataset_handle(zhp->zfs_hdl, 3493168404Spjd dependents[i])) == NULL) 3494168404Spjd continue; 3495168404Spjd 3496168404Spjd if ((ret = func(child, data)) != 0) 3497168404Spjd break; 3498168404Spjd } 3499168404Spjd 3500168404Spjd for (i = 0; i < count; i++) 3501168404Spjd free(dependents[i]); 3502168404Spjd free(dependents); 3503168404Spjd 3504168404Spjd return (ret); 3505168404Spjd} 3506168404Spjd 3507168404Spjd/* 3508168404Spjd * Renames the given dataset. 3509168404Spjd */ 3510168404Spjdint 3511185029Spjdzfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) 3512168404Spjd{ 3513168404Spjd int ret; 3514168404Spjd zfs_cmd_t zc = { 0 }; 3515168404Spjd char *delim; 3516168676Spjd prop_changelist_t *cl = NULL; 3517168676Spjd zfs_handle_t *zhrp = NULL; 3518168676Spjd char *parentname = NULL; 3519168404Spjd char parent[ZFS_MAXNAMELEN]; 3520168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3521168404Spjd char errbuf[1024]; 3522168404Spjd 3523168404Spjd /* if we have the same exact name, just return success */ 3524168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3525168404Spjd return (0); 3526168404Spjd 3527168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3528168404Spjd "cannot rename to '%s'"), target); 3529168404Spjd 3530168404Spjd /* 3531168404Spjd * Make sure the target name is valid 3532168404Spjd */ 3533168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3534168404Spjd if ((strchr(target, '@') == NULL) || 3535168404Spjd *target == '@') { 3536168404Spjd /* 3537168404Spjd * Snapshot target name is abbreviated, 3538168404Spjd * reconstruct full dataset name 3539168404Spjd */ 3540168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3541168404Spjd sizeof (parent)); 3542168404Spjd delim = strchr(parent, '@'); 3543168404Spjd if (strchr(target, '@') == NULL) 3544168404Spjd *(++delim) = '\0'; 3545168404Spjd else 3546168404Spjd *delim = '\0'; 3547168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3548168404Spjd target = parent; 3549168404Spjd } else { 3550168404Spjd /* 3551168404Spjd * Make sure we're renaming within the same dataset. 3552168404Spjd */ 3553168404Spjd delim = strchr(target, '@'); 3554168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3555168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3556168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3557168404Spjd "snapshots must be part of same " 3558168404Spjd "dataset")); 3559168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3560168404Spjd errbuf)); 3561168404Spjd } 3562168404Spjd } 3563185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3564168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3565168404Spjd } else { 3566168676Spjd if (recursive) { 3567168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3568168676Spjd "recursive rename must be a snapshot")); 3569168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3570168676Spjd } 3571168676Spjd 3572185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3573168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3574168404Spjd uint64_t unused; 3575168404Spjd 3576168404Spjd /* validate parents */ 3577185029Spjd if (check_parents(hdl, target, &unused, B_FALSE, NULL) != 0) 3578168404Spjd return (-1); 3579168404Spjd 3580168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3581168404Spjd 3582168404Spjd /* make sure we're in the same pool */ 3583168404Spjd verify((delim = strchr(target, '/')) != NULL); 3584168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3585168404Spjd zhp->zfs_name[delim - target] != '/') { 3586168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3587168404Spjd "datasets must be within same pool")); 3588168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3589168404Spjd } 3590168404Spjd 3591168404Spjd /* new name cannot be a child of the current dataset name */ 3592168404Spjd if (strncmp(parent, zhp->zfs_name, 3593168404Spjd strlen(zhp->zfs_name)) == 0) { 3594168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3595168404Spjd "New dataset name cannot be a descendent of " 3596168404Spjd "current dataset name")); 3597168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3598168404Spjd } 3599168404Spjd } 3600168404Spjd 3601168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3602168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3603168404Spjd 3604168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3605168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3606168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3607168404Spjd "dataset is used in a non-global zone")); 3608168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3609168404Spjd } 3610168404Spjd 3611168676Spjd if (recursive) { 3612168676Spjd struct destroydata dd; 3613168404Spjd 3614185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3615185029Spjd if (parentname == NULL) { 3616185029Spjd ret = -1; 3617185029Spjd goto error; 3618185029Spjd } 3619168676Spjd delim = strchr(parentname, '@'); 3620168676Spjd *delim = '\0'; 3621185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3622168676Spjd if (zhrp == NULL) { 3623185029Spjd ret = -1; 3624185029Spjd goto error; 3625168676Spjd } 3626168676Spjd 3627168676Spjd dd.snapname = delim + 1; 3628168676Spjd dd.gotone = B_FALSE; 3629185029Spjd dd.closezhp = B_TRUE; 3630168676Spjd 3631168676Spjd /* We remove any zvol links prior to renaming them */ 3632168676Spjd ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3633168676Spjd if (ret) { 3634168676Spjd goto error; 3635168676Spjd } 3636168676Spjd } else { 3637185029Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) 3638168676Spjd return (-1); 3639168676Spjd 3640168676Spjd if (changelist_haszonedchild(cl)) { 3641168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3642168676Spjd "child dataset with inherited mountpoint is used " 3643168676Spjd "in a non-global zone")); 3644168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3645168676Spjd goto error; 3646168676Spjd } 3647168676Spjd 3648168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3649168676Spjd goto error; 3650168404Spjd } 3651168404Spjd 3652168404Spjd if (ZFS_IS_VOLUME(zhp)) 3653168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3654168404Spjd else 3655168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3656168404Spjd 3657168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3658168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3659168404Spjd 3660168676Spjd zc.zc_cookie = recursive; 3661168676Spjd 3662185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3663168676Spjd /* 3664168676Spjd * if it was recursive, the one that actually failed will 3665168676Spjd * be in zc.zc_name 3666168676Spjd */ 3667168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3668185029Spjd "cannot rename '%s'"), zc.zc_name); 3669168404Spjd 3670168676Spjd if (recursive && errno == EEXIST) { 3671168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3672168676Spjd "a child dataset already has a snapshot " 3673168676Spjd "with the new name")); 3674185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3675168676Spjd } else { 3676168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3677168676Spjd } 3678168676Spjd 3679168404Spjd /* 3680168404Spjd * On failure, we still want to remount any filesystems that 3681168404Spjd * were previously mounted, so we don't alter the system state. 3682168404Spjd */ 3683168676Spjd if (recursive) { 3684168676Spjd struct createdata cd; 3685168676Spjd 3686168676Spjd /* only create links for datasets that had existed */ 3687168676Spjd cd.cd_snapname = delim + 1; 3688168676Spjd cd.cd_ifexists = B_TRUE; 3689168676Spjd (void) zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3690168676Spjd &cd); 3691168676Spjd } else { 3692168676Spjd (void) changelist_postfix(cl); 3693168676Spjd } 3694168404Spjd } else { 3695168676Spjd if (recursive) { 3696168676Spjd struct createdata cd; 3697168404Spjd 3698168676Spjd /* only create links for datasets that had existed */ 3699168676Spjd cd.cd_snapname = strchr(target, '@') + 1; 3700168676Spjd cd.cd_ifexists = B_TRUE; 3701168676Spjd ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3702168676Spjd &cd); 3703168676Spjd } else { 3704168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3705168676Spjd ret = changelist_postfix(cl); 3706168676Spjd } 3707168404Spjd } 3708168404Spjd 3709168404Spjderror: 3710168676Spjd if (parentname) { 3711168676Spjd free(parentname); 3712168676Spjd } 3713168676Spjd if (zhrp) { 3714168676Spjd zfs_close(zhrp); 3715168676Spjd } 3716168676Spjd if (cl) { 3717168676Spjd changelist_free(cl); 3718168676Spjd } 3719168404Spjd return (ret); 3720168404Spjd} 3721168404Spjd 3722168404Spjd/* 3723168404Spjd * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3724168404Spjd * poke devfsadm to create the /dev link, and then wait for the link to appear. 3725168404Spjd */ 3726168404Spjdint 3727168404Spjdzvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3728168404Spjd{ 3729168676Spjd return (zvol_create_link_common(hdl, dataset, B_FALSE)); 3730168676Spjd} 3731168676Spjd 3732168676Spjdstatic int 3733168676Spjdzvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3734168676Spjd{ 3735168404Spjd zfs_cmd_t zc = { 0 }; 3736168404Spjd#if 0 3737168404Spjd di_devlink_handle_t dhdl; 3738185029Spjd priv_set_t *priv_effective; 3739185029Spjd int privileged; 3740168404Spjd#endif 3741168404Spjd 3742168404Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3743168404Spjd 3744168404Spjd /* 3745168404Spjd * Issue the appropriate ioctl. 3746168404Spjd */ 3747168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3748168404Spjd switch (errno) { 3749168404Spjd case EEXIST: 3750168404Spjd /* 3751168404Spjd * Silently ignore the case where the link already 3752168404Spjd * exists. This allows 'zfs volinit' to be run multiple 3753168404Spjd * times without errors. 3754168404Spjd */ 3755168404Spjd return (0); 3756168404Spjd 3757168676Spjd case ENOENT: 3758168676Spjd /* 3759168676Spjd * Dataset does not exist in the kernel. If we 3760168676Spjd * don't care (see zfs_rename), then ignore the 3761168676Spjd * error quietly. 3762168676Spjd */ 3763168676Spjd if (ifexists) { 3764168676Spjd return (0); 3765168676Spjd } 3766168676Spjd 3767168676Spjd /* FALLTHROUGH */ 3768168676Spjd 3769168404Spjd default: 3770168404Spjd return (zfs_standard_error_fmt(hdl, errno, 3771168404Spjd dgettext(TEXT_DOMAIN, "cannot create device links " 3772168404Spjd "for '%s'"), dataset)); 3773168404Spjd } 3774168404Spjd } 3775168404Spjd 3776168404Spjd#if 0 3777168404Spjd /* 3778185029Spjd * If privileged call devfsadm and wait for the links to 3779185029Spjd * magically appear. 3780185029Spjd * Otherwise, print out an informational message. 3781168404Spjd */ 3782185029Spjd 3783185029Spjd priv_effective = priv_allocset(); 3784185029Spjd (void) getppriv(PRIV_EFFECTIVE, priv_effective); 3785185029Spjd privileged = (priv_isfullset(priv_effective) == B_TRUE); 3786185029Spjd priv_freeset(priv_effective); 3787185029Spjd 3788185029Spjd if (privileged) { 3789185029Spjd if ((dhdl = di_devlink_init(ZFS_DRIVER, 3790185029Spjd DI_MAKE_LINK)) == NULL) { 3791185029Spjd zfs_error_aux(hdl, strerror(errno)); 3792185029Spjd (void) zfs_error_fmt(hdl, errno, 3793185029Spjd dgettext(TEXT_DOMAIN, "cannot create device links " 3794185029Spjd "for '%s'"), dataset); 3795185029Spjd (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3796185029Spjd return (-1); 3797185029Spjd } else { 3798185029Spjd (void) di_devlink_fini(&dhdl); 3799185029Spjd } 3800168404Spjd } else { 3801185029Spjd char pathname[MAXPATHLEN]; 3802185029Spjd struct stat64 statbuf; 3803185029Spjd int i; 3804185029Spjd 3805185029Spjd#define MAX_WAIT 10 3806185029Spjd 3807185029Spjd /* 3808185029Spjd * This is the poor mans way of waiting for the link 3809185029Spjd * to show up. If after 10 seconds we still don't 3810185029Spjd * have it, then print out a message. 3811185029Spjd */ 3812185029Spjd (void) snprintf(pathname, sizeof (pathname), "/dev/zvol/dsk/%s", 3813185029Spjd dataset); 3814185029Spjd 3815185029Spjd for (i = 0; i != MAX_WAIT; i++) { 3816185029Spjd if (stat64(pathname, &statbuf) == 0) 3817185029Spjd break; 3818185029Spjd (void) sleep(1); 3819185029Spjd } 3820185029Spjd if (i == MAX_WAIT) 3821185029Spjd (void) printf(gettext("%s may not be immediately " 3822185029Spjd "available\n"), pathname); 3823168404Spjd } 3824168404Spjd#endif 3825168404Spjd 3826168404Spjd return (0); 3827168404Spjd} 3828168404Spjd 3829168404Spjd/* 3830168404Spjd * Remove a minor node for the given zvol and the associated /dev links. 3831168404Spjd */ 3832168404Spjdint 3833168404Spjdzvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3834168404Spjd{ 3835168404Spjd zfs_cmd_t zc = { 0 }; 3836168404Spjd 3837168404Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3838168404Spjd 3839168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3840168404Spjd switch (errno) { 3841168404Spjd case ENXIO: 3842168404Spjd /* 3843168404Spjd * Silently ignore the case where the link no longer 3844168404Spjd * exists, so that 'zfs volfini' can be run multiple 3845168404Spjd * times without errors. 3846168404Spjd */ 3847168404Spjd return (0); 3848168404Spjd 3849168404Spjd default: 3850168404Spjd return (zfs_standard_error_fmt(hdl, errno, 3851168404Spjd dgettext(TEXT_DOMAIN, "cannot remove device " 3852168404Spjd "links for '%s'"), dataset)); 3853168404Spjd } 3854168404Spjd } 3855168404Spjd 3856168404Spjd return (0); 3857168404Spjd} 3858168404Spjd 3859168404Spjdnvlist_t * 3860168404Spjdzfs_get_user_props(zfs_handle_t *zhp) 3861168404Spjd{ 3862168404Spjd return (zhp->zfs_user_props); 3863168404Spjd} 3864168404Spjd 3865168404Spjd/* 3866168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3867168404Spjd * display, and their maximum widths. This does two main things: 3868168404Spjd * 3869168404Spjd * - If this is a list of all properties, then expand the list to include 3870168404Spjd * all native properties, and set a flag so that for each dataset we look 3871168404Spjd * for new unique user properties and add them to the list. 3872168404Spjd * 3873168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3874168404Spjd * so that we can size the column appropriately. 3875168404Spjd */ 3876168404Spjdint 3877185029Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp) 3878168404Spjd{ 3879168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3880185029Spjd zprop_list_t *entry; 3881185029Spjd zprop_list_t **last, **start; 3882168404Spjd nvlist_t *userprops, *propval; 3883168404Spjd nvpair_t *elem; 3884168404Spjd char *strval; 3885168404Spjd char buf[ZFS_MAXPROPLEN]; 3886168404Spjd 3887185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3888168404Spjd return (-1); 3889168404Spjd 3890168404Spjd userprops = zfs_get_user_props(zhp); 3891168404Spjd 3892168404Spjd entry = *plp; 3893168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3894168404Spjd /* 3895168404Spjd * Go through and add any user properties as necessary. We 3896168404Spjd * start by incrementing our list pointer to the first 3897168404Spjd * non-native property. 3898168404Spjd */ 3899168404Spjd start = plp; 3900168404Spjd while (*start != NULL) { 3901185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3902168404Spjd break; 3903168404Spjd start = &(*start)->pl_next; 3904168404Spjd } 3905168404Spjd 3906168404Spjd elem = NULL; 3907168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3908168404Spjd /* 3909168404Spjd * See if we've already found this property in our list. 3910168404Spjd */ 3911168404Spjd for (last = start; *last != NULL; 3912168404Spjd last = &(*last)->pl_next) { 3913168404Spjd if (strcmp((*last)->pl_user_prop, 3914168404Spjd nvpair_name(elem)) == 0) 3915168404Spjd break; 3916168404Spjd } 3917168404Spjd 3918168404Spjd if (*last == NULL) { 3919168404Spjd if ((entry = zfs_alloc(hdl, 3920185029Spjd sizeof (zprop_list_t))) == NULL || 3921168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3922168404Spjd nvpair_name(elem)))) == NULL) { 3923168404Spjd free(entry); 3924168404Spjd return (-1); 3925168404Spjd } 3926168404Spjd 3927185029Spjd entry->pl_prop = ZPROP_INVAL; 3928168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3929168404Spjd entry->pl_all = B_TRUE; 3930168404Spjd *last = entry; 3931168404Spjd } 3932168404Spjd } 3933168404Spjd } 3934168404Spjd 3935168404Spjd /* 3936168404Spjd * Now go through and check the width of any non-fixed columns 3937168404Spjd */ 3938168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3939168404Spjd if (entry->pl_fixed) 3940168404Spjd continue; 3941168404Spjd 3942185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 3943168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3944168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3945168404Spjd if (strlen(buf) > entry->pl_width) 3946168404Spjd entry->pl_width = strlen(buf); 3947168404Spjd } 3948168404Spjd } else if (nvlist_lookup_nvlist(userprops, 3949168404Spjd entry->pl_user_prop, &propval) == 0) { 3950168404Spjd verify(nvlist_lookup_string(propval, 3951185029Spjd ZPROP_VALUE, &strval) == 0); 3952168404Spjd if (strlen(strval) > entry->pl_width) 3953168404Spjd entry->pl_width = strlen(strval); 3954168404Spjd } 3955168404Spjd } 3956168404Spjd 3957168404Spjd return (0); 3958168404Spjd} 3959168404Spjd 3960185029Spjd#ifdef TODO 3961185029Spjdint 3962185029Spjdzfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred) 3963185029Spjd{ 3964185029Spjd zfs_cmd_t zc = { 0 }; 3965185029Spjd nvlist_t *nvp; 3966185029Spjd gid_t gid; 3967185029Spjd uid_t uid; 3968185029Spjd const gid_t *groups; 3969185029Spjd int group_cnt; 3970185029Spjd int error; 3971185029Spjd 3972185029Spjd if (nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0) != 0) 3973185029Spjd return (no_memory(hdl)); 3974185029Spjd 3975185029Spjd uid = ucred_geteuid(cred); 3976185029Spjd gid = ucred_getegid(cred); 3977185029Spjd group_cnt = ucred_getgroups(cred, &groups); 3978185029Spjd 3979185029Spjd if (uid == (uid_t)-1 || gid == (uid_t)-1 || group_cnt == (uid_t)-1) 3980185029Spjd return (1); 3981185029Spjd 3982185029Spjd if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_UID, uid) != 0) { 3983185029Spjd nvlist_free(nvp); 3984185029Spjd return (1); 3985185029Spjd } 3986185029Spjd 3987185029Spjd if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_GID, gid) != 0) { 3988185029Spjd nvlist_free(nvp); 3989185029Spjd return (1); 3990185029Spjd } 3991185029Spjd 3992185029Spjd if (nvlist_add_uint32_array(nvp, 3993185029Spjd ZFS_DELEG_PERM_GROUPS, (uint32_t *)groups, group_cnt) != 0) { 3994185029Spjd nvlist_free(nvp); 3995185029Spjd return (1); 3996185029Spjd } 3997185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3998185029Spjd 3999185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvp)) 4000185029Spjd return (-1); 4001185029Spjd 4002185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc); 4003185029Spjd nvlist_free(nvp); 4004185029Spjd return (error); 4005185029Spjd} 4006185029Spjd#endif 4007185029Spjd 4008185029Spjdint 4009185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4010209962Smm char *resource, void *export, void *sharetab, 4011209962Smm int sharemax, zfs_share_op_t operation) 4012185029Spjd{ 4013185029Spjd zfs_cmd_t zc = { 0 }; 4014185029Spjd int error; 4015185029Spjd 4016185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4017185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4018209962Smm if (resource) 4019209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4020185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4021185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4022185029Spjd zc.zc_share.z_sharetype = operation; 4023185029Spjd zc.zc_share.z_sharemax = sharemax; 4024185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4025185029Spjd return (error); 4026185029Spjd} 4027185029Spjd 4028205198Sdelphijvoid 4029205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4030205198Sdelphij{ 4031205198Sdelphij nvpair_t *curr; 4032205198Sdelphij 4033205198Sdelphij /* 4034205198Sdelphij * Keep a reference to the props-table against which we prune the 4035205198Sdelphij * properties. 4036205198Sdelphij */ 4037205198Sdelphij zhp->zfs_props_table = props; 4038205198Sdelphij 4039205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4040205198Sdelphij 4041205198Sdelphij while (curr) { 4042205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4043205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4044205198Sdelphij 4045206199Sdelphij /* 4046206199Sdelphij * We leave user:props in the nvlist, so there will be 4047206199Sdelphij * some ZPROP_INVAL. To be extra safe, don't prune 4048206199Sdelphij * those. 4049206199Sdelphij */ 4050206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4051205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4052205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4053205198Sdelphij curr = next; 4054205198Sdelphij } 4055205198Sdelphij} 4056205198Sdelphij 4057209962Smm#ifdef sun 4058209962Smmstatic int 4059209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4060209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4061209962Smm{ 4062209962Smm zfs_cmd_t zc = { 0 }; 4063209962Smm nvlist_t *nvlist = NULL; 4064209962Smm int error; 4065209962Smm 4066209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4067209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4068209962Smm zc.zc_cookie = (uint64_t)cmd; 4069209962Smm 4070209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4071209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4072209962Smm (void) no_memory(hdl); 4073209962Smm return (NULL); 4074209962Smm } 4075209962Smm } 4076209962Smm 4077209962Smm switch (cmd) { 4078209962Smm case ZFS_SMB_ACL_ADD: 4079209962Smm case ZFS_SMB_ACL_REMOVE: 4080209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4081209962Smm break; 4082209962Smm case ZFS_SMB_ACL_RENAME: 4083209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4084209962Smm resource1) != 0) { 4085209962Smm (void) no_memory(hdl); 4086209962Smm return (-1); 4087209962Smm } 4088209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4089209962Smm resource2) != 0) { 4090209962Smm (void) no_memory(hdl); 4091209962Smm return (-1); 4092209962Smm } 4093209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4094209962Smm nvlist_free(nvlist); 4095209962Smm return (-1); 4096209962Smm } 4097209962Smm break; 4098209962Smm case ZFS_SMB_ACL_PURGE: 4099209962Smm break; 4100209962Smm default: 4101209962Smm return (-1); 4102209962Smm } 4103209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4104209962Smm if (nvlist) 4105209962Smm nvlist_free(nvlist); 4106209962Smm return (error); 4107209962Smm} 4108209962Smm 4109209962Smmint 4110209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4111209962Smm char *path, char *resource) 4112209962Smm{ 4113209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4114209962Smm resource, NULL)); 4115209962Smm} 4116209962Smm 4117209962Smmint 4118209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4119209962Smm char *path, char *resource) 4120209962Smm{ 4121209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4122209962Smm resource, NULL)); 4123209962Smm} 4124209962Smm 4125209962Smmint 4126209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4127209962Smm{ 4128209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4129209962Smm NULL, NULL)); 4130209962Smm} 4131209962Smm 4132209962Smmint 4133209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4134209962Smm char *oldname, char *newname) 4135209962Smm{ 4136209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4137209962Smm oldname, newname)); 4138209962Smm} 4139209962Smm#endif /* sun */ 4140209962Smm 4141209962Smmint 4142209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4143209962Smm zfs_userspace_cb_t func, void *arg) 4144209962Smm{ 4145209962Smm zfs_cmd_t zc = { 0 }; 4146209962Smm int error; 4147209962Smm zfs_useracct_t buf[100]; 4148209962Smm 4149209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4150209962Smm 4151209962Smm zc.zc_objset_type = type; 4152209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4153209962Smm 4154209962Smm /* CONSTCOND */ 4155209962Smm while (1) { 4156209962Smm zfs_useracct_t *zua = buf; 4157209962Smm 4158209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4159209962Smm error = ioctl(zhp->zfs_hdl->libzfs_fd, 4160209962Smm ZFS_IOC_USERSPACE_MANY, &zc); 4161209962Smm if (error || zc.zc_nvlist_dst_size == 0) 4162209962Smm break; 4163209962Smm 4164209962Smm while (zc.zc_nvlist_dst_size > 0) { 4165209962Smm error = func(arg, zua->zu_domain, zua->zu_rid, 4166209962Smm zua->zu_space); 4167209962Smm if (error != 0) 4168209962Smm return (error); 4169209962Smm zua++; 4170209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4171209962Smm } 4172209962Smm } 4173209962Smm 4174209962Smm return (error); 4175209962Smm} 4176209962Smm 4177168404Spjd/* 4178168404Spjd * Attach/detach the given filesystem to/from the given jail. 4179168404Spjd */ 4180168404Spjdint 4181168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4182168404Spjd{ 4183168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4184168404Spjd zfs_cmd_t zc = { 0 }; 4185168404Spjd char errbuf[1024]; 4186168404Spjd int cmd, ret; 4187168404Spjd 4188168404Spjd if (attach) { 4189168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4190168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4191168404Spjd } else { 4192168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4193168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4194168404Spjd } 4195168404Spjd 4196168404Spjd switch (zhp->zfs_type) { 4197168404Spjd case ZFS_TYPE_VOLUME: 4198168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4199168404Spjd "volumes can not be jailed")); 4200168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4201168404Spjd case ZFS_TYPE_SNAPSHOT: 4202168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4203168404Spjd "snapshots can not be jailed")); 4204168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4205168404Spjd } 4206168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4207168404Spjd 4208168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4209168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4210168404Spjd zc.zc_jailid = jailid; 4211168404Spjd 4212168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4213168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4214168404Spjd zfs_standard_error(hdl, errno, errbuf); 4215168404Spjd 4216168404Spjd return (ret); 4217168404Spjd} 4218