libzfs_dataset.c revision 219089
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. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <ctype.h> 28168404Spjd#include <errno.h> 29168404Spjd#include <libintl.h> 30168404Spjd#include <math.h> 31168404Spjd#include <stdio.h> 32168404Spjd#include <stdlib.h> 33168404Spjd#include <strings.h> 34168404Spjd#include <unistd.h> 35185029Spjd#include <stddef.h> 36168404Spjd#include <zone.h> 37168404Spjd#include <fcntl.h> 38168404Spjd#include <sys/mntent.h> 39168404Spjd#include <sys/mount.h> 40185029Spjd#include <priv.h> 41185029Spjd#include <pwd.h> 42185029Spjd#include <grp.h> 43185029Spjd#include <stddef.h> 44209962Smm#include <idmap.h> 45168404Spjd 46219089Spjd#include <sys/dnode.h> 47168404Spjd#include <sys/spa.h> 48168404Spjd#include <sys/zap.h> 49209962Smm#include <sys/misc.h> 50168404Spjd#include <libzfs.h> 51168404Spjd 52168404Spjd#include "zfs_namecheck.h" 53168404Spjd#include "zfs_prop.h" 54168404Spjd#include "libzfs_impl.h" 55185029Spjd#include "zfs_deleg.h" 56168404Spjd 57209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 58209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 59168676Spjd 60168404Spjd/* 61168404Spjd * Given a single type (not a mask of types), return the type in a human 62168404Spjd * readable form. 63168404Spjd */ 64168404Spjdconst char * 65168404Spjdzfs_type_to_name(zfs_type_t type) 66168404Spjd{ 67168404Spjd switch (type) { 68168404Spjd case ZFS_TYPE_FILESYSTEM: 69168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 70168404Spjd case ZFS_TYPE_SNAPSHOT: 71168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 72168404Spjd case ZFS_TYPE_VOLUME: 73168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 74168404Spjd } 75168404Spjd 76168404Spjd return (NULL); 77168404Spjd} 78168404Spjd 79168404Spjd/* 80168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 81168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 82168404Spjd * We guess what the type would have been based on the path and the mask of 83168404Spjd * acceptable types. 84168404Spjd */ 85168404Spjdstatic const char * 86168404Spjdpath_to_str(const char *path, int types) 87168404Spjd{ 88168404Spjd /* 89168404Spjd * When given a single type, always report the exact type. 90168404Spjd */ 91168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 92168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 93168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 94168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 95168404Spjd if (types == ZFS_TYPE_VOLUME) 96168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 97168404Spjd 98168404Spjd /* 99168404Spjd * The user is requesting more than one type of dataset. If this is the 100168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 101168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 102168404Spjd * snapshot attribute and try again. 103168404Spjd */ 104168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 105168404Spjd if (strchr(path, '@') != NULL) 106168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 107168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 108168404Spjd } 109168404Spjd 110168404Spjd /* 111168404Spjd * The user has requested either filesystems or volumes. 112168404Spjd * We have no way of knowing a priori what type this would be, so always 113168404Spjd * report it as "filesystem" or "volume", our two primitive types. 114168404Spjd */ 115168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 116168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 117168404Spjd 118168404Spjd assert(types & ZFS_TYPE_VOLUME); 119168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 120168404Spjd} 121168404Spjd 122168404Spjd/* 123168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 124209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 125209962Smm * explain exactly why the name was not valid. 126168404Spjd */ 127219089Spjdint 128185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 129185029Spjd boolean_t modifying) 130168404Spjd{ 131168404Spjd namecheck_err_t why; 132168404Spjd char what; 133168404Spjd 134219089Spjd (void) zfs_prop_get_table(); 135168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 136168404Spjd if (hdl != NULL) { 137168404Spjd switch (why) { 138168404Spjd case NAME_ERR_TOOLONG: 139168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 140168404Spjd "name is too long")); 141168404Spjd break; 142168404Spjd 143168404Spjd case NAME_ERR_LEADING_SLASH: 144168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 145168404Spjd "leading slash in name")); 146168404Spjd break; 147168404Spjd 148168404Spjd case NAME_ERR_EMPTY_COMPONENT: 149168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 150168404Spjd "empty component in name")); 151168404Spjd break; 152168404Spjd 153168404Spjd case NAME_ERR_TRAILING_SLASH: 154168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 155168404Spjd "trailing slash in name")); 156168404Spjd break; 157168404Spjd 158168404Spjd case NAME_ERR_INVALCHAR: 159168404Spjd zfs_error_aux(hdl, 160168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 161168404Spjd "'%c' in name"), what); 162168404Spjd break; 163168404Spjd 164168404Spjd case NAME_ERR_MULTIPLE_AT: 165168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 166168404Spjd "multiple '@' delimiters in name")); 167168404Spjd break; 168168404Spjd 169168404Spjd case NAME_ERR_NOLETTER: 170168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 171168404Spjd "pool doesn't begin with a letter")); 172168404Spjd break; 173168404Spjd 174168404Spjd case NAME_ERR_RESERVED: 175168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 176168404Spjd "name is reserved")); 177168404Spjd break; 178168404Spjd 179168404Spjd case NAME_ERR_DISKLIKE: 180168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 181168404Spjd "reserved disk name")); 182168404Spjd break; 183168404Spjd } 184168404Spjd } 185168404Spjd 186168404Spjd return (0); 187168404Spjd } 188168404Spjd 189168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 190168404Spjd if (hdl != NULL) 191168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 192168404Spjd "snapshot delimiter '@' in filesystem name")); 193168404Spjd return (0); 194168404Spjd } 195168404Spjd 196168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 197168404Spjd if (hdl != NULL) 198168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 199168404Spjd "missing '@' delimiter in snapshot name")); 200168404Spjd return (0); 201168404Spjd } 202168404Spjd 203185029Spjd if (modifying && strchr(path, '%') != NULL) { 204185029Spjd if (hdl != NULL) 205185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 206185029Spjd "invalid character %c in name"), '%'); 207185029Spjd return (0); 208185029Spjd } 209185029Spjd 210168404Spjd return (-1); 211168404Spjd} 212168404Spjd 213168404Spjdint 214168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 215168404Spjd{ 216185029Spjd if (type == ZFS_TYPE_POOL) 217185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 218185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 219168404Spjd} 220168404Spjd 221168404Spjd/* 222168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 223168404Spjd * properties into a separate nvlist. 224168404Spjd */ 225185029Spjdstatic nvlist_t * 226185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 227168404Spjd{ 228168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 229168404Spjd nvpair_t *elem; 230168404Spjd nvlist_t *propval; 231185029Spjd nvlist_t *nvl; 232168404Spjd 233185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 234185029Spjd (void) no_memory(hdl); 235185029Spjd return (NULL); 236185029Spjd } 237168404Spjd 238168404Spjd elem = NULL; 239185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 240168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 241168404Spjd continue; 242168404Spjd 243168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 244185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 245185029Spjd nvlist_free(nvl); 246185029Spjd (void) no_memory(hdl); 247185029Spjd return (NULL); 248185029Spjd } 249168404Spjd } 250168404Spjd 251185029Spjd return (nvl); 252168404Spjd} 253168404Spjd 254185029Spjdstatic zpool_handle_t * 255185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 256185029Spjd{ 257185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 258185029Spjd zpool_handle_t *zph; 259185029Spjd 260185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 261185029Spjd if (hdl->libzfs_pool_handles != NULL) 262185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 263185029Spjd hdl->libzfs_pool_handles = zph; 264185029Spjd } 265185029Spjd return (zph); 266185029Spjd} 267185029Spjd 268185029Spjdstatic zpool_handle_t * 269185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 270185029Spjd{ 271185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 272185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 273185029Spjd 274185029Spjd while ((zph != NULL) && 275185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 276185029Spjd zph = zph->zpool_next; 277185029Spjd return (zph); 278185029Spjd} 279185029Spjd 280168404Spjd/* 281185029Spjd * Returns a handle to the pool that contains the provided dataset. 282185029Spjd * If a handle to that pool already exists then that handle is returned. 283185029Spjd * Otherwise, a new handle is created and added to the list of handles. 284185029Spjd */ 285185029Spjdstatic zpool_handle_t * 286185029Spjdzpool_handle(zfs_handle_t *zhp) 287185029Spjd{ 288185029Spjd char *pool_name; 289185029Spjd int len; 290185029Spjd zpool_handle_t *zph; 291185029Spjd 292185029Spjd len = strcspn(zhp->zfs_name, "/@") + 1; 293185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 294185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 295185029Spjd 296185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 297185029Spjd if (zph == NULL) 298185029Spjd zph = zpool_add_handle(zhp, pool_name); 299185029Spjd 300185029Spjd free(pool_name); 301185029Spjd return (zph); 302185029Spjd} 303185029Spjd 304185029Spjdvoid 305185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 306185029Spjd{ 307185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 308185029Spjd 309185029Spjd while (zph != NULL) { 310185029Spjd next = zph->zpool_next; 311185029Spjd zpool_close(zph); 312185029Spjd zph = next; 313185029Spjd } 314185029Spjd hdl->libzfs_pool_handles = NULL; 315185029Spjd} 316185029Spjd 317185029Spjd/* 318168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 319168404Spjd */ 320219089Spjdstatic int 321209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 322168404Spjd{ 323168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 324168404Spjd 325209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 326168404Spjd 327209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 328168404Spjd if (errno == ENOMEM) { 329209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 330168404Spjd return (-1); 331168404Spjd } 332168404Spjd } else { 333168404Spjd return (-1); 334168404Spjd } 335168404Spjd } 336209962Smm return (0); 337209962Smm} 338168404Spjd 339219089Spjd/* 340219089Spjd * Utility function to get the received properties of the given object. 341219089Spjd */ 342209962Smmstatic int 343219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 344219089Spjd{ 345219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 346219089Spjd nvlist_t *recvdprops; 347219089Spjd zfs_cmd_t zc = { 0 }; 348219089Spjd int err; 349219089Spjd 350219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 351219089Spjd return (-1); 352219089Spjd 353219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 354219089Spjd 355219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 356219089Spjd if (errno == ENOMEM) { 357219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 358219089Spjd return (-1); 359219089Spjd } 360219089Spjd } else { 361219089Spjd zcmd_free_nvlists(&zc); 362219089Spjd return (-1); 363219089Spjd } 364219089Spjd } 365219089Spjd 366219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 367219089Spjd zcmd_free_nvlists(&zc); 368219089Spjd if (err != 0) 369219089Spjd return (-1); 370219089Spjd 371219089Spjd nvlist_free(zhp->zfs_recvd_props); 372219089Spjd zhp->zfs_recvd_props = recvdprops; 373219089Spjd 374219089Spjd return (0); 375219089Spjd} 376219089Spjd 377219089Spjdstatic int 378209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 379209962Smm{ 380209962Smm nvlist_t *allprops, *userprops; 381168404Spjd 382209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 383209962Smm 384209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 385168404Spjd return (-1); 386168404Spjd } 387168404Spjd 388209962Smm /* 389209962Smm * XXX Why do we store the user props separately, in addition to 390209962Smm * storing them in zfs_props? 391209962Smm */ 392185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 393185029Spjd nvlist_free(allprops); 394168404Spjd return (-1); 395185029Spjd } 396168404Spjd 397185029Spjd nvlist_free(zhp->zfs_props); 398185029Spjd nvlist_free(zhp->zfs_user_props); 399185029Spjd 400185029Spjd zhp->zfs_props = allprops; 401185029Spjd zhp->zfs_user_props = userprops; 402185029Spjd 403168404Spjd return (0); 404168404Spjd} 405168404Spjd 406209962Smmstatic int 407209962Smmget_stats(zfs_handle_t *zhp) 408209962Smm{ 409209962Smm int rc = 0; 410209962Smm zfs_cmd_t zc = { 0 }; 411209962Smm 412209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 413209962Smm return (-1); 414209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 415209962Smm rc = -1; 416209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 417209962Smm rc = -1; 418209962Smm zcmd_free_nvlists(&zc); 419209962Smm return (rc); 420209962Smm} 421209962Smm 422168404Spjd/* 423168404Spjd * Refresh the properties currently stored in the handle. 424168404Spjd */ 425168404Spjdvoid 426168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 427168404Spjd{ 428168404Spjd (void) get_stats(zhp); 429168404Spjd} 430168404Spjd 431168404Spjd/* 432168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 433168404Spjd * zfs_iter_* to create child handles on the fly. 434168404Spjd */ 435209962Smmstatic int 436209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 437168404Spjd{ 438219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 439209962Smm return (-1); 440168404Spjd 441168404Spjd /* 442168404Spjd * We've managed to open the dataset and gather statistics. Determine 443168404Spjd * the high-level type. 444168404Spjd */ 445168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 446168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 447168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 448168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 449168404Spjd else 450168404Spjd abort(); 451168404Spjd 452168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 453168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 454168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 455168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 456168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 457168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 458168404Spjd else 459168404Spjd abort(); /* we should never see any other types */ 460168404Spjd 461219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 462219089Spjd return (-1); 463219089Spjd 464209962Smm return (0); 465209962Smm} 466209962Smm 467209962Smmzfs_handle_t * 468209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 469209962Smm{ 470209962Smm zfs_cmd_t zc = { 0 }; 471209962Smm 472209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 473209962Smm 474209962Smm if (zhp == NULL) 475209962Smm return (NULL); 476209962Smm 477209962Smm zhp->zfs_hdl = hdl; 478209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 479209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 480209962Smm free(zhp); 481209962Smm return (NULL); 482209962Smm } 483209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 484209962Smm zcmd_free_nvlists(&zc); 485209962Smm free(zhp); 486209962Smm return (NULL); 487209962Smm } 488209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 489209962Smm free(zhp); 490209962Smm zhp = NULL; 491209962Smm } 492209962Smm zcmd_free_nvlists(&zc); 493168404Spjd return (zhp); 494168404Spjd} 495168404Spjd 496209962Smmstatic zfs_handle_t * 497209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 498209962Smm{ 499209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 500209962Smm 501209962Smm if (zhp == NULL) 502209962Smm return (NULL); 503209962Smm 504209962Smm zhp->zfs_hdl = hdl; 505209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 506209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 507209962Smm free(zhp); 508209962Smm return (NULL); 509209962Smm } 510209962Smm return (zhp); 511209962Smm} 512209962Smm 513168404Spjd/* 514168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 515168404Spjd * argument is a mask of acceptable types. The function will print an 516168404Spjd * appropriate error message and return NULL if it can't be opened. 517168404Spjd */ 518168404Spjdzfs_handle_t * 519168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 520168404Spjd{ 521168404Spjd zfs_handle_t *zhp; 522168404Spjd char errbuf[1024]; 523168404Spjd 524168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 525168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 526168404Spjd 527168404Spjd /* 528168404Spjd * Validate the name before we even try to open it. 529168404Spjd */ 530185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 531168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 532168404Spjd "invalid dataset name")); 533168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 534168404Spjd return (NULL); 535168404Spjd } 536168404Spjd 537168404Spjd /* 538168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 539168404Spjd */ 540168404Spjd errno = 0; 541168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 542168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 543168404Spjd return (NULL); 544168404Spjd } 545168404Spjd 546168404Spjd if (!(types & zhp->zfs_type)) { 547168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 548168404Spjd zfs_close(zhp); 549168404Spjd return (NULL); 550168404Spjd } 551168404Spjd 552168404Spjd return (zhp); 553168404Spjd} 554168404Spjd 555168404Spjd/* 556168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 557168404Spjd */ 558168404Spjdvoid 559168404Spjdzfs_close(zfs_handle_t *zhp) 560168404Spjd{ 561168404Spjd if (zhp->zfs_mntopts) 562168404Spjd free(zhp->zfs_mntopts); 563168404Spjd nvlist_free(zhp->zfs_props); 564168404Spjd nvlist_free(zhp->zfs_user_props); 565219089Spjd nvlist_free(zhp->zfs_recvd_props); 566168404Spjd free(zhp); 567168404Spjd} 568168404Spjd 569209962Smmtypedef struct mnttab_node { 570209962Smm struct mnttab mtn_mt; 571209962Smm avl_node_t mtn_node; 572209962Smm} mnttab_node_t; 573209962Smm 574209962Smmstatic int 575209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 576209962Smm{ 577209962Smm const mnttab_node_t *mtn1 = arg1; 578209962Smm const mnttab_node_t *mtn2 = arg2; 579209962Smm int rv; 580209962Smm 581209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 582209962Smm 583209962Smm if (rv == 0) 584209962Smm return (0); 585209962Smm return (rv > 0 ? 1 : -1); 586209962Smm} 587209962Smm 588209962Smmvoid 589209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 590209962Smm{ 591209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 592209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 593209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 594209962Smm} 595209962Smm 596209962Smmvoid 597209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 598209962Smm{ 599209962Smm struct mnttab entry; 600209962Smm 601209962Smm rewind(hdl->libzfs_mnttab); 602209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 603209962Smm mnttab_node_t *mtn; 604209962Smm 605209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 606209962Smm continue; 607209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 608209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 609209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 610209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 611209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 612209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 613209962Smm } 614209962Smm} 615209962Smm 616209962Smmvoid 617209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 618209962Smm{ 619209962Smm void *cookie = NULL; 620209962Smm mnttab_node_t *mtn; 621209962Smm 622209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 623209962Smm free(mtn->mtn_mt.mnt_special); 624209962Smm free(mtn->mtn_mt.mnt_mountp); 625209962Smm free(mtn->mtn_mt.mnt_fstype); 626209962Smm free(mtn->mtn_mt.mnt_mntopts); 627209962Smm free(mtn); 628209962Smm } 629209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 630209962Smm} 631209962Smm 632209962Smmvoid 633209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 634209962Smm{ 635209962Smm hdl->libzfs_mnttab_enable = enable; 636209962Smm} 637209962Smm 638185029Spjdint 639209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 640209962Smm struct mnttab *entry) 641209962Smm{ 642209962Smm mnttab_node_t find; 643209962Smm mnttab_node_t *mtn; 644209962Smm 645209962Smm if (!hdl->libzfs_mnttab_enable) { 646209962Smm struct mnttab srch = { 0 }; 647209962Smm 648209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 649209962Smm libzfs_mnttab_fini(hdl); 650209962Smm rewind(hdl->libzfs_mnttab); 651209962Smm srch.mnt_special = (char *)fsname; 652209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 653209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 654209962Smm return (0); 655209962Smm else 656209962Smm return (ENOENT); 657209962Smm } 658209962Smm 659209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 660209962Smm libzfs_mnttab_update(hdl); 661209962Smm 662209962Smm find.mtn_mt.mnt_special = (char *)fsname; 663209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 664209962Smm if (mtn) { 665209962Smm *entry = mtn->mtn_mt; 666209962Smm return (0); 667209962Smm } 668209962Smm return (ENOENT); 669209962Smm} 670209962Smm 671209962Smmvoid 672209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 673209962Smm const char *mountp, const char *mntopts) 674209962Smm{ 675209962Smm mnttab_node_t *mtn; 676209962Smm 677209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 678209962Smm return; 679209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 680209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 681209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 682209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 683209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 684209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 685209962Smm} 686209962Smm 687209962Smmvoid 688209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 689209962Smm{ 690209962Smm mnttab_node_t find; 691209962Smm mnttab_node_t *ret; 692209962Smm 693209962Smm find.mtn_mt.mnt_special = (char *)fsname; 694209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 695209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 696209962Smm free(ret->mtn_mt.mnt_special); 697209962Smm free(ret->mtn_mt.mnt_mountp); 698209962Smm free(ret->mtn_mt.mnt_fstype); 699209962Smm free(ret->mtn_mt.mnt_mntopts); 700209962Smm free(ret); 701209962Smm } 702209962Smm} 703209962Smm 704209962Smmint 705185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 706168404Spjd{ 707185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 708168404Spjd 709185029Spjd if (zpool_handle == NULL) 710168404Spjd return (-1); 711168404Spjd 712185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 713185029Spjd ZPOOL_PROP_VERSION, NULL); 714168404Spjd return (0); 715168404Spjd} 716168404Spjd 717168404Spjd/* 718185029Spjd * The choice of reservation property depends on the SPA version. 719168404Spjd */ 720168404Spjdstatic int 721185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 722168404Spjd{ 723185029Spjd int spa_version; 724168404Spjd 725185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 726168404Spjd return (-1); 727168404Spjd 728185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 729185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 730185029Spjd else 731185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 732168404Spjd 733168404Spjd return (0); 734168404Spjd} 735168404Spjd 736168404Spjd/* 737168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 738168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 739168404Spjd * strings. 740168404Spjd */ 741168404Spjdnvlist_t * 742185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 743185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 744168404Spjd{ 745168404Spjd nvpair_t *elem; 746168404Spjd uint64_t intval; 747168404Spjd char *strval; 748185029Spjd zfs_prop_t prop; 749168404Spjd nvlist_t *ret; 750185029Spjd int chosen_normal = -1; 751185029Spjd int chosen_utf = -1; 752168404Spjd 753168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 754168404Spjd (void) no_memory(hdl); 755168404Spjd return (NULL); 756168404Spjd } 757168404Spjd 758209962Smm /* 759209962Smm * Make sure this property is valid and applies to this type. 760209962Smm */ 761209962Smm 762168404Spjd elem = NULL; 763168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 764185029Spjd const char *propname = nvpair_name(elem); 765168404Spjd 766209962Smm prop = zfs_name_to_prop(propname); 767209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 768185029Spjd /* 769209962Smm * This is a user property: make sure it's a 770185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 771185029Spjd */ 772185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 773185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 774185029Spjd "'%s' must be a string"), propname); 775185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 776185029Spjd goto error; 777168404Spjd } 778168404Spjd 779185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 780185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 781185029Spjd "property name '%s' is too long"), 782185029Spjd propname); 783185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 784185029Spjd goto error; 785185029Spjd } 786185029Spjd 787168404Spjd (void) nvpair_value_string(elem, &strval); 788168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 789168404Spjd (void) no_memory(hdl); 790168404Spjd goto error; 791168404Spjd } 792168404Spjd continue; 793168404Spjd } 794168404Spjd 795209962Smm /* 796209962Smm * Currently, only user properties can be modified on 797209962Smm * snapshots. 798209962Smm */ 799185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 800185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 801185029Spjd "this property can not be modified for snapshots")); 802185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 803185029Spjd goto error; 804185029Spjd } 805168404Spjd 806209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 807209962Smm zfs_userquota_prop_t uqtype; 808209962Smm char newpropname[128]; 809209962Smm char domain[128]; 810209962Smm uint64_t rid; 811209962Smm uint64_t valary[3]; 812209962Smm 813209962Smm if (userquota_propname_decode(propname, zoned, 814209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 815209962Smm zfs_error_aux(hdl, 816209962Smm dgettext(TEXT_DOMAIN, 817209962Smm "'%s' has an invalid user/group name"), 818209962Smm propname); 819209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 820209962Smm goto error; 821209962Smm } 822209962Smm 823209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 824209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 825209962Smm zfs_error_aux(hdl, 826209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 827209962Smm propname); 828209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 829209962Smm errbuf); 830209962Smm goto error; 831209962Smm } 832209962Smm 833209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 834209962Smm (void) nvpair_value_string(elem, &strval); 835209962Smm if (strcmp(strval, "none") == 0) { 836209962Smm intval = 0; 837209962Smm } else if (zfs_nicestrtonum(hdl, 838209962Smm strval, &intval) != 0) { 839209962Smm (void) zfs_error(hdl, 840209962Smm EZFS_BADPROP, errbuf); 841209962Smm goto error; 842209962Smm } 843209962Smm } else if (nvpair_type(elem) == 844209962Smm DATA_TYPE_UINT64) { 845209962Smm (void) nvpair_value_uint64(elem, &intval); 846209962Smm if (intval == 0) { 847209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 848209962Smm "use 'none' to disable " 849209962Smm "userquota/groupquota")); 850209962Smm goto error; 851209962Smm } 852209962Smm } else { 853209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 854209962Smm "'%s' must be a number"), propname); 855209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 856209962Smm goto error; 857209962Smm } 858209962Smm 859219089Spjd /* 860219089Spjd * Encode the prop name as 861219089Spjd * userquota@<hex-rid>-domain, to make it easy 862219089Spjd * for the kernel to decode. 863219089Spjd */ 864209962Smm (void) snprintf(newpropname, sizeof (newpropname), 865219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 866219089Spjd (longlong_t)rid, domain); 867209962Smm valary[0] = uqtype; 868209962Smm valary[1] = rid; 869209962Smm valary[2] = intval; 870209962Smm if (nvlist_add_uint64_array(ret, newpropname, 871209962Smm valary, 3) != 0) { 872209962Smm (void) no_memory(hdl); 873209962Smm goto error; 874209962Smm } 875209962Smm continue; 876209962Smm } 877209962Smm 878209962Smm if (prop == ZPROP_INVAL) { 879209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 880209962Smm "invalid property '%s'"), propname); 881209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 882209962Smm goto error; 883209962Smm } 884209962Smm 885168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 886168404Spjd zfs_error_aux(hdl, 887168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 888168404Spjd "apply to datasets of this type"), propname); 889168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 890168404Spjd goto error; 891168404Spjd } 892168404Spjd 893168404Spjd if (zfs_prop_readonly(prop) && 894185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 895168404Spjd zfs_error_aux(hdl, 896168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 897168404Spjd propname); 898168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 899168404Spjd goto error; 900168404Spjd } 901168404Spjd 902185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 903185029Spjd &strval, &intval, errbuf) != 0) 904185029Spjd goto error; 905185029Spjd 906168404Spjd /* 907185029Spjd * Perform some additional checks for specific properties. 908168404Spjd */ 909185029Spjd switch (prop) { 910185029Spjd case ZFS_PROP_VERSION: 911185029Spjd { 912185029Spjd int version; 913168404Spjd 914185029Spjd if (zhp == NULL) 915185029Spjd break; 916185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 917185029Spjd if (intval < version) { 918168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 919185029Spjd "Can not downgrade; already at version %u"), 920185029Spjd version); 921168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 922168404Spjd goto error; 923168404Spjd } 924168404Spjd break; 925168404Spjd } 926168404Spjd 927168404Spjd case ZFS_PROP_RECORDSIZE: 928168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 929168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 930168404Spjd if (intval < SPA_MINBLOCKSIZE || 931168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 932168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 933168404Spjd "'%s' must be power of 2 from %u " 934168404Spjd "to %uk"), propname, 935168404Spjd (uint_t)SPA_MINBLOCKSIZE, 936168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 937168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 938168404Spjd goto error; 939168404Spjd } 940168404Spjd break; 941168404Spjd 942219089Spjd case ZFS_PROP_MLSLABEL: 943219089Spjd { 944219089Spjd#ifdef sun 945219089Spjd /* 946219089Spjd * Verify the mlslabel string and convert to 947219089Spjd * internal hex label string. 948219089Spjd */ 949219089Spjd 950219089Spjd m_label_t *new_sl; 951219089Spjd char *hex = NULL; /* internal label string */ 952219089Spjd 953219089Spjd /* Default value is already OK. */ 954219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 955219089Spjd break; 956219089Spjd 957219089Spjd /* Verify the label can be converted to binary form */ 958219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 959219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 960219089Spjd L_NO_CORRECTION, NULL) == -1)) { 961219089Spjd goto badlabel; 962168404Spjd } 963168404Spjd 964219089Spjd /* Now translate to hex internal label string */ 965219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 966219089Spjd DEF_NAMES) != 0) { 967219089Spjd if (hex) 968219089Spjd free(hex); 969219089Spjd goto badlabel; 970219089Spjd } 971219089Spjd m_label_free(new_sl); 972219089Spjd 973219089Spjd /* If string is already in internal form, we're done. */ 974219089Spjd if (strcmp(strval, hex) == 0) { 975219089Spjd free(hex); 976219089Spjd break; 977219089Spjd } 978219089Spjd 979219089Spjd /* Replace the label string with the internal form. */ 980219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 981219089Spjd DATA_TYPE_STRING); 982219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 983219089Spjd hex) == 0); 984219089Spjd free(hex); 985219089Spjd 986168404Spjd break; 987168404Spjd 988219089Spjdbadlabel: 989219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 990219089Spjd "invalid mlslabel '%s'"), strval); 991219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 992219089Spjd m_label_free(new_sl); /* OK if null */ 993219089Spjd#else /* !sun */ 994219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 995219089Spjd "mlslabel is not supported on FreeBSD")); 996219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 997219089Spjd#endif /* !sun */ 998219089Spjd goto error; 999219089Spjd 1000219089Spjd } 1001219089Spjd 1002168404Spjd case ZFS_PROP_MOUNTPOINT: 1003185029Spjd { 1004185029Spjd namecheck_err_t why; 1005185029Spjd 1006168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1007168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1008168404Spjd break; 1009168404Spjd 1010185029Spjd if (mountpoint_namecheck(strval, &why)) { 1011185029Spjd switch (why) { 1012185029Spjd case NAME_ERR_LEADING_SLASH: 1013185029Spjd zfs_error_aux(hdl, 1014185029Spjd dgettext(TEXT_DOMAIN, 1015185029Spjd "'%s' must be an absolute path, " 1016185029Spjd "'none', or 'legacy'"), propname); 1017185029Spjd break; 1018185029Spjd case NAME_ERR_TOOLONG: 1019185029Spjd zfs_error_aux(hdl, 1020185029Spjd dgettext(TEXT_DOMAIN, 1021185029Spjd "component of '%s' is too long"), 1022185029Spjd propname); 1023185029Spjd break; 1024185029Spjd } 1025168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1026168404Spjd goto error; 1027168404Spjd } 1028185029Spjd } 1029185029Spjd 1030168404Spjd /*FALLTHRU*/ 1031168404Spjd 1032185029Spjd case ZFS_PROP_SHARESMB: 1033168404Spjd case ZFS_PROP_SHARENFS: 1034168404Spjd /* 1035185029Spjd * For the mountpoint and sharenfs or sharesmb 1036185029Spjd * properties, check if it can be set in a 1037185029Spjd * global/non-global zone based on 1038168404Spjd * the zoned property value: 1039168404Spjd * 1040168404Spjd * global zone non-global zone 1041168404Spjd * -------------------------------------------------- 1042168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1043168404Spjd * sharenfs (no) sharenfs (no) 1044185029Spjd * sharesmb (no) sharesmb (no) 1045168404Spjd * 1046168404Spjd * zoned=off mountpoint (yes) N/A 1047168404Spjd * sharenfs (yes) 1048185029Spjd * sharesmb (yes) 1049168404Spjd */ 1050168404Spjd if (zoned) { 1051168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1052168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1053168404Spjd "'%s' cannot be set on " 1054168404Spjd "dataset in a non-global zone"), 1055168404Spjd propname); 1056168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1057168404Spjd errbuf); 1058168404Spjd goto error; 1059185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1060185029Spjd prop == ZFS_PROP_SHARESMB) { 1061168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1062168404Spjd "'%s' cannot be set in " 1063168404Spjd "a non-global zone"), propname); 1064168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1065168404Spjd errbuf); 1066168404Spjd goto error; 1067168404Spjd } 1068168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1069168404Spjd /* 1070168404Spjd * If zoned property is 'off', this must be in 1071209962Smm * a global zone. If not, something is wrong. 1072168404Spjd */ 1073168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1074168404Spjd "'%s' cannot be set while dataset " 1075168404Spjd "'zoned' property is set"), propname); 1076168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1077168404Spjd goto error; 1078168404Spjd } 1079168404Spjd 1080168404Spjd /* 1081185029Spjd * At this point, it is legitimate to set the 1082185029Spjd * property. Now we want to make sure that the 1083185029Spjd * property value is valid if it is sharenfs. 1084168404Spjd */ 1085185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1086185029Spjd prop == ZFS_PROP_SHARESMB) && 1087185029Spjd strcmp(strval, "on") != 0 && 1088185029Spjd strcmp(strval, "off") != 0) { 1089185029Spjd zfs_share_proto_t proto; 1090168404Spjd 1091185029Spjd if (prop == ZFS_PROP_SHARESMB) 1092185029Spjd proto = PROTO_SMB; 1093185029Spjd else 1094185029Spjd proto = PROTO_NFS; 1095185029Spjd 1096185029Spjd /* 1097185029Spjd * Must be an valid sharing protocol 1098185029Spjd * option string so init the libshare 1099185029Spjd * in order to enable the parser and 1100185029Spjd * then parse the options. We use the 1101185029Spjd * control API since we don't care about 1102185029Spjd * the current configuration and don't 1103185029Spjd * want the overhead of loading it 1104185029Spjd * until we actually do something. 1105185029Spjd */ 1106185029Spjd 1107185029Spjd if (zfs_init_libshare(hdl, 1108185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1109185029Spjd /* 1110185029Spjd * An error occurred so we can't do 1111185029Spjd * anything 1112185029Spjd */ 1113185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1114185029Spjd "'%s' cannot be set: problem " 1115185029Spjd "in share initialization"), 1116185029Spjd propname); 1117185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1118185029Spjd errbuf); 1119185029Spjd goto error; 1120185029Spjd } 1121185029Spjd 1122185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1123185029Spjd /* 1124185029Spjd * There was an error in parsing so 1125185029Spjd * deal with it by issuing an error 1126185029Spjd * message and leaving after 1127185029Spjd * uninitializing the the libshare 1128185029Spjd * interface. 1129185029Spjd */ 1130185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1131185029Spjd "'%s' cannot be set to invalid " 1132185029Spjd "options"), propname); 1133185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1134185029Spjd errbuf); 1135185029Spjd zfs_uninit_libshare(hdl); 1136185029Spjd goto error; 1137185029Spjd } 1138185029Spjd zfs_uninit_libshare(hdl); 1139168404Spjd } 1140185029Spjd 1141168404Spjd break; 1142185029Spjd case ZFS_PROP_UTF8ONLY: 1143185029Spjd chosen_utf = (int)intval; 1144185029Spjd break; 1145185029Spjd case ZFS_PROP_NORMALIZE: 1146185029Spjd chosen_normal = (int)intval; 1147185029Spjd break; 1148168404Spjd } 1149168404Spjd 1150168404Spjd /* 1151168404Spjd * For changes to existing volumes, we have some additional 1152168404Spjd * checks to enforce. 1153168404Spjd */ 1154168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1155168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1156168404Spjd ZFS_PROP_VOLSIZE); 1157168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1158168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1159168404Spjd char buf[64]; 1160168404Spjd 1161168404Spjd switch (prop) { 1162168404Spjd case ZFS_PROP_RESERVATION: 1163185029Spjd case ZFS_PROP_REFRESERVATION: 1164168404Spjd if (intval > volsize) { 1165168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1166168404Spjd "'%s' is greater than current " 1167168404Spjd "volume size"), propname); 1168168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1169168404Spjd errbuf); 1170168404Spjd goto error; 1171168404Spjd } 1172168404Spjd break; 1173168404Spjd 1174168404Spjd case ZFS_PROP_VOLSIZE: 1175168404Spjd if (intval % blocksize != 0) { 1176168404Spjd zfs_nicenum(blocksize, buf, 1177168404Spjd sizeof (buf)); 1178168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1179168404Spjd "'%s' must be a multiple of " 1180168404Spjd "volume block size (%s)"), 1181168404Spjd propname, buf); 1182168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1183168404Spjd errbuf); 1184168404Spjd goto error; 1185168404Spjd } 1186168404Spjd 1187168404Spjd if (intval == 0) { 1188168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1189168404Spjd "'%s' cannot be zero"), 1190168404Spjd propname); 1191168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1192168404Spjd errbuf); 1193168404Spjd goto error; 1194168404Spjd } 1195168404Spjd break; 1196168404Spjd } 1197168404Spjd } 1198168404Spjd } 1199168404Spjd 1200168404Spjd /* 1201185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1202185029Spjd * enforce rejection of non-UTF8 names. 1203185029Spjd * 1204185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1205185029Spjd * was explicitly not chosen, it is an error. 1206185029Spjd */ 1207185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1208185029Spjd if (nvlist_add_uint64(ret, 1209185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1210185029Spjd (void) no_memory(hdl); 1211185029Spjd goto error; 1212185029Spjd } 1213185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1214185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1215185029Spjd "'%s' must be set 'on' if normalization chosen"), 1216185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1217185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1218185029Spjd goto error; 1219185029Spjd } 1220219089Spjd return (ret); 1221185029Spjd 1222219089Spjderror: 1223219089Spjd nvlist_free(ret); 1224219089Spjd return (NULL); 1225219089Spjd} 1226219089Spjd 1227219089Spjdint 1228219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1229219089Spjd{ 1230219089Spjd uint64_t old_volsize; 1231219089Spjd uint64_t new_volsize; 1232219089Spjd uint64_t old_reservation; 1233219089Spjd uint64_t new_reservation; 1234219089Spjd zfs_prop_t resv_prop; 1235219089Spjd 1236185029Spjd /* 1237168404Spjd * If this is an existing volume, and someone is setting the volsize, 1238168404Spjd * make sure that it matches the reservation, or add it if necessary. 1239168404Spjd */ 1240219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1241219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1242219089Spjd return (-1); 1243219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1244219089Spjd if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != 1245219089Spjd old_reservation) || nvlist_lookup_uint64(nvl, 1246219089Spjd zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { 1247219089Spjd return (0); 1248219089Spjd } 1249219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1250219089Spjd &new_volsize) != 0) 1251219089Spjd return (-1); 1252219089Spjd new_reservation = zvol_volsize_to_reservation(new_volsize, 1253219089Spjd zhp->zfs_props); 1254219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1255219089Spjd new_reservation) != 0) { 1256219089Spjd (void) no_memory(zhp->zfs_hdl); 1257219089Spjd return (-1); 1258219089Spjd } 1259219089Spjd return (1); 1260219089Spjd} 1261168404Spjd 1262219089Spjdvoid 1263219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1264219089Spjd char *errbuf) 1265219089Spjd{ 1266219089Spjd switch (err) { 1267185029Spjd 1268219089Spjd case ENOSPC: 1269219089Spjd /* 1270219089Spjd * For quotas and reservations, ENOSPC indicates 1271219089Spjd * something different; setting a quota or reservation 1272219089Spjd * doesn't use any disk space. 1273219089Spjd */ 1274219089Spjd switch (prop) { 1275219089Spjd case ZFS_PROP_QUOTA: 1276219089Spjd case ZFS_PROP_REFQUOTA: 1277219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1278219089Spjd "size is less than current used or " 1279219089Spjd "reserved space")); 1280219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1281219089Spjd break; 1282219089Spjd 1283219089Spjd case ZFS_PROP_RESERVATION: 1284219089Spjd case ZFS_PROP_REFRESERVATION: 1285219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1286219089Spjd "size is greater than available space")); 1287219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1288219089Spjd break; 1289219089Spjd 1290219089Spjd default: 1291219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1292219089Spjd break; 1293168404Spjd } 1294219089Spjd break; 1295219089Spjd 1296219089Spjd case EBUSY: 1297219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1298219089Spjd break; 1299219089Spjd 1300219089Spjd case EROFS: 1301219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1302219089Spjd break; 1303219089Spjd 1304219089Spjd case ENOTSUP: 1305219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1306219089Spjd "pool and or dataset must be upgraded to set this " 1307219089Spjd "property or value")); 1308219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1309219089Spjd break; 1310219089Spjd 1311219089Spjd case ERANGE: 1312219089Spjd if (prop == ZFS_PROP_COMPRESSION) { 1313219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1314219089Spjd "property setting is not allowed on " 1315219089Spjd "bootable datasets")); 1316219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1317219089Spjd } else { 1318219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1319219089Spjd } 1320219089Spjd break; 1321219089Spjd 1322219089Spjd case EINVAL: 1323219089Spjd if (prop == ZPROP_INVAL) { 1324219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1325219089Spjd } else { 1326219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1327219089Spjd } 1328219089Spjd break; 1329219089Spjd 1330219089Spjd case EOVERFLOW: 1331219089Spjd /* 1332219089Spjd * This platform can't address a volume this big. 1333219089Spjd */ 1334219089Spjd#ifdef _ILP32 1335219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1336219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1337219089Spjd break; 1338219089Spjd } 1339219089Spjd#endif 1340219089Spjd /* FALLTHROUGH */ 1341219089Spjd default: 1342219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1343168404Spjd } 1344168404Spjd} 1345168404Spjd 1346168404Spjd/* 1347168404Spjd * Given a property name and value, set the property for the given dataset. 1348168404Spjd */ 1349168404Spjdint 1350168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1351168404Spjd{ 1352168404Spjd zfs_cmd_t zc = { 0 }; 1353168404Spjd int ret = -1; 1354168404Spjd prop_changelist_t *cl = NULL; 1355168404Spjd char errbuf[1024]; 1356168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1357168404Spjd nvlist_t *nvl = NULL, *realprops; 1358168404Spjd zfs_prop_t prop; 1359185029Spjd boolean_t do_prefix; 1360185029Spjd uint64_t idx; 1361219089Spjd int added_resv; 1362168404Spjd 1363168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1364168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1365168404Spjd zhp->zfs_name); 1366168404Spjd 1367168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1368168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1369168404Spjd (void) no_memory(hdl); 1370168404Spjd goto error; 1371168404Spjd } 1372168404Spjd 1373185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1374168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1375168404Spjd goto error; 1376185029Spjd 1377168404Spjd nvlist_free(nvl); 1378168404Spjd nvl = realprops; 1379168404Spjd 1380168404Spjd prop = zfs_name_to_prop(propname); 1381168404Spjd 1382168404Spjd /* We don't support those properties on FreeBSD. */ 1383168404Spjd switch (prop) { 1384197867Strasz case ZFS_PROP_DEVICES: 1385168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1386197867Strasz case ZFS_PROP_XATTR: 1387197867Strasz case ZFS_PROP_VSCAN: 1388197867Strasz case ZFS_PROP_NBMAND: 1389219089Spjd case ZFS_PROP_MLSLABEL: 1390168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1391168404Spjd "property '%s' not supported on FreeBSD", propname); 1392168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1393168404Spjd goto error; 1394168404Spjd } 1395168404Spjd 1396219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1397219089Spjd if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) 1398219089Spjd goto error; 1399219089Spjd } 1400219089Spjd 1401185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1402168404Spjd goto error; 1403168404Spjd 1404168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1405168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1406168404Spjd "child dataset with inherited mountpoint is used " 1407168404Spjd "in a non-global zone")); 1408168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1409168404Spjd goto error; 1410168404Spjd } 1411168404Spjd 1412185029Spjd /* 1413185029Spjd * If the dataset's canmount property is being set to noauto, 1414185029Spjd * then we want to prevent unmounting & remounting it. 1415185029Spjd */ 1416185029Spjd do_prefix = !((prop == ZFS_PROP_CANMOUNT) && 1417185029Spjd (zprop_string_to_index(prop, propval, &idx, 1418185029Spjd ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); 1419185029Spjd 1420185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1421168404Spjd goto error; 1422168404Spjd 1423168404Spjd /* 1424168404Spjd * Execute the corresponding ioctl() to set this property. 1425168404Spjd */ 1426168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1427168404Spjd 1428185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1429168404Spjd goto error; 1430168404Spjd 1431185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1432209962Smm 1433168404Spjd if (ret != 0) { 1434219089Spjd zfs_setprop_error(hdl, prop, errno, errbuf); 1435219089Spjd if (added_resv && errno == ENOSPC) { 1436219089Spjd /* clean up the volsize property we tried to set */ 1437219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1438219089Spjd ZFS_PROP_VOLSIZE); 1439219089Spjd nvlist_free(nvl); 1440219089Spjd zcmd_free_nvlists(&zc); 1441219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1442219089Spjd goto error; 1443219089Spjd if (nvlist_add_uint64(nvl, 1444219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1445219089Spjd old_volsize) != 0) 1446219089Spjd goto error; 1447219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1448219089Spjd goto error; 1449219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1450168404Spjd } 1451168404Spjd } else { 1452185029Spjd if (do_prefix) 1453185029Spjd ret = changelist_postfix(cl); 1454185029Spjd 1455168404Spjd /* 1456168404Spjd * Refresh the statistics so the new property value 1457168404Spjd * is reflected. 1458168404Spjd */ 1459185029Spjd if (ret == 0) 1460168404Spjd (void) get_stats(zhp); 1461168404Spjd } 1462168404Spjd 1463168404Spjderror: 1464168404Spjd nvlist_free(nvl); 1465168404Spjd zcmd_free_nvlists(&zc); 1466168404Spjd if (cl) 1467168404Spjd changelist_free(cl); 1468168404Spjd return (ret); 1469168404Spjd} 1470168404Spjd 1471168404Spjd/* 1472219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1473219089Spjd * is TRUE, revert to the received value, if any. 1474168404Spjd */ 1475168404Spjdint 1476219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1477168404Spjd{ 1478168404Spjd zfs_cmd_t zc = { 0 }; 1479168404Spjd int ret; 1480168404Spjd prop_changelist_t *cl; 1481168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1482168404Spjd char errbuf[1024]; 1483168404Spjd zfs_prop_t prop; 1484168404Spjd 1485168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1486168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1487168404Spjd 1488219089Spjd zc.zc_cookie = received; 1489185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1490168404Spjd /* 1491168404Spjd * For user properties, the amount of work we have to do is very 1492168404Spjd * small, so just do it here. 1493168404Spjd */ 1494168404Spjd if (!zfs_prop_user(propname)) { 1495168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1496168404Spjd "invalid property")); 1497168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1498168404Spjd } 1499168404Spjd 1500168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1501168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1502168404Spjd 1503185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1504168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1505168404Spjd 1506168404Spjd return (0); 1507168404Spjd } 1508168404Spjd 1509168404Spjd /* 1510168404Spjd * Verify that this property is inheritable. 1511168404Spjd */ 1512168404Spjd if (zfs_prop_readonly(prop)) 1513168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1514168404Spjd 1515219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1516168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1517168404Spjd 1518168404Spjd /* 1519168404Spjd * Check to see if the value applies to this type 1520168404Spjd */ 1521168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1522168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1523168404Spjd 1524168404Spjd /* 1525219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1526168404Spjd */ 1527168404Spjd propname = zfs_prop_to_name(prop); 1528168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1529168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1530168404Spjd 1531168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1532168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1533168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1534168404Spjd "dataset is used in a non-global zone")); 1535168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1536168404Spjd } 1537168404Spjd 1538168404Spjd /* 1539168404Spjd * Determine datasets which will be affected by this change, if any. 1540168404Spjd */ 1541185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1542168404Spjd return (-1); 1543168404Spjd 1544168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1545168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1546168404Spjd "child dataset with inherited mountpoint is used " 1547168404Spjd "in a non-global zone")); 1548168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1549168404Spjd goto error; 1550168404Spjd } 1551168404Spjd 1552168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1553168404Spjd goto error; 1554168404Spjd 1555185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1556168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1557168404Spjd } else { 1558168404Spjd 1559168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1560168404Spjd goto error; 1561168404Spjd 1562168404Spjd /* 1563168404Spjd * Refresh the statistics so the new property is reflected. 1564168404Spjd */ 1565168404Spjd (void) get_stats(zhp); 1566168404Spjd } 1567168404Spjd 1568168404Spjderror: 1569168404Spjd changelist_free(cl); 1570168404Spjd return (ret); 1571168404Spjd} 1572168404Spjd 1573168404Spjd/* 1574168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1575168404Spjd * extract them appropriately. 1576168404Spjd */ 1577168404Spjdstatic uint64_t 1578168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1579168404Spjd{ 1580168404Spjd nvlist_t *nv; 1581168404Spjd uint64_t value; 1582168404Spjd 1583168404Spjd *source = NULL; 1584168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1585168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1586185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1587185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1588168404Spjd } else { 1589205198Sdelphij verify(!zhp->zfs_props_table || 1590205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1591168404Spjd value = zfs_prop_default_numeric(prop); 1592168404Spjd *source = ""; 1593168404Spjd } 1594168404Spjd 1595168404Spjd return (value); 1596168404Spjd} 1597168404Spjd 1598168404Spjdstatic char * 1599168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1600168404Spjd{ 1601168404Spjd nvlist_t *nv; 1602168404Spjd char *value; 1603168404Spjd 1604168404Spjd *source = NULL; 1605168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1606168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1607185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1608185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1609168404Spjd } else { 1610205198Sdelphij verify(!zhp->zfs_props_table || 1611205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1612168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1613168404Spjd value = ""; 1614168404Spjd *source = ""; 1615168404Spjd } 1616168404Spjd 1617168404Spjd return (value); 1618168404Spjd} 1619168404Spjd 1620219089Spjdstatic boolean_t 1621219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1622219089Spjd{ 1623219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1624219089Spjd} 1625219089Spjd 1626219089Spjdstatic void 1627219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1628219089Spjd{ 1629219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1630219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1631219089Spjd} 1632219089Spjd 1633219089Spjdstatic void 1634219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1635219089Spjd{ 1636219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1637219089Spjd *cookie = 0; 1638219089Spjd} 1639219089Spjd 1640168404Spjd/* 1641168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1642168404Spjd * zfs_prop_get_int() are built using this interface. 1643168404Spjd * 1644168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1645168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1646168404Spjd * If they differ from the on-disk values, report the current values and mark 1647168404Spjd * the source "temporary". 1648168404Spjd */ 1649168404Spjdstatic int 1650185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1651168404Spjd char **source, uint64_t *val) 1652168404Spjd{ 1653185029Spjd zfs_cmd_t zc = { 0 }; 1654185029Spjd nvlist_t *zplprops = NULL; 1655168404Spjd struct mnttab mnt; 1656168404Spjd char *mntopt_on = NULL; 1657168404Spjd char *mntopt_off = NULL; 1658219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1659168404Spjd 1660168404Spjd *source = NULL; 1661168404Spjd 1662168404Spjd switch (prop) { 1663168404Spjd case ZFS_PROP_ATIME: 1664168404Spjd mntopt_on = MNTOPT_ATIME; 1665168404Spjd mntopt_off = MNTOPT_NOATIME; 1666168404Spjd break; 1667168404Spjd 1668168404Spjd case ZFS_PROP_DEVICES: 1669168404Spjd mntopt_on = MNTOPT_DEVICES; 1670168404Spjd mntopt_off = MNTOPT_NODEVICES; 1671168404Spjd break; 1672168404Spjd 1673168404Spjd case ZFS_PROP_EXEC: 1674168404Spjd mntopt_on = MNTOPT_EXEC; 1675168404Spjd mntopt_off = MNTOPT_NOEXEC; 1676168404Spjd break; 1677168404Spjd 1678168404Spjd case ZFS_PROP_READONLY: 1679168404Spjd mntopt_on = MNTOPT_RO; 1680168404Spjd mntopt_off = MNTOPT_RW; 1681168404Spjd break; 1682168404Spjd 1683168404Spjd case ZFS_PROP_SETUID: 1684168404Spjd mntopt_on = MNTOPT_SETUID; 1685168404Spjd mntopt_off = MNTOPT_NOSETUID; 1686168404Spjd break; 1687168404Spjd 1688168404Spjd case ZFS_PROP_XATTR: 1689168404Spjd mntopt_on = MNTOPT_XATTR; 1690168404Spjd mntopt_off = MNTOPT_NOXATTR; 1691168404Spjd break; 1692185029Spjd 1693185029Spjd case ZFS_PROP_NBMAND: 1694185029Spjd mntopt_on = MNTOPT_NBMAND; 1695185029Spjd mntopt_off = MNTOPT_NONBMAND; 1696185029Spjd break; 1697168404Spjd } 1698168404Spjd 1699168404Spjd /* 1700168404Spjd * Because looking up the mount options is potentially expensive 1701168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1702168404Spjd * we're looking up a property which requires its presence. 1703168404Spjd */ 1704168404Spjd if (!zhp->zfs_mntcheck && 1705168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1706209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1707209962Smm struct mnttab entry; 1708168404Spjd 1709209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1710209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1711168404Spjd entry.mnt_mntopts); 1712168404Spjd if (zhp->zfs_mntopts == NULL) 1713168404Spjd return (-1); 1714168404Spjd } 1715168404Spjd 1716168404Spjd zhp->zfs_mntcheck = B_TRUE; 1717168404Spjd } 1718168404Spjd 1719168404Spjd if (zhp->zfs_mntopts == NULL) 1720168404Spjd mnt.mnt_mntopts = ""; 1721168404Spjd else 1722168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1723168404Spjd 1724168404Spjd switch (prop) { 1725168404Spjd case ZFS_PROP_ATIME: 1726168404Spjd case ZFS_PROP_DEVICES: 1727168404Spjd case ZFS_PROP_EXEC: 1728168404Spjd case ZFS_PROP_READONLY: 1729168404Spjd case ZFS_PROP_SETUID: 1730168404Spjd case ZFS_PROP_XATTR: 1731185029Spjd case ZFS_PROP_NBMAND: 1732168404Spjd *val = getprop_uint64(zhp, prop, source); 1733168404Spjd 1734219089Spjd if (received) 1735219089Spjd break; 1736219089Spjd 1737168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1738168404Spjd *val = B_TRUE; 1739168404Spjd if (src) 1740185029Spjd *src = ZPROP_SRC_TEMPORARY; 1741168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1742168404Spjd *val = B_FALSE; 1743168404Spjd if (src) 1744185029Spjd *src = ZPROP_SRC_TEMPORARY; 1745168404Spjd } 1746168404Spjd break; 1747168404Spjd 1748168404Spjd case ZFS_PROP_CANMOUNT: 1749219089Spjd case ZFS_PROP_VOLSIZE: 1750168404Spjd case ZFS_PROP_QUOTA: 1751185029Spjd case ZFS_PROP_REFQUOTA: 1752168404Spjd case ZFS_PROP_RESERVATION: 1753185029Spjd case ZFS_PROP_REFRESERVATION: 1754168404Spjd *val = getprop_uint64(zhp, prop, source); 1755219089Spjd 1756219089Spjd if (*source == NULL) { 1757219089Spjd /* not default, must be local */ 1758168404Spjd *source = zhp->zfs_name; 1759219089Spjd } 1760168404Spjd break; 1761168404Spjd 1762168404Spjd case ZFS_PROP_MOUNTED: 1763168404Spjd *val = (zhp->zfs_mntopts != NULL); 1764168404Spjd break; 1765168404Spjd 1766168404Spjd case ZFS_PROP_NUMCLONES: 1767168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1768168404Spjd break; 1769168404Spjd 1770185029Spjd case ZFS_PROP_VERSION: 1771185029Spjd case ZFS_PROP_NORMALIZE: 1772185029Spjd case ZFS_PROP_UTF8ONLY: 1773185029Spjd case ZFS_PROP_CASE: 1774185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1775185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1776185029Spjd return (-1); 1777185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1778185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1779185029Spjd zcmd_free_nvlists(&zc); 1780219089Spjd return (-1); 1781185029Spjd } 1782185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1783185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1784185029Spjd val) != 0) { 1785185029Spjd zcmd_free_nvlists(&zc); 1786219089Spjd return (-1); 1787185029Spjd } 1788185029Spjd if (zplprops) 1789185029Spjd nvlist_free(zplprops); 1790185029Spjd zcmd_free_nvlists(&zc); 1791185029Spjd break; 1792185029Spjd 1793168404Spjd default: 1794185029Spjd switch (zfs_prop_get_type(prop)) { 1795185029Spjd case PROP_TYPE_NUMBER: 1796185029Spjd case PROP_TYPE_INDEX: 1797185029Spjd *val = getprop_uint64(zhp, prop, source); 1798185029Spjd /* 1799209962Smm * If we tried to use a default value for a 1800185029Spjd * readonly property, it means that it was not 1801219089Spjd * present. 1802185029Spjd */ 1803185029Spjd if (zfs_prop_readonly(prop) && 1804219089Spjd *source != NULL && (*source)[0] == '\0') { 1805219089Spjd *source = NULL; 1806185029Spjd } 1807185029Spjd break; 1808185029Spjd 1809185029Spjd case PROP_TYPE_STRING: 1810185029Spjd default: 1811185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1812185029Spjd "cannot get non-numeric property")); 1813185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1814185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1815185029Spjd } 1816168404Spjd } 1817168404Spjd 1818168404Spjd return (0); 1819168404Spjd} 1820168404Spjd 1821168404Spjd/* 1822168404Spjd * Calculate the source type, given the raw source string. 1823168404Spjd */ 1824168404Spjdstatic void 1825185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1826168404Spjd char *statbuf, size_t statlen) 1827168404Spjd{ 1828185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1829168404Spjd return; 1830168404Spjd 1831168404Spjd if (source == NULL) { 1832185029Spjd *srctype = ZPROP_SRC_NONE; 1833168404Spjd } else if (source[0] == '\0') { 1834185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1835219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 1836219089Spjd *srctype = ZPROP_SRC_RECEIVED; 1837168404Spjd } else { 1838168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1839185029Spjd *srctype = ZPROP_SRC_LOCAL; 1840168404Spjd } else { 1841168404Spjd (void) strlcpy(statbuf, source, statlen); 1842185029Spjd *srctype = ZPROP_SRC_INHERITED; 1843168404Spjd } 1844168404Spjd } 1845168404Spjd 1846168404Spjd} 1847168404Spjd 1848219089Spjdint 1849219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 1850219089Spjd size_t proplen, boolean_t literal) 1851219089Spjd{ 1852219089Spjd zfs_prop_t prop; 1853219089Spjd int err = 0; 1854219089Spjd 1855219089Spjd if (zhp->zfs_recvd_props == NULL) 1856219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 1857219089Spjd return (-1); 1858219089Spjd 1859219089Spjd prop = zfs_name_to_prop(propname); 1860219089Spjd 1861219089Spjd if (prop != ZPROP_INVAL) { 1862219089Spjd uint64_t cookie; 1863219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 1864219089Spjd return (-1); 1865219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 1866219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 1867219089Spjd NULL, NULL, 0, literal); 1868219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 1869219089Spjd } else if (zfs_prop_userquota(propname)) { 1870219089Spjd return (-1); 1871219089Spjd } else { 1872219089Spjd nvlist_t *propval; 1873219089Spjd char *recvdval; 1874219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 1875219089Spjd propname, &propval) != 0) 1876219089Spjd return (-1); 1877219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 1878219089Spjd &recvdval) == 0); 1879219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 1880219089Spjd } 1881219089Spjd 1882219089Spjd return (err == 0 ? 0 : -1); 1883219089Spjd} 1884219089Spjd 1885168404Spjd/* 1886168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 1887168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 1888168404Spjd * human-readable form. 1889168404Spjd * 1890168404Spjd * Returns 0 on success, or -1 on error. 1891168404Spjd */ 1892168404Spjdint 1893168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1894185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1895168404Spjd{ 1896168404Spjd char *source = NULL; 1897168404Spjd uint64_t val; 1898168404Spjd char *str; 1899168404Spjd const char *strval; 1900219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1901168404Spjd 1902168404Spjd /* 1903168404Spjd * Check to see if this property applies to our object 1904168404Spjd */ 1905168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1906168404Spjd return (-1); 1907168404Spjd 1908219089Spjd if (received && zfs_prop_readonly(prop)) 1909219089Spjd return (-1); 1910219089Spjd 1911168404Spjd if (src) 1912185029Spjd *src = ZPROP_SRC_NONE; 1913168404Spjd 1914168404Spjd switch (prop) { 1915168404Spjd case ZFS_PROP_CREATION: 1916168404Spjd /* 1917168404Spjd * 'creation' is a time_t stored in the statistics. We convert 1918168404Spjd * this into a string unless 'literal' is specified. 1919168404Spjd */ 1920168404Spjd { 1921168404Spjd val = getprop_uint64(zhp, prop, &source); 1922168404Spjd time_t time = (time_t)val; 1923168404Spjd struct tm t; 1924168404Spjd 1925168404Spjd if (literal || 1926168404Spjd localtime_r(&time, &t) == NULL || 1927168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1928168404Spjd &t) == 0) 1929168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 1930168404Spjd } 1931168404Spjd break; 1932168404Spjd 1933168404Spjd case ZFS_PROP_MOUNTPOINT: 1934168404Spjd /* 1935168404Spjd * Getting the precise mountpoint can be tricky. 1936168404Spjd * 1937168404Spjd * - for 'none' or 'legacy', return those values. 1938168404Spjd * - for inherited mountpoints, we want to take everything 1939168404Spjd * after our ancestor and append it to the inherited value. 1940168404Spjd * 1941168404Spjd * If the pool has an alternate root, we want to prepend that 1942168404Spjd * root to any values we return. 1943168404Spjd */ 1944185029Spjd 1945168404Spjd str = getprop_string(zhp, prop, &source); 1946168404Spjd 1947185029Spjd if (str[0] == '/') { 1948185029Spjd char buf[MAXPATHLEN]; 1949185029Spjd char *root = buf; 1950219089Spjd const char *relpath; 1951168404Spjd 1952219089Spjd /* 1953219089Spjd * If we inherit the mountpoint, even from a dataset 1954219089Spjd * with a received value, the source will be the path of 1955219089Spjd * the dataset we inherit from. If source is 1956219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 1957219089Spjd * inherited. 1958219089Spjd */ 1959219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 1960219089Spjd relpath = ""; 1961219089Spjd } else { 1962219089Spjd relpath = zhp->zfs_name + strlen(source); 1963219089Spjd if (relpath[0] == '/') 1964219089Spjd relpath++; 1965219089Spjd } 1966185029Spjd 1967185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 1968185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 1969185029Spjd (strcmp(root, "-") == 0)) 1970185029Spjd root[0] = '\0'; 1971185029Spjd /* 1972185029Spjd * Special case an alternate root of '/'. This will 1973185029Spjd * avoid having multiple leading slashes in the 1974185029Spjd * mountpoint path. 1975185029Spjd */ 1976185029Spjd if (strcmp(root, "/") == 0) 1977185029Spjd root++; 1978185029Spjd 1979185029Spjd /* 1980185029Spjd * If the mountpoint is '/' then skip over this 1981185029Spjd * if we are obtaining either an alternate root or 1982185029Spjd * an inherited mountpoint. 1983185029Spjd */ 1984185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 1985185029Spjd relpath[0] != '\0')) 1986168404Spjd str++; 1987168404Spjd 1988168404Spjd if (relpath[0] == '\0') 1989168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 1990168404Spjd root, str); 1991168404Spjd else 1992168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 1993168404Spjd root, str, relpath[0] == '@' ? "" : "/", 1994168404Spjd relpath); 1995168404Spjd } else { 1996168404Spjd /* 'legacy' or 'none' */ 1997168404Spjd (void) strlcpy(propbuf, str, proplen); 1998168404Spjd } 1999168404Spjd 2000168404Spjd break; 2001168404Spjd 2002168404Spjd case ZFS_PROP_ORIGIN: 2003168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2004168404Spjd proplen); 2005168404Spjd /* 2006168404Spjd * If there is no parent at all, return failure to indicate that 2007168404Spjd * it doesn't apply to this dataset. 2008168404Spjd */ 2009168404Spjd if (propbuf[0] == '\0') 2010168404Spjd return (-1); 2011168404Spjd break; 2012168404Spjd 2013168404Spjd case ZFS_PROP_QUOTA: 2014185029Spjd case ZFS_PROP_REFQUOTA: 2015168404Spjd case ZFS_PROP_RESERVATION: 2016185029Spjd case ZFS_PROP_REFRESERVATION: 2017185029Spjd 2018168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2019168404Spjd return (-1); 2020168404Spjd 2021168404Spjd /* 2022168404Spjd * If quota or reservation is 0, we translate this into 'none' 2023168404Spjd * (unless literal is set), and indicate that it's the default 2024168404Spjd * value. Otherwise, we print the number nicely and indicate 2025168404Spjd * that its set locally. 2026168404Spjd */ 2027168404Spjd if (val == 0) { 2028168404Spjd if (literal) 2029168404Spjd (void) strlcpy(propbuf, "0", proplen); 2030168404Spjd else 2031168404Spjd (void) strlcpy(propbuf, "none", proplen); 2032168404Spjd } else { 2033168404Spjd if (literal) 2034168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2035168404Spjd (u_longlong_t)val); 2036168404Spjd else 2037168404Spjd zfs_nicenum(val, propbuf, proplen); 2038168404Spjd } 2039168404Spjd break; 2040168404Spjd 2041168404Spjd case ZFS_PROP_COMPRESSRATIO: 2042168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2043168404Spjd return (-1); 2044219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2045219089Spjd (u_longlong_t)(val / 100), 2046219089Spjd (u_longlong_t)(val % 100)); 2047168404Spjd break; 2048168404Spjd 2049168404Spjd case ZFS_PROP_TYPE: 2050168404Spjd switch (zhp->zfs_type) { 2051168404Spjd case ZFS_TYPE_FILESYSTEM: 2052168404Spjd str = "filesystem"; 2053168404Spjd break; 2054168404Spjd case ZFS_TYPE_VOLUME: 2055168404Spjd str = "volume"; 2056168404Spjd break; 2057168404Spjd case ZFS_TYPE_SNAPSHOT: 2058168404Spjd str = "snapshot"; 2059168404Spjd break; 2060168404Spjd default: 2061168404Spjd abort(); 2062168404Spjd } 2063168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2064168404Spjd break; 2065168404Spjd 2066168404Spjd case ZFS_PROP_MOUNTED: 2067168404Spjd /* 2068168404Spjd * The 'mounted' property is a pseudo-property that described 2069168404Spjd * whether the filesystem is currently mounted. Even though 2070168404Spjd * it's a boolean value, the typical values of "on" and "off" 2071168404Spjd * don't make sense, so we translate to "yes" and "no". 2072168404Spjd */ 2073168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2074168404Spjd src, &source, &val) != 0) 2075168404Spjd return (-1); 2076168404Spjd if (val) 2077168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2078168404Spjd else 2079168404Spjd (void) strlcpy(propbuf, "no", proplen); 2080168404Spjd break; 2081168404Spjd 2082168404Spjd case ZFS_PROP_NAME: 2083168404Spjd /* 2084168404Spjd * The 'name' property is a pseudo-property derived from the 2085168404Spjd * dataset name. It is presented as a real property to simplify 2086168404Spjd * consumers. 2087168404Spjd */ 2088168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2089168404Spjd break; 2090168404Spjd 2091219089Spjd case ZFS_PROP_MLSLABEL: 2092219089Spjd { 2093219089Spjd#ifdef sun 2094219089Spjd m_label_t *new_sl = NULL; 2095219089Spjd char *ascii = NULL; /* human readable label */ 2096219089Spjd 2097219089Spjd (void) strlcpy(propbuf, 2098219089Spjd getprop_string(zhp, prop, &source), proplen); 2099219089Spjd 2100219089Spjd if (literal || (strcasecmp(propbuf, 2101219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2102219089Spjd break; 2103219089Spjd 2104219089Spjd /* 2105219089Spjd * Try to translate the internal hex string to 2106219089Spjd * human-readable output. If there are any 2107219089Spjd * problems just use the hex string. 2108219089Spjd */ 2109219089Spjd 2110219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2111219089Spjd L_NO_CORRECTION, NULL) == -1) { 2112219089Spjd m_label_free(new_sl); 2113219089Spjd break; 2114219089Spjd } 2115219089Spjd 2116219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2117219089Spjd DEF_NAMES) != 0) { 2118219089Spjd if (ascii) 2119219089Spjd free(ascii); 2120219089Spjd m_label_free(new_sl); 2121219089Spjd break; 2122219089Spjd } 2123219089Spjd m_label_free(new_sl); 2124219089Spjd 2125219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2126219089Spjd free(ascii); 2127219089Spjd#else /* !sun */ 2128219089Spjd propbuf[0] = '\0'; 2129219089Spjd#endif /* !sun */ 2130219089Spjd } 2131219089Spjd break; 2132219089Spjd 2133168404Spjd default: 2134185029Spjd switch (zfs_prop_get_type(prop)) { 2135185029Spjd case PROP_TYPE_NUMBER: 2136185029Spjd if (get_numeric_property(zhp, prop, src, 2137185029Spjd &source, &val) != 0) 2138185029Spjd return (-1); 2139185029Spjd if (literal) 2140185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2141185029Spjd (u_longlong_t)val); 2142185029Spjd else 2143185029Spjd zfs_nicenum(val, propbuf, proplen); 2144185029Spjd break; 2145185029Spjd 2146185029Spjd case PROP_TYPE_STRING: 2147185029Spjd (void) strlcpy(propbuf, 2148185029Spjd getprop_string(zhp, prop, &source), proplen); 2149185029Spjd break; 2150185029Spjd 2151185029Spjd case PROP_TYPE_INDEX: 2152185029Spjd if (get_numeric_property(zhp, prop, src, 2153185029Spjd &source, &val) != 0) 2154185029Spjd return (-1); 2155185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2156185029Spjd return (-1); 2157185029Spjd (void) strlcpy(propbuf, strval, proplen); 2158185029Spjd break; 2159185029Spjd 2160185029Spjd default: 2161185029Spjd abort(); 2162185029Spjd } 2163168404Spjd } 2164168404Spjd 2165168404Spjd get_source(zhp, src, source, statbuf, statlen); 2166168404Spjd 2167168404Spjd return (0); 2168168404Spjd} 2169168404Spjd 2170168404Spjd/* 2171168404Spjd * Utility function to get the given numeric property. Does no validation that 2172168404Spjd * the given property is the appropriate type; should only be used with 2173168404Spjd * hard-coded property types. 2174168404Spjd */ 2175168404Spjduint64_t 2176168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2177168404Spjd{ 2178168404Spjd char *source; 2179168404Spjd uint64_t val; 2180168404Spjd 2181185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2182168404Spjd 2183168404Spjd return (val); 2184168404Spjd} 2185168404Spjd 2186185029Spjdint 2187185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2188185029Spjd{ 2189185029Spjd char buf[64]; 2190185029Spjd 2191209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2192185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2193185029Spjd} 2194185029Spjd 2195168404Spjd/* 2196168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2197168404Spjd */ 2198168404Spjdint 2199168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2200185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2201168404Spjd{ 2202168404Spjd char *source; 2203168404Spjd 2204168404Spjd /* 2205168404Spjd * Check to see if this property applies to our object 2206168404Spjd */ 2207185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2208168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2209168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2210168404Spjd zfs_prop_to_name(prop))); 2211185029Spjd } 2212168404Spjd 2213168404Spjd if (src) 2214185029Spjd *src = ZPROP_SRC_NONE; 2215168404Spjd 2216168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2217168404Spjd return (-1); 2218168404Spjd 2219168404Spjd get_source(zhp, src, source, statbuf, statlen); 2220168404Spjd 2221168404Spjd return (0); 2222168404Spjd} 2223168404Spjd 2224209962Smmstatic int 2225209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2226209962Smm char **domainp, idmap_rid_t *ridp) 2227209962Smm{ 2228209962Smm#ifdef sun 2229209962Smm idmap_get_handle_t *get_hdl = NULL; 2230209962Smm idmap_stat status; 2231209962Smm int err = EINVAL; 2232209962Smm 2233219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2234209962Smm goto out; 2235209962Smm 2236209962Smm if (isuser) { 2237209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2238209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2239209962Smm } else { 2240209962Smm err = idmap_get_sidbygid(get_hdl, id, 2241209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2242209962Smm } 2243209962Smm if (err == IDMAP_SUCCESS && 2244209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2245209962Smm status == IDMAP_SUCCESS) 2246209962Smm err = 0; 2247209962Smm else 2248209962Smm err = EINVAL; 2249209962Smmout: 2250209962Smm if (get_hdl) 2251209962Smm idmap_get_destroy(get_hdl); 2252209962Smm return (err); 2253209962Smm#else /* !sun */ 2254209962Smm assert(!"invalid code path"); 2255209962Smm#endif /* !sun */ 2256209962Smm} 2257209962Smm 2258168404Spjd/* 2259209962Smm * convert the propname into parameters needed by kernel 2260209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2261209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2262209962Smm */ 2263209962Smmstatic int 2264209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2265209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2266209962Smm{ 2267209962Smm zfs_userquota_prop_t type; 2268209962Smm char *cp, *end; 2269209962Smm char *numericsid = NULL; 2270209962Smm boolean_t isuser; 2271209962Smm 2272209962Smm domain[0] = '\0'; 2273209962Smm 2274209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2275209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2276209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2277209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2278209962Smm break; 2279209962Smm } 2280209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2281209962Smm return (EINVAL); 2282209962Smm *typep = type; 2283209962Smm 2284209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2285209962Smm type == ZFS_PROP_USERUSED); 2286209962Smm 2287209962Smm cp = strchr(propname, '@') + 1; 2288209962Smm 2289209962Smm if (strchr(cp, '@')) { 2290209962Smm#ifdef sun 2291209962Smm /* 2292209962Smm * It's a SID name (eg "user@domain") that needs to be 2293209962Smm * turned into S-1-domainID-RID. 2294209962Smm */ 2295209962Smm directory_error_t e; 2296209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2297209962Smm return (ENOENT); 2298209962Smm if (isuser) { 2299209962Smm e = directory_sid_from_user_name(NULL, 2300209962Smm cp, &numericsid); 2301209962Smm } else { 2302209962Smm e = directory_sid_from_group_name(NULL, 2303209962Smm cp, &numericsid); 2304209962Smm } 2305209962Smm if (e != NULL) { 2306209962Smm directory_error_free(e); 2307209962Smm return (ENOENT); 2308209962Smm } 2309209962Smm if (numericsid == NULL) 2310209962Smm return (ENOENT); 2311209962Smm cp = numericsid; 2312209962Smm /* will be further decoded below */ 2313209962Smm#else /* !sun */ 2314219089Spjd return (ENOENT); 2315209962Smm#endif /* !sun */ 2316209962Smm } 2317209962Smm 2318209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2319209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2320209962Smm (void) strlcpy(domain, cp, domainlen); 2321209962Smm cp = strrchr(domain, '-'); 2322209962Smm *cp = '\0'; 2323209962Smm cp++; 2324209962Smm 2325209962Smm errno = 0; 2326209962Smm *ridp = strtoull(cp, &end, 10); 2327209962Smm if (numericsid) { 2328209962Smm free(numericsid); 2329209962Smm numericsid = NULL; 2330209962Smm } 2331209962Smm if (errno != 0 || *end != '\0') 2332209962Smm return (EINVAL); 2333209962Smm } else if (!isdigit(*cp)) { 2334209962Smm /* 2335209962Smm * It's a user/group name (eg "user") that needs to be 2336209962Smm * turned into a uid/gid 2337209962Smm */ 2338209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2339209962Smm return (ENOENT); 2340209962Smm if (isuser) { 2341209962Smm struct passwd *pw; 2342209962Smm pw = getpwnam(cp); 2343209962Smm if (pw == NULL) 2344209962Smm return (ENOENT); 2345209962Smm *ridp = pw->pw_uid; 2346209962Smm } else { 2347209962Smm struct group *gr; 2348209962Smm gr = getgrnam(cp); 2349209962Smm if (gr == NULL) 2350209962Smm return (ENOENT); 2351209962Smm *ridp = gr->gr_gid; 2352209962Smm } 2353209962Smm } else { 2354209962Smm /* It's a user/group ID (eg "12345"). */ 2355209962Smm uid_t id = strtoul(cp, &end, 10); 2356209962Smm idmap_rid_t rid; 2357209962Smm char *mapdomain; 2358209962Smm 2359209962Smm if (*end != '\0') 2360209962Smm return (EINVAL); 2361209962Smm if (id > MAXUID) { 2362209962Smm /* It's an ephemeral ID. */ 2363209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2364209962Smm &mapdomain, &rid) != 0) 2365209962Smm return (ENOENT); 2366209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2367209962Smm *ridp = rid; 2368209962Smm } else { 2369209962Smm *ridp = id; 2370209962Smm } 2371209962Smm } 2372209962Smm 2373209962Smm ASSERT3P(numericsid, ==, NULL); 2374209962Smm return (0); 2375209962Smm} 2376209962Smm 2377209962Smmstatic int 2378209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2379209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2380209962Smm{ 2381209962Smm int err; 2382209962Smm zfs_cmd_t zc = { 0 }; 2383209962Smm 2384209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2385209962Smm 2386209962Smm err = userquota_propname_decode(propname, 2387209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2388209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2389209962Smm zc.zc_objset_type = *typep; 2390209962Smm if (err) 2391209962Smm return (err); 2392209962Smm 2393209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2394209962Smm if (err) 2395209962Smm return (err); 2396209962Smm 2397209962Smm *propvalue = zc.zc_cookie; 2398209962Smm return (0); 2399209962Smm} 2400209962Smm 2401209962Smmint 2402209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2403209962Smm uint64_t *propvalue) 2404209962Smm{ 2405209962Smm zfs_userquota_prop_t type; 2406209962Smm 2407209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2408209962Smm &type)); 2409209962Smm} 2410209962Smm 2411209962Smmint 2412209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2413209962Smm char *propbuf, int proplen, boolean_t literal) 2414209962Smm{ 2415209962Smm int err; 2416209962Smm uint64_t propvalue; 2417209962Smm zfs_userquota_prop_t type; 2418209962Smm 2419209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2420209962Smm &type); 2421209962Smm 2422209962Smm if (err) 2423209962Smm return (err); 2424209962Smm 2425209962Smm if (literal) { 2426209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2427209962Smm } else if (propvalue == 0 && 2428209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2429209962Smm (void) strlcpy(propbuf, "none", proplen); 2430209962Smm } else { 2431209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2432209962Smm } 2433209962Smm return (0); 2434209962Smm} 2435209962Smm 2436209962Smm/* 2437168404Spjd * Returns the name of the given zfs handle. 2438168404Spjd */ 2439168404Spjdconst char * 2440168404Spjdzfs_get_name(const zfs_handle_t *zhp) 2441168404Spjd{ 2442168404Spjd return (zhp->zfs_name); 2443168404Spjd} 2444168404Spjd 2445168404Spjd/* 2446168404Spjd * Returns the type of the given zfs handle. 2447168404Spjd */ 2448168404Spjdzfs_type_t 2449168404Spjdzfs_get_type(const zfs_handle_t *zhp) 2450168404Spjd{ 2451168404Spjd return (zhp->zfs_type); 2452168404Spjd} 2453168404Spjd 2454209962Smmstatic int 2455209962Smmzfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc) 2456209962Smm{ 2457209962Smm int rc; 2458209962Smm uint64_t orig_cookie; 2459209962Smm 2460209962Smm orig_cookie = zc->zc_cookie; 2461209962Smmtop: 2462209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 2463209962Smm rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); 2464209962Smm 2465209962Smm if (rc == -1) { 2466209962Smm switch (errno) { 2467209962Smm case ENOMEM: 2468209962Smm /* expand nvlist memory and try again */ 2469209962Smm if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { 2470209962Smm zcmd_free_nvlists(zc); 2471209962Smm return (-1); 2472209962Smm } 2473209962Smm zc->zc_cookie = orig_cookie; 2474209962Smm goto top; 2475209962Smm /* 2476209962Smm * An errno value of ESRCH indicates normal completion. 2477209962Smm * If ENOENT is returned, then the underlying dataset 2478209962Smm * has been removed since we obtained the handle. 2479209962Smm */ 2480209962Smm case ESRCH: 2481209962Smm case ENOENT: 2482209962Smm rc = 1; 2483209962Smm break; 2484209962Smm default: 2485209962Smm rc = zfs_standard_error(zhp->zfs_hdl, errno, 2486209962Smm dgettext(TEXT_DOMAIN, 2487209962Smm "cannot iterate filesystems")); 2488209962Smm break; 2489209962Smm } 2490209962Smm } 2491209962Smm return (rc); 2492209962Smm} 2493209962Smm 2494168404Spjd/* 2495168404Spjd * Iterate over all child filesystems 2496168404Spjd */ 2497168404Spjdint 2498168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2499168404Spjd{ 2500168404Spjd zfs_cmd_t zc = { 0 }; 2501168404Spjd zfs_handle_t *nzhp; 2502168404Spjd int ret; 2503168404Spjd 2504185029Spjd if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 2505185029Spjd return (0); 2506185029Spjd 2507209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2508209962Smm return (-1); 2509209962Smm 2510209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, 2511209962Smm &zc)) == 0) { 2512168404Spjd /* 2513168404Spjd * Silently ignore errors, as the only plausible explanation is 2514168404Spjd * that the pool has since been removed. 2515168404Spjd */ 2516209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2517209962Smm &zc)) == NULL) { 2518168404Spjd continue; 2519209962Smm } 2520168404Spjd 2521209962Smm if ((ret = func(nzhp, data)) != 0) { 2522209962Smm zcmd_free_nvlists(&zc); 2523168404Spjd return (ret); 2524209962Smm } 2525168404Spjd } 2526209962Smm zcmd_free_nvlists(&zc); 2527209962Smm return ((ret < 0) ? ret : 0); 2528168404Spjd} 2529168404Spjd 2530168404Spjd/* 2531168404Spjd * Iterate over all snapshots 2532168404Spjd */ 2533168404Spjdint 2534168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2535168404Spjd{ 2536168404Spjd zfs_cmd_t zc = { 0 }; 2537168404Spjd zfs_handle_t *nzhp; 2538168404Spjd int ret; 2539168404Spjd 2540185029Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 2541185029Spjd return (0); 2542185029Spjd 2543209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2544209962Smm return (-1); 2545209962Smm while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, 2546209962Smm &zc)) == 0) { 2547168404Spjd 2548209962Smm if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 2549209962Smm &zc)) == NULL) { 2550209962Smm continue; 2551209962Smm } 2552209962Smm 2553209962Smm if ((ret = func(nzhp, data)) != 0) { 2554209962Smm zcmd_free_nvlists(&zc); 2555168404Spjd return (ret); 2556209962Smm } 2557168404Spjd } 2558209962Smm zcmd_free_nvlists(&zc); 2559209962Smm return ((ret < 0) ? ret : 0); 2560168404Spjd} 2561168404Spjd 2562168404Spjd/* 2563168404Spjd * Iterate over all children, snapshots and filesystems 2564168404Spjd */ 2565168404Spjdint 2566168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2567168404Spjd{ 2568168404Spjd int ret; 2569168404Spjd 2570168404Spjd if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 2571168404Spjd return (ret); 2572168404Spjd 2573168404Spjd return (zfs_iter_snapshots(zhp, func, data)); 2574168404Spjd} 2575168404Spjd 2576168404Spjd/* 2577219089Spjd * Is one dataset name a child dataset of another? 2578219089Spjd * 2579219089Spjd * Needs to handle these cases: 2580219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2581219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2582219089Spjd * Descendant? No. No. No. Yes. 2583219089Spjd */ 2584219089Spjdstatic boolean_t 2585219089Spjdis_descendant(const char *ds1, const char *ds2) 2586219089Spjd{ 2587219089Spjd size_t d1len = strlen(ds1); 2588219089Spjd 2589219089Spjd /* ds2 can't be a descendant if it's smaller */ 2590219089Spjd if (strlen(ds2) < d1len) 2591219089Spjd return (B_FALSE); 2592219089Spjd 2593219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2594219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2595219089Spjd} 2596219089Spjd 2597219089Spjd/* 2598168404Spjd * Given a complete name, return just the portion that refers to the parent. 2599168404Spjd * Can return NULL if this is a pool. 2600168404Spjd */ 2601168404Spjdstatic int 2602168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2603168404Spjd{ 2604168404Spjd char *loc; 2605168404Spjd 2606168404Spjd if ((loc = strrchr(path, '/')) == NULL) 2607168404Spjd return (-1); 2608168404Spjd 2609168404Spjd (void) strncpy(buf, path, MIN(buflen, loc - path)); 2610168404Spjd buf[loc - path] = '\0'; 2611168404Spjd 2612168404Spjd return (0); 2613168404Spjd} 2614168404Spjd 2615168404Spjd/* 2616185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2617185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2618185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2619185029Spjd * length of already existing prefix of the given path. We also fetch the 2620185029Spjd * 'zoned' property, which is used to validate property settings when creating 2621185029Spjd * new datasets. 2622168404Spjd */ 2623168404Spjdstatic int 2624185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2625185029Spjd boolean_t accept_ancestor, int *prefixlen) 2626168404Spjd{ 2627168404Spjd zfs_cmd_t zc = { 0 }; 2628168404Spjd char parent[ZFS_MAXNAMELEN]; 2629168404Spjd char *slash; 2630168404Spjd zfs_handle_t *zhp; 2631168404Spjd char errbuf[1024]; 2632219089Spjd uint64_t is_zoned; 2633168404Spjd 2634209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2635209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2636168404Spjd 2637168404Spjd /* get parent, and check to see if this is just a pool */ 2638168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2639168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2640168404Spjd "missing dataset name")); 2641168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2642168404Spjd } 2643168404Spjd 2644168404Spjd /* check to see if the pool exists */ 2645168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2646168404Spjd slash = parent + strlen(parent); 2647168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2648168404Spjd zc.zc_name[slash - parent] = '\0'; 2649168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2650168404Spjd errno == ENOENT) { 2651168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2652168404Spjd "no such pool '%s'"), zc.zc_name); 2653168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2654168404Spjd } 2655168404Spjd 2656168404Spjd /* check to see if the parent dataset exists */ 2657185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2658185029Spjd if (errno == ENOENT && accept_ancestor) { 2659185029Spjd /* 2660185029Spjd * Go deeper to find an ancestor, give up on top level. 2661185029Spjd */ 2662185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2663185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2664185029Spjd "no such pool '%s'"), zc.zc_name); 2665185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2666185029Spjd } 2667185029Spjd } else if (errno == ENOENT) { 2668168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2669168404Spjd "parent does not exist")); 2670168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2671185029Spjd } else 2672168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2673168404Spjd } 2674168404Spjd 2675219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2676219089Spjd if (zoned != NULL) 2677219089Spjd *zoned = is_zoned; 2678219089Spjd 2679168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2680219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 2681168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2682168404Spjd zfs_close(zhp); 2683168404Spjd return (-1); 2684168404Spjd } 2685168404Spjd 2686168404Spjd /* make sure parent is a filesystem */ 2687168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2688168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2689168404Spjd "parent is not a filesystem")); 2690168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2691168404Spjd zfs_close(zhp); 2692168404Spjd return (-1); 2693168404Spjd } 2694168404Spjd 2695168404Spjd zfs_close(zhp); 2696185029Spjd if (prefixlen != NULL) 2697185029Spjd *prefixlen = strlen(parent); 2698168404Spjd return (0); 2699168404Spjd} 2700168404Spjd 2701168404Spjd/* 2702185029Spjd * Finds whether the dataset of the given type(s) exists. 2703185029Spjd */ 2704185029Spjdboolean_t 2705185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2706185029Spjd{ 2707185029Spjd zfs_handle_t *zhp; 2708185029Spjd 2709185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2710185029Spjd return (B_FALSE); 2711185029Spjd 2712185029Spjd /* 2713185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2714185029Spjd */ 2715185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2716185029Spjd int ds_type = zhp->zfs_type; 2717185029Spjd 2718185029Spjd zfs_close(zhp); 2719185029Spjd if (types & ds_type) 2720185029Spjd return (B_TRUE); 2721185029Spjd } 2722185029Spjd return (B_FALSE); 2723185029Spjd} 2724185029Spjd 2725185029Spjd/* 2726185029Spjd * Given a path to 'target', create all the ancestors between 2727185029Spjd * the prefixlen portion of the path, and the target itself. 2728185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2729185029Spjd */ 2730185029Spjdint 2731185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2732185029Spjd{ 2733185029Spjd zfs_handle_t *h; 2734185029Spjd char *cp; 2735185029Spjd const char *opname; 2736185029Spjd 2737185029Spjd /* make sure prefix exists */ 2738185029Spjd cp = target + prefixlen; 2739185029Spjd if (*cp != '/') { 2740185029Spjd assert(strchr(cp, '/') == NULL); 2741185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2742185029Spjd } else { 2743185029Spjd *cp = '\0'; 2744185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2745185029Spjd *cp = '/'; 2746185029Spjd } 2747185029Spjd if (h == NULL) 2748185029Spjd return (-1); 2749185029Spjd zfs_close(h); 2750185029Spjd 2751185029Spjd /* 2752185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2753185029Spjd * up to the prefixlen-long one. 2754185029Spjd */ 2755185029Spjd for (cp = target + prefixlen + 1; 2756185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2757185029Spjd char *logstr; 2758185029Spjd 2759185029Spjd *cp = '\0'; 2760185029Spjd 2761185029Spjd h = make_dataset_handle(hdl, target); 2762185029Spjd if (h) { 2763185029Spjd /* it already exists, nothing to do here */ 2764185029Spjd zfs_close(h); 2765185029Spjd continue; 2766185029Spjd } 2767185029Spjd 2768185029Spjd logstr = hdl->libzfs_log_str; 2769185029Spjd hdl->libzfs_log_str = NULL; 2770185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2771185029Spjd NULL) != 0) { 2772185029Spjd hdl->libzfs_log_str = logstr; 2773185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2774185029Spjd goto ancestorerr; 2775185029Spjd } 2776185029Spjd 2777185029Spjd hdl->libzfs_log_str = logstr; 2778185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2779185029Spjd if (h == NULL) { 2780185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2781185029Spjd goto ancestorerr; 2782185029Spjd } 2783185029Spjd 2784185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 2785185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2786185029Spjd goto ancestorerr; 2787185029Spjd } 2788185029Spjd 2789185029Spjd if (zfs_share(h) != 0) { 2790185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2791185029Spjd goto ancestorerr; 2792185029Spjd } 2793185029Spjd 2794185029Spjd zfs_close(h); 2795185029Spjd } 2796185029Spjd 2797185029Spjd return (0); 2798185029Spjd 2799185029Spjdancestorerr: 2800185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2801185029Spjd "failed to %s ancestor '%s'"), opname, target); 2802185029Spjd return (-1); 2803185029Spjd} 2804185029Spjd 2805185029Spjd/* 2806185029Spjd * Creates non-existing ancestors of the given path. 2807185029Spjd */ 2808185029Spjdint 2809185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2810185029Spjd{ 2811185029Spjd int prefix; 2812185029Spjd char *path_copy; 2813185029Spjd int rc; 2814185029Spjd 2815219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 2816185029Spjd return (-1); 2817185029Spjd 2818185029Spjd if ((path_copy = strdup(path)) != NULL) { 2819185029Spjd rc = create_parents(hdl, path_copy, prefix); 2820185029Spjd free(path_copy); 2821185029Spjd } 2822185029Spjd if (path_copy == NULL || rc != 0) 2823185029Spjd return (-1); 2824185029Spjd 2825185029Spjd return (0); 2826185029Spjd} 2827185029Spjd 2828185029Spjd/* 2829168404Spjd * Create a new filesystem or volume. 2830168404Spjd */ 2831168404Spjdint 2832168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2833168404Spjd nvlist_t *props) 2834168404Spjd{ 2835168404Spjd zfs_cmd_t zc = { 0 }; 2836168404Spjd int ret; 2837168404Spjd uint64_t size = 0; 2838168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2839168404Spjd char errbuf[1024]; 2840168404Spjd uint64_t zoned; 2841168404Spjd 2842168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2843168404Spjd "cannot create '%s'"), path); 2844168404Spjd 2845168404Spjd /* validate the path, taking care to note the extended error message */ 2846185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 2847168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2848168404Spjd 2849168404Spjd /* validate parents exist */ 2850185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 2851168404Spjd return (-1); 2852168404Spjd 2853168404Spjd /* 2854168404Spjd * The failure modes when creating a dataset of a different type over 2855168404Spjd * one that already exists is a little strange. In particular, if you 2856168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 2857168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 2858168404Spjd * first try to see if the dataset exists. 2859168404Spjd */ 2860168404Spjd (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2861185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 2862168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2863168404Spjd "dataset already exists")); 2864168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2865168404Spjd } 2866168404Spjd 2867168404Spjd if (type == ZFS_TYPE_VOLUME) 2868168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2869168404Spjd else 2870168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2871168404Spjd 2872185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 2873168404Spjd zoned, NULL, errbuf)) == 0) 2874168404Spjd return (-1); 2875168404Spjd 2876168404Spjd if (type == ZFS_TYPE_VOLUME) { 2877168404Spjd /* 2878168404Spjd * If we are creating a volume, the size and block size must 2879168404Spjd * satisfy a few restraints. First, the blocksize must be a 2880168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 2881168404Spjd * volsize must be a multiple of the block size, and cannot be 2882168404Spjd * zero. 2883168404Spjd */ 2884168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 2885168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2886168404Spjd nvlist_free(props); 2887168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2888168404Spjd "missing volume size")); 2889168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2890168404Spjd } 2891168404Spjd 2892168404Spjd if ((ret = nvlist_lookup_uint64(props, 2893168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2894168404Spjd &blocksize)) != 0) { 2895168404Spjd if (ret == ENOENT) { 2896168404Spjd blocksize = zfs_prop_default_numeric( 2897168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2898168404Spjd } else { 2899168404Spjd nvlist_free(props); 2900168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2901168404Spjd "missing volume block size")); 2902168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2903168404Spjd } 2904168404Spjd } 2905168404Spjd 2906168404Spjd if (size == 0) { 2907168404Spjd nvlist_free(props); 2908168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2909168404Spjd "volume size cannot be zero")); 2910168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2911168404Spjd } 2912168404Spjd 2913168404Spjd if (size % blocksize != 0) { 2914168404Spjd nvlist_free(props); 2915168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2916168404Spjd "volume size must be a multiple of volume block " 2917168404Spjd "size")); 2918168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2919168404Spjd } 2920168404Spjd } 2921168404Spjd 2922185029Spjd if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) 2923168404Spjd return (-1); 2924168404Spjd nvlist_free(props); 2925168404Spjd 2926168404Spjd /* create the dataset */ 2927185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); 2928168404Spjd 2929168404Spjd zcmd_free_nvlists(&zc); 2930168404Spjd 2931168404Spjd /* check for failure */ 2932168404Spjd if (ret != 0) { 2933168404Spjd char parent[ZFS_MAXNAMELEN]; 2934168404Spjd (void) parent_name(path, parent, sizeof (parent)); 2935168404Spjd 2936168404Spjd switch (errno) { 2937168404Spjd case ENOENT: 2938168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2939168404Spjd "no such parent '%s'"), parent); 2940168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2941168404Spjd 2942168404Spjd case EINVAL: 2943168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2944168404Spjd "parent '%s' is not a filesystem"), parent); 2945168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2946168404Spjd 2947168404Spjd case EDOM: 2948168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2949168404Spjd "volume block size must be power of 2 from " 2950168404Spjd "%u to %uk"), 2951168404Spjd (uint_t)SPA_MINBLOCKSIZE, 2952168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 2953168404Spjd 2954168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2955168404Spjd 2956185029Spjd case ENOTSUP: 2957185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2958185029Spjd "pool must be upgraded to set this " 2959185029Spjd "property or value")); 2960185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 2961168404Spjd#ifdef _ILP32 2962168404Spjd case EOVERFLOW: 2963168404Spjd /* 2964168404Spjd * This platform can't address a volume this big. 2965168404Spjd */ 2966168404Spjd if (type == ZFS_TYPE_VOLUME) 2967168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 2968168404Spjd errbuf)); 2969168404Spjd#endif 2970168404Spjd /* FALLTHROUGH */ 2971168404Spjd default: 2972168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2973168404Spjd } 2974168404Spjd } 2975168404Spjd 2976168404Spjd return (0); 2977168404Spjd} 2978168404Spjd 2979168404Spjd/* 2980168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 2981168404Spjd * isn't mounted, and that there are no active dependents. 2982168404Spjd */ 2983168404Spjdint 2984219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 2985168404Spjd{ 2986168404Spjd zfs_cmd_t zc = { 0 }; 2987168404Spjd 2988168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2989168404Spjd 2990168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2991168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2992168404Spjd } else { 2993168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2994168404Spjd } 2995168404Spjd 2996219089Spjd zc.zc_defer_destroy = defer; 2997185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { 2998168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 2999168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3000168404Spjd zhp->zfs_name)); 3001168404Spjd } 3002168404Spjd 3003168404Spjd remove_mountpoint(zhp); 3004168404Spjd 3005168404Spjd return (0); 3006168404Spjd} 3007168404Spjd 3008168404Spjdstruct destroydata { 3009168404Spjd char *snapname; 3010168404Spjd boolean_t gotone; 3011168404Spjd boolean_t closezhp; 3012168404Spjd}; 3013168404Spjd 3014168404Spjdstatic int 3015219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3016168404Spjd{ 3017168404Spjd struct destroydata *dd = arg; 3018168404Spjd zfs_handle_t *szhp; 3019168404Spjd char name[ZFS_MAXNAMELEN]; 3020168404Spjd boolean_t closezhp = dd->closezhp; 3021219089Spjd int rv = 0; 3022168404Spjd 3023168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 3024168404Spjd (void) strlcat(name, "@", sizeof (name)); 3025168404Spjd (void) strlcat(name, dd->snapname, sizeof (name)); 3026168404Spjd 3027168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, name); 3028168404Spjd if (szhp) { 3029168404Spjd dd->gotone = B_TRUE; 3030168404Spjd zfs_close(szhp); 3031168404Spjd } 3032168404Spjd 3033168404Spjd dd->closezhp = B_TRUE; 3034219089Spjd if (!dd->gotone) 3035219089Spjd rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg); 3036168404Spjd if (closezhp) 3037168404Spjd zfs_close(zhp); 3038168404Spjd return (rv); 3039168404Spjd} 3040168404Spjd 3041168404Spjd/* 3042168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3043168404Spjd */ 3044168404Spjdint 3045219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3046168404Spjd{ 3047168404Spjd zfs_cmd_t zc = { 0 }; 3048168404Spjd int ret; 3049168404Spjd struct destroydata dd = { 0 }; 3050168404Spjd 3051168404Spjd dd.snapname = snapname; 3052219089Spjd (void) zfs_check_snap_cb(zhp, &dd); 3053168404Spjd 3054168404Spjd if (!dd.gotone) { 3055168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3056168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3057168404Spjd zhp->zfs_name, snapname)); 3058168404Spjd } 3059168404Spjd 3060168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3061168404Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3062219089Spjd zc.zc_defer_destroy = defer; 3063168404Spjd 3064185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); 3065168404Spjd if (ret != 0) { 3066168404Spjd char errbuf[1024]; 3067168404Spjd 3068168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3069168404Spjd "cannot destroy '%s@%s'"), zc.zc_name, snapname); 3070168404Spjd 3071168404Spjd switch (errno) { 3072168404Spjd case EEXIST: 3073168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3074168404Spjd "snapshot is cloned")); 3075168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 3076168404Spjd 3077168404Spjd default: 3078168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3079168404Spjd errbuf)); 3080168404Spjd } 3081168404Spjd } 3082168404Spjd 3083168404Spjd return (0); 3084168404Spjd} 3085168404Spjd 3086168404Spjd/* 3087168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3088168404Spjd */ 3089168404Spjdint 3090168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3091168404Spjd{ 3092168404Spjd zfs_cmd_t zc = { 0 }; 3093168404Spjd char parent[ZFS_MAXNAMELEN]; 3094168404Spjd int ret; 3095168404Spjd char errbuf[1024]; 3096168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3097168404Spjd zfs_type_t type; 3098168404Spjd uint64_t zoned; 3099168404Spjd 3100168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3101168404Spjd 3102168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3103168404Spjd "cannot create '%s'"), target); 3104168404Spjd 3105168404Spjd /* validate the target name */ 3106185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3107168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3108168404Spjd 3109168404Spjd /* validate parents exist */ 3110185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3111168404Spjd return (-1); 3112168404Spjd 3113168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3114168404Spjd 3115168404Spjd /* do the clone */ 3116168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3117168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3118168404Spjd type = ZFS_TYPE_VOLUME; 3119168404Spjd } else { 3120168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3121168404Spjd type = ZFS_TYPE_FILESYSTEM; 3122168404Spjd } 3123168404Spjd 3124168404Spjd if (props) { 3125185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3126185029Spjd zhp, errbuf)) == NULL) 3127168404Spjd return (-1); 3128168404Spjd 3129185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3130168404Spjd nvlist_free(props); 3131168404Spjd return (-1); 3132168404Spjd } 3133168404Spjd 3134168404Spjd nvlist_free(props); 3135168404Spjd } 3136168404Spjd 3137168404Spjd (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 3138168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 3139185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); 3140168404Spjd 3141168404Spjd zcmd_free_nvlists(&zc); 3142168404Spjd 3143168404Spjd if (ret != 0) { 3144168404Spjd switch (errno) { 3145168404Spjd 3146168404Spjd case ENOENT: 3147168404Spjd /* 3148168404Spjd * The parent doesn't exist. We should have caught this 3149168404Spjd * above, but there may a race condition that has since 3150168404Spjd * destroyed the parent. 3151168404Spjd * 3152168404Spjd * At this point, we don't know whether it's the source 3153168404Spjd * that doesn't exist anymore, or whether the target 3154168404Spjd * dataset doesn't exist. 3155168404Spjd */ 3156168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3157168404Spjd "no such parent '%s'"), parent); 3158168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3159168404Spjd 3160168404Spjd case EXDEV: 3161168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3162168404Spjd "source and target pools differ")); 3163168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3164168404Spjd errbuf)); 3165168404Spjd 3166168404Spjd default: 3167168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3168168404Spjd errbuf)); 3169168404Spjd } 3170168404Spjd } 3171168404Spjd 3172168404Spjd return (ret); 3173168404Spjd} 3174168404Spjd 3175168404Spjd/* 3176168404Spjd * Promotes the given clone fs to be the clone parent. 3177168404Spjd */ 3178168404Spjdint 3179168404Spjdzfs_promote(zfs_handle_t *zhp) 3180168404Spjd{ 3181168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3182168404Spjd zfs_cmd_t zc = { 0 }; 3183168404Spjd char parent[MAXPATHLEN]; 3184168404Spjd int ret; 3185168404Spjd char errbuf[1024]; 3186168404Spjd 3187168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3188168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3189168404Spjd 3190168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3191168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3192168404Spjd "snapshots can not be promoted")); 3193168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3194168404Spjd } 3195168404Spjd 3196185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3197168404Spjd if (parent[0] == '\0') { 3198168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3199168404Spjd "not a cloned filesystem")); 3200168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3201168404Spjd } 3202168404Spjd 3203185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3204168404Spjd sizeof (zc.zc_value)); 3205168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3206185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3207168404Spjd 3208168404Spjd if (ret != 0) { 3209168404Spjd int save_errno = errno; 3210168404Spjd 3211168404Spjd switch (save_errno) { 3212168404Spjd case EEXIST: 3213219089Spjd /* There is a conflicting snapshot name. */ 3214168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3215219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3216219089Spjd zc.zc_string, parent); 3217168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3218168404Spjd 3219168404Spjd default: 3220168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3221168404Spjd } 3222168404Spjd } 3223168404Spjd return (ret); 3224168404Spjd} 3225168404Spjd 3226168404Spjd/* 3227168404Spjd * Takes a snapshot of the given dataset. 3228168404Spjd */ 3229168404Spjdint 3230185029Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3231185029Spjd nvlist_t *props) 3232168404Spjd{ 3233168404Spjd const char *delim; 3234185029Spjd char parent[ZFS_MAXNAMELEN]; 3235168404Spjd zfs_handle_t *zhp; 3236168404Spjd zfs_cmd_t zc = { 0 }; 3237168404Spjd int ret; 3238168404Spjd char errbuf[1024]; 3239168404Spjd 3240168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3241168404Spjd "cannot snapshot '%s'"), path); 3242168404Spjd 3243168404Spjd /* validate the target name */ 3244185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3245168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3246168404Spjd 3247185029Spjd if (props) { 3248185029Spjd if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3249185029Spjd props, B_FALSE, NULL, errbuf)) == NULL) 3250185029Spjd return (-1); 3251185029Spjd 3252185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3253185029Spjd nvlist_free(props); 3254185029Spjd return (-1); 3255185029Spjd } 3256185029Spjd 3257185029Spjd nvlist_free(props); 3258185029Spjd } 3259185029Spjd 3260168404Spjd /* make sure the parent exists and is of the appropriate type */ 3261168404Spjd delim = strchr(path, '@'); 3262168404Spjd (void) strncpy(parent, path, delim - path); 3263168404Spjd parent[delim - path] = '\0'; 3264168404Spjd 3265168404Spjd if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 3266168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3267185029Spjd zcmd_free_nvlists(&zc); 3268168404Spjd return (-1); 3269168404Spjd } 3270168404Spjd 3271168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3272168404Spjd (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 3273185029Spjd if (ZFS_IS_VOLUME(zhp)) 3274185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3275185029Spjd else 3276185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3277168404Spjd zc.zc_cookie = recursive; 3278185029Spjd ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); 3279168404Spjd 3280185029Spjd zcmd_free_nvlists(&zc); 3281185029Spjd 3282168404Spjd /* 3283168404Spjd * if it was recursive, the one that actually failed will be in 3284168404Spjd * zc.zc_name. 3285168404Spjd */ 3286219089Spjd if (ret != 0) { 3287185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3288185029Spjd "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 3289219089Spjd (void) zfs_standard_error(hdl, errno, errbuf); 3290168404Spjd } 3291168404Spjd 3292168404Spjd zfs_close(zhp); 3293168404Spjd 3294168404Spjd return (ret); 3295168404Spjd} 3296168404Spjd 3297168404Spjd/* 3298168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3299168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3300168404Spjd * is a dependent and we should just destroy it without checking the transaction 3301168404Spjd * group. 3302168404Spjd */ 3303168404Spjdtypedef struct rollback_data { 3304168404Spjd const char *cb_target; /* the snapshot */ 3305168404Spjd uint64_t cb_create; /* creation time reference */ 3306185029Spjd boolean_t cb_error; 3307168404Spjd boolean_t cb_dependent; 3308185029Spjd boolean_t cb_force; 3309168404Spjd} rollback_data_t; 3310168404Spjd 3311168404Spjdstatic int 3312168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3313168404Spjd{ 3314168404Spjd rollback_data_t *cbp = data; 3315168404Spjd 3316168404Spjd if (!cbp->cb_dependent) { 3317168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3318168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3319168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3320168404Spjd cbp->cb_create) { 3321185029Spjd char *logstr; 3322168404Spjd 3323168404Spjd cbp->cb_dependent = B_TRUE; 3324185029Spjd cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3325185029Spjd rollback_destroy, cbp); 3326168404Spjd cbp->cb_dependent = B_FALSE; 3327168404Spjd 3328185029Spjd logstr = zhp->zfs_hdl->libzfs_log_str; 3329185029Spjd zhp->zfs_hdl->libzfs_log_str = NULL; 3330219089Spjd cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3331185029Spjd zhp->zfs_hdl->libzfs_log_str = logstr; 3332168404Spjd } 3333168404Spjd } else { 3334185029Spjd /* We must destroy this clone; first unmount it */ 3335185029Spjd prop_changelist_t *clp; 3336185029Spjd 3337185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3338185029Spjd cbp->cb_force ? MS_FORCE: 0); 3339185029Spjd if (clp == NULL || changelist_prefix(clp) != 0) { 3340185029Spjd cbp->cb_error = B_TRUE; 3341185029Spjd zfs_close(zhp); 3342185029Spjd return (0); 3343185029Spjd } 3344219089Spjd if (zfs_destroy(zhp, B_FALSE) != 0) 3345185029Spjd cbp->cb_error = B_TRUE; 3346168404Spjd else 3347185029Spjd changelist_remove(clp, zhp->zfs_name); 3348185029Spjd (void) changelist_postfix(clp); 3349185029Spjd changelist_free(clp); 3350168404Spjd } 3351168404Spjd 3352168404Spjd zfs_close(zhp); 3353168404Spjd return (0); 3354168404Spjd} 3355168404Spjd 3356168404Spjd/* 3357168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3358168404Spjd * data changes since then and making it the active dataset. 3359168404Spjd * 3360168404Spjd * Any snapshots more recent than the target are destroyed, along with 3361168404Spjd * their dependents. 3362168404Spjd */ 3363168404Spjdint 3364185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3365168404Spjd{ 3366168404Spjd rollback_data_t cb = { 0 }; 3367185029Spjd int err; 3368185029Spjd zfs_cmd_t zc = { 0 }; 3369185029Spjd boolean_t restore_resv = 0; 3370185029Spjd uint64_t old_volsize, new_volsize; 3371185029Spjd zfs_prop_t resv_prop; 3372168404Spjd 3373185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3374185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3375168404Spjd 3376168404Spjd /* 3377168404Spjd * Destroy all recent snapshots and its dependends. 3378168404Spjd */ 3379185029Spjd cb.cb_force = force; 3380168404Spjd cb.cb_target = snap->zfs_name; 3381168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3382168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3383168404Spjd 3384185029Spjd if (cb.cb_error) 3385185029Spjd return (-1); 3386168404Spjd 3387168404Spjd /* 3388168404Spjd * Now that we have verified that the snapshot is the latest, 3389168404Spjd * rollback to the given snapshot. 3390168404Spjd */ 3391168404Spjd 3392185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3393185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3394185029Spjd return (-1); 3395185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3396185029Spjd restore_resv = 3397185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3398168404Spjd } 3399168404Spjd 3400185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3401185029Spjd 3402185029Spjd if (ZFS_IS_VOLUME(zhp)) 3403185029Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3404185029Spjd else 3405185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 3406185029Spjd 3407168404Spjd /* 3408185029Spjd * We rely on zfs_iter_children() to verify that there are no 3409185029Spjd * newer snapshots for the given dataset. Therefore, we can 3410185029Spjd * simply pass the name on to the ioctl() call. There is still 3411185029Spjd * an unlikely race condition where the user has taken a 3412185029Spjd * snapshot since we verified that this was the most recent. 3413185029Spjd * 3414168404Spjd */ 3415185029Spjd if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3416185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3417185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3418185029Spjd zhp->zfs_name); 3419185029Spjd return (err); 3420185029Spjd } 3421168404Spjd 3422185029Spjd /* 3423185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3424185029Spjd * rollback reservation and the volsize has changed then set 3425185029Spjd * the reservation property to the post-rollback volsize. 3426185029Spjd * Make a new handle since the rollback closed the dataset. 3427185029Spjd */ 3428185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3429185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3430185029Spjd if (restore_resv) { 3431185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3432185029Spjd if (old_volsize != new_volsize) 3433185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3434185029Spjd new_volsize); 3435185029Spjd } 3436185029Spjd zfs_close(zhp); 3437185029Spjd } 3438185029Spjd return (err); 3439168404Spjd} 3440168404Spjd 3441168404Spjd/* 3442168404Spjd * Iterate over all dependents for a given dataset. This includes both 3443168404Spjd * hierarchical dependents (children) and data dependents (snapshots and 3444168404Spjd * clones). The bulk of the processing occurs in get_dependents() in 3445168404Spjd * libzfs_graph.c. 3446168404Spjd */ 3447168404Spjdint 3448168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 3449168404Spjd zfs_iter_f func, void *data) 3450168404Spjd{ 3451168404Spjd char **dependents; 3452168404Spjd size_t count; 3453168404Spjd int i; 3454168404Spjd zfs_handle_t *child; 3455168404Spjd int ret = 0; 3456168404Spjd 3457168404Spjd if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 3458168404Spjd &dependents, &count) != 0) 3459168404Spjd return (-1); 3460168404Spjd 3461168404Spjd for (i = 0; i < count; i++) { 3462168404Spjd if ((child = make_dataset_handle(zhp->zfs_hdl, 3463168404Spjd dependents[i])) == NULL) 3464168404Spjd continue; 3465168404Spjd 3466168404Spjd if ((ret = func(child, data)) != 0) 3467168404Spjd break; 3468168404Spjd } 3469168404Spjd 3470168404Spjd for (i = 0; i < count; i++) 3471168404Spjd free(dependents[i]); 3472168404Spjd free(dependents); 3473168404Spjd 3474168404Spjd return (ret); 3475168404Spjd} 3476168404Spjd 3477168404Spjd/* 3478168404Spjd * Renames the given dataset. 3479168404Spjd */ 3480168404Spjdint 3481185029Spjdzfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) 3482168404Spjd{ 3483168404Spjd int ret; 3484168404Spjd zfs_cmd_t zc = { 0 }; 3485168404Spjd char *delim; 3486168676Spjd prop_changelist_t *cl = NULL; 3487168676Spjd zfs_handle_t *zhrp = NULL; 3488168676Spjd char *parentname = NULL; 3489168404Spjd char parent[ZFS_MAXNAMELEN]; 3490168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3491168404Spjd char errbuf[1024]; 3492168404Spjd 3493168404Spjd /* if we have the same exact name, just return success */ 3494168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3495168404Spjd return (0); 3496168404Spjd 3497168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3498168404Spjd "cannot rename to '%s'"), target); 3499168404Spjd 3500168404Spjd /* 3501168404Spjd * Make sure the target name is valid 3502168404Spjd */ 3503168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3504168404Spjd if ((strchr(target, '@') == NULL) || 3505168404Spjd *target == '@') { 3506168404Spjd /* 3507168404Spjd * Snapshot target name is abbreviated, 3508168404Spjd * reconstruct full dataset name 3509168404Spjd */ 3510168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3511168404Spjd sizeof (parent)); 3512168404Spjd delim = strchr(parent, '@'); 3513168404Spjd if (strchr(target, '@') == NULL) 3514168404Spjd *(++delim) = '\0'; 3515168404Spjd else 3516168404Spjd *delim = '\0'; 3517168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3518168404Spjd target = parent; 3519168404Spjd } else { 3520168404Spjd /* 3521168404Spjd * Make sure we're renaming within the same dataset. 3522168404Spjd */ 3523168404Spjd delim = strchr(target, '@'); 3524168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3525168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3526168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3527168404Spjd "snapshots must be part of same " 3528168404Spjd "dataset")); 3529168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3530168404Spjd errbuf)); 3531168404Spjd } 3532168404Spjd } 3533185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3534168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3535168404Spjd } else { 3536168676Spjd if (recursive) { 3537168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3538168676Spjd "recursive rename must be a snapshot")); 3539168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3540168676Spjd } 3541168676Spjd 3542185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3543168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3544168404Spjd 3545168404Spjd /* validate parents */ 3546219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3547168404Spjd return (-1); 3548168404Spjd 3549168404Spjd /* make sure we're in the same pool */ 3550168404Spjd verify((delim = strchr(target, '/')) != NULL); 3551168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3552168404Spjd zhp->zfs_name[delim - target] != '/') { 3553168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3554168404Spjd "datasets must be within same pool")); 3555168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3556168404Spjd } 3557168404Spjd 3558168404Spjd /* new name cannot be a child of the current dataset name */ 3559219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3560168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3561219089Spjd "New dataset name cannot be a descendant of " 3562168404Spjd "current dataset name")); 3563168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3564168404Spjd } 3565168404Spjd } 3566168404Spjd 3567168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3568168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3569168404Spjd 3570168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3571168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3572168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3573168404Spjd "dataset is used in a non-global zone")); 3574168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3575168404Spjd } 3576168404Spjd 3577168676Spjd if (recursive) { 3578168404Spjd 3579185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3580185029Spjd if (parentname == NULL) { 3581185029Spjd ret = -1; 3582185029Spjd goto error; 3583185029Spjd } 3584168676Spjd delim = strchr(parentname, '@'); 3585168676Spjd *delim = '\0'; 3586185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3587168676Spjd if (zhrp == NULL) { 3588185029Spjd ret = -1; 3589185029Spjd goto error; 3590168676Spjd } 3591168676Spjd 3592168676Spjd } else { 3593185029Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) 3594168676Spjd return (-1); 3595168676Spjd 3596168676Spjd if (changelist_haszonedchild(cl)) { 3597168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3598168676Spjd "child dataset with inherited mountpoint is used " 3599168676Spjd "in a non-global zone")); 3600168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3601168676Spjd goto error; 3602168676Spjd } 3603168676Spjd 3604168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3605168676Spjd goto error; 3606168404Spjd } 3607168404Spjd 3608168404Spjd if (ZFS_IS_VOLUME(zhp)) 3609168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3610168404Spjd else 3611168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3612168404Spjd 3613168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3614168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3615168404Spjd 3616168676Spjd zc.zc_cookie = recursive; 3617168676Spjd 3618185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3619168676Spjd /* 3620168676Spjd * if it was recursive, the one that actually failed will 3621168676Spjd * be in zc.zc_name 3622168676Spjd */ 3623168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3624185029Spjd "cannot rename '%s'"), zc.zc_name); 3625168404Spjd 3626168676Spjd if (recursive && errno == EEXIST) { 3627168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3628168676Spjd "a child dataset already has a snapshot " 3629168676Spjd "with the new name")); 3630185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3631168676Spjd } else { 3632168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3633168676Spjd } 3634168676Spjd 3635168404Spjd /* 3636168404Spjd * On failure, we still want to remount any filesystems that 3637168404Spjd * were previously mounted, so we don't alter the system state. 3638168404Spjd */ 3639219089Spjd if (!recursive) 3640168676Spjd (void) changelist_postfix(cl); 3641168404Spjd } else { 3642219089Spjd if (!recursive) { 3643168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3644168676Spjd ret = changelist_postfix(cl); 3645168676Spjd } 3646168404Spjd } 3647168404Spjd 3648168404Spjderror: 3649168676Spjd if (parentname) { 3650168676Spjd free(parentname); 3651168676Spjd } 3652168676Spjd if (zhrp) { 3653168676Spjd zfs_close(zhrp); 3654168676Spjd } 3655168676Spjd if (cl) { 3656168676Spjd changelist_free(cl); 3657168676Spjd } 3658168404Spjd return (ret); 3659168404Spjd} 3660168404Spjd 3661219089Spjdnvlist_t * 3662219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 3663168404Spjd{ 3664219089Spjd return (zhp->zfs_user_props); 3665168676Spjd} 3666168676Spjd 3667168404Spjdnvlist_t * 3668219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 3669168404Spjd{ 3670219089Spjd if (zhp->zfs_recvd_props == NULL) 3671219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 3672219089Spjd return (NULL); 3673219089Spjd return (zhp->zfs_recvd_props); 3674168404Spjd} 3675168404Spjd 3676168404Spjd/* 3677168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3678168404Spjd * display, and their maximum widths. This does two main things: 3679168404Spjd * 3680168404Spjd * - If this is a list of all properties, then expand the list to include 3681168404Spjd * all native properties, and set a flag so that for each dataset we look 3682168404Spjd * for new unique user properties and add them to the list. 3683168404Spjd * 3684168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3685219089Spjd * so that we can size the column appropriately. If the user has 3686219089Spjd * requested received property values, we also need to compute the width 3687219089Spjd * of the RECEIVED column. 3688168404Spjd */ 3689168404Spjdint 3690219089Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) 3691168404Spjd{ 3692168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3693185029Spjd zprop_list_t *entry; 3694185029Spjd zprop_list_t **last, **start; 3695168404Spjd nvlist_t *userprops, *propval; 3696168404Spjd nvpair_t *elem; 3697168404Spjd char *strval; 3698168404Spjd char buf[ZFS_MAXPROPLEN]; 3699168404Spjd 3700185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3701168404Spjd return (-1); 3702168404Spjd 3703168404Spjd userprops = zfs_get_user_props(zhp); 3704168404Spjd 3705168404Spjd entry = *plp; 3706168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3707168404Spjd /* 3708168404Spjd * Go through and add any user properties as necessary. We 3709168404Spjd * start by incrementing our list pointer to the first 3710168404Spjd * non-native property. 3711168404Spjd */ 3712168404Spjd start = plp; 3713168404Spjd while (*start != NULL) { 3714185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3715168404Spjd break; 3716168404Spjd start = &(*start)->pl_next; 3717168404Spjd } 3718168404Spjd 3719168404Spjd elem = NULL; 3720168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3721168404Spjd /* 3722168404Spjd * See if we've already found this property in our list. 3723168404Spjd */ 3724168404Spjd for (last = start; *last != NULL; 3725168404Spjd last = &(*last)->pl_next) { 3726168404Spjd if (strcmp((*last)->pl_user_prop, 3727168404Spjd nvpair_name(elem)) == 0) 3728168404Spjd break; 3729168404Spjd } 3730168404Spjd 3731168404Spjd if (*last == NULL) { 3732168404Spjd if ((entry = zfs_alloc(hdl, 3733185029Spjd sizeof (zprop_list_t))) == NULL || 3734168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3735168404Spjd nvpair_name(elem)))) == NULL) { 3736168404Spjd free(entry); 3737168404Spjd return (-1); 3738168404Spjd } 3739168404Spjd 3740185029Spjd entry->pl_prop = ZPROP_INVAL; 3741168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3742168404Spjd entry->pl_all = B_TRUE; 3743168404Spjd *last = entry; 3744168404Spjd } 3745168404Spjd } 3746168404Spjd } 3747168404Spjd 3748168404Spjd /* 3749168404Spjd * Now go through and check the width of any non-fixed columns 3750168404Spjd */ 3751168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3752168404Spjd if (entry->pl_fixed) 3753168404Spjd continue; 3754168404Spjd 3755185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 3756168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3757168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3758168404Spjd if (strlen(buf) > entry->pl_width) 3759168404Spjd entry->pl_width = strlen(buf); 3760168404Spjd } 3761219089Spjd if (received && zfs_prop_get_recvd(zhp, 3762219089Spjd zfs_prop_to_name(entry->pl_prop), 3763219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3764219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3765219089Spjd entry->pl_recvd_width = strlen(buf); 3766219089Spjd } else { 3767219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 3768219089Spjd &propval) == 0) { 3769219089Spjd verify(nvlist_lookup_string(propval, 3770219089Spjd ZPROP_VALUE, &strval) == 0); 3771219089Spjd if (strlen(strval) > entry->pl_width) 3772219089Spjd entry->pl_width = strlen(strval); 3773219089Spjd } 3774219089Spjd if (received && zfs_prop_get_recvd(zhp, 3775219089Spjd entry->pl_user_prop, 3776219089Spjd buf, sizeof (buf), B_FALSE) == 0) 3777219089Spjd if (strlen(buf) > entry->pl_recvd_width) 3778219089Spjd entry->pl_recvd_width = strlen(buf); 3779168404Spjd } 3780168404Spjd } 3781168404Spjd 3782168404Spjd return (0); 3783168404Spjd} 3784168404Spjd 3785185029Spjdint 3786185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 3787209962Smm char *resource, void *export, void *sharetab, 3788209962Smm int sharemax, zfs_share_op_t operation) 3789185029Spjd{ 3790185029Spjd zfs_cmd_t zc = { 0 }; 3791185029Spjd int error; 3792185029Spjd 3793185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3794185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3795209962Smm if (resource) 3796209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 3797185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 3798185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 3799185029Spjd zc.zc_share.z_sharetype = operation; 3800185029Spjd zc.zc_share.z_sharemax = sharemax; 3801185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 3802185029Spjd return (error); 3803185029Spjd} 3804185029Spjd 3805205198Sdelphijvoid 3806205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 3807205198Sdelphij{ 3808205198Sdelphij nvpair_t *curr; 3809205198Sdelphij 3810205198Sdelphij /* 3811205198Sdelphij * Keep a reference to the props-table against which we prune the 3812205198Sdelphij * properties. 3813205198Sdelphij */ 3814205198Sdelphij zhp->zfs_props_table = props; 3815205198Sdelphij 3816205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 3817205198Sdelphij 3818205198Sdelphij while (curr) { 3819205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 3820205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 3821205198Sdelphij 3822206199Sdelphij /* 3823219089Spjd * User properties will result in ZPROP_INVAL, and since we 3824219089Spjd * only know how to prune standard ZFS properties, we always 3825219089Spjd * leave these in the list. This can also happen if we 3826219089Spjd * encounter an unknown DSL property (when running older 3827219089Spjd * software, for example). 3828206199Sdelphij */ 3829206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 3830205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 3831205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 3832205198Sdelphij curr = next; 3833205198Sdelphij } 3834205198Sdelphij} 3835205198Sdelphij 3836209962Smm#ifdef sun 3837209962Smmstatic int 3838209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 3839209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 3840209962Smm{ 3841209962Smm zfs_cmd_t zc = { 0 }; 3842209962Smm nvlist_t *nvlist = NULL; 3843209962Smm int error; 3844209962Smm 3845209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3846209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 3847209962Smm zc.zc_cookie = (uint64_t)cmd; 3848209962Smm 3849209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 3850209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 3851209962Smm (void) no_memory(hdl); 3852209962Smm return (NULL); 3853209962Smm } 3854209962Smm } 3855209962Smm 3856209962Smm switch (cmd) { 3857209962Smm case ZFS_SMB_ACL_ADD: 3858209962Smm case ZFS_SMB_ACL_REMOVE: 3859209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 3860209962Smm break; 3861209962Smm case ZFS_SMB_ACL_RENAME: 3862209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 3863209962Smm resource1) != 0) { 3864209962Smm (void) no_memory(hdl); 3865209962Smm return (-1); 3866209962Smm } 3867209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 3868209962Smm resource2) != 0) { 3869209962Smm (void) no_memory(hdl); 3870209962Smm return (-1); 3871209962Smm } 3872209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 3873209962Smm nvlist_free(nvlist); 3874209962Smm return (-1); 3875209962Smm } 3876209962Smm break; 3877209962Smm case ZFS_SMB_ACL_PURGE: 3878209962Smm break; 3879209962Smm default: 3880209962Smm return (-1); 3881209962Smm } 3882209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 3883209962Smm if (nvlist) 3884209962Smm nvlist_free(nvlist); 3885209962Smm return (error); 3886209962Smm} 3887209962Smm 3888209962Smmint 3889209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 3890209962Smm char *path, char *resource) 3891209962Smm{ 3892209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 3893209962Smm resource, NULL)); 3894209962Smm} 3895209962Smm 3896209962Smmint 3897209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 3898209962Smm char *path, char *resource) 3899209962Smm{ 3900209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 3901209962Smm resource, NULL)); 3902209962Smm} 3903209962Smm 3904209962Smmint 3905209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 3906209962Smm{ 3907209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 3908209962Smm NULL, NULL)); 3909209962Smm} 3910209962Smm 3911209962Smmint 3912209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 3913209962Smm char *oldname, char *newname) 3914209962Smm{ 3915209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 3916209962Smm oldname, newname)); 3917209962Smm} 3918209962Smm#endif /* sun */ 3919209962Smm 3920209962Smmint 3921209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 3922209962Smm zfs_userspace_cb_t func, void *arg) 3923209962Smm{ 3924209962Smm zfs_cmd_t zc = { 0 }; 3925209962Smm int error; 3926209962Smm zfs_useracct_t buf[100]; 3927209962Smm 3928209962Smm (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3929209962Smm 3930209962Smm zc.zc_objset_type = type; 3931209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 3932209962Smm 3933209962Smm /* CONSTCOND */ 3934209962Smm while (1) { 3935209962Smm zfs_useracct_t *zua = buf; 3936209962Smm 3937209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 3938209962Smm error = ioctl(zhp->zfs_hdl->libzfs_fd, 3939209962Smm ZFS_IOC_USERSPACE_MANY, &zc); 3940209962Smm if (error || zc.zc_nvlist_dst_size == 0) 3941209962Smm break; 3942209962Smm 3943209962Smm while (zc.zc_nvlist_dst_size > 0) { 3944209962Smm error = func(arg, zua->zu_domain, zua->zu_rid, 3945209962Smm zua->zu_space); 3946209962Smm if (error != 0) 3947209962Smm return (error); 3948209962Smm zua++; 3949209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 3950209962Smm } 3951209962Smm } 3952209962Smm 3953209962Smm return (error); 3954209962Smm} 3955209962Smm 3956219089Spjdint 3957219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 3958219089Spjd boolean_t recursive, boolean_t temphold, boolean_t enoent_ok, 3959219089Spjd int cleanup_fd, uint64_t dsobj, uint64_t createtxg) 3960219089Spjd{ 3961219089Spjd zfs_cmd_t zc = { 0 }; 3962219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3963219089Spjd 3964219089Spjd ASSERT(!recursive || dsobj == 0); 3965219089Spjd 3966219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3967219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3968219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 3969219089Spjd >= sizeof (zc.zc_string)) 3970219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 3971219089Spjd zc.zc_cookie = recursive; 3972219089Spjd zc.zc_temphold = temphold; 3973219089Spjd zc.zc_cleanup_fd = cleanup_fd; 3974219089Spjd zc.zc_sendobj = dsobj; 3975219089Spjd zc.zc_createtxg = createtxg; 3976219089Spjd 3977219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) { 3978219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 3979219089Spjd 3980219089Spjd /* 3981219089Spjd * if it was recursive, the one that actually failed will be in 3982219089Spjd * zc.zc_name. 3983219089Spjd */ 3984219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3985219089Spjd "cannot hold '%s@%s'"), zc.zc_name, snapname); 3986219089Spjd switch (errno) { 3987219089Spjd case E2BIG: 3988219089Spjd /* 3989219089Spjd * Temporary tags wind up having the ds object id 3990219089Spjd * prepended. So even if we passed the length check 3991219089Spjd * above, it's still possible for the tag to wind 3992219089Spjd * up being slightly too long. 3993219089Spjd */ 3994219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf)); 3995219089Spjd case ENOTSUP: 3996219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3997219089Spjd "pool must be upgraded")); 3998219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3999219089Spjd case EINVAL: 4000219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4001219089Spjd case EEXIST: 4002219089Spjd return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf)); 4003219089Spjd case ENOENT: 4004219089Spjd if (enoent_ok) 4005219089Spjd return (ENOENT); 4006219089Spjd /* FALLTHROUGH */ 4007219089Spjd default: 4008219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4009219089Spjd } 4010219089Spjd } 4011219089Spjd 4012219089Spjd return (0); 4013219089Spjd} 4014219089Spjd 4015219089Spjdint 4016219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4017219089Spjd boolean_t recursive) 4018219089Spjd{ 4019219089Spjd zfs_cmd_t zc = { 0 }; 4020219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4021219089Spjd 4022219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4023219089Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 4024219089Spjd if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) 4025219089Spjd >= sizeof (zc.zc_string)) 4026219089Spjd return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); 4027219089Spjd zc.zc_cookie = recursive; 4028219089Spjd 4029219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) { 4030219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4031219089Spjd 4032219089Spjd /* 4033219089Spjd * if it was recursive, the one that actually failed will be in 4034219089Spjd * zc.zc_name. 4035219089Spjd */ 4036219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4037219089Spjd "cannot release '%s' from '%s@%s'"), tag, zc.zc_name, 4038219089Spjd snapname); 4039219089Spjd switch (errno) { 4040219089Spjd case ESRCH: 4041219089Spjd return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf)); 4042219089Spjd case ENOTSUP: 4043219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4044219089Spjd "pool must be upgraded")); 4045219089Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 4046219089Spjd case EINVAL: 4047219089Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4048219089Spjd default: 4049219089Spjd return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4050219089Spjd } 4051219089Spjd } 4052219089Spjd 4053219089Spjd return (0); 4054219089Spjd} 4055219089Spjd 4056219089Spjdint 4057219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4058219089Spjd{ 4059219089Spjd zfs_cmd_t zc = { 0 }; 4060219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4061219089Spjd int nvsz = 2048; 4062219089Spjd void *nvbuf; 4063219089Spjd int err = 0; 4064219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4065219089Spjd 4066219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4067219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4068219089Spjd 4069219089Spjdtryagain: 4070219089Spjd 4071219089Spjd nvbuf = malloc(nvsz); 4072219089Spjd if (nvbuf == NULL) { 4073219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4074219089Spjd goto out; 4075219089Spjd } 4076219089Spjd 4077219089Spjd zc.zc_nvlist_dst_size = nvsz; 4078219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4079219089Spjd 4080219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4081219089Spjd 4082219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { 4083219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4084219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4085219089Spjd zc.zc_name); 4086219089Spjd switch (errno) { 4087219089Spjd case ENOMEM: 4088219089Spjd free(nvbuf); 4089219089Spjd nvsz = zc.zc_nvlist_dst_size; 4090219089Spjd goto tryagain; 4091219089Spjd 4092219089Spjd case ENOTSUP: 4093219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4094219089Spjd "pool must be upgraded")); 4095219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4096219089Spjd break; 4097219089Spjd case EINVAL: 4098219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4099219089Spjd break; 4100219089Spjd case ENOENT: 4101219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4102219089Spjd break; 4103219089Spjd default: 4104219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4105219089Spjd break; 4106219089Spjd } 4107219089Spjd } else { 4108219089Spjd /* success */ 4109219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4110219089Spjd if (rc) { 4111219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4112219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4113219089Spjd zc.zc_name); 4114219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4115219089Spjd } 4116219089Spjd } 4117219089Spjd 4118219089Spjd free(nvbuf); 4119219089Spjdout: 4120219089Spjd return (err); 4121219089Spjd} 4122219089Spjd 4123219089Spjdint 4124219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4125219089Spjd{ 4126219089Spjd zfs_cmd_t zc = { 0 }; 4127219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4128219089Spjd char *nvbuf; 4129219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4130219089Spjd size_t nvsz; 4131219089Spjd int err; 4132219089Spjd 4133219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4134219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4135219089Spjd 4136219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4137219089Spjd assert(err == 0); 4138219089Spjd 4139219089Spjd nvbuf = malloc(nvsz); 4140219089Spjd 4141219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4142219089Spjd assert(err == 0); 4143219089Spjd 4144219089Spjd zc.zc_nvlist_src_size = nvsz; 4145219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4146219089Spjd zc.zc_perm_action = un; 4147219089Spjd 4148219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4149219089Spjd 4150219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4151219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4152219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4153219089Spjd zc.zc_name); 4154219089Spjd switch (errno) { 4155219089Spjd case ENOTSUP: 4156219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4157219089Spjd "pool must be upgraded")); 4158219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4159219089Spjd break; 4160219089Spjd case EINVAL: 4161219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4162219089Spjd break; 4163219089Spjd case ENOENT: 4164219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4165219089Spjd break; 4166219089Spjd default: 4167219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4168219089Spjd break; 4169219089Spjd } 4170219089Spjd } 4171219089Spjd 4172219089Spjd free(nvbuf); 4173219089Spjd 4174219089Spjd return (err); 4175219089Spjd} 4176219089Spjd 4177219089Spjdint 4178219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4179219089Spjd{ 4180219089Spjd zfs_cmd_t zc = { 0 }; 4181219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4182219089Spjd int nvsz = 2048; 4183219089Spjd void *nvbuf; 4184219089Spjd int err = 0; 4185219089Spjd char errbuf[ZFS_MAXNAMELEN+32]; 4186219089Spjd 4187219089Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 4188219089Spjd 4189219089Spjdtryagain: 4190219089Spjd 4191219089Spjd nvbuf = malloc(nvsz); 4192219089Spjd if (nvbuf == NULL) { 4193219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4194219089Spjd goto out; 4195219089Spjd } 4196219089Spjd 4197219089Spjd zc.zc_nvlist_dst_size = nvsz; 4198219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4199219089Spjd 4200219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4201219089Spjd 4202219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) { 4203219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4204219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4205219089Spjd zc.zc_name); 4206219089Spjd switch (errno) { 4207219089Spjd case ENOMEM: 4208219089Spjd free(nvbuf); 4209219089Spjd nvsz = zc.zc_nvlist_dst_size; 4210219089Spjd goto tryagain; 4211219089Spjd 4212219089Spjd case ENOTSUP: 4213219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4214219089Spjd "pool must be upgraded")); 4215219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4216219089Spjd break; 4217219089Spjd case EINVAL: 4218219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4219219089Spjd break; 4220219089Spjd case ENOENT: 4221219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4222219089Spjd break; 4223219089Spjd default: 4224219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4225219089Spjd break; 4226219089Spjd } 4227219089Spjd } else { 4228219089Spjd /* success */ 4229219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4230219089Spjd if (rc) { 4231219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4232219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4233219089Spjd zc.zc_name); 4234219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4235219089Spjd } 4236219089Spjd } 4237219089Spjd 4238219089Spjd free(nvbuf); 4239219089Spjdout: 4240219089Spjd return (err); 4241219089Spjd} 4242219089Spjd 4243219089Spjduint64_t 4244219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4245219089Spjd{ 4246219089Spjd uint64_t numdb; 4247219089Spjd uint64_t nblocks, volblocksize; 4248219089Spjd int ncopies; 4249219089Spjd char *strval; 4250219089Spjd 4251219089Spjd if (nvlist_lookup_string(props, 4252219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4253219089Spjd ncopies = atoi(strval); 4254219089Spjd else 4255219089Spjd ncopies = 1; 4256219089Spjd if (nvlist_lookup_uint64(props, 4257219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4258219089Spjd &volblocksize) != 0) 4259219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4260219089Spjd nblocks = volsize/volblocksize; 4261219089Spjd /* start with metadnode L0-L6 */ 4262219089Spjd numdb = 7; 4263219089Spjd /* calculate number of indirects */ 4264219089Spjd while (nblocks > 1) { 4265219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4266219089Spjd nblocks /= DNODES_PER_LEVEL; 4267219089Spjd numdb += nblocks; 4268219089Spjd } 4269219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4270219089Spjd volsize *= ncopies; 4271219089Spjd /* 4272219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4273219089Spjd * compressed, but in practice they compress down to about 4274219089Spjd * 1100 bytes 4275219089Spjd */ 4276219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4277219089Spjd volsize += numdb; 4278219089Spjd return (volsize); 4279219089Spjd} 4280219089Spjd 4281168404Spjd/* 4282168404Spjd * Attach/detach the given filesystem to/from the given jail. 4283168404Spjd */ 4284168404Spjdint 4285168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4286168404Spjd{ 4287168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4288168404Spjd zfs_cmd_t zc = { 0 }; 4289168404Spjd char errbuf[1024]; 4290168404Spjd int cmd, ret; 4291168404Spjd 4292168404Spjd if (attach) { 4293168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4294168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4295168404Spjd } else { 4296168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4297168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4298168404Spjd } 4299168404Spjd 4300168404Spjd switch (zhp->zfs_type) { 4301168404Spjd case ZFS_TYPE_VOLUME: 4302168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4303168404Spjd "volumes can not be jailed")); 4304168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4305168404Spjd case ZFS_TYPE_SNAPSHOT: 4306168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4307168404Spjd "snapshots can not be jailed")); 4308168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4309168404Spjd } 4310168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4311168404Spjd 4312168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4313168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4314168404Spjd zc.zc_jailid = jailid; 4315168404Spjd 4316168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4317168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4318168404Spjd zfs_standard_error(hdl, errno, errbuf); 4319168404Spjd 4320168404Spjd return (ret); 4321168404Spjd} 4322