libzfs_dataset.c revision 223623
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24219089Spjd * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 25223623Smm * Copyright (c) 2011 by Delphix. All rights reserved. 26168404Spjd */ 27168404Spjd 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 <priv.h> 42185029Spjd#include <pwd.h> 43185029Spjd#include <grp.h> 44185029Spjd#include <stddef.h> 45209962Smm#include <idmap.h> 46168404Spjd 47219089Spjd#include <sys/dnode.h> 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 58209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 59209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 60168676Spjd 61168404Spjd/* 62168404Spjd * Given a single type (not a mask of types), return the type in a human 63168404Spjd * readable form. 64168404Spjd */ 65168404Spjdconst char * 66168404Spjdzfs_type_to_name(zfs_type_t type) 67168404Spjd{ 68168404Spjd switch (type) { 69168404Spjd case ZFS_TYPE_FILESYSTEM: 70168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 71168404Spjd case ZFS_TYPE_SNAPSHOT: 72168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 73168404Spjd case ZFS_TYPE_VOLUME: 74168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 75168404Spjd } 76168404Spjd 77168404Spjd return (NULL); 78168404Spjd} 79168404Spjd 80168404Spjd/* 81168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 82168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 83168404Spjd * We guess what the type would have been based on the path and the mask of 84168404Spjd * acceptable types. 85168404Spjd */ 86168404Spjdstatic const char * 87168404Spjdpath_to_str(const char *path, int types) 88168404Spjd{ 89168404Spjd /* 90168404Spjd * When given a single type, always report the exact type. 91168404Spjd */ 92168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 93168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 94168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 95168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 96168404Spjd if (types == ZFS_TYPE_VOLUME) 97168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 98168404Spjd 99168404Spjd /* 100168404Spjd * The user is requesting more than one type of dataset. If this is the 101168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 102168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 103168404Spjd * snapshot attribute and try again. 104168404Spjd */ 105168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 106168404Spjd if (strchr(path, '@') != NULL) 107168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 108168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 109168404Spjd } 110168404Spjd 111168404Spjd /* 112168404Spjd * The user has requested either filesystems or volumes. 113168404Spjd * We have no way of knowing a priori what type this would be, so always 114168404Spjd * report it as "filesystem" or "volume", our two primitive types. 115168404Spjd */ 116168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 117168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 118168404Spjd 119168404Spjd assert(types & ZFS_TYPE_VOLUME); 120168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 121168404Spjd} 122168404Spjd 123168404Spjd/* 124168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 125209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 126209962Smm * explain exactly why the name was not valid. 127168404Spjd */ 128219089Spjdint 129185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 130185029Spjd boolean_t modifying) 131168404Spjd{ 132168404Spjd namecheck_err_t why; 133168404Spjd char what; 134168404Spjd 135219089Spjd (void) zfs_prop_get_table(); 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 */ 321219089Spjdstatic int 322209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 323168404Spjd{ 324168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 325168404Spjd 326209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 327168404Spjd 328209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 329168404Spjd if (errno == ENOMEM) { 330209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 331168404Spjd return (-1); 332168404Spjd } 333168404Spjd } else { 334168404Spjd return (-1); 335168404Spjd } 336168404Spjd } 337209962Smm return (0); 338209962Smm} 339168404Spjd 340219089Spjd/* 341219089Spjd * Utility function to get the received properties of the given object. 342219089Spjd */ 343209962Smmstatic int 344219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 345219089Spjd{ 346219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 347219089Spjd nvlist_t *recvdprops; 348219089Spjd zfs_cmd_t zc = { 0 }; 349219089Spjd int err; 350219089Spjd 351219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 352219089Spjd return (-1); 353219089Spjd 354219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 355219089Spjd 356219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 357219089Spjd if (errno == ENOMEM) { 358219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 359219089Spjd return (-1); 360219089Spjd } 361219089Spjd } else { 362219089Spjd zcmd_free_nvlists(&zc); 363219089Spjd return (-1); 364219089Spjd } 365219089Spjd } 366219089Spjd 367219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 368219089Spjd zcmd_free_nvlists(&zc); 369219089Spjd if (err != 0) 370219089Spjd return (-1); 371219089Spjd 372219089Spjd nvlist_free(zhp->zfs_recvd_props); 373219089Spjd zhp->zfs_recvd_props = recvdprops; 374219089Spjd 375219089Spjd return (0); 376219089Spjd} 377219089Spjd 378219089Spjdstatic int 379209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 380209962Smm{ 381209962Smm nvlist_t *allprops, *userprops; 382168404Spjd 383209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 384209962Smm 385209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 386168404Spjd return (-1); 387168404Spjd } 388168404Spjd 389209962Smm /* 390209962Smm * XXX Why do we store the user props separately, in addition to 391209962Smm * storing them in zfs_props? 392209962Smm */ 393185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 394185029Spjd nvlist_free(allprops); 395168404Spjd return (-1); 396185029Spjd } 397168404Spjd 398185029Spjd nvlist_free(zhp->zfs_props); 399185029Spjd nvlist_free(zhp->zfs_user_props); 400185029Spjd 401185029Spjd zhp->zfs_props = allprops; 402185029Spjd zhp->zfs_user_props = userprops; 403185029Spjd 404168404Spjd return (0); 405168404Spjd} 406168404Spjd 407209962Smmstatic int 408209962Smmget_stats(zfs_handle_t *zhp) 409209962Smm{ 410209962Smm int rc = 0; 411209962Smm zfs_cmd_t zc = { 0 }; 412209962Smm 413209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 414209962Smm return (-1); 415209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 416209962Smm rc = -1; 417209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 418209962Smm rc = -1; 419209962Smm zcmd_free_nvlists(&zc); 420209962Smm return (rc); 421209962Smm} 422209962Smm 423168404Spjd/* 424168404Spjd * Refresh the properties currently stored in the handle. 425168404Spjd */ 426168404Spjdvoid 427168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 428168404Spjd{ 429168404Spjd (void) get_stats(zhp); 430168404Spjd} 431168404Spjd 432168404Spjd/* 433168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 434168404Spjd * zfs_iter_* to create child handles on the fly. 435168404Spjd */ 436209962Smmstatic int 437209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 438168404Spjd{ 439219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 440209962Smm return (-1); 441168404Spjd 442168404Spjd /* 443168404Spjd * We've managed to open the dataset and gather statistics. Determine 444168404Spjd * the high-level type. 445168404Spjd */ 446168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 447168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 448168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 449168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 450168404Spjd else 451168404Spjd abort(); 452168404Spjd 453168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 454168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 455168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 456168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 457168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 458168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 459168404Spjd else 460168404Spjd abort(); /* we should never see any other types */ 461168404Spjd 462219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 463219089Spjd return (-1); 464219089Spjd 465209962Smm return (0); 466209962Smm} 467209962Smm 468209962Smmzfs_handle_t * 469209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 470209962Smm{ 471209962Smm zfs_cmd_t zc = { 0 }; 472209962Smm 473209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 474209962Smm 475209962Smm if (zhp == NULL) 476209962Smm return (NULL); 477209962Smm 478209962Smm zhp->zfs_hdl = hdl; 479209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 480209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 481209962Smm free(zhp); 482209962Smm return (NULL); 483209962Smm } 484209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 485209962Smm zcmd_free_nvlists(&zc); 486209962Smm free(zhp); 487209962Smm return (NULL); 488209962Smm } 489209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 490209962Smm free(zhp); 491209962Smm zhp = NULL; 492209962Smm } 493209962Smm zcmd_free_nvlists(&zc); 494168404Spjd return (zhp); 495168404Spjd} 496168404Spjd 497209962Smmstatic zfs_handle_t * 498209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 499209962Smm{ 500209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 501209962Smm 502209962Smm if (zhp == NULL) 503209962Smm return (NULL); 504209962Smm 505209962Smm zhp->zfs_hdl = hdl; 506209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 507209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 508209962Smm free(zhp); 509209962Smm return (NULL); 510209962Smm } 511209962Smm return (zhp); 512209962Smm} 513209962Smm 514168404Spjd/* 515168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 516168404Spjd * argument is a mask of acceptable types. The function will print an 517168404Spjd * appropriate error message and return NULL if it can't be opened. 518168404Spjd */ 519168404Spjdzfs_handle_t * 520168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 521168404Spjd{ 522168404Spjd zfs_handle_t *zhp; 523168404Spjd char errbuf[1024]; 524168404Spjd 525168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 526168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 527168404Spjd 528168404Spjd /* 529168404Spjd * Validate the name before we even try to open it. 530168404Spjd */ 531185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 532168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 533168404Spjd "invalid dataset name")); 534168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 535168404Spjd return (NULL); 536168404Spjd } 537168404Spjd 538168404Spjd /* 539168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 540168404Spjd */ 541168404Spjd errno = 0; 542168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 543168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 544168404Spjd return (NULL); 545168404Spjd } 546168404Spjd 547168404Spjd if (!(types & zhp->zfs_type)) { 548168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 549168404Spjd zfs_close(zhp); 550168404Spjd return (NULL); 551168404Spjd } 552168404Spjd 553168404Spjd return (zhp); 554168404Spjd} 555168404Spjd 556168404Spjd/* 557168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 558168404Spjd */ 559168404Spjdvoid 560168404Spjdzfs_close(zfs_handle_t *zhp) 561168404Spjd{ 562168404Spjd if (zhp->zfs_mntopts) 563168404Spjd free(zhp->zfs_mntopts); 564168404Spjd nvlist_free(zhp->zfs_props); 565168404Spjd nvlist_free(zhp->zfs_user_props); 566219089Spjd nvlist_free(zhp->zfs_recvd_props); 567168404Spjd free(zhp); 568168404Spjd} 569168404Spjd 570209962Smmtypedef struct mnttab_node { 571209962Smm struct mnttab mtn_mt; 572209962Smm avl_node_t mtn_node; 573209962Smm} mnttab_node_t; 574209962Smm 575209962Smmstatic int 576209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 577209962Smm{ 578209962Smm const mnttab_node_t *mtn1 = arg1; 579209962Smm const mnttab_node_t *mtn2 = arg2; 580209962Smm int rv; 581209962Smm 582209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 583209962Smm 584209962Smm if (rv == 0) 585209962Smm return (0); 586209962Smm return (rv > 0 ? 1 : -1); 587209962Smm} 588209962Smm 589209962Smmvoid 590209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 591209962Smm{ 592209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 593209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 594209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 595209962Smm} 596209962Smm 597209962Smmvoid 598209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 599209962Smm{ 600209962Smm struct mnttab entry; 601209962Smm 602209962Smm rewind(hdl->libzfs_mnttab); 603209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 604209962Smm mnttab_node_t *mtn; 605209962Smm 606209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 607209962Smm continue; 608209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 609209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 610209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 611209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 612209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 613209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 614209962Smm } 615209962Smm} 616209962Smm 617209962Smmvoid 618209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 619209962Smm{ 620209962Smm void *cookie = NULL; 621209962Smm mnttab_node_t *mtn; 622209962Smm 623209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 624209962Smm free(mtn->mtn_mt.mnt_special); 625209962Smm free(mtn->mtn_mt.mnt_mountp); 626209962Smm free(mtn->mtn_mt.mnt_fstype); 627209962Smm free(mtn->mtn_mt.mnt_mntopts); 628209962Smm free(mtn); 629209962Smm } 630209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 631209962Smm} 632209962Smm 633209962Smmvoid 634209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 635209962Smm{ 636209962Smm hdl->libzfs_mnttab_enable = enable; 637209962Smm} 638209962Smm 639185029Spjdint 640209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 641209962Smm struct mnttab *entry) 642209962Smm{ 643209962Smm mnttab_node_t find; 644209962Smm mnttab_node_t *mtn; 645209962Smm 646209962Smm if (!hdl->libzfs_mnttab_enable) { 647209962Smm struct mnttab srch = { 0 }; 648209962Smm 649209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 650209962Smm libzfs_mnttab_fini(hdl); 651209962Smm rewind(hdl->libzfs_mnttab); 652209962Smm srch.mnt_special = (char *)fsname; 653209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 654209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 655209962Smm return (0); 656209962Smm else 657209962Smm return (ENOENT); 658209962Smm } 659209962Smm 660209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 661209962Smm libzfs_mnttab_update(hdl); 662209962Smm 663209962Smm find.mtn_mt.mnt_special = (char *)fsname; 664209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 665209962Smm if (mtn) { 666209962Smm *entry = mtn->mtn_mt; 667209962Smm return (0); 668209962Smm } 669209962Smm return (ENOENT); 670209962Smm} 671209962Smm 672209962Smmvoid 673209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 674209962Smm const char *mountp, const char *mntopts) 675209962Smm{ 676209962Smm mnttab_node_t *mtn; 677209962Smm 678209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 679209962Smm return; 680209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 681209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 682209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 683209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 684209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 685209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 686209962Smm} 687209962Smm 688209962Smmvoid 689209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 690209962Smm{ 691209962Smm mnttab_node_t find; 692209962Smm mnttab_node_t *ret; 693209962Smm 694209962Smm find.mtn_mt.mnt_special = (char *)fsname; 695209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 696209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 697209962Smm free(ret->mtn_mt.mnt_special); 698209962Smm free(ret->mtn_mt.mnt_mountp); 699209962Smm free(ret->mtn_mt.mnt_fstype); 700209962Smm free(ret->mtn_mt.mnt_mntopts); 701209962Smm free(ret); 702209962Smm } 703209962Smm} 704209962Smm 705209962Smmint 706185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 707168404Spjd{ 708185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 709168404Spjd 710185029Spjd if (zpool_handle == NULL) 711168404Spjd return (-1); 712168404Spjd 713185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 714185029Spjd ZPOOL_PROP_VERSION, NULL); 715168404Spjd return (0); 716168404Spjd} 717168404Spjd 718168404Spjd/* 719185029Spjd * The choice of reservation property depends on the SPA version. 720168404Spjd */ 721168404Spjdstatic int 722185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 723168404Spjd{ 724185029Spjd int spa_version; 725168404Spjd 726185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 727168404Spjd return (-1); 728168404Spjd 729185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 730185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 731185029Spjd else 732185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 733168404Spjd 734168404Spjd return (0); 735168404Spjd} 736168404Spjd 737168404Spjd/* 738168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 739168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 740168404Spjd * strings. 741168404Spjd */ 742168404Spjdnvlist_t * 743185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 744185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 745168404Spjd{ 746168404Spjd nvpair_t *elem; 747168404Spjd uint64_t intval; 748168404Spjd char *strval; 749185029Spjd zfs_prop_t prop; 750168404Spjd nvlist_t *ret; 751185029Spjd int chosen_normal = -1; 752185029Spjd int chosen_utf = -1; 753168404Spjd 754168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 755168404Spjd (void) no_memory(hdl); 756168404Spjd return (NULL); 757168404Spjd } 758168404Spjd 759209962Smm /* 760209962Smm * Make sure this property is valid and applies to this type. 761209962Smm */ 762209962Smm 763168404Spjd elem = NULL; 764168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 765185029Spjd const char *propname = nvpair_name(elem); 766168404Spjd 767209962Smm prop = zfs_name_to_prop(propname); 768209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 769185029Spjd /* 770209962Smm * This is a user property: make sure it's a 771185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 772185029Spjd */ 773185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 774185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 775185029Spjd "'%s' must be a string"), propname); 776185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 777185029Spjd goto error; 778168404Spjd } 779168404Spjd 780185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 781185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 782185029Spjd "property name '%s' is too long"), 783185029Spjd propname); 784185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 785185029Spjd goto error; 786185029Spjd } 787185029Spjd 788168404Spjd (void) nvpair_value_string(elem, &strval); 789168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 790168404Spjd (void) no_memory(hdl); 791168404Spjd goto error; 792168404Spjd } 793168404Spjd continue; 794168404Spjd } 795168404Spjd 796209962Smm /* 797209962Smm * Currently, only user properties can be modified on 798209962Smm * snapshots. 799209962Smm */ 800185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 801185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 802185029Spjd "this property can not be modified for snapshots")); 803185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 804185029Spjd goto error; 805185029Spjd } 806168404Spjd 807209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 808209962Smm zfs_userquota_prop_t uqtype; 809209962Smm char newpropname[128]; 810209962Smm char domain[128]; 811209962Smm uint64_t rid; 812209962Smm uint64_t valary[3]; 813209962Smm 814209962Smm if (userquota_propname_decode(propname, zoned, 815209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 816209962Smm zfs_error_aux(hdl, 817209962Smm dgettext(TEXT_DOMAIN, 818209962Smm "'%s' has an invalid user/group name"), 819209962Smm propname); 820209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 821209962Smm goto error; 822209962Smm } 823209962Smm 824209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 825209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 826209962Smm zfs_error_aux(hdl, 827209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 828209962Smm propname); 829209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 830209962Smm errbuf); 831209962Smm goto error; 832209962Smm } 833209962Smm 834209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 835209962Smm (void) nvpair_value_string(elem, &strval); 836209962Smm if (strcmp(strval, "none") == 0) { 837209962Smm intval = 0; 838209962Smm } else if (zfs_nicestrtonum(hdl, 839209962Smm strval, &intval) != 0) { 840209962Smm (void) zfs_error(hdl, 841209962Smm EZFS_BADPROP, errbuf); 842209962Smm goto error; 843209962Smm } 844209962Smm } else if (nvpair_type(elem) == 845209962Smm DATA_TYPE_UINT64) { 846209962Smm (void) nvpair_value_uint64(elem, &intval); 847209962Smm if (intval == 0) { 848209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 849209962Smm "use 'none' to disable " 850209962Smm "userquota/groupquota")); 851209962Smm goto error; 852209962Smm } 853209962Smm } else { 854209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 855209962Smm "'%s' must be a number"), propname); 856209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 857209962Smm goto error; 858209962Smm } 859209962Smm 860219089Spjd /* 861219089Spjd * Encode the prop name as 862219089Spjd * userquota@<hex-rid>-domain, to make it easy 863219089Spjd * for the kernel to decode. 864219089Spjd */ 865209962Smm (void) snprintf(newpropname, sizeof (newpropname), 866219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 867219089Spjd (longlong_t)rid, domain); 868209962Smm valary[0] = uqtype; 869209962Smm valary[1] = rid; 870209962Smm valary[2] = intval; 871209962Smm if (nvlist_add_uint64_array(ret, newpropname, 872209962Smm valary, 3) != 0) { 873209962Smm (void) no_memory(hdl); 874209962Smm goto error; 875209962Smm } 876209962Smm continue; 877209962Smm } 878209962Smm 879209962Smm if (prop == ZPROP_INVAL) { 880209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 881209962Smm "invalid property '%s'"), propname); 882209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 883209962Smm goto error; 884209962Smm } 885209962Smm 886168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 887168404Spjd zfs_error_aux(hdl, 888168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 889168404Spjd "apply to datasets of this type"), propname); 890168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 891168404Spjd goto error; 892168404Spjd } 893168404Spjd 894168404Spjd if (zfs_prop_readonly(prop) && 895185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 896168404Spjd zfs_error_aux(hdl, 897168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 898168404Spjd propname); 899168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 900168404Spjd goto error; 901168404Spjd } 902168404Spjd 903185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 904185029Spjd &strval, &intval, errbuf) != 0) 905185029Spjd goto error; 906185029Spjd 907168404Spjd /* 908185029Spjd * Perform some additional checks for specific properties. 909168404Spjd */ 910185029Spjd switch (prop) { 911185029Spjd case ZFS_PROP_VERSION: 912185029Spjd { 913185029Spjd int version; 914168404Spjd 915185029Spjd if (zhp == NULL) 916185029Spjd break; 917185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 918185029Spjd if (intval < version) { 919168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 920185029Spjd "Can not downgrade; already at version %u"), 921185029Spjd version); 922168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 923168404Spjd goto error; 924168404Spjd } 925168404Spjd break; 926168404Spjd } 927168404Spjd 928168404Spjd case ZFS_PROP_RECORDSIZE: 929168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 930168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 931168404Spjd if (intval < SPA_MINBLOCKSIZE || 932168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 933168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 934168404Spjd "'%s' must be power of 2 from %u " 935168404Spjd "to %uk"), propname, 936168404Spjd (uint_t)SPA_MINBLOCKSIZE, 937168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 938168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 939168404Spjd goto error; 940168404Spjd } 941168404Spjd break; 942168404Spjd 943219089Spjd case ZFS_PROP_MLSLABEL: 944219089Spjd { 945219089Spjd#ifdef sun 946219089Spjd /* 947219089Spjd * Verify the mlslabel string and convert to 948219089Spjd * internal hex label string. 949219089Spjd */ 950219089Spjd 951219089Spjd m_label_t *new_sl; 952219089Spjd char *hex = NULL; /* internal label string */ 953219089Spjd 954219089Spjd /* Default value is already OK. */ 955219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 956219089Spjd break; 957219089Spjd 958219089Spjd /* Verify the label can be converted to binary form */ 959219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 960219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 961219089Spjd L_NO_CORRECTION, NULL) == -1)) { 962219089Spjd goto badlabel; 963168404Spjd } 964168404Spjd 965219089Spjd /* Now translate to hex internal label string */ 966219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 967219089Spjd DEF_NAMES) != 0) { 968219089Spjd if (hex) 969219089Spjd free(hex); 970219089Spjd goto badlabel; 971219089Spjd } 972219089Spjd m_label_free(new_sl); 973219089Spjd 974219089Spjd /* If string is already in internal form, we're done. */ 975219089Spjd if (strcmp(strval, hex) == 0) { 976219089Spjd free(hex); 977219089Spjd break; 978219089Spjd } 979219089Spjd 980219089Spjd /* Replace the label string with the internal form. */ 981219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 982219089Spjd DATA_TYPE_STRING); 983219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 984219089Spjd hex) == 0); 985219089Spjd free(hex); 986219089Spjd 987168404Spjd break; 988168404Spjd 989219089Spjdbadlabel: 990219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 991219089Spjd "invalid mlslabel '%s'"), strval); 992219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 993219089Spjd m_label_free(new_sl); /* OK if null */ 994219089Spjd#else /* !sun */ 995219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 996219089Spjd "mlslabel is not supported on FreeBSD")); 997219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 998219089Spjd#endif /* !sun */ 999219089Spjd goto error; 1000219089Spjd 1001219089Spjd } 1002219089Spjd 1003168404Spjd case ZFS_PROP_MOUNTPOINT: 1004185029Spjd { 1005185029Spjd namecheck_err_t why; 1006185029Spjd 1007168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1008168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1009168404Spjd break; 1010168404Spjd 1011185029Spjd if (mountpoint_namecheck(strval, &why)) { 1012185029Spjd switch (why) { 1013185029Spjd case NAME_ERR_LEADING_SLASH: 1014185029Spjd zfs_error_aux(hdl, 1015185029Spjd dgettext(TEXT_DOMAIN, 1016185029Spjd "'%s' must be an absolute path, " 1017185029Spjd "'none', or 'legacy'"), propname); 1018185029Spjd break; 1019185029Spjd case NAME_ERR_TOOLONG: 1020185029Spjd zfs_error_aux(hdl, 1021185029Spjd dgettext(TEXT_DOMAIN, 1022185029Spjd "component of '%s' is too long"), 1023185029Spjd propname); 1024185029Spjd break; 1025185029Spjd } 1026168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1027168404Spjd goto error; 1028168404Spjd } 1029185029Spjd } 1030185029Spjd 1031168404Spjd /*FALLTHRU*/ 1032168404Spjd 1033185029Spjd case ZFS_PROP_SHARESMB: 1034168404Spjd case ZFS_PROP_SHARENFS: 1035168404Spjd /* 1036185029Spjd * For the mountpoint and sharenfs or sharesmb 1037185029Spjd * properties, check if it can be set in a 1038185029Spjd * global/non-global zone based on 1039168404Spjd * the zoned property value: 1040168404Spjd * 1041168404Spjd * global zone non-global zone 1042168404Spjd * -------------------------------------------------- 1043168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1044168404Spjd * sharenfs (no) sharenfs (no) 1045185029Spjd * sharesmb (no) sharesmb (no) 1046168404Spjd * 1047168404Spjd * zoned=off mountpoint (yes) N/A 1048168404Spjd * sharenfs (yes) 1049185029Spjd * sharesmb (yes) 1050168404Spjd */ 1051168404Spjd if (zoned) { 1052168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1053168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1054168404Spjd "'%s' cannot be set on " 1055168404Spjd "dataset in a non-global zone"), 1056168404Spjd propname); 1057168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1058168404Spjd errbuf); 1059168404Spjd goto error; 1060185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1061185029Spjd prop == ZFS_PROP_SHARESMB) { 1062168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1063168404Spjd "'%s' cannot be set in " 1064168404Spjd "a non-global zone"), propname); 1065168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1066168404Spjd errbuf); 1067168404Spjd goto error; 1068168404Spjd } 1069168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1070168404Spjd /* 1071168404Spjd * If zoned property is 'off', this must be in 1072209962Smm * a global zone. If not, something is wrong. 1073168404Spjd */ 1074168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1075168404Spjd "'%s' cannot be set while dataset " 1076168404Spjd "'zoned' property is set"), propname); 1077168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1078168404Spjd goto error; 1079168404Spjd } 1080168404Spjd 1081168404Spjd /* 1082185029Spjd * At this point, it is legitimate to set the 1083185029Spjd * property. Now we want to make sure that the 1084185029Spjd * property value is valid if it is sharenfs. 1085168404Spjd */ 1086185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1087185029Spjd prop == ZFS_PROP_SHARESMB) && 1088185029Spjd strcmp(strval, "on") != 0 && 1089185029Spjd strcmp(strval, "off") != 0) { 1090185029Spjd zfs_share_proto_t proto; 1091168404Spjd 1092185029Spjd if (prop == ZFS_PROP_SHARESMB) 1093185029Spjd proto = PROTO_SMB; 1094185029Spjd else 1095185029Spjd proto = PROTO_NFS; 1096185029Spjd 1097185029Spjd /* 1098185029Spjd * Must be an valid sharing protocol 1099185029Spjd * option string so init the libshare 1100185029Spjd * in order to enable the parser and 1101185029Spjd * then parse the options. We use the 1102185029Spjd * control API since we don't care about 1103185029Spjd * the current configuration and don't 1104185029Spjd * want the overhead of loading it 1105185029Spjd * until we actually do something. 1106185029Spjd */ 1107185029Spjd 1108185029Spjd if (zfs_init_libshare(hdl, 1109185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1110185029Spjd /* 1111185029Spjd * An error occurred so we can't do 1112185029Spjd * anything 1113185029Spjd */ 1114185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1115185029Spjd "'%s' cannot be set: problem " 1116185029Spjd "in share initialization"), 1117185029Spjd propname); 1118185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1119185029Spjd errbuf); 1120185029Spjd goto error; 1121185029Spjd } 1122185029Spjd 1123185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1124185029Spjd /* 1125185029Spjd * There was an error in parsing so 1126185029Spjd * deal with it by issuing an error 1127185029Spjd * message and leaving after 1128185029Spjd * uninitializing the the libshare 1129185029Spjd * interface. 1130185029Spjd */ 1131185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1132185029Spjd "'%s' cannot be set to invalid " 1133185029Spjd "options"), propname); 1134185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1135185029Spjd errbuf); 1136185029Spjd zfs_uninit_libshare(hdl); 1137185029Spjd goto error; 1138185029Spjd } 1139185029Spjd zfs_uninit_libshare(hdl); 1140168404Spjd } 1141185029Spjd 1142168404Spjd break; 1143185029Spjd case ZFS_PROP_UTF8ONLY: 1144185029Spjd chosen_utf = (int)intval; 1145185029Spjd break; 1146185029Spjd case ZFS_PROP_NORMALIZE: 1147185029Spjd chosen_normal = (int)intval; 1148185029Spjd break; 1149168404Spjd } 1150168404Spjd 1151168404Spjd /* 1152168404Spjd * For changes to existing volumes, we have some additional 1153168404Spjd * checks to enforce. 1154168404Spjd */ 1155168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1156168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1157168404Spjd ZFS_PROP_VOLSIZE); 1158168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1159168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1160168404Spjd char buf[64]; 1161168404Spjd 1162168404Spjd switch (prop) { 1163168404Spjd case ZFS_PROP_RESERVATION: 1164185029Spjd case ZFS_PROP_REFRESERVATION: 1165168404Spjd if (intval > volsize) { 1166168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1167168404Spjd "'%s' is greater than current " 1168168404Spjd "volume size"), propname); 1169168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1170168404Spjd errbuf); 1171168404Spjd goto error; 1172168404Spjd } 1173168404Spjd break; 1174168404Spjd 1175168404Spjd case ZFS_PROP_VOLSIZE: 1176168404Spjd if (intval % blocksize != 0) { 1177168404Spjd zfs_nicenum(blocksize, buf, 1178168404Spjd sizeof (buf)); 1179168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1180168404Spjd "'%s' must be a multiple of " 1181168404Spjd "volume block size (%s)"), 1182168404Spjd propname, buf); 1183168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1184168404Spjd errbuf); 1185168404Spjd goto error; 1186168404Spjd } 1187168404Spjd 1188168404Spjd if (intval == 0) { 1189168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1190168404Spjd "'%s' cannot be zero"), 1191168404Spjd propname); 1192168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1193168404Spjd errbuf); 1194168404Spjd goto error; 1195168404Spjd } 1196168404Spjd break; 1197168404Spjd } 1198168404Spjd } 1199168404Spjd } 1200168404Spjd 1201168404Spjd /* 1202185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1203185029Spjd * enforce rejection of non-UTF8 names. 1204185029Spjd * 1205185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1206185029Spjd * was explicitly not chosen, it is an error. 1207185029Spjd */ 1208185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1209185029Spjd if (nvlist_add_uint64(ret, 1210185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1211185029Spjd (void) no_memory(hdl); 1212185029Spjd goto error; 1213185029Spjd } 1214185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1215185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1216185029Spjd "'%s' must be set 'on' if normalization chosen"), 1217185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1218185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1219185029Spjd goto error; 1220185029Spjd } 1221219089Spjd return (ret); 1222185029Spjd 1223219089Spjderror: 1224219089Spjd nvlist_free(ret); 1225219089Spjd return (NULL); 1226219089Spjd} 1227219089Spjd 1228219089Spjdint 1229219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1230219089Spjd{ 1231219089Spjd uint64_t old_volsize; 1232219089Spjd uint64_t new_volsize; 1233219089Spjd uint64_t old_reservation; 1234219089Spjd uint64_t new_reservation; 1235219089Spjd zfs_prop_t resv_prop; 1236219089Spjd 1237185029Spjd /* 1238168404Spjd * If this is an existing volume, and someone is setting the volsize, 1239168404Spjd * make sure that it matches the reservation, or add it if necessary. 1240168404Spjd */ 1241219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1242219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1243219089Spjd return (-1); 1244219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1245219089Spjd if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != 1246219089Spjd old_reservation) || nvlist_lookup_uint64(nvl, 1247219089Spjd zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { 1248219089Spjd return (0); 1249219089Spjd } 1250219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1251219089Spjd &new_volsize) != 0) 1252219089Spjd return (-1); 1253219089Spjd new_reservation = zvol_volsize_to_reservation(new_volsize, 1254219089Spjd zhp->zfs_props); 1255219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1256219089Spjd new_reservation) != 0) { 1257219089Spjd (void) no_memory(zhp->zfs_hdl); 1258219089Spjd return (-1); 1259219089Spjd } 1260219089Spjd return (1); 1261219089Spjd} 1262168404Spjd 1263219089Spjdvoid 1264219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1265219089Spjd char *errbuf) 1266219089Spjd{ 1267219089Spjd switch (err) { 1268185029Spjd 1269219089Spjd case ENOSPC: 1270219089Spjd /* 1271219089Spjd * For quotas and reservations, ENOSPC indicates 1272219089Spjd * something different; setting a quota or reservation 1273219089Spjd * doesn't use any disk space. 1274219089Spjd */ 1275219089Spjd switch (prop) { 1276219089Spjd case ZFS_PROP_QUOTA: 1277219089Spjd case ZFS_PROP_REFQUOTA: 1278219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1279219089Spjd "size is less than current used or " 1280219089Spjd "reserved space")); 1281219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1282219089Spjd break; 1283219089Spjd 1284219089Spjd case ZFS_PROP_RESERVATION: 1285219089Spjd case ZFS_PROP_REFRESERVATION: 1286219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1287219089Spjd "size is greater than available space")); 1288219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1289219089Spjd break; 1290219089Spjd 1291219089Spjd default: 1292219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1293219089Spjd break; 1294168404Spjd } 1295219089Spjd break; 1296219089Spjd 1297219089Spjd case EBUSY: 1298219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1299219089Spjd break; 1300219089Spjd 1301219089Spjd case EROFS: 1302219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1303219089Spjd break; 1304219089Spjd 1305219089Spjd case ENOTSUP: 1306219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1307219089Spjd "pool and or dataset must be upgraded to set this " 1308219089Spjd "property or value")); 1309219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1310219089Spjd break; 1311219089Spjd 1312219089Spjd case ERANGE: 1313219089Spjd if (prop == ZFS_PROP_COMPRESSION) { 1314219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1315219089Spjd "property setting is not allowed on " 1316219089Spjd "bootable datasets")); 1317219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1318219089Spjd } else { 1319219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1320219089Spjd } 1321219089Spjd break; 1322219089Spjd 1323219089Spjd case EINVAL: 1324219089Spjd if (prop == ZPROP_INVAL) { 1325219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1326219089Spjd } else { 1327219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1328219089Spjd } 1329219089Spjd break; 1330219089Spjd 1331219089Spjd case EOVERFLOW: 1332219089Spjd /* 1333219089Spjd * This platform can't address a volume this big. 1334219089Spjd */ 1335219089Spjd#ifdef _ILP32 1336219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1337219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1338219089Spjd break; 1339219089Spjd } 1340219089Spjd#endif 1341219089Spjd /* FALLTHROUGH */ 1342219089Spjd default: 1343219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1344168404Spjd } 1345168404Spjd} 1346168404Spjd 1347168404Spjd/* 1348168404Spjd * Given a property name and value, set the property for the given dataset. 1349168404Spjd */ 1350168404Spjdint 1351168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1352168404Spjd{ 1353168404Spjd zfs_cmd_t zc = { 0 }; 1354168404Spjd int ret = -1; 1355168404Spjd prop_changelist_t *cl = NULL; 1356168404Spjd char errbuf[1024]; 1357168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1358168404Spjd nvlist_t *nvl = NULL, *realprops; 1359168404Spjd zfs_prop_t prop; 1360185029Spjd boolean_t do_prefix; 1361185029Spjd uint64_t idx; 1362219089Spjd int added_resv; 1363168404Spjd 1364168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1365168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1366168404Spjd zhp->zfs_name); 1367168404Spjd 1368168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1369168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1370168404Spjd (void) no_memory(hdl); 1371168404Spjd goto error; 1372168404Spjd } 1373168404Spjd 1374185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1375168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1376168404Spjd goto error; 1377185029Spjd 1378168404Spjd nvlist_free(nvl); 1379168404Spjd nvl = realprops; 1380168404Spjd 1381168404Spjd prop = zfs_name_to_prop(propname); 1382168404Spjd 1383168404Spjd /* We don't support those properties on FreeBSD. */ 1384168404Spjd switch (prop) { 1385197867Strasz case ZFS_PROP_DEVICES: 1386168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1387197867Strasz case ZFS_PROP_XATTR: 1388197867Strasz case ZFS_PROP_VSCAN: 1389197867Strasz case ZFS_PROP_NBMAND: 1390219089Spjd case ZFS_PROP_MLSLABEL: 1391168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1392168404Spjd "property '%s' not supported on FreeBSD", propname); 1393168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1394168404Spjd goto error; 1395168404Spjd } 1396168404Spjd 1397219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1398219089Spjd if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) 1399219089Spjd goto error; 1400219089Spjd } 1401219089Spjd 1402185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1403168404Spjd goto error; 1404168404Spjd 1405168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1406168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1407168404Spjd "child dataset with inherited mountpoint is used " 1408168404Spjd "in a non-global zone")); 1409168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1410168404Spjd goto error; 1411168404Spjd } 1412168404Spjd 1413185029Spjd /* 1414185029Spjd * If the dataset's canmount property is being set to noauto, 1415185029Spjd * then we want to prevent unmounting & remounting it. 1416185029Spjd */ 1417185029Spjd do_prefix = !((prop == ZFS_PROP_CANMOUNT) && 1418185029Spjd (zprop_string_to_index(prop, propval, &idx, 1419185029Spjd ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); 1420185029Spjd 1421185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1422168404Spjd goto error; 1423168404Spjd 1424168404Spjd /* 1425168404Spjd * Execute the corresponding ioctl() to set this property. 1426168404Spjd */ 1427168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1428168404Spjd 1429185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1430168404Spjd goto error; 1431168404Spjd 1432185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1433209962Smm 1434168404Spjd if (ret != 0) { 1435219089Spjd zfs_setprop_error(hdl, prop, errno, errbuf); 1436219089Spjd if (added_resv && errno == ENOSPC) { 1437219089Spjd /* clean up the volsize property we tried to set */ 1438219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1439219089Spjd ZFS_PROP_VOLSIZE); 1440219089Spjd nvlist_free(nvl); 1441219089Spjd zcmd_free_nvlists(&zc); 1442219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1443219089Spjd goto error; 1444219089Spjd if (nvlist_add_uint64(nvl, 1445219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1446219089Spjd old_volsize) != 0) 1447219089Spjd goto error; 1448219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1449219089Spjd goto error; 1450219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1451168404Spjd } 1452168404Spjd } else { 1453185029Spjd if (do_prefix) 1454185029Spjd ret = changelist_postfix(cl); 1455185029Spjd 1456168404Spjd /* 1457168404Spjd * Refresh the statistics so the new property value 1458168404Spjd * is reflected. 1459168404Spjd */ 1460185029Spjd if (ret == 0) 1461168404Spjd (void) get_stats(zhp); 1462168404Spjd } 1463168404Spjd 1464168404Spjderror: 1465168404Spjd nvlist_free(nvl); 1466168404Spjd zcmd_free_nvlists(&zc); 1467168404Spjd if (cl) 1468168404Spjd changelist_free(cl); 1469168404Spjd return (ret); 1470168404Spjd} 1471168404Spjd 1472168404Spjd/* 1473219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1474219089Spjd * is TRUE, revert to the received value, if any. 1475168404Spjd */ 1476168404Spjdint 1477219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1478168404Spjd{ 1479168404Spjd zfs_cmd_t zc = { 0 }; 1480168404Spjd int ret; 1481168404Spjd prop_changelist_t *cl; 1482168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1483168404Spjd char errbuf[1024]; 1484168404Spjd zfs_prop_t prop; 1485168404Spjd 1486168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1487168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1488168404Spjd 1489219089Spjd zc.zc_cookie = received; 1490185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1491168404Spjd /* 1492168404Spjd * For user properties, the amount of work we have to do is very 1493168404Spjd * small, so just do it here. 1494168404Spjd */ 1495168404Spjd if (!zfs_prop_user(propname)) { 1496168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1497168404Spjd "invalid property")); 1498168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1499168404Spjd } 1500168404Spjd 1501168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1502168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1503168404Spjd 1504185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1505168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1506168404Spjd 1507168404Spjd return (0); 1508168404Spjd } 1509168404Spjd 1510168404Spjd /* 1511168404Spjd * Verify that this property is inheritable. 1512168404Spjd */ 1513168404Spjd if (zfs_prop_readonly(prop)) 1514168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1515168404Spjd 1516219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1517168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1518168404Spjd 1519168404Spjd /* 1520168404Spjd * Check to see if the value applies to this type 1521168404Spjd */ 1522168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1523168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1524168404Spjd 1525168404Spjd /* 1526219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1527168404Spjd */ 1528168404Spjd propname = zfs_prop_to_name(prop); 1529168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1530168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1531168404Spjd 1532168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1533168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1534168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1535168404Spjd "dataset is used in a non-global zone")); 1536168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1537168404Spjd } 1538168404Spjd 1539168404Spjd /* 1540168404Spjd * Determine datasets which will be affected by this change, if any. 1541168404Spjd */ 1542185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1543168404Spjd return (-1); 1544168404Spjd 1545168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1546168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1547168404Spjd "child dataset with inherited mountpoint is used " 1548168404Spjd "in a non-global zone")); 1549168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1550168404Spjd goto error; 1551168404Spjd } 1552168404Spjd 1553168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1554168404Spjd goto error; 1555168404Spjd 1556185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1557168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1558168404Spjd } else { 1559168404Spjd 1560168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1561168404Spjd goto error; 1562168404Spjd 1563168404Spjd /* 1564168404Spjd * Refresh the statistics so the new property is reflected. 1565168404Spjd */ 1566168404Spjd (void) get_stats(zhp); 1567168404Spjd } 1568168404Spjd 1569168404Spjderror: 1570168404Spjd changelist_free(cl); 1571168404Spjd return (ret); 1572168404Spjd} 1573168404Spjd 1574168404Spjd/* 1575168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1576168404Spjd * extract them appropriately. 1577168404Spjd */ 1578168404Spjdstatic uint64_t 1579168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1580168404Spjd{ 1581168404Spjd nvlist_t *nv; 1582168404Spjd uint64_t value; 1583168404Spjd 1584168404Spjd *source = NULL; 1585168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1586168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1587185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1588185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1589168404Spjd } else { 1590205198Sdelphij verify(!zhp->zfs_props_table || 1591205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1592168404Spjd value = zfs_prop_default_numeric(prop); 1593168404Spjd *source = ""; 1594168404Spjd } 1595168404Spjd 1596168404Spjd return (value); 1597168404Spjd} 1598168404Spjd 1599168404Spjdstatic char * 1600168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1601168404Spjd{ 1602168404Spjd nvlist_t *nv; 1603168404Spjd char *value; 1604168404Spjd 1605168404Spjd *source = NULL; 1606168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1607168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1608185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1609185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1610168404Spjd } else { 1611205198Sdelphij verify(!zhp->zfs_props_table || 1612205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1613168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1614168404Spjd value = ""; 1615168404Spjd *source = ""; 1616168404Spjd } 1617168404Spjd 1618168404Spjd return (value); 1619168404Spjd} 1620168404Spjd 1621219089Spjdstatic boolean_t 1622219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1623219089Spjd{ 1624219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1625219089Spjd} 1626219089Spjd 1627219089Spjdstatic void 1628219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1629219089Spjd{ 1630219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1631219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1632219089Spjd} 1633219089Spjd 1634219089Spjdstatic void 1635219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1636219089Spjd{ 1637219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1638219089Spjd *cookie = 0; 1639219089Spjd} 1640219089Spjd 1641168404Spjd/* 1642168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1643168404Spjd * zfs_prop_get_int() are built using this interface. 1644168404Spjd * 1645168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1646168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1647168404Spjd * If they differ from the on-disk values, report the current values and mark 1648168404Spjd * the source "temporary". 1649168404Spjd */ 1650168404Spjdstatic int 1651185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1652168404Spjd char **source, uint64_t *val) 1653168404Spjd{ 1654185029Spjd zfs_cmd_t zc = { 0 }; 1655185029Spjd nvlist_t *zplprops = NULL; 1656168404Spjd struct mnttab mnt; 1657168404Spjd char *mntopt_on = NULL; 1658168404Spjd char *mntopt_off = NULL; 1659219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1660168404Spjd 1661168404Spjd *source = NULL; 1662168404Spjd 1663168404Spjd switch (prop) { 1664168404Spjd case ZFS_PROP_ATIME: 1665168404Spjd mntopt_on = MNTOPT_ATIME; 1666168404Spjd mntopt_off = MNTOPT_NOATIME; 1667168404Spjd break; 1668168404Spjd 1669168404Spjd case ZFS_PROP_DEVICES: 1670168404Spjd mntopt_on = MNTOPT_DEVICES; 1671168404Spjd mntopt_off = MNTOPT_NODEVICES; 1672168404Spjd break; 1673168404Spjd 1674168404Spjd case ZFS_PROP_EXEC: 1675168404Spjd mntopt_on = MNTOPT_EXEC; 1676168404Spjd mntopt_off = MNTOPT_NOEXEC; 1677168404Spjd break; 1678168404Spjd 1679168404Spjd case ZFS_PROP_READONLY: 1680168404Spjd mntopt_on = MNTOPT_RO; 1681168404Spjd mntopt_off = MNTOPT_RW; 1682168404Spjd break; 1683168404Spjd 1684168404Spjd case ZFS_PROP_SETUID: 1685168404Spjd mntopt_on = MNTOPT_SETUID; 1686168404Spjd mntopt_off = MNTOPT_NOSETUID; 1687168404Spjd break; 1688168404Spjd 1689168404Spjd case ZFS_PROP_XATTR: 1690168404Spjd mntopt_on = MNTOPT_XATTR; 1691168404Spjd mntopt_off = MNTOPT_NOXATTR; 1692168404Spjd break; 1693185029Spjd 1694185029Spjd case ZFS_PROP_NBMAND: 1695185029Spjd mntopt_on = MNTOPT_NBMAND; 1696185029Spjd mntopt_off = MNTOPT_NONBMAND; 1697185029Spjd break; 1698168404Spjd } 1699168404Spjd 1700168404Spjd /* 1701168404Spjd * Because looking up the mount options is potentially expensive 1702168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1703168404Spjd * we're looking up a property which requires its presence. 1704168404Spjd */ 1705168404Spjd if (!zhp->zfs_mntcheck && 1706168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1707209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1708209962Smm struct mnttab entry; 1709168404Spjd 1710209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1711209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1712168404Spjd entry.mnt_mntopts); 1713168404Spjd if (zhp->zfs_mntopts == NULL) 1714168404Spjd return (-1); 1715168404Spjd } 1716168404Spjd 1717168404Spjd zhp->zfs_mntcheck = B_TRUE; 1718168404Spjd } 1719168404Spjd 1720168404Spjd if (zhp->zfs_mntopts == NULL) 1721168404Spjd mnt.mnt_mntopts = ""; 1722168404Spjd else 1723168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1724168404Spjd 1725168404Spjd switch (prop) { 1726168404Spjd case ZFS_PROP_ATIME: 1727168404Spjd case ZFS_PROP_DEVICES: 1728168404Spjd case ZFS_PROP_EXEC: 1729168404Spjd case ZFS_PROP_READONLY: 1730168404Spjd case ZFS_PROP_SETUID: 1731168404Spjd case ZFS_PROP_XATTR: 1732185029Spjd case ZFS_PROP_NBMAND: 1733168404Spjd *val = getprop_uint64(zhp, prop, source); 1734168404Spjd 1735219089Spjd if (received) 1736219089Spjd break; 1737219089Spjd 1738168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1739168404Spjd *val = B_TRUE; 1740168404Spjd if (src) 1741185029Spjd *src = ZPROP_SRC_TEMPORARY; 1742168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1743168404Spjd *val = B_FALSE; 1744168404Spjd if (src) 1745185029Spjd *src = ZPROP_SRC_TEMPORARY; 1746168404Spjd } 1747168404Spjd break; 1748168404Spjd 1749168404Spjd case ZFS_PROP_CANMOUNT: 1750219089Spjd case ZFS_PROP_VOLSIZE: 1751168404Spjd case ZFS_PROP_QUOTA: 1752185029Spjd case ZFS_PROP_REFQUOTA: 1753168404Spjd case ZFS_PROP_RESERVATION: 1754185029Spjd case ZFS_PROP_REFRESERVATION: 1755168404Spjd *val = getprop_uint64(zhp, prop, source); 1756219089Spjd 1757219089Spjd if (*source == NULL) { 1758219089Spjd /* not default, must be local */ 1759168404Spjd *source = zhp->zfs_name; 1760219089Spjd } 1761168404Spjd break; 1762168404Spjd 1763168404Spjd case ZFS_PROP_MOUNTED: 1764168404Spjd *val = (zhp->zfs_mntopts != NULL); 1765168404Spjd break; 1766168404Spjd 1767168404Spjd case ZFS_PROP_NUMCLONES: 1768168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1769168404Spjd break; 1770168404Spjd 1771185029Spjd case ZFS_PROP_VERSION: 1772185029Spjd case ZFS_PROP_NORMALIZE: 1773185029Spjd case ZFS_PROP_UTF8ONLY: 1774185029Spjd case ZFS_PROP_CASE: 1775185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1776185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1777185029Spjd return (-1); 1778185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1779185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1780185029Spjd zcmd_free_nvlists(&zc); 1781219089Spjd return (-1); 1782185029Spjd } 1783185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1784185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1785185029Spjd val) != 0) { 1786185029Spjd zcmd_free_nvlists(&zc); 1787219089Spjd return (-1); 1788185029Spjd } 1789185029Spjd if (zplprops) 1790185029Spjd nvlist_free(zplprops); 1791185029Spjd zcmd_free_nvlists(&zc); 1792185029Spjd break; 1793185029Spjd 1794168404Spjd default: 1795185029Spjd switch (zfs_prop_get_type(prop)) { 1796185029Spjd case PROP_TYPE_NUMBER: 1797185029Spjd case PROP_TYPE_INDEX: 1798185029Spjd *val = getprop_uint64(zhp, prop, source); 1799185029Spjd /* 1800209962Smm * If we tried to use a default value for a 1801185029Spjd * readonly property, it means that it was not 1802219089Spjd * present. 1803185029Spjd */ 1804185029Spjd if (zfs_prop_readonly(prop) && 1805219089Spjd *source != NULL && (*source)[0] == '\0') { 1806219089Spjd *source = NULL; 1807185029Spjd } 1808185029Spjd break; 1809185029Spjd 1810185029Spjd case PROP_TYPE_STRING: 1811185029Spjd default: 1812185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1813185029Spjd "cannot get non-numeric property")); 1814185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1815185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1816185029Spjd } 1817168404Spjd } 1818168404Spjd 1819168404Spjd return (0); 1820168404Spjd} 1821168404Spjd 1822168404Spjd/* 1823168404Spjd * Calculate the source type, given the raw source string. 1824168404Spjd */ 1825168404Spjdstatic void 1826185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1827168404Spjd char *statbuf, size_t statlen) 1828168404Spjd{ 1829185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1830168404Spjd return; 1831168404Spjd 1832168404Spjd if (source == NULL) { 1833185029Spjd *srctype = ZPROP_SRC_NONE; 1834168404Spjd } else if (source[0] == '\0') { 1835185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1836219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 1837219089Spjd *srctype = ZPROP_SRC_RECEIVED; 1838168404Spjd } else { 1839168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1840185029Spjd *srctype = ZPROP_SRC_LOCAL; 1841168404Spjd } else { 1842168404Spjd (void) strlcpy(statbuf, source, statlen); 1843185029Spjd *srctype = ZPROP_SRC_INHERITED; 1844168404Spjd } 1845168404Spjd } 1846168404Spjd 1847168404Spjd} 1848168404Spjd 1849219089Spjdint 1850219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 1851219089Spjd size_t proplen, boolean_t literal) 1852219089Spjd{ 1853219089Spjd zfs_prop_t prop; 1854219089Spjd int err = 0; 1855219089Spjd 1856219089Spjd if (zhp->zfs_recvd_props == NULL) 1857219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 1858219089Spjd return (-1); 1859219089Spjd 1860219089Spjd prop = zfs_name_to_prop(propname); 1861219089Spjd 1862219089Spjd if (prop != ZPROP_INVAL) { 1863219089Spjd uint64_t cookie; 1864219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 1865219089Spjd return (-1); 1866219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 1867219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 1868219089Spjd NULL, NULL, 0, literal); 1869219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 1870219089Spjd } else if (zfs_prop_userquota(propname)) { 1871219089Spjd return (-1); 1872219089Spjd } else { 1873219089Spjd nvlist_t *propval; 1874219089Spjd char *recvdval; 1875219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 1876219089Spjd propname, &propval) != 0) 1877219089Spjd return (-1); 1878219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 1879219089Spjd &recvdval) == 0); 1880219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 1881219089Spjd } 1882219089Spjd 1883219089Spjd return (err == 0 ? 0 : -1); 1884219089Spjd} 1885219089Spjd 1886168404Spjd/* 1887168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 1888168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 1889168404Spjd * human-readable form. 1890168404Spjd * 1891168404Spjd * Returns 0 on success, or -1 on error. 1892168404Spjd */ 1893168404Spjdint 1894168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1895185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1896168404Spjd{ 1897168404Spjd char *source = NULL; 1898168404Spjd uint64_t val; 1899168404Spjd char *str; 1900168404Spjd const char *strval; 1901219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1902168404Spjd 1903168404Spjd /* 1904168404Spjd * Check to see if this property applies to our object 1905168404Spjd */ 1906168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1907168404Spjd return (-1); 1908168404Spjd 1909219089Spjd if (received && zfs_prop_readonly(prop)) 1910219089Spjd return (-1); 1911219089Spjd 1912168404Spjd if (src) 1913185029Spjd *src = ZPROP_SRC_NONE; 1914168404Spjd 1915168404Spjd switch (prop) { 1916168404Spjd case ZFS_PROP_CREATION: 1917168404Spjd /* 1918168404Spjd * 'creation' is a time_t stored in the statistics. We convert 1919168404Spjd * this into a string unless 'literal' is specified. 1920168404Spjd */ 1921168404Spjd { 1922168404Spjd val = getprop_uint64(zhp, prop, &source); 1923168404Spjd time_t time = (time_t)val; 1924168404Spjd struct tm t; 1925168404Spjd 1926168404Spjd if (literal || 1927168404Spjd localtime_r(&time, &t) == NULL || 1928168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1929168404Spjd &t) == 0) 1930168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 1931168404Spjd } 1932168404Spjd break; 1933168404Spjd 1934168404Spjd case ZFS_PROP_MOUNTPOINT: 1935168404Spjd /* 1936168404Spjd * Getting the precise mountpoint can be tricky. 1937168404Spjd * 1938168404Spjd * - for 'none' or 'legacy', return those values. 1939168404Spjd * - for inherited mountpoints, we want to take everything 1940168404Spjd * after our ancestor and append it to the inherited value. 1941168404Spjd * 1942168404Spjd * If the pool has an alternate root, we want to prepend that 1943168404Spjd * root to any values we return. 1944168404Spjd */ 1945185029Spjd 1946168404Spjd str = getprop_string(zhp, prop, &source); 1947168404Spjd 1948185029Spjd if (str[0] == '/') { 1949185029Spjd char buf[MAXPATHLEN]; 1950185029Spjd char *root = buf; 1951219089Spjd const char *relpath; 1952168404Spjd 1953219089Spjd /* 1954219089Spjd * If we inherit the mountpoint, even from a dataset 1955219089Spjd * with a received value, the source will be the path of 1956219089Spjd * the dataset we inherit from. If source is 1957219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 1958219089Spjd * inherited. 1959219089Spjd */ 1960219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 1961219089Spjd relpath = ""; 1962219089Spjd } else { 1963219089Spjd relpath = zhp->zfs_name + strlen(source); 1964219089Spjd if (relpath[0] == '/') 1965219089Spjd relpath++; 1966219089Spjd } 1967185029Spjd 1968185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 1969185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 1970185029Spjd (strcmp(root, "-") == 0)) 1971185029Spjd root[0] = '\0'; 1972185029Spjd /* 1973185029Spjd * Special case an alternate root of '/'. This will 1974185029Spjd * avoid having multiple leading slashes in the 1975185029Spjd * mountpoint path. 1976185029Spjd */ 1977185029Spjd if (strcmp(root, "/") == 0) 1978185029Spjd root++; 1979185029Spjd 1980185029Spjd /* 1981185029Spjd * If the mountpoint is '/' then skip over this 1982185029Spjd * if we are obtaining either an alternate root or 1983185029Spjd * an inherited mountpoint. 1984185029Spjd */ 1985185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 1986185029Spjd relpath[0] != '\0')) 1987168404Spjd str++; 1988168404Spjd 1989168404Spjd if (relpath[0] == '\0') 1990168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 1991168404Spjd root, str); 1992168404Spjd else 1993168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 1994168404Spjd root, str, relpath[0] == '@' ? "" : "/", 1995168404Spjd relpath); 1996168404Spjd } else { 1997168404Spjd /* 'legacy' or 'none' */ 1998168404Spjd (void) strlcpy(propbuf, str, proplen); 1999168404Spjd } 2000168404Spjd 2001168404Spjd break; 2002168404Spjd 2003168404Spjd case ZFS_PROP_ORIGIN: 2004168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2005168404Spjd proplen); 2006168404Spjd /* 2007168404Spjd * If there is no parent at all, return failure to indicate that 2008168404Spjd * it doesn't apply to this dataset. 2009168404Spjd */ 2010168404Spjd if (propbuf[0] == '\0') 2011168404Spjd return (-1); 2012168404Spjd break; 2013168404Spjd 2014168404Spjd case ZFS_PROP_QUOTA: 2015185029Spjd case ZFS_PROP_REFQUOTA: 2016168404Spjd case ZFS_PROP_RESERVATION: 2017185029Spjd case ZFS_PROP_REFRESERVATION: 2018185029Spjd 2019168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2020168404Spjd return (-1); 2021168404Spjd 2022168404Spjd /* 2023168404Spjd * If quota or reservation is 0, we translate this into 'none' 2024168404Spjd * (unless literal is set), and indicate that it's the default 2025168404Spjd * value. Otherwise, we print the number nicely and indicate 2026168404Spjd * that its set locally. 2027168404Spjd */ 2028168404Spjd if (val == 0) { 2029168404Spjd if (literal) 2030168404Spjd (void) strlcpy(propbuf, "0", proplen); 2031168404Spjd else 2032168404Spjd (void) strlcpy(propbuf, "none", proplen); 2033168404Spjd } else { 2034168404Spjd if (literal) 2035168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2036168404Spjd (u_longlong_t)val); 2037168404Spjd else 2038168404Spjd zfs_nicenum(val, propbuf, proplen); 2039168404Spjd } 2040168404Spjd break; 2041168404Spjd 2042223623Smm case ZFS_PROP_REFRATIO: 2043168404Spjd case ZFS_PROP_COMPRESSRATIO: 2044168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2045168404Spjd return (-1); 2046219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2047219089Spjd (u_longlong_t)(val / 100), 2048219089Spjd (u_longlong_t)(val % 100)); 2049168404Spjd break; 2050168404Spjd 2051168404Spjd case ZFS_PROP_TYPE: 2052168404Spjd switch (zhp->zfs_type) { 2053168404Spjd case ZFS_TYPE_FILESYSTEM: 2054168404Spjd str = "filesystem"; 2055168404Spjd break; 2056168404Spjd case ZFS_TYPE_VOLUME: 2057168404Spjd str = "volume"; 2058168404Spjd break; 2059168404Spjd case ZFS_TYPE_SNAPSHOT: 2060168404Spjd str = "snapshot"; 2061168404Spjd break; 2062168404Spjd default: 2063168404Spjd abort(); 2064168404Spjd } 2065168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2066168404Spjd break; 2067168404Spjd 2068168404Spjd case ZFS_PROP_MOUNTED: 2069168404Spjd /* 2070168404Spjd * The 'mounted' property is a pseudo-property that described 2071168404Spjd * whether the filesystem is currently mounted. Even though 2072168404Spjd * it's a boolean value, the typical values of "on" and "off" 2073168404Spjd * don't make sense, so we translate to "yes" and "no". 2074168404Spjd */ 2075168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2076168404Spjd src, &source, &val) != 0) 2077168404Spjd return (-1); 2078168404Spjd if (val) 2079168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2080168404Spjd else 2081168404Spjd (void) strlcpy(propbuf, "no", proplen); 2082168404Spjd break; 2083168404Spjd 2084168404Spjd case ZFS_PROP_NAME: 2085168404Spjd /* 2086168404Spjd * The 'name' property is a pseudo-property derived from the 2087168404Spjd * dataset name. It is presented as a real property to simplify 2088168404Spjd * consumers. 2089168404Spjd */ 2090168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2091168404Spjd break; 2092168404Spjd 2093219089Spjd case ZFS_PROP_MLSLABEL: 2094219089Spjd { 2095219089Spjd#ifdef sun 2096219089Spjd m_label_t *new_sl = NULL; 2097219089Spjd char *ascii = NULL; /* human readable label */ 2098219089Spjd 2099219089Spjd (void) strlcpy(propbuf, 2100219089Spjd getprop_string(zhp, prop, &source), proplen); 2101219089Spjd 2102219089Spjd if (literal || (strcasecmp(propbuf, 2103219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2104219089Spjd break; 2105219089Spjd 2106219089Spjd /* 2107219089Spjd * Try to translate the internal hex string to 2108219089Spjd * human-readable output. If there are any 2109219089Spjd * problems just use the hex string. 2110219089Spjd */ 2111219089Spjd 2112219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2113219089Spjd L_NO_CORRECTION, NULL) == -1) { 2114219089Spjd m_label_free(new_sl); 2115219089Spjd break; 2116219089Spjd } 2117219089Spjd 2118219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2119219089Spjd DEF_NAMES) != 0) { 2120219089Spjd if (ascii) 2121219089Spjd free(ascii); 2122219089Spjd m_label_free(new_sl); 2123219089Spjd break; 2124219089Spjd } 2125219089Spjd m_label_free(new_sl); 2126219089Spjd 2127219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2128219089Spjd free(ascii); 2129219089Spjd#else /* !sun */ 2130219089Spjd propbuf[0] = '\0'; 2131219089Spjd#endif /* !sun */ 2132219089Spjd } 2133219089Spjd break; 2134219089Spjd 2135168404Spjd default: 2136185029Spjd switch (zfs_prop_get_type(prop)) { 2137185029Spjd case PROP_TYPE_NUMBER: 2138185029Spjd if (get_numeric_property(zhp, prop, src, 2139185029Spjd &source, &val) != 0) 2140185029Spjd return (-1); 2141185029Spjd if (literal) 2142185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2143185029Spjd (u_longlong_t)val); 2144185029Spjd else 2145185029Spjd zfs_nicenum(val, propbuf, proplen); 2146185029Spjd break; 2147185029Spjd 2148185029Spjd case PROP_TYPE_STRING: 2149185029Spjd (void) strlcpy(propbuf, 2150185029Spjd getprop_string(zhp, prop, &source), proplen); 2151185029Spjd break; 2152185029Spjd 2153185029Spjd case PROP_TYPE_INDEX: 2154185029Spjd if (get_numeric_property(zhp, prop, src, 2155185029Spjd &source, &val) != 0) 2156185029Spjd return (-1); 2157185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2158185029Spjd return (-1); 2159185029Spjd (void) strlcpy(propbuf, strval, proplen); 2160185029Spjd break; 2161185029Spjd 2162185029Spjd default: 2163185029Spjd abort(); 2164185029Spjd } 2165168404Spjd } 2166168404Spjd 2167168404Spjd get_source(zhp, src, source, statbuf, statlen); 2168168404Spjd 2169168404Spjd return (0); 2170168404Spjd} 2171168404Spjd 2172168404Spjd/* 2173168404Spjd * Utility function to get the given numeric property. Does no validation that 2174168404Spjd * the given property is the appropriate type; should only be used with 2175168404Spjd * hard-coded property types. 2176168404Spjd */ 2177168404Spjduint64_t 2178168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2179168404Spjd{ 2180168404Spjd char *source; 2181168404Spjd uint64_t val; 2182168404Spjd 2183185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2184168404Spjd 2185168404Spjd return (val); 2186168404Spjd} 2187168404Spjd 2188185029Spjdint 2189185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2190185029Spjd{ 2191185029Spjd char buf[64]; 2192185029Spjd 2193209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2194185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2195185029Spjd} 2196185029Spjd 2197168404Spjd/* 2198168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2199168404Spjd */ 2200168404Spjdint 2201168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2202185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2203168404Spjd{ 2204168404Spjd char *source; 2205168404Spjd 2206168404Spjd /* 2207168404Spjd * Check to see if this property applies to our object 2208168404Spjd */ 2209185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2210168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2211168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2212168404Spjd zfs_prop_to_name(prop))); 2213185029Spjd } 2214168404Spjd 2215168404Spjd if (src) 2216185029Spjd *src = ZPROP_SRC_NONE; 2217168404Spjd 2218168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2219168404Spjd return (-1); 2220168404Spjd 2221168404Spjd get_source(zhp, src, source, statbuf, statlen); 2222168404Spjd 2223168404Spjd return (0); 2224168404Spjd} 2225168404Spjd 2226209962Smmstatic int 2227209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2228209962Smm char **domainp, idmap_rid_t *ridp) 2229209962Smm{ 2230209962Smm#ifdef sun 2231209962Smm idmap_get_handle_t *get_hdl = NULL; 2232209962Smm idmap_stat status; 2233209962Smm int err = EINVAL; 2234209962Smm 2235219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2236209962Smm goto out; 2237209962Smm 2238209962Smm if (isuser) { 2239209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2240209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2241209962Smm } else { 2242209962Smm err = idmap_get_sidbygid(get_hdl, id, 2243209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2244209962Smm } 2245209962Smm if (err == IDMAP_SUCCESS && 2246209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2247209962Smm status == IDMAP_SUCCESS) 2248209962Smm err = 0; 2249209962Smm else 2250209962Smm err = EINVAL; 2251209962Smmout: 2252209962Smm if (get_hdl) 2253209962Smm idmap_get_destroy(get_hdl); 2254209962Smm return (err); 2255209962Smm#else /* !sun */ 2256209962Smm assert(!"invalid code path"); 2257209962Smm#endif /* !sun */ 2258209962Smm} 2259209962Smm 2260168404Spjd/* 2261209962Smm * convert the propname into parameters needed by kernel 2262209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2263209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2264209962Smm */ 2265209962Smmstatic int 2266209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2267209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2268209962Smm{ 2269209962Smm zfs_userquota_prop_t type; 2270209962Smm char *cp, *end; 2271209962Smm char *numericsid = NULL; 2272209962Smm boolean_t isuser; 2273209962Smm 2274209962Smm domain[0] = '\0'; 2275209962Smm 2276209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2277209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2278209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2279209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2280209962Smm break; 2281209962Smm } 2282209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2283209962Smm return (EINVAL); 2284209962Smm *typep = type; 2285209962Smm 2286209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2287209962Smm type == ZFS_PROP_USERUSED); 2288209962Smm 2289209962Smm cp = strchr(propname, '@') + 1; 2290209962Smm 2291209962Smm if (strchr(cp, '@')) { 2292209962Smm#ifdef sun 2293209962Smm /* 2294209962Smm * It's a SID name (eg "user@domain") that needs to be 2295209962Smm * turned into S-1-domainID-RID. 2296209962Smm */ 2297209962Smm directory_error_t e; 2298209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2299209962Smm return (ENOENT); 2300209962Smm if (isuser) { 2301209962Smm e = directory_sid_from_user_name(NULL, 2302209962Smm cp, &numericsid); 2303209962Smm } else { 2304209962Smm e = directory_sid_from_group_name(NULL, 2305209962Smm cp, &numericsid); 2306209962Smm } 2307209962Smm if (e != NULL) { 2308209962Smm directory_error_free(e); 2309209962Smm return (ENOENT); 2310209962Smm } 2311209962Smm if (numericsid == NULL) 2312209962Smm return (ENOENT); 2313209962Smm cp = numericsid; 2314209962Smm /* will be further decoded below */ 2315209962Smm#else /* !sun */ 2316219089Spjd return (ENOENT); 2317209962Smm#endif /* !sun */ 2318209962Smm } 2319209962Smm 2320209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2321209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2322209962Smm (void) strlcpy(domain, cp, domainlen); 2323209962Smm cp = strrchr(domain, '-'); 2324209962Smm *cp = '\0'; 2325209962Smm cp++; 2326209962Smm 2327209962Smm errno = 0; 2328209962Smm *ridp = strtoull(cp, &end, 10); 2329209962Smm if (numericsid) { 2330209962Smm free(numericsid); 2331209962Smm numericsid = NULL; 2332209962Smm } 2333209962Smm if (errno != 0 || *end != '\0') 2334209962Smm return (EINVAL); 2335209962Smm } else if (!isdigit(*cp)) { 2336209962Smm /* 2337209962Smm * It's a user/group name (eg "user") that needs to be 2338209962Smm * turned into a uid/gid 2339209962Smm */ 2340209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2341209962Smm return (ENOENT); 2342209962Smm if (isuser) { 2343209962Smm struct passwd *pw; 2344209962Smm pw = getpwnam(cp); 2345209962Smm if (pw == NULL) 2346209962Smm return (ENOENT); 2347209962Smm *ridp = pw->pw_uid; 2348209962Smm } else { 2349209962Smm struct group *gr; 2350209962Smm gr = getgrnam(cp); 2351209962Smm if (gr == NULL) 2352209962Smm return (ENOENT); 2353209962Smm *ridp = gr->gr_gid; 2354209962Smm } 2355209962Smm } else { 2356209962Smm /* It's a user/group ID (eg "12345"). */ 2357209962Smm uid_t id = strtoul(cp, &end, 10); 2358209962Smm idmap_rid_t rid; 2359209962Smm char *mapdomain; 2360209962Smm 2361209962Smm if (*end != '\0') 2362209962Smm return (EINVAL); 2363209962Smm if (id > MAXUID) { 2364209962Smm /* It's an ephemeral ID. */ 2365209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2366209962Smm &mapdomain, &rid) != 0) 2367209962Smm return (ENOENT); 2368209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2369209962Smm *ridp = rid; 2370209962Smm } else { 2371209962Smm *ridp = id; 2372209962Smm } 2373209962Smm } 2374209962Smm 2375209962Smm ASSERT3P(numericsid, ==, NULL); 2376209962Smm return (0); 2377209962Smm} 2378209962Smm 2379209962Smmstatic int 2380209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2381209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2382209962Smm{ 2383209962Smm int err; 2384209962Smm zfs_cmd_t zc = { 0 }; 2385209962Smm 2386209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2387209962Smm 2388209962Smm err = userquota_propname_decode(propname, 2389209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2390209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2391209962Smm zc.zc_objset_type = *typep; 2392209962Smm if (err) 2393209962Smm return (err); 2394209962Smm 2395209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2396209962Smm if (err) 2397209962Smm return (err); 2398209962Smm 2399209962Smm *propvalue = zc.zc_cookie; 2400209962Smm return (0); 2401209962Smm} 2402209962Smm 2403209962Smmint 2404209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2405209962Smm uint64_t *propvalue) 2406209962Smm{ 2407209962Smm zfs_userquota_prop_t type; 2408209962Smm 2409209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2410209962Smm &type)); 2411209962Smm} 2412209962Smm 2413209962Smmint 2414209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2415209962Smm char *propbuf, int proplen, boolean_t literal) 2416209962Smm{ 2417209962Smm int err; 2418209962Smm uint64_t propvalue; 2419209962Smm zfs_userquota_prop_t type; 2420209962Smm 2421209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2422209962Smm &type); 2423209962Smm 2424209962Smm if (err) 2425209962Smm return (err); 2426209962Smm 2427209962Smm if (literal) { 2428209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2429209962Smm } else if (propvalue == 0 && 2430209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2431209962Smm (void) strlcpy(propbuf, "none", proplen); 2432209962Smm } else { 2433209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2434209962Smm } 2435209962Smm return (0); 2436209962Smm} 2437209962Smm 2438209962Smm/* 2439168404Spjd * Returns the name of the given zfs handle. 2440168404Spjd */ 2441168404Spjdconst char * 2442168404Spjdzfs_get_name(const zfs_handle_t *zhp) 2443168404Spjd{ 2444168404Spjd return (zhp->zfs_name); 2445168404Spjd} 2446168404Spjd 2447168404Spjd/* 2448168404Spjd * Returns the type of the given zfs handle. 2449168404Spjd */ 2450168404Spjdzfs_type_t 2451168404Spjdzfs_get_type(const zfs_handle_t *zhp) 2452168404Spjd{ 2453168404Spjd return (zhp->zfs_type); 2454168404Spjd} 2455168404Spjd 2456209962Smmstatic int 2457209962Smmzfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc) 2458209962Smm{ 2459209962Smm int rc; 2460209962Smm uint64_t orig_cookie; 2461209962Smm 2462209962Smm orig_cookie = zc->zc_cookie; 2463209962Smmtop: 2464209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 2465209962Smm rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); 2466209962Smm 2467209962Smm if (rc == -1) { 2468209962Smm switch (errno) { 2469209962Smm case ENOMEM: 2470209962Smm /* expand nvlist memory and try again */ 2471209962Smm if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { 2472209962Smm zcmd_free_nvlists(zc); 2473209962Smm return (-1); 2474209962Smm } 2475209962Smm zc->zc_cookie = orig_cookie; 2476209962Smm goto top; 2477209962Smm /* 2478209962Smm * An errno value of ESRCH indicates normal completion. 2479209962Smm * If ENOENT is returned, then the underlying dataset 2480209962Smm * has been removed since we obtained the handle. 2481209962Smm */ 2482209962Smm case ESRCH: 2483209962Smm case ENOENT: 2484209962Smm rc = 1; 2485209962Smm break; 2486209962Smm default: 2487209962Smm rc = zfs_standard_error(zhp->zfs_hdl, errno, 2488209962Smm dgettext(TEXT_DOMAIN, 2489209962Smm "cannot iterate filesystems")); 2490209962Smm break; 2491209962Smm } 2492209962Smm } 2493209962Smm return (rc); 2494209962Smm} 2495209962Smm 2496168404Spjd/* 2497168404Spjd * Iterate over all child filesystems 2498168404Spjd */ 2499168404Spjdint 2500168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2501168404Spjd{ 2502168404Spjd zfs_cmd_t zc = { 0 }; 2503168404Spjd zfs_handle_t *nzhp; 2504168404Spjd int ret; 2505168404Spjd 2506185029Spjd if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 2507185029Spjd return (0); 2508185029Spjd 2509209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2510209962Smm return (-1); 2511209962Smm 2512209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, 2513209962Smm &zc)) == 0) { 2514168404Spjd /* 2515168404Spjd * Silently ignore errors, as the only plausible explanation is 2516168404Spjd * that the pool has since been removed. 2517168404Spjd */ 2518209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2519209962Smm &zc)) == NULL) { 2520168404Spjd continue; 2521209962Smm } 2522168404Spjd 2523209962Smm if ((ret = func(nzhp, data)) != 0) { 2524209962Smm zcmd_free_nvlists(&zc); 2525168404Spjd return (ret); 2526209962Smm } 2527168404Spjd } 2528209962Smm zcmd_free_nvlists(&zc); 2529209962Smm return ((ret < 0) ? ret : 0); 2530168404Spjd} 2531168404Spjd 2532168404Spjd/* 2533168404Spjd * Iterate over all snapshots 2534168404Spjd */ 2535168404Spjdint 2536168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2537168404Spjd{ 2538168404Spjd zfs_cmd_t zc = { 0 }; 2539168404Spjd zfs_handle_t *nzhp; 2540168404Spjd int ret; 2541168404Spjd 2542185029Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 2543185029Spjd return (0); 2544185029Spjd 2545209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2546209962Smm return (-1); 2547209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, 2548209962Smm &zc)) == 0) { 2549168404Spjd 2550209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2551209962Smm &zc)) == NULL) { 2552209962Smm continue; 2553209962Smm } 2554209962Smm 2555209962Smm if ((ret = func(nzhp, data)) != 0) { 2556209962Smm zcmd_free_nvlists(&zc); 2557168404Spjd return (ret); 2558209962Smm } 2559168404Spjd } 2560209962Smm zcmd_free_nvlists(&zc); 2561209962Smm return ((ret < 0) ? ret : 0); 2562168404Spjd} 2563168404Spjd 2564168404Spjd/* 2565168404Spjd * Iterate over all children, snapshots and filesystems 2566168404Spjd */ 2567168404Spjdint 2568168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2569168404Spjd{ 2570168404Spjd int ret; 2571168404Spjd 2572168404Spjd if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 2573168404Spjd return (ret); 2574168404Spjd 2575168404Spjd return (zfs_iter_snapshots(zhp, func, data)); 2576168404Spjd} 2577168404Spjd 2578168404Spjd/* 2579219089Spjd * Is one dataset name a child dataset of another? 2580219089Spjd * 2581219089Spjd * Needs to handle these cases: 2582219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2583219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2584219089Spjd * Descendant? No. No. No. Yes. 2585219089Spjd */ 2586219089Spjdstatic boolean_t 2587219089Spjdis_descendant(const char *ds1, const char *ds2) 2588219089Spjd{ 2589219089Spjd size_t d1len = strlen(ds1); 2590219089Spjd 2591219089Spjd /* ds2 can't be a descendant if it's smaller */ 2592219089Spjd if (strlen(ds2) < d1len) 2593219089Spjd return (B_FALSE); 2594219089Spjd 2595219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2596219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2597219089Spjd} 2598219089Spjd 2599219089Spjd/* 2600168404Spjd * Given a complete name, return just the portion that refers to the parent. 2601168404Spjd * Can return NULL if this is a pool. 2602168404Spjd */ 2603168404Spjdstatic int 2604168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2605168404Spjd{ 2606168404Spjd char *loc; 2607168404Spjd 2608168404Spjd if ((loc = strrchr(path, '/')) == NULL) 2609168404Spjd return (-1); 2610168404Spjd 2611168404Spjd (void) strncpy(buf, path, MIN(buflen, loc - path)); 2612168404Spjd buf[loc - path] = '\0'; 2613168404Spjd 2614168404Spjd return (0); 2615168404Spjd} 2616168404Spjd 2617168404Spjd/* 2618185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2619185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2620185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2621185029Spjd * length of already existing prefix of the given path. We also fetch the 2622185029Spjd * 'zoned' property, which is used to validate property settings when creating 2623185029Spjd * new datasets. 2624168404Spjd */ 2625168404Spjdstatic int 2626185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2627185029Spjd boolean_t accept_ancestor, int *prefixlen) 2628168404Spjd{ 2629168404Spjd zfs_cmd_t zc = { 0 }; 2630168404Spjd char parent[ZFS_MAXNAMELEN]; 2631168404Spjd char *slash; 2632168404Spjd zfs_handle_t *zhp; 2633168404Spjd char errbuf[1024]; 2634219089Spjd uint64_t is_zoned; 2635168404Spjd 2636209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2637209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2638168404Spjd 2639168404Spjd /* get parent, and check to see if this is just a pool */ 2640168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2641168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2642168404Spjd "missing dataset name")); 2643168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2644168404Spjd } 2645168404Spjd 2646168404Spjd /* check to see if the pool exists */ 2647168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2648168404Spjd slash = parent + strlen(parent); 2649168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2650168404Spjd zc.zc_name[slash - parent] = '\0'; 2651168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2652168404Spjd errno == ENOENT) { 2653168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2654168404Spjd "no such pool '%s'"), zc.zc_name); 2655168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2656168404Spjd } 2657168404Spjd 2658168404Spjd /* check to see if the parent dataset exists */ 2659185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2660185029Spjd if (errno == ENOENT && accept_ancestor) { 2661185029Spjd /* 2662185029Spjd * Go deeper to find an ancestor, give up on top level. 2663185029Spjd */ 2664185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2665185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2666185029Spjd "no such pool '%s'"), zc.zc_name); 2667185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2668185029Spjd } 2669185029Spjd } else if (errno == ENOENT) { 2670168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2671168404Spjd "parent does not exist")); 2672168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2673185029Spjd } else 2674168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2675168404Spjd } 2676168404Spjd 2677219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2678219089Spjd if (zoned != NULL) 2679219089Spjd *zoned = is_zoned; 2680219089Spjd 2681168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2682219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 2683168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2684168404Spjd zfs_close(zhp); 2685168404Spjd return (-1); 2686168404Spjd } 2687168404Spjd 2688168404Spjd /* make sure parent is a filesystem */ 2689168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2690168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2691168404Spjd "parent is not a filesystem")); 2692168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2693168404Spjd zfs_close(zhp); 2694168404Spjd return (-1); 2695168404Spjd } 2696168404Spjd 2697168404Spjd zfs_close(zhp); 2698185029Spjd if (prefixlen != NULL) 2699185029Spjd *prefixlen = strlen(parent); 2700168404Spjd return (0); 2701168404Spjd} 2702168404Spjd 2703168404Spjd/* 2704185029Spjd * Finds whether the dataset of the given type(s) exists. 2705185029Spjd */ 2706185029Spjdboolean_t 2707185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2708185029Spjd{ 2709185029Spjd zfs_handle_t *zhp; 2710185029Spjd 2711185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2712185029Spjd return (B_FALSE); 2713185029Spjd 2714185029Spjd /* 2715185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2716185029Spjd */ 2717185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2718185029Spjd int ds_type = zhp->zfs_type; 2719185029Spjd 2720185029Spjd zfs_close(zhp); 2721185029Spjd if (types & ds_type) 2722185029Spjd return (B_TRUE); 2723185029Spjd } 2724185029Spjd return (B_FALSE); 2725185029Spjd} 2726185029Spjd 2727185029Spjd/* 2728185029Spjd * Given a path to 'target', create all the ancestors between 2729185029Spjd * the prefixlen portion of the path, and the target itself. 2730185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2731185029Spjd */ 2732185029Spjdint 2733185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2734185029Spjd{ 2735185029Spjd zfs_handle_t *h; 2736185029Spjd char *cp; 2737185029Spjd const char *opname; 2738185029Spjd 2739185029Spjd /* make sure prefix exists */ 2740185029Spjd cp = target + prefixlen; 2741185029Spjd if (*cp != '/') { 2742185029Spjd assert(strchr(cp, '/') == NULL); 2743185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2744185029Spjd } else { 2745185029Spjd *cp = '\0'; 2746185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2747185029Spjd *cp = '/'; 2748185029Spjd } 2749185029Spjd if (h == NULL) 2750185029Spjd return (-1); 2751185029Spjd zfs_close(h); 2752185029Spjd 2753185029Spjd /* 2754185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2755185029Spjd * up to the prefixlen-long one. 2756185029Spjd */ 2757185029Spjd for (cp = target + prefixlen + 1; 2758185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2759185029Spjd char *logstr; 2760185029Spjd 2761185029Spjd *cp = '\0'; 2762185029Spjd 2763185029Spjd h = make_dataset_handle(hdl, target); 2764185029Spjd if (h) { 2765185029Spjd /* it already exists, nothing to do here */ 2766185029Spjd zfs_close(h); 2767185029Spjd continue; 2768185029Spjd } 2769185029Spjd 2770185029Spjd logstr = hdl->libzfs_log_str; 2771185029Spjd hdl->libzfs_log_str = NULL; 2772185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2773185029Spjd NULL) != 0) { 2774185029Spjd hdl->libzfs_log_str = logstr; 2775185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2776185029Spjd goto ancestorerr; 2777185029Spjd } 2778185029Spjd 2779185029Spjd hdl->libzfs_log_str = logstr; 2780185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2781185029Spjd if (h == NULL) { 2782185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2783185029Spjd goto ancestorerr; 2784185029Spjd } 2785185029Spjd 2786185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 2787185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2788185029Spjd goto ancestorerr; 2789185029Spjd } 2790185029Spjd 2791185029Spjd if (zfs_share(h) != 0) { 2792185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2793185029Spjd goto ancestorerr; 2794185029Spjd } 2795185029Spjd 2796185029Spjd zfs_close(h); 2797185029Spjd } 2798185029Spjd 2799185029Spjd return (0); 2800185029Spjd 2801185029Spjdancestorerr: 2802185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2803185029Spjd "failed to %s ancestor '%s'"), opname, target); 2804185029Spjd return (-1); 2805185029Spjd} 2806185029Spjd 2807185029Spjd/* 2808185029Spjd * Creates non-existing ancestors of the given path. 2809185029Spjd */ 2810185029Spjdint 2811185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2812185029Spjd{ 2813185029Spjd int prefix; 2814185029Spjd char *path_copy; 2815185029Spjd int rc; 2816185029Spjd 2817219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 2818185029Spjd return (-1); 2819185029Spjd 2820185029Spjd if ((path_copy = strdup(path)) != NULL) { 2821185029Spjd rc = create_parents(hdl, path_copy, prefix); 2822185029Spjd free(path_copy); 2823185029Spjd } 2824185029Spjd if (path_copy == NULL || rc != 0) 2825185029Spjd return (-1); 2826185029Spjd 2827185029Spjd return (0); 2828185029Spjd} 2829185029Spjd 2830185029Spjd/* 2831168404Spjd * Create a new filesystem or volume. 2832168404Spjd */ 2833168404Spjdint 2834168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2835168404Spjd nvlist_t *props) 2836168404Spjd{ 2837168404Spjd zfs_cmd_t zc = { 0 }; 2838168404Spjd int ret; 2839168404Spjd uint64_t size = 0; 2840168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2841168404Spjd char errbuf[1024]; 2842168404Spjd uint64_t zoned; 2843168404Spjd 2844168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2845168404Spjd "cannot create '%s'"), path); 2846168404Spjd 2847168404Spjd /* validate the path, taking care to note the extended error message */ 2848185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 2849168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2850168404Spjd 2851168404Spjd /* validate parents exist */ 2852185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 2853168404Spjd return (-1); 2854168404Spjd 2855168404Spjd /* 2856168404Spjd * The failure modes when creating a dataset of a different type over 2857168404Spjd * one that already exists is a little strange. In particular, if you 2858168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 2859168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 2860168404Spjd * first try to see if the dataset exists. 2861168404Spjd */ 2862168404Spjd (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2863185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 2864168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2865168404Spjd "dataset already exists")); 2866168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2867168404Spjd } 2868168404Spjd 2869168404Spjd if (type == ZFS_TYPE_VOLUME) 2870168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2871168404Spjd else 2872168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2873168404Spjd 2874185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 2875168404Spjd zoned, NULL, errbuf)) == 0) 2876168404Spjd return (-1); 2877168404Spjd 2878168404Spjd if (type == ZFS_TYPE_VOLUME) { 2879168404Spjd /* 2880168404Spjd * If we are creating a volume, the size and block size must 2881168404Spjd * satisfy a few restraints. First, the blocksize must be a 2882168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 2883168404Spjd * volsize must be a multiple of the block size, and cannot be 2884168404Spjd * zero. 2885168404Spjd */ 2886168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 2887168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2888168404Spjd nvlist_free(props); 2889168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2890168404Spjd "missing volume size")); 2891168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2892168404Spjd } 2893168404Spjd 2894168404Spjd if ((ret = nvlist_lookup_uint64(props, 2895168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2896168404Spjd &blocksize)) != 0) { 2897168404Spjd if (ret == ENOENT) { 2898168404Spjd blocksize = zfs_prop_default_numeric( 2899168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2900168404Spjd } else { 2901168404Spjd nvlist_free(props); 2902168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2903168404Spjd "missing volume block size")); 2904168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2905168404Spjd } 2906168404Spjd } 2907168404Spjd 2908168404Spjd if (size == 0) { 2909168404Spjd nvlist_free(props); 2910168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2911168404Spjd "volume size cannot be zero")); 2912168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2913168404Spjd } 2914168404Spjd 2915168404Spjd if (size % blocksize != 0) { 2916168404Spjd nvlist_free(props); 2917168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2918168404Spjd "volume size must be a multiple of volume block " 2919168404Spjd "size")); 2920168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2921168404Spjd } 2922168404Spjd } 2923168404Spjd 2924185029Spjd if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) 2925168404Spjd return (-1); 2926168404Spjd nvlist_free(props); 2927168404Spjd 2928168404Spjd /* create the dataset */ 2929185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); 2930168404Spjd 2931168404Spjd zcmd_free_nvlists(&zc); 2932168404Spjd 2933168404Spjd /* check for failure */ 2934168404Spjd if (ret != 0) { 2935168404Spjd char parent[ZFS_MAXNAMELEN]; 2936168404Spjd (void) parent_name(path, parent, sizeof (parent)); 2937168404Spjd 2938168404Spjd switch (errno) { 2939168404Spjd case ENOENT: 2940168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2941168404Spjd "no such parent '%s'"), parent); 2942168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2943168404Spjd 2944168404Spjd case EINVAL: 2945168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2946168404Spjd "parent '%s' is not a filesystem"), parent); 2947168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2948168404Spjd 2949168404Spjd case EDOM: 2950168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2951168404Spjd "volume block size must be power of 2 from " 2952168404Spjd "%u to %uk"), 2953168404Spjd (uint_t)SPA_MINBLOCKSIZE, 2954168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 2955168404Spjd 2956168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2957168404Spjd 2958185029Spjd case ENOTSUP: 2959185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2960185029Spjd "pool must be upgraded to set this " 2961185029Spjd "property or value")); 2962185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 2963168404Spjd#ifdef _ILP32 2964168404Spjd case EOVERFLOW: 2965168404Spjd /* 2966168404Spjd * This platform can't address a volume this big. 2967168404Spjd */ 2968168404Spjd if (type == ZFS_TYPE_VOLUME) 2969168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 2970168404Spjd errbuf)); 2971168404Spjd#endif 2972168404Spjd /* FALLTHROUGH */ 2973168404Spjd default: 2974168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2975168404Spjd } 2976168404Spjd } 2977168404Spjd 2978168404Spjd return (0); 2979168404Spjd} 2980168404Spjd 2981168404Spjd/* 2982168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 2983168404Spjd * isn't mounted, and that there are no active dependents. 2984168404Spjd */ 2985168404Spjdint 2986219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 2987168404Spjd{ 2988168404Spjd zfs_cmd_t zc = { 0 }; 2989168404Spjd 2990168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2991168404Spjd 2992168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2993168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2994168404Spjd } else { 2995168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2996168404Spjd } 2997168404Spjd 2998219089Spjd zc.zc_defer_destroy = defer; 2999185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { 3000168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3001168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3002168404Spjd zhp->zfs_name)); 3003168404Spjd } 3004168404Spjd 3005168404Spjd remove_mountpoint(zhp); 3006168404Spjd 3007168404Spjd return (0); 3008168404Spjd} 3009168404Spjd 3010168404Spjdstruct destroydata { 3011168404Spjd char *snapname; 3012168404Spjd boolean_t gotone; 3013168404Spjd boolean_t closezhp; 3014168404Spjd}; 3015168404Spjd 3016168404Spjdstatic int 3017219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3018168404Spjd{ 3019168404Spjd struct destroydata *dd = arg; 3020168404Spjd zfs_handle_t *szhp; 3021168404Spjd char name[ZFS_MAXNAMELEN]; 3022168404Spjd boolean_t closezhp = dd->closezhp; 3023219089Spjd int rv = 0; 3024168404Spjd 3025168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 3026168404Spjd (void) strlcat(name, "@", sizeof (name)); 3027168404Spjd (void) strlcat(name, dd->snapname, sizeof (name)); 3028168404Spjd 3029168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, name); 3030168404Spjd if (szhp) { 3031168404Spjd dd->gotone = B_TRUE; 3032168404Spjd zfs_close(szhp); 3033168404Spjd } 3034168404Spjd 3035168404Spjd dd->closezhp = B_TRUE; 3036219089Spjd if (!dd->gotone) 3037219089Spjd rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg); 3038168404Spjd if (closezhp) 3039168404Spjd zfs_close(zhp); 3040168404Spjd return (rv); 3041168404Spjd} 3042168404Spjd 3043168404Spjd/* 3044168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3045168404Spjd */ 3046168404Spjdint 3047219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3048168404Spjd{ 3049168404Spjd zfs_cmd_t zc = { 0 }; 3050168404Spjd int ret; 3051168404Spjd struct destroydata dd = { 0 }; 3052168404Spjd 3053168404Spjd dd.snapname = snapname; 3054219089Spjd (void) zfs_check_snap_cb(zhp, &dd); 3055168404Spjd 3056168404Spjd if (!dd.gotone) { 3057168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3058168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3059168404Spjd zhp->zfs_name, snapname)); 3060168404Spjd } 3061168404Spjd 3062168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3063168404Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3064219089Spjd zc.zc_defer_destroy = defer; 3065168404Spjd 3066185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); 3067168404Spjd if (ret != 0) { 3068168404Spjd char errbuf[1024]; 3069168404Spjd 3070168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3071168404Spjd "cannot destroy '%s@%s'"), zc.zc_name, snapname); 3072168404Spjd 3073168404Spjd switch (errno) { 3074168404Spjd case EEXIST: 3075168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3076168404Spjd "snapshot is cloned")); 3077168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 3078168404Spjd 3079168404Spjd default: 3080168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3081168404Spjd errbuf)); 3082168404Spjd } 3083168404Spjd } 3084168404Spjd 3085168404Spjd return (0); 3086168404Spjd} 3087168404Spjd 3088168404Spjd/* 3089168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3090168404Spjd */ 3091168404Spjdint 3092168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3093168404Spjd{ 3094168404Spjd zfs_cmd_t zc = { 0 }; 3095168404Spjd char parent[ZFS_MAXNAMELEN]; 3096168404Spjd int ret; 3097168404Spjd char errbuf[1024]; 3098168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3099168404Spjd zfs_type_t type; 3100168404Spjd uint64_t zoned; 3101168404Spjd 3102168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3103168404Spjd 3104168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3105168404Spjd "cannot create '%s'"), target); 3106168404Spjd 3107168404Spjd /* validate the target name */ 3108185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3109168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3110168404Spjd 3111168404Spjd /* validate parents exist */ 3112185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3113168404Spjd return (-1); 3114168404Spjd 3115168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3116168404Spjd 3117168404Spjd /* do the clone */ 3118168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3119168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3120168404Spjd type = ZFS_TYPE_VOLUME; 3121168404Spjd } else { 3122168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3123168404Spjd type = ZFS_TYPE_FILESYSTEM; 3124168404Spjd } 3125168404Spjd 3126168404Spjd if (props) { 3127185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3128185029Spjd zhp, errbuf)) == NULL) 3129168404Spjd return (-1); 3130168404Spjd 3131185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3132168404Spjd nvlist_free(props); 3133168404Spjd return (-1); 3134168404Spjd } 3135168404Spjd 3136168404Spjd nvlist_free(props); 3137168404Spjd } 3138168404Spjd 3139168404Spjd (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 3140168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 3141185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); 3142168404Spjd 3143168404Spjd zcmd_free_nvlists(&zc); 3144168404Spjd 3145168404Spjd if (ret != 0) { 3146168404Spjd switch (errno) { 3147168404Spjd 3148168404Spjd case ENOENT: 3149168404Spjd /* 3150168404Spjd * The parent doesn't exist. We should have caught this 3151168404Spjd * above, but there may a race condition that has since 3152168404Spjd * destroyed the parent. 3153168404Spjd * 3154168404Spjd * At this point, we don't know whether it's the source 3155168404Spjd * that doesn't exist anymore, or whether the target 3156168404Spjd * dataset doesn't exist. 3157168404Spjd */ 3158168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3159168404Spjd "no such parent '%s'"), parent); 3160168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3161168404Spjd 3162168404Spjd case EXDEV: 3163168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3164168404Spjd "source and target pools differ")); 3165168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3166168404Spjd errbuf)); 3167168404Spjd 3168168404Spjd default: 3169168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3170168404Spjd errbuf)); 3171168404Spjd } 3172168404Spjd } 3173168404Spjd 3174168404Spjd return (ret); 3175168404Spjd} 3176168404Spjd 3177168404Spjd/* 3178168404Spjd * Promotes the given clone fs to be the clone parent. 3179168404Spjd */ 3180168404Spjdint 3181168404Spjdzfs_promote(zfs_handle_t *zhp) 3182168404Spjd{ 3183168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3184168404Spjd zfs_cmd_t zc = { 0 }; 3185168404Spjd char parent[MAXPATHLEN]; 3186168404Spjd int ret; 3187168404Spjd char errbuf[1024]; 3188168404Spjd 3189168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3190168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3191168404Spjd 3192168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3193168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3194168404Spjd "snapshots can not be promoted")); 3195168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3196168404Spjd } 3197168404Spjd 3198185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3199168404Spjd if (parent[0] == '\0') { 3200168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3201168404Spjd "not a cloned filesystem")); 3202168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3203168404Spjd } 3204168404Spjd 3205185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3206168404Spjd sizeof (zc.zc_value)); 3207168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3208185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3209168404Spjd 3210168404Spjd if (ret != 0) { 3211168404Spjd int save_errno = errno; 3212168404Spjd 3213168404Spjd switch (save_errno) { 3214168404Spjd case EEXIST: 3215219089Spjd /* There is a conflicting snapshot name. */ 3216168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3217219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3218219089Spjd zc.zc_string, parent); 3219168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3220168404Spjd 3221168404Spjd default: 3222168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3223168404Spjd } 3224168404Spjd } 3225168404Spjd return (ret); 3226168404Spjd} 3227168404Spjd 3228168404Spjd/* 3229168404Spjd * Takes a snapshot of the given dataset. 3230168404Spjd */ 3231168404Spjdint 3232185029Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3233185029Spjd nvlist_t *props) 3234168404Spjd{ 3235168404Spjd const char *delim; 3236185029Spjd char parent[ZFS_MAXNAMELEN]; 3237168404Spjd zfs_handle_t *zhp; 3238168404Spjd zfs_cmd_t zc = { 0 }; 3239168404Spjd int ret; 3240168404Spjd char errbuf[1024]; 3241168404Spjd 3242168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3243168404Spjd "cannot snapshot '%s'"), path); 3244168404Spjd 3245168404Spjd /* validate the target name */ 3246185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3247168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3248168404Spjd 3249185029Spjd if (props) { 3250185029Spjd if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3251185029Spjd props, B_FALSE, NULL, errbuf)) == NULL) 3252185029Spjd return (-1); 3253185029Spjd 3254185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3255185029Spjd nvlist_free(props); 3256185029Spjd return (-1); 3257185029Spjd } 3258185029Spjd 3259185029Spjd nvlist_free(props); 3260185029Spjd } 3261185029Spjd 3262168404Spjd /* make sure the parent exists and is of the appropriate type */ 3263168404Spjd delim = strchr(path, '@'); 3264168404Spjd (void) strncpy(parent, path, delim - path); 3265168404Spjd parent[delim - path] = '\0'; 3266168404Spjd 3267168404Spjd if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 3268168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3269185029Spjd zcmd_free_nvlists(&zc); 3270168404Spjd return (-1); 3271168404Spjd } 3272168404Spjd 3273168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3274168404Spjd (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 3275185029Spjd if (ZFS_IS_VOLUME(zhp)) 3276185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3277185029Spjd else 3278185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3279168404Spjd zc.zc_cookie = recursive; 3280185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); 3281168404Spjd 3282185029Spjd zcmd_free_nvlists(&zc); 3283185029Spjd 3284168404Spjd /* 3285168404Spjd * if it was recursive, the one that actually failed will be in 3286168404Spjd * zc.zc_name. 3287168404Spjd */ 3288219089Spjd if (ret != 0) { 3289185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3290185029Spjd "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 3291219089Spjd (void) zfs_standard_error(hdl, errno, errbuf); 3292168404Spjd } 3293168404Spjd 3294168404Spjd zfs_close(zhp); 3295168404Spjd 3296168404Spjd return (ret); 3297168404Spjd} 3298168404Spjd 3299168404Spjd/* 3300168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3301168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3302168404Spjd * is a dependent and we should just destroy it without checking the transaction 3303168404Spjd * group. 3304168404Spjd */ 3305168404Spjdtypedef struct rollback_data { 3306168404Spjd const char *cb_target; /* the snapshot */ 3307168404Spjd uint64_t cb_create; /* creation time reference */ 3308185029Spjd boolean_t cb_error; 3309168404Spjd boolean_t cb_dependent; 3310185029Spjd boolean_t cb_force; 3311168404Spjd} rollback_data_t; 3312168404Spjd 3313168404Spjdstatic int 3314168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3315168404Spjd{ 3316168404Spjd rollback_data_t *cbp = data; 3317168404Spjd 3318168404Spjd if (!cbp->cb_dependent) { 3319168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3320168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3321168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3322168404Spjd cbp->cb_create) { 3323185029Spjd char *logstr; 3324168404Spjd 3325168404Spjd cbp->cb_dependent = B_TRUE; 3326185029Spjd cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3327185029Spjd rollback_destroy, cbp); 3328168404Spjd cbp->cb_dependent = B_FALSE; 3329168404Spjd 3330185029Spjd logstr = zhp->zfs_hdl->libzfs_log_str; 3331185029Spjd zhp->zfs_hdl->libzfs_log_str = NULL; 3332219089Spjd cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3333185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 3334168404Spjd } 3335168404Spjd } else { 3336185029Spjd /* We must destroy this clone; first unmount it */ 3337185029Spjd prop_changelist_t *clp; 3338185029Spjd 3339185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3340185029Spjd cbp->cb_force ? MS_FORCE: 0); 3341185029Spjd if (clp == NULL || changelist_prefix(clp) != 0) { 3342185029Spjd cbp->cb_error = B_TRUE; 3343185029Spjd zfs_close(zhp); 3344185029Spjd return (0); 3345185029Spjd } 3346219089Spjd if (zfs_destroy(zhp, B_FALSE) != 0) 3347185029Spjd cbp->cb_error = B_TRUE; 3348168404Spjd else 3349185029Spjd changelist_remove(clp, zhp->zfs_name); 3350185029Spjd (void) changelist_postfix(clp); 3351185029Spjd changelist_free(clp); 3352168404Spjd } 3353168404Spjd 3354168404Spjd zfs_close(zhp); 3355168404Spjd return (0); 3356168404Spjd} 3357168404Spjd 3358168404Spjd/* 3359168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3360168404Spjd * data changes since then and making it the active dataset. 3361168404Spjd * 3362168404Spjd * Any snapshots more recent than the target are destroyed, along with 3363168404Spjd * their dependents. 3364168404Spjd */ 3365168404Spjdint 3366185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3367168404Spjd{ 3368168404Spjd rollback_data_t cb = { 0 }; 3369185029Spjd int err; 3370185029Spjd zfs_cmd_t zc = { 0 }; 3371185029Spjd boolean_t restore_resv = 0; 3372185029Spjd uint64_t old_volsize, new_volsize; 3373185029Spjd zfs_prop_t resv_prop; 3374168404Spjd 3375185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3376185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3377168404Spjd 3378168404Spjd /* 3379168404Spjd * Destroy all recent snapshots and its dependends. 3380168404Spjd */ 3381185029Spjd cb.cb_force = force; 3382168404Spjd cb.cb_target = snap->zfs_name; 3383168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3384168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3385168404Spjd 3386185029Spjd if (cb.cb_error) 3387185029Spjd return (-1); 3388168404Spjd 3389168404Spjd /* 3390168404Spjd * Now that we have verified that the snapshot is the latest, 3391168404Spjd * rollback to the given snapshot. 3392168404Spjd */ 3393168404Spjd 3394185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3395185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3396185029Spjd return (-1); 3397185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3398185029Spjd restore_resv = 3399185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3400168404Spjd } 3401168404Spjd 3402185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3403185029Spjd 3404185029Spjd if (ZFS_IS_VOLUME(zhp)) 3405185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3406185029Spjd else 3407185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3408185029Spjd 3409168404Spjd /* 3410185029Spjd * We rely on zfs_iter_children() to verify that there are no 3411185029Spjd * newer snapshots for the given dataset. Therefore, we can 3412185029Spjd * simply pass the name on to the ioctl() call. There is still 3413185029Spjd * an unlikely race condition where the user has taken a 3414185029Spjd * snapshot since we verified that this was the most recent. 3415185029Spjd * 3416168404Spjd */ 3417185029Spjd if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3418185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3419185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3420185029Spjd zhp->zfs_name); 3421185029Spjd return (err); 3422185029Spjd } 3423168404Spjd 3424185029Spjd /* 3425185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3426185029Spjd * rollback reservation and the volsize has changed then set 3427185029Spjd * the reservation property to the post-rollback volsize. 3428185029Spjd * Make a new handle since the rollback closed the dataset. 3429185029Spjd */ 3430185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3431185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3432185029Spjd if (restore_resv) { 3433185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3434185029Spjd if (old_volsize != new_volsize) 3435185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3436185029Spjd new_volsize); 3437185029Spjd } 3438185029Spjd zfs_close(zhp); 3439185029Spjd } 3440185029Spjd return (err); 3441168404Spjd} 3442168404Spjd 3443168404Spjd/* 3444168404Spjd * Iterate over all dependents for a given dataset. This includes both 3445168404Spjd * hierarchical dependents (children) and data dependents (snapshots and 3446168404Spjd * clones). The bulk of the processing occurs in get_dependents() in 3447168404Spjd * libzfs_graph.c. 3448168404Spjd */ 3449168404Spjdint 3450168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 3451168404Spjd zfs_iter_f func, void *data) 3452168404Spjd{ 3453168404Spjd char **dependents; 3454168404Spjd size_t count; 3455168404Spjd int i; 3456168404Spjd zfs_handle_t *child; 3457168404Spjd int ret = 0; 3458168404Spjd 3459168404Spjd if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 3460168404Spjd &dependents, &count) != 0) 3461168404Spjd return (-1); 3462168404Spjd 3463168404Spjd for (i = 0; i < count; i++) { 3464168404Spjd if ((child = make_dataset_handle(zhp->zfs_hdl, 3465168404Spjd dependents[i])) == NULL) 3466168404Spjd continue; 3467168404Spjd 3468168404Spjd if ((ret = func(child, data)) != 0) 3469168404Spjd break; 3470168404Spjd } 3471168404Spjd 3472168404Spjd for (i = 0; i < count; i++) 3473168404Spjd free(dependents[i]); 3474168404Spjd free(dependents); 3475168404Spjd 3476168404Spjd return (ret); 3477168404Spjd} 3478168404Spjd 3479168404Spjd/* 3480168404Spjd * Renames the given dataset. 3481168404Spjd */ 3482168404Spjdint 3483185029Spjdzfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) 3484168404Spjd{ 3485168404Spjd int ret; 3486168404Spjd zfs_cmd_t zc = { 0 }; 3487168404Spjd char *delim; 3488168676Spjd prop_changelist_t *cl = NULL; 3489168676Spjd zfs_handle_t *zhrp = NULL; 3490168676Spjd char *parentname = NULL; 3491168404Spjd char parent[ZFS_MAXNAMELEN]; 3492168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3493168404Spjd char errbuf[1024]; 3494168404Spjd 3495168404Spjd /* if we have the same exact name, just return success */ 3496168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3497168404Spjd return (0); 3498168404Spjd 3499168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3500168404Spjd "cannot rename to '%s'"), target); 3501168404Spjd 3502168404Spjd /* 3503168404Spjd * Make sure the target name is valid 3504168404Spjd */ 3505168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3506168404Spjd if ((strchr(target, '@') == NULL) || 3507168404Spjd *target == '@') { 3508168404Spjd /* 3509168404Spjd * Snapshot target name is abbreviated, 3510168404Spjd * reconstruct full dataset name 3511168404Spjd */ 3512168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3513168404Spjd sizeof (parent)); 3514168404Spjd delim = strchr(parent, '@'); 3515168404Spjd if (strchr(target, '@') == NULL) 3516168404Spjd *(++delim) = '\0'; 3517168404Spjd else 3518168404Spjd *delim = '\0'; 3519168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3520168404Spjd target = parent; 3521168404Spjd } else { 3522168404Spjd /* 3523168404Spjd * Make sure we're renaming within the same dataset. 3524168404Spjd */ 3525168404Spjd delim = strchr(target, '@'); 3526168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3527168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3528168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3529168404Spjd "snapshots must be part of same " 3530168404Spjd "dataset")); 3531168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3532168404Spjd errbuf)); 3533168404Spjd } 3534168404Spjd } 3535185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3536168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3537168404Spjd } else { 3538168676Spjd if (recursive) { 3539168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3540168676Spjd "recursive rename must be a snapshot")); 3541168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3542168676Spjd } 3543168676Spjd 3544185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3545168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3546168404Spjd 3547168404Spjd /* validate parents */ 3548219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3549168404Spjd return (-1); 3550168404Spjd 3551168404Spjd /* make sure we're in the same pool */ 3552168404Spjd verify((delim = strchr(target, '/')) != NULL); 3553168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3554168404Spjd zhp->zfs_name[delim - target] != '/') { 3555168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3556168404Spjd "datasets must be within same pool")); 3557168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3558168404Spjd } 3559168404Spjd 3560168404Spjd /* new name cannot be a child of the current dataset name */ 3561219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3562168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3563219089Spjd "New dataset name cannot be a descendant of " 3564168404Spjd "current dataset name")); 3565168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3566168404Spjd } 3567168404Spjd } 3568168404Spjd 3569168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3570168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3571168404Spjd 3572168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3573168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3574168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3575168404Spjd "dataset is used in a non-global zone")); 3576168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3577168404Spjd } 3578168404Spjd 3579168676Spjd if (recursive) { 3580168404Spjd 3581185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3582185029Spjd if (parentname == NULL) { 3583185029Spjd ret = -1; 3584185029Spjd goto error; 3585185029Spjd } 3586168676Spjd delim = strchr(parentname, '@'); 3587168676Spjd *delim = '\0'; 3588185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3589168676Spjd if (zhrp == NULL) { 3590185029Spjd ret = -1; 3591185029Spjd goto error; 3592168676Spjd } 3593168676Spjd 3594168676Spjd } else { 3595185029Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) 3596168676Spjd return (-1); 3597168676Spjd 3598168676Spjd if (changelist_haszonedchild(cl)) { 3599168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3600168676Spjd "child dataset with inherited mountpoint is used " 3601168676Spjd "in a non-global zone")); 3602168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3603168676Spjd goto error; 3604168676Spjd } 3605168676Spjd 3606168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3607168676Spjd goto error; 3608168404Spjd } 3609168404Spjd 3610168404Spjd if (ZFS_IS_VOLUME(zhp)) 3611168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3612168404Spjd else 3613168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3614168404Spjd 3615168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3616168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3617168404Spjd 3618168676Spjd zc.zc_cookie = recursive; 3619168676Spjd 3620185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3621168676Spjd /* 3622168676Spjd * if it was recursive, the one that actually failed will 3623168676Spjd * be in zc.zc_name 3624168676Spjd */ 3625168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3626185029Spjd "cannot rename '%s'"), zc.zc_name); 3627168404Spjd 3628168676Spjd if (recursive && errno == EEXIST) { 3629168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3630168676Spjd "a child dataset already has a snapshot " 3631168676Spjd "with the new name")); 3632185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3633168676Spjd } else { 3634168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3635168676Spjd } 3636168676Spjd 3637168404Spjd /* 3638168404Spjd * On failure, we still want to remount any filesystems that 3639168404Spjd * were previously mounted, so we don't alter the system state. 3640168404Spjd */ 3641219089Spjd if (!recursive) 3642168676Spjd (void) changelist_postfix(cl); 3643168404Spjd } else { 3644219089Spjd if (!recursive) { 3645168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3646168676Spjd ret = changelist_postfix(cl); 3647168676Spjd } 3648168404Spjd } 3649168404Spjd 3650168404Spjderror: 3651168676Spjd if (parentname) { 3652168676Spjd free(parentname); 3653168676Spjd } 3654168676Spjd if (zhrp) { 3655168676Spjd zfs_close(zhrp); 3656168676Spjd } 3657168676Spjd if (cl) { 3658168676Spjd changelist_free(cl); 3659168676Spjd } 3660168404Spjd return (ret); 3661168404Spjd} 3662168404Spjd 3663219089Spjdnvlist_t * 3664219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 3665168404Spjd{ 3666219089Spjd return (zhp->zfs_user_props); 3667168676Spjd} 3668168676Spjd 3669168404Spjdnvlist_t * 3670219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 3671168404Spjd{ 3672219089Spjd if (zhp->zfs_recvd_props == NULL) 3673219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 3674219089Spjd return (NULL); 3675219089Spjd return (zhp->zfs_recvd_props); 3676168404Spjd} 3677168404Spjd 3678168404Spjd/* 3679168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3680168404Spjd * display, and their maximum widths. This does two main things: 3681168404Spjd * 3682168404Spjd * - If this is a list of all properties, then expand the list to include 3683168404Spjd * all native properties, and set a flag so that for each dataset we look 3684168404Spjd * for new unique user properties and add them to the list. 3685168404Spjd * 3686168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3687219089Spjd * so that we can size the column appropriately. If the user has 3688219089Spjd * requested received property values, we also need to compute the width 3689219089Spjd * of the RECEIVED column. 3690168404Spjd */ 3691168404Spjdint 3692219089Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) 3693168404Spjd{ 3694168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3695185029Spjd zprop_list_t *entry; 3696185029Spjd zprop_list_t **last, **start; 3697168404Spjd nvlist_t *userprops, *propval; 3698168404Spjd nvpair_t *elem; 3699168404Spjd char *strval; 3700168404Spjd char buf[ZFS_MAXPROPLEN]; 3701168404Spjd 3702185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3703168404Spjd return (-1); 3704168404Spjd 3705168404Spjd userprops = zfs_get_user_props(zhp); 3706168404Spjd 3707168404Spjd entry = *plp; 3708168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3709168404Spjd /* 3710168404Spjd * Go through and add any user properties as necessary. We 3711168404Spjd * start by incrementing our list pointer to the first 3712168404Spjd * non-native property. 3713168404Spjd */ 3714168404Spjd start = plp; 3715168404Spjd while (*start != NULL) { 3716185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3717168404Spjd break; 3718168404Spjd start = &(*start)->pl_next; 3719168404Spjd } 3720168404Spjd 3721168404Spjd elem = NULL; 3722168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3723168404Spjd /* 3724168404Spjd * See if we've already found this property in our list. 3725168404Spjd */ 3726168404Spjd for (last = start; *last != NULL; 3727168404Spjd last = &(*last)->pl_next) { 3728168404Spjd if (strcmp((*last)->pl_user_prop, 3729168404Spjd nvpair_name(elem)) == 0) 3730168404Spjd break; 3731168404Spjd } 3732168404Spjd 3733168404Spjd if (*last == NULL) { 3734168404Spjd if ((entry = zfs_alloc(hdl, 3735185029Spjd sizeof (zprop_list_t))) == NULL || 3736168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3737168404Spjd nvpair_name(elem)))) == NULL) { 3738168404Spjd free(entry); 3739168404Spjd return (-1); 3740168404Spjd } 3741168404Spjd 3742185029Spjd entry->pl_prop = ZPROP_INVAL; 3743168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3744168404Spjd entry->pl_all = B_TRUE; 3745168404Spjd *last = entry; 3746168404Spjd } 3747168404Spjd } 3748168404Spjd } 3749168404Spjd 3750168404Spjd /* 3751168404Spjd * Now go through and check the width of any non-fixed columns 3752168404Spjd */ 3753168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3754168404Spjd if (entry->pl_fixed) 3755168404Spjd continue; 3756168404Spjd 3757185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 3758168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3759168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3760168404Spjd if (strlen(buf) > entry->pl_width) 3761168404Spjd entry->pl_width = strlen(buf); 3762168404Spjd } 3763219089Spjd if (received && zfs_prop_get_recvd(zhp, 3764219089Spjd zfs_prop_to_name(entry->pl_prop), 3765219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3766219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3767219089Spjd entry->pl_recvd_width = strlen(buf); 3768219089Spjd } else { 3769219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 3770219089Spjd &propval) == 0) { 3771219089Spjd verify(nvlist_lookup_string(propval, 3772219089Spjd ZPROP_VALUE, &strval) == 0); 3773219089Spjd if (strlen(strval) > entry->pl_width) 3774219089Spjd entry->pl_width = strlen(strval); 3775219089Spjd } 3776219089Spjd if (received && zfs_prop_get_recvd(zhp, 3777219089Spjd entry->pl_user_prop, 3778219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3779219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3780219089Spjd entry->pl_recvd_width = strlen(buf); 3781168404Spjd } 3782168404Spjd } 3783168404Spjd 3784168404Spjd return (0); 3785168404Spjd} 3786168404Spjd 3787185029Spjdint 3788185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 3789209962Smm char *resource, void *export, void *sharetab, 3790209962Smm int sharemax, zfs_share_op_t operation) 3791185029Spjd{ 3792185029Spjd zfs_cmd_t zc = { 0 }; 3793185029Spjd int error; 3794185029Spjd 3795185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3796185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3797209962Smm if (resource) 3798209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 3799185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 3800185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 3801185029Spjd zc.zc_share.z_sharetype = operation; 3802185029Spjd zc.zc_share.z_sharemax = sharemax; 3803185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 3804185029Spjd return (error); 3805185029Spjd} 3806185029Spjd 3807205198Sdelphijvoid 3808205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 3809205198Sdelphij{ 3810205198Sdelphij nvpair_t *curr; 3811205198Sdelphij 3812205198Sdelphij /* 3813205198Sdelphij * Keep a reference to the props-table against which we prune the 3814205198Sdelphij * properties. 3815205198Sdelphij */ 3816205198Sdelphij zhp->zfs_props_table = props; 3817205198Sdelphij 3818205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 3819205198Sdelphij 3820205198Sdelphij while (curr) { 3821205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 3822205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 3823205198Sdelphij 3824206199Sdelphij /* 3825219089Spjd * User properties will result in ZPROP_INVAL, and since we 3826219089Spjd * only know how to prune standard ZFS properties, we always 3827219089Spjd * leave these in the list. This can also happen if we 3828219089Spjd * encounter an unknown DSL property (when running older 3829219089Spjd * software, for example). 3830206199Sdelphij */ 3831206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 3832205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 3833205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 3834205198Sdelphij curr = next; 3835205198Sdelphij } 3836205198Sdelphij} 3837205198Sdelphij 3838209962Smm#ifdef sun 3839209962Smmstatic int 3840209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 3841209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 3842209962Smm{ 3843209962Smm zfs_cmd_t zc = { 0 }; 3844209962Smm nvlist_t *nvlist = NULL; 3845209962Smm int error; 3846209962Smm 3847209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3848209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3849209962Smm zc.zc_cookie = (uint64_t)cmd; 3850209962Smm 3851209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 3852209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 3853209962Smm (void) no_memory(hdl); 3854209962Smm return (NULL); 3855209962Smm } 3856209962Smm } 3857209962Smm 3858209962Smm switch (cmd) { 3859209962Smm case ZFS_SMB_ACL_ADD: 3860209962Smm case ZFS_SMB_ACL_REMOVE: 3861209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 3862209962Smm break; 3863209962Smm case ZFS_SMB_ACL_RENAME: 3864209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 3865209962Smm resource1) != 0) { 3866209962Smm (void) no_memory(hdl); 3867209962Smm return (-1); 3868209962Smm } 3869209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 3870209962Smm resource2) != 0) { 3871209962Smm (void) no_memory(hdl); 3872209962Smm return (-1); 3873209962Smm } 3874209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 3875209962Smm nvlist_free(nvlist); 3876209962Smm return (-1); 3877209962Smm } 3878209962Smm break; 3879209962Smm case ZFS_SMB_ACL_PURGE: 3880209962Smm break; 3881209962Smm default: 3882209962Smm return (-1); 3883209962Smm } 3884209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 3885209962Smm if (nvlist) 3886209962Smm nvlist_free(nvlist); 3887209962Smm return (error); 3888209962Smm} 3889209962Smm 3890209962Smmint 3891209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 3892209962Smm char *path, char *resource) 3893209962Smm{ 3894209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 3895209962Smm resource, NULL)); 3896209962Smm} 3897209962Smm 3898209962Smmint 3899209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 3900209962Smm char *path, char *resource) 3901209962Smm{ 3902209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 3903209962Smm resource, NULL)); 3904209962Smm} 3905209962Smm 3906209962Smmint 3907209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 3908209962Smm{ 3909209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 3910209962Smm NULL, NULL)); 3911209962Smm} 3912209962Smm 3913209962Smmint 3914209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 3915209962Smm char *oldname, char *newname) 3916209962Smm{ 3917209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 3918209962Smm oldname, newname)); 3919209962Smm} 3920209962Smm#endif /* sun */ 3921209962Smm 3922209962Smmint 3923209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 3924209962Smm zfs_userspace_cb_t func, void *arg) 3925209962Smm{ 3926209962Smm zfs_cmd_t zc = { 0 }; 3927209962Smm int error; 3928209962Smm zfs_useracct_t buf[100]; 3929209962Smm 3930209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3931209962Smm 3932209962Smm zc.zc_objset_type = type; 3933209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 3934209962Smm 3935209962Smm /* CONSTCOND */ 3936209962Smm while (1) { 3937209962Smm zfs_useracct_t *zua = buf; 3938209962Smm 3939209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 3940209962Smm error = ioctl(zhp->zfs_hdl->libzfs_fd, 3941209962Smm ZFS_IOC_USERSPACE_MANY, &zc); 3942209962Smm if (error || zc.zc_nvlist_dst_size == 0) 3943209962Smm break; 3944209962Smm 3945209962Smm while (zc.zc_nvlist_dst_size > 0) { 3946209962Smm error = func(arg, zua->zu_domain, zua->zu_rid, 3947209962Smm zua->zu_space); 3948209962Smm if (error != 0) 3949209962Smm return (error); 3950209962Smm zua++; 3951209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 3952209962Smm } 3953209962Smm } 3954209962Smm 3955209962Smm return (error); 3956209962Smm} 3957209962Smm 3958219089Spjdint 3959219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 3960219089Spjd boolean_t recursive, boolean_t temphold, boolean_t enoent_ok, 3961219089Spjd int cleanup_fd, uint64_t dsobj, uint64_t createtxg) 3962219089Spjd{ 3963219089Spjd zfs_cmd_t zc = { 0 }; 3964219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3965219089Spjd 3966219089Spjd ASSERT(!recursive || dsobj == 0); 3967219089Spjd 3968219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3969219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3970219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 3971219089Spjd >= sizeof (zc.zc_string)) 3972219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 3973219089Spjd zc.zc_cookie = recursive; 3974219089Spjd zc.zc_temphold = temphold; 3975219089Spjd zc.zc_cleanup_fd = cleanup_fd; 3976219089Spjd zc.zc_sendobj = dsobj; 3977219089Spjd zc.zc_createtxg = createtxg; 3978219089Spjd 3979219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) { 3980219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 3981219089Spjd 3982219089Spjd /* 3983219089Spjd * if it was recursive, the one that actually failed will be in 3984219089Spjd * zc.zc_name. 3985219089Spjd */ 3986219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3987219089Spjd "cannot hold '%s@%s'"), zc.zc_name, snapname); 3988219089Spjd switch (errno) { 3989219089Spjd case E2BIG: 3990219089Spjd /* 3991219089Spjd * Temporary tags wind up having the ds object id 3992219089Spjd * prepended. So even if we passed the length check 3993219089Spjd * above, it's still possible for the tag to wind 3994219089Spjd * up being slightly too long. 3995219089Spjd */ 3996219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf)); 3997219089Spjd case ENOTSUP: 3998219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3999219089Spjd "pool must be upgraded")); 4000219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 4001219089Spjd case EINVAL: 4002219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4003219089Spjd case EEXIST: 4004219089Spjd return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf)); 4005219089Spjd case ENOENT: 4006219089Spjd if (enoent_ok) 4007219089Spjd return (ENOENT); 4008219089Spjd /* FALLTHROUGH */ 4009219089Spjd default: 4010219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4011219089Spjd } 4012219089Spjd } 4013219089Spjd 4014219089Spjd return (0); 4015219089Spjd} 4016219089Spjd 4017219089Spjdint 4018219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4019219089Spjd boolean_t recursive) 4020219089Spjd{ 4021219089Spjd zfs_cmd_t zc = { 0 }; 4022219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4023219089Spjd 4024219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4025219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 4026219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 4027219089Spjd >= sizeof (zc.zc_string)) 4028219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 4029219089Spjd zc.zc_cookie = recursive; 4030219089Spjd 4031219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) { 4032219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4033219089Spjd 4034219089Spjd /* 4035219089Spjd * if it was recursive, the one that actually failed will be in 4036219089Spjd * zc.zc_name. 4037219089Spjd */ 4038219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4039219089Spjd "cannot release '%s' from '%s@%s'"), tag, zc.zc_name, 4040219089Spjd snapname); 4041219089Spjd switch (errno) { 4042219089Spjd case ESRCH: 4043219089Spjd return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf)); 4044219089Spjd case ENOTSUP: 4045219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4046219089Spjd "pool must be upgraded")); 4047219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 4048219089Spjd case EINVAL: 4049219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4050219089Spjd default: 4051219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4052219089Spjd } 4053219089Spjd } 4054219089Spjd 4055219089Spjd return (0); 4056219089Spjd} 4057219089Spjd 4058219089Spjdint 4059219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4060219089Spjd{ 4061219089Spjd zfs_cmd_t zc = { 0 }; 4062219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4063219089Spjd int nvsz = 2048; 4064219089Spjd void *nvbuf; 4065219089Spjd int err = 0; 4066219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4067219089Spjd 4068219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4069219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4070219089Spjd 4071219089Spjdtryagain: 4072219089Spjd 4073219089Spjd nvbuf = malloc(nvsz); 4074219089Spjd if (nvbuf == NULL) { 4075219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4076219089Spjd goto out; 4077219089Spjd } 4078219089Spjd 4079219089Spjd zc.zc_nvlist_dst_size = nvsz; 4080219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4081219089Spjd 4082219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4083219089Spjd 4084219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { 4085219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4086219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4087219089Spjd zc.zc_name); 4088219089Spjd switch (errno) { 4089219089Spjd case ENOMEM: 4090219089Spjd free(nvbuf); 4091219089Spjd nvsz = zc.zc_nvlist_dst_size; 4092219089Spjd goto tryagain; 4093219089Spjd 4094219089Spjd case ENOTSUP: 4095219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4096219089Spjd "pool must be upgraded")); 4097219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4098219089Spjd break; 4099219089Spjd case EINVAL: 4100219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4101219089Spjd break; 4102219089Spjd case ENOENT: 4103219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4104219089Spjd break; 4105219089Spjd default: 4106219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4107219089Spjd break; 4108219089Spjd } 4109219089Spjd } else { 4110219089Spjd /* success */ 4111219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4112219089Spjd if (rc) { 4113219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4114219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4115219089Spjd zc.zc_name); 4116219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4117219089Spjd } 4118219089Spjd } 4119219089Spjd 4120219089Spjd free(nvbuf); 4121219089Spjdout: 4122219089Spjd return (err); 4123219089Spjd} 4124219089Spjd 4125219089Spjdint 4126219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4127219089Spjd{ 4128219089Spjd zfs_cmd_t zc = { 0 }; 4129219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4130219089Spjd char *nvbuf; 4131219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4132219089Spjd size_t nvsz; 4133219089Spjd int err; 4134219089Spjd 4135219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4136219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4137219089Spjd 4138219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4139219089Spjd assert(err == 0); 4140219089Spjd 4141219089Spjd nvbuf = malloc(nvsz); 4142219089Spjd 4143219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4144219089Spjd assert(err == 0); 4145219089Spjd 4146219089Spjd zc.zc_nvlist_src_size = nvsz; 4147219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4148219089Spjd zc.zc_perm_action = un; 4149219089Spjd 4150219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4151219089Spjd 4152219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4153219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4154219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4155219089Spjd zc.zc_name); 4156219089Spjd switch (errno) { 4157219089Spjd case ENOTSUP: 4158219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4159219089Spjd "pool must be upgraded")); 4160219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4161219089Spjd break; 4162219089Spjd case EINVAL: 4163219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4164219089Spjd break; 4165219089Spjd case ENOENT: 4166219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4167219089Spjd break; 4168219089Spjd default: 4169219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4170219089Spjd break; 4171219089Spjd } 4172219089Spjd } 4173219089Spjd 4174219089Spjd free(nvbuf); 4175219089Spjd 4176219089Spjd return (err); 4177219089Spjd} 4178219089Spjd 4179219089Spjdint 4180219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4181219089Spjd{ 4182219089Spjd zfs_cmd_t zc = { 0 }; 4183219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4184219089Spjd int nvsz = 2048; 4185219089Spjd void *nvbuf; 4186219089Spjd int err = 0; 4187219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4188219089Spjd 4189219089Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 4190219089Spjd 4191219089Spjdtryagain: 4192219089Spjd 4193219089Spjd nvbuf = malloc(nvsz); 4194219089Spjd if (nvbuf == NULL) { 4195219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4196219089Spjd goto out; 4197219089Spjd } 4198219089Spjd 4199219089Spjd zc.zc_nvlist_dst_size = nvsz; 4200219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4201219089Spjd 4202219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4203219089Spjd 4204219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) { 4205219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4206219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4207219089Spjd zc.zc_name); 4208219089Spjd switch (errno) { 4209219089Spjd case ENOMEM: 4210219089Spjd free(nvbuf); 4211219089Spjd nvsz = zc.zc_nvlist_dst_size; 4212219089Spjd goto tryagain; 4213219089Spjd 4214219089Spjd case ENOTSUP: 4215219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4216219089Spjd "pool must be upgraded")); 4217219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4218219089Spjd break; 4219219089Spjd case EINVAL: 4220219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4221219089Spjd break; 4222219089Spjd case ENOENT: 4223219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4224219089Spjd break; 4225219089Spjd default: 4226219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4227219089Spjd break; 4228219089Spjd } 4229219089Spjd } else { 4230219089Spjd /* success */ 4231219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4232219089Spjd if (rc) { 4233219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4234219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4235219089Spjd zc.zc_name); 4236219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4237219089Spjd } 4238219089Spjd } 4239219089Spjd 4240219089Spjd free(nvbuf); 4241219089Spjdout: 4242219089Spjd return (err); 4243219089Spjd} 4244219089Spjd 4245219089Spjduint64_t 4246219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4247219089Spjd{ 4248219089Spjd uint64_t numdb; 4249219089Spjd uint64_t nblocks, volblocksize; 4250219089Spjd int ncopies; 4251219089Spjd char *strval; 4252219089Spjd 4253219089Spjd if (nvlist_lookup_string(props, 4254219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4255219089Spjd ncopies = atoi(strval); 4256219089Spjd else 4257219089Spjd ncopies = 1; 4258219089Spjd if (nvlist_lookup_uint64(props, 4259219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4260219089Spjd &volblocksize) != 0) 4261219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4262219089Spjd nblocks = volsize/volblocksize; 4263219089Spjd /* start with metadnode L0-L6 */ 4264219089Spjd numdb = 7; 4265219089Spjd /* calculate number of indirects */ 4266219089Spjd while (nblocks > 1) { 4267219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4268219089Spjd nblocks /= DNODES_PER_LEVEL; 4269219089Spjd numdb += nblocks; 4270219089Spjd } 4271219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4272219089Spjd volsize *= ncopies; 4273219089Spjd /* 4274219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4275219089Spjd * compressed, but in practice they compress down to about 4276219089Spjd * 1100 bytes 4277219089Spjd */ 4278219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4279219089Spjd volsize += numdb; 4280219089Spjd return (volsize); 4281219089Spjd} 4282219089Spjd 4283168404Spjd/* 4284168404Spjd * Attach/detach the given filesystem to/from the given jail. 4285168404Spjd */ 4286168404Spjdint 4287168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4288168404Spjd{ 4289168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4290168404Spjd zfs_cmd_t zc = { 0 }; 4291168404Spjd char errbuf[1024]; 4292168404Spjd int cmd, ret; 4293168404Spjd 4294168404Spjd if (attach) { 4295168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4296168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4297168404Spjd } else { 4298168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4299168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4300168404Spjd } 4301168404Spjd 4302168404Spjd switch (zhp->zfs_type) { 4303168404Spjd case ZFS_TYPE_VOLUME: 4304168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4305168404Spjd "volumes can not be jailed")); 4306168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4307168404Spjd case ZFS_TYPE_SNAPSHOT: 4308168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4309168404Spjd "snapshots can not be jailed")); 4310168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4311168404Spjd } 4312168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4313168404Spjd 4314168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4315168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4316168404Spjd zc.zc_jailid = jailid; 4317168404Spjd 4318168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4319168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4320168404Spjd zfs_standard_error(hdl, errno, errbuf); 4321168404Spjd 4322168404Spjd return (ret); 4323168404Spjd} 4324