libzfs_dataset.c revision 260183
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24252219Sdelphij * Copyright (c) 2013 by Delphix. All rights reserved. 25252219Sdelphij * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. 26230438Spjd * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>. 27226706Spjd * All rights reserved. 28235216Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 29251646Sdelphij * Copyright (c) 2013 Steven Hartland. All rights reserved. 30259850Sdelphij * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 31168404Spjd */ 32168404Spjd 33168404Spjd#include <ctype.h> 34168404Spjd#include <errno.h> 35168404Spjd#include <libintl.h> 36168404Spjd#include <math.h> 37168404Spjd#include <stdio.h> 38168404Spjd#include <stdlib.h> 39168404Spjd#include <strings.h> 40168404Spjd#include <unistd.h> 41185029Spjd#include <stddef.h> 42168404Spjd#include <zone.h> 43168404Spjd#include <fcntl.h> 44168404Spjd#include <sys/mntent.h> 45168404Spjd#include <sys/mount.h> 46185029Spjd#include <priv.h> 47185029Spjd#include <pwd.h> 48185029Spjd#include <grp.h> 49185029Spjd#include <stddef.h> 50209962Smm#include <idmap.h> 51168404Spjd 52219089Spjd#include <sys/dnode.h> 53168404Spjd#include <sys/spa.h> 54168404Spjd#include <sys/zap.h> 55209962Smm#include <sys/misc.h> 56168404Spjd#include <libzfs.h> 57168404Spjd 58168404Spjd#include "zfs_namecheck.h" 59168404Spjd#include "zfs_prop.h" 60168404Spjd#include "libzfs_impl.h" 61185029Spjd#include "zfs_deleg.h" 62168404Spjd 63209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned, 64209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); 65168676Spjd 66168404Spjd/* 67168404Spjd * Given a single type (not a mask of types), return the type in a human 68168404Spjd * readable form. 69168404Spjd */ 70168404Spjdconst char * 71168404Spjdzfs_type_to_name(zfs_type_t type) 72168404Spjd{ 73168404Spjd switch (type) { 74168404Spjd case ZFS_TYPE_FILESYSTEM: 75168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 76168404Spjd case ZFS_TYPE_SNAPSHOT: 77168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 78168404Spjd case ZFS_TYPE_VOLUME: 79168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 80168404Spjd } 81168404Spjd 82168404Spjd return (NULL); 83168404Spjd} 84168404Spjd 85168404Spjd/* 86168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 87168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 88168404Spjd * We guess what the type would have been based on the path and the mask of 89168404Spjd * acceptable types. 90168404Spjd */ 91168404Spjdstatic const char * 92168404Spjdpath_to_str(const char *path, int types) 93168404Spjd{ 94168404Spjd /* 95168404Spjd * When given a single type, always report the exact type. 96168404Spjd */ 97168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 98168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 99168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 100168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 101168404Spjd if (types == ZFS_TYPE_VOLUME) 102168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 103168404Spjd 104168404Spjd /* 105168404Spjd * The user is requesting more than one type of dataset. If this is the 106168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 107168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 108168404Spjd * snapshot attribute and try again. 109168404Spjd */ 110168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 111168404Spjd if (strchr(path, '@') != NULL) 112168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 113168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 114168404Spjd } 115168404Spjd 116168404Spjd /* 117168404Spjd * The user has requested either filesystems or volumes. 118168404Spjd * We have no way of knowing a priori what type this would be, so always 119168404Spjd * report it as "filesystem" or "volume", our two primitive types. 120168404Spjd */ 121168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 122168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 123168404Spjd 124168404Spjd assert(types & ZFS_TYPE_VOLUME); 125168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 126168404Spjd} 127168404Spjd 128168404Spjd/* 129168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 130209962Smm * provide a more meaningful error message. We call zfs_error_aux() to 131209962Smm * explain exactly why the name was not valid. 132168404Spjd */ 133219089Spjdint 134185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 135185029Spjd boolean_t modifying) 136168404Spjd{ 137168404Spjd namecheck_err_t why; 138168404Spjd char what; 139168404Spjd 140219089Spjd (void) zfs_prop_get_table(); 141168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 142168404Spjd if (hdl != NULL) { 143168404Spjd switch (why) { 144168404Spjd case NAME_ERR_TOOLONG: 145168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 146168404Spjd "name is too long")); 147168404Spjd break; 148168404Spjd 149168404Spjd case NAME_ERR_LEADING_SLASH: 150168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 151168404Spjd "leading slash in name")); 152168404Spjd break; 153168404Spjd 154168404Spjd case NAME_ERR_EMPTY_COMPONENT: 155168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 156168404Spjd "empty component in name")); 157168404Spjd break; 158168404Spjd 159168404Spjd case NAME_ERR_TRAILING_SLASH: 160168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 161168404Spjd "trailing slash in name")); 162168404Spjd break; 163168404Spjd 164168404Spjd case NAME_ERR_INVALCHAR: 165168404Spjd zfs_error_aux(hdl, 166168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 167168404Spjd "'%c' in name"), what); 168168404Spjd break; 169168404Spjd 170168404Spjd case NAME_ERR_MULTIPLE_AT: 171168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 172168404Spjd "multiple '@' delimiters in name")); 173168404Spjd break; 174168404Spjd 175168404Spjd case NAME_ERR_NOLETTER: 176168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 177168404Spjd "pool doesn't begin with a letter")); 178168404Spjd break; 179168404Spjd 180168404Spjd case NAME_ERR_RESERVED: 181168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 182168404Spjd "name is reserved")); 183168404Spjd break; 184168404Spjd 185168404Spjd case NAME_ERR_DISKLIKE: 186168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 187168404Spjd "reserved disk name")); 188168404Spjd break; 189168404Spjd } 190168404Spjd } 191168404Spjd 192168404Spjd return (0); 193168404Spjd } 194168404Spjd 195168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 196168404Spjd if (hdl != NULL) 197168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 198168404Spjd "snapshot delimiter '@' in filesystem name")); 199168404Spjd return (0); 200168404Spjd } 201168404Spjd 202168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 203168404Spjd if (hdl != NULL) 204168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 205168404Spjd "missing '@' delimiter in snapshot name")); 206168404Spjd return (0); 207168404Spjd } 208168404Spjd 209185029Spjd if (modifying && strchr(path, '%') != NULL) { 210185029Spjd if (hdl != NULL) 211185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 212185029Spjd "invalid character %c in name"), '%'); 213185029Spjd return (0); 214185029Spjd } 215185029Spjd 216168404Spjd return (-1); 217168404Spjd} 218168404Spjd 219168404Spjdint 220168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 221168404Spjd{ 222185029Spjd if (type == ZFS_TYPE_POOL) 223185029Spjd return (zpool_name_valid(NULL, B_FALSE, name)); 224185029Spjd return (zfs_validate_name(NULL, name, type, B_FALSE)); 225168404Spjd} 226168404Spjd 227168404Spjd/* 228168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 229168404Spjd * properties into a separate nvlist. 230168404Spjd */ 231185029Spjdstatic nvlist_t * 232185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props) 233168404Spjd{ 234168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 235168404Spjd nvpair_t *elem; 236168404Spjd nvlist_t *propval; 237185029Spjd nvlist_t *nvl; 238168404Spjd 239185029Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 240185029Spjd (void) no_memory(hdl); 241185029Spjd return (NULL); 242185029Spjd } 243168404Spjd 244168404Spjd elem = NULL; 245185029Spjd while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 246168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 247168404Spjd continue; 248168404Spjd 249168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 250185029Spjd if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 251185029Spjd nvlist_free(nvl); 252185029Spjd (void) no_memory(hdl); 253185029Spjd return (NULL); 254185029Spjd } 255168404Spjd } 256168404Spjd 257185029Spjd return (nvl); 258168404Spjd} 259168404Spjd 260185029Spjdstatic zpool_handle_t * 261185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 262185029Spjd{ 263185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 264185029Spjd zpool_handle_t *zph; 265185029Spjd 266185029Spjd if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 267185029Spjd if (hdl->libzfs_pool_handles != NULL) 268185029Spjd zph->zpool_next = hdl->libzfs_pool_handles; 269185029Spjd hdl->libzfs_pool_handles = zph; 270185029Spjd } 271185029Spjd return (zph); 272185029Spjd} 273185029Spjd 274185029Spjdstatic zpool_handle_t * 275185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 276185029Spjd{ 277185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 278185029Spjd zpool_handle_t *zph = hdl->libzfs_pool_handles; 279185029Spjd 280185029Spjd while ((zph != NULL) && 281185029Spjd (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 282185029Spjd zph = zph->zpool_next; 283185029Spjd return (zph); 284185029Spjd} 285185029Spjd 286168404Spjd/* 287185029Spjd * Returns a handle to the pool that contains the provided dataset. 288185029Spjd * If a handle to that pool already exists then that handle is returned. 289185029Spjd * Otherwise, a new handle is created and added to the list of handles. 290185029Spjd */ 291185029Spjdstatic zpool_handle_t * 292185029Spjdzpool_handle(zfs_handle_t *zhp) 293185029Spjd{ 294185029Spjd char *pool_name; 295185029Spjd int len; 296185029Spjd zpool_handle_t *zph; 297185029Spjd 298260183Sdelphij len = strcspn(zhp->zfs_name, "/@#") + 1; 299185029Spjd pool_name = zfs_alloc(zhp->zfs_hdl, len); 300185029Spjd (void) strlcpy(pool_name, zhp->zfs_name, len); 301185029Spjd 302185029Spjd zph = zpool_find_handle(zhp, pool_name, len); 303185029Spjd if (zph == NULL) 304185029Spjd zph = zpool_add_handle(zhp, pool_name); 305185029Spjd 306185029Spjd free(pool_name); 307185029Spjd return (zph); 308185029Spjd} 309185029Spjd 310185029Spjdvoid 311185029Spjdzpool_free_handles(libzfs_handle_t *hdl) 312185029Spjd{ 313185029Spjd zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 314185029Spjd 315185029Spjd while (zph != NULL) { 316185029Spjd next = zph->zpool_next; 317185029Spjd zpool_close(zph); 318185029Spjd zph = next; 319185029Spjd } 320185029Spjd hdl->libzfs_pool_handles = NULL; 321185029Spjd} 322185029Spjd 323185029Spjd/* 324168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 325168404Spjd */ 326219089Spjdstatic int 327209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) 328168404Spjd{ 329168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 330168404Spjd 331209962Smm (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 332168404Spjd 333209962Smm while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) { 334168404Spjd if (errno == ENOMEM) { 335209962Smm if (zcmd_expand_dst_nvlist(hdl, zc) != 0) { 336168404Spjd return (-1); 337168404Spjd } 338168404Spjd } else { 339168404Spjd return (-1); 340168404Spjd } 341168404Spjd } 342209962Smm return (0); 343209962Smm} 344168404Spjd 345219089Spjd/* 346219089Spjd * Utility function to get the received properties of the given object. 347219089Spjd */ 348209962Smmstatic int 349219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp) 350219089Spjd{ 351219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 352219089Spjd nvlist_t *recvdprops; 353219089Spjd zfs_cmd_t zc = { 0 }; 354219089Spjd int err; 355219089Spjd 356219089Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 357219089Spjd return (-1); 358219089Spjd 359219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 360219089Spjd 361219089Spjd while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) { 362219089Spjd if (errno == ENOMEM) { 363219089Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 364219089Spjd return (-1); 365219089Spjd } 366219089Spjd } else { 367219089Spjd zcmd_free_nvlists(&zc); 368219089Spjd return (-1); 369219089Spjd } 370219089Spjd } 371219089Spjd 372219089Spjd err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); 373219089Spjd zcmd_free_nvlists(&zc); 374219089Spjd if (err != 0) 375219089Spjd return (-1); 376219089Spjd 377219089Spjd nvlist_free(zhp->zfs_recvd_props); 378219089Spjd zhp->zfs_recvd_props = recvdprops; 379219089Spjd 380219089Spjd return (0); 381219089Spjd} 382219089Spjd 383219089Spjdstatic int 384209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) 385209962Smm{ 386209962Smm nvlist_t *allprops, *userprops; 387168404Spjd 388209962Smm zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */ 389209962Smm 390209962Smm if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) { 391168404Spjd return (-1); 392168404Spjd } 393168404Spjd 394209962Smm /* 395209962Smm * XXX Why do we store the user props separately, in addition to 396209962Smm * storing them in zfs_props? 397209962Smm */ 398185029Spjd if ((userprops = process_user_props(zhp, allprops)) == NULL) { 399185029Spjd nvlist_free(allprops); 400168404Spjd return (-1); 401185029Spjd } 402168404Spjd 403185029Spjd nvlist_free(zhp->zfs_props); 404185029Spjd nvlist_free(zhp->zfs_user_props); 405185029Spjd 406185029Spjd zhp->zfs_props = allprops; 407185029Spjd zhp->zfs_user_props = userprops; 408185029Spjd 409168404Spjd return (0); 410168404Spjd} 411168404Spjd 412209962Smmstatic int 413209962Smmget_stats(zfs_handle_t *zhp) 414209962Smm{ 415209962Smm int rc = 0; 416209962Smm zfs_cmd_t zc = { 0 }; 417209962Smm 418209962Smm if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 419209962Smm return (-1); 420209962Smm if (get_stats_ioctl(zhp, &zc) != 0) 421209962Smm rc = -1; 422209962Smm else if (put_stats_zhdl(zhp, &zc) != 0) 423209962Smm rc = -1; 424209962Smm zcmd_free_nvlists(&zc); 425209962Smm return (rc); 426209962Smm} 427209962Smm 428168404Spjd/* 429168404Spjd * Refresh the properties currently stored in the handle. 430168404Spjd */ 431168404Spjdvoid 432168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 433168404Spjd{ 434168404Spjd (void) get_stats(zhp); 435168404Spjd} 436168404Spjd 437168404Spjd/* 438168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 439168404Spjd * zfs_iter_* to create child handles on the fly. 440168404Spjd */ 441209962Smmstatic int 442209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) 443168404Spjd{ 444219089Spjd if (put_stats_zhdl(zhp, zc) != 0) 445209962Smm return (-1); 446168404Spjd 447168404Spjd /* 448168404Spjd * We've managed to open the dataset and gather statistics. Determine 449168404Spjd * the high-level type. 450168404Spjd */ 451168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 452168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 453168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 454168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 455168404Spjd else 456168404Spjd abort(); 457168404Spjd 458168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 459168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 460168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 461168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 462168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 463168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 464168404Spjd else 465168404Spjd abort(); /* we should never see any other types */ 466168404Spjd 467219089Spjd if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) 468219089Spjd return (-1); 469219089Spjd 470209962Smm return (0); 471209962Smm} 472209962Smm 473209962Smmzfs_handle_t * 474209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 475209962Smm{ 476209962Smm zfs_cmd_t zc = { 0 }; 477209962Smm 478209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 479209962Smm 480209962Smm if (zhp == NULL) 481209962Smm return (NULL); 482209962Smm 483209962Smm zhp->zfs_hdl = hdl; 484209962Smm (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 485209962Smm if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) { 486209962Smm free(zhp); 487209962Smm return (NULL); 488209962Smm } 489209962Smm if (get_stats_ioctl(zhp, &zc) == -1) { 490209962Smm zcmd_free_nvlists(&zc); 491209962Smm free(zhp); 492209962Smm return (NULL); 493209962Smm } 494209962Smm if (make_dataset_handle_common(zhp, &zc) == -1) { 495209962Smm free(zhp); 496209962Smm zhp = NULL; 497209962Smm } 498209962Smm zcmd_free_nvlists(&zc); 499168404Spjd return (zhp); 500168404Spjd} 501168404Spjd 502228103Smmzfs_handle_t * 503209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) 504209962Smm{ 505209962Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 506209962Smm 507209962Smm if (zhp == NULL) 508209962Smm return (NULL); 509209962Smm 510209962Smm zhp->zfs_hdl = hdl; 511209962Smm (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 512209962Smm if (make_dataset_handle_common(zhp, zc) == -1) { 513209962Smm free(zhp); 514209962Smm return (NULL); 515209962Smm } 516209962Smm return (zhp); 517209962Smm} 518209962Smm 519228103Smmzfs_handle_t * 520230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) 521230438Spjd{ 522230438Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 523230438Spjd 524230438Spjd if (zhp == NULL) 525230438Spjd return (NULL); 526230438Spjd 527230438Spjd zhp->zfs_hdl = pzhp->zfs_hdl; 528230438Spjd (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); 529230438Spjd zhp->zfs_head_type = pzhp->zfs_type; 530230438Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 531230438Spjd zhp->zpool_hdl = zpool_handle(zhp); 532230438Spjd return (zhp); 533230438Spjd} 534230438Spjd 535230438Spjdzfs_handle_t * 536228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig) 537228103Smm{ 538228103Smm zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 539228103Smm 540228103Smm if (zhp == NULL) 541228103Smm return (NULL); 542228103Smm 543228103Smm zhp->zfs_hdl = zhp_orig->zfs_hdl; 544228103Smm zhp->zpool_hdl = zhp_orig->zpool_hdl; 545228103Smm (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, 546228103Smm sizeof (zhp->zfs_name)); 547228103Smm zhp->zfs_type = zhp_orig->zfs_type; 548228103Smm zhp->zfs_head_type = zhp_orig->zfs_head_type; 549228103Smm zhp->zfs_dmustats = zhp_orig->zfs_dmustats; 550228103Smm if (zhp_orig->zfs_props != NULL) { 551228103Smm if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { 552228103Smm (void) no_memory(zhp->zfs_hdl); 553228103Smm zfs_close(zhp); 554228103Smm return (NULL); 555228103Smm } 556228103Smm } 557228103Smm if (zhp_orig->zfs_user_props != NULL) { 558228103Smm if (nvlist_dup(zhp_orig->zfs_user_props, 559228103Smm &zhp->zfs_user_props, 0) != 0) { 560228103Smm (void) no_memory(zhp->zfs_hdl); 561228103Smm zfs_close(zhp); 562228103Smm return (NULL); 563228103Smm } 564228103Smm } 565228103Smm if (zhp_orig->zfs_recvd_props != NULL) { 566228103Smm if (nvlist_dup(zhp_orig->zfs_recvd_props, 567228103Smm &zhp->zfs_recvd_props, 0)) { 568228103Smm (void) no_memory(zhp->zfs_hdl); 569228103Smm zfs_close(zhp); 570228103Smm return (NULL); 571228103Smm } 572228103Smm } 573228103Smm zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; 574228103Smm if (zhp_orig->zfs_mntopts != NULL) { 575228103Smm zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, 576228103Smm zhp_orig->zfs_mntopts); 577228103Smm } 578228103Smm zhp->zfs_props_table = zhp_orig->zfs_props_table; 579228103Smm return (zhp); 580228103Smm} 581228103Smm 582260183Sdelphijboolean_t 583260183Sdelphijzfs_bookmark_exists(const char *path) 584260183Sdelphij{ 585260183Sdelphij nvlist_t *bmarks; 586260183Sdelphij nvlist_t *props; 587260183Sdelphij char fsname[ZFS_MAXNAMELEN]; 588260183Sdelphij char *bmark_name; 589260183Sdelphij char *pound; 590260183Sdelphij int err; 591260183Sdelphij boolean_t rv; 592260183Sdelphij 593260183Sdelphij 594260183Sdelphij (void) strlcpy(fsname, path, sizeof (fsname)); 595260183Sdelphij pound = strchr(fsname, '#'); 596260183Sdelphij if (pound == NULL) 597260183Sdelphij return (B_FALSE); 598260183Sdelphij 599260183Sdelphij *pound = '\0'; 600260183Sdelphij bmark_name = pound + 1; 601260183Sdelphij props = fnvlist_alloc(); 602260183Sdelphij err = lzc_get_bookmarks(fsname, props, &bmarks); 603260183Sdelphij nvlist_free(props); 604260183Sdelphij if (err != 0) { 605260183Sdelphij nvlist_free(bmarks); 606260183Sdelphij return (B_FALSE); 607260183Sdelphij } 608260183Sdelphij 609260183Sdelphij rv = nvlist_exists(bmarks, bmark_name); 610260183Sdelphij nvlist_free(bmarks); 611260183Sdelphij return (rv); 612260183Sdelphij} 613260183Sdelphij 614260183Sdelphijzfs_handle_t * 615260183Sdelphijmake_bookmark_handle(zfs_handle_t *parent, const char *path, 616260183Sdelphij nvlist_t *bmark_props) 617260183Sdelphij{ 618260183Sdelphij zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 619260183Sdelphij 620260183Sdelphij if (zhp == NULL) 621260183Sdelphij return (NULL); 622260183Sdelphij 623260183Sdelphij /* Fill in the name. */ 624260183Sdelphij zhp->zfs_hdl = parent->zfs_hdl; 625260183Sdelphij (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 626260183Sdelphij 627260183Sdelphij /* Set the property lists. */ 628260183Sdelphij if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { 629260183Sdelphij free(zhp); 630260183Sdelphij return (NULL); 631260183Sdelphij } 632260183Sdelphij 633260183Sdelphij /* Set the types. */ 634260183Sdelphij zhp->zfs_head_type = parent->zfs_head_type; 635260183Sdelphij zhp->zfs_type = ZFS_TYPE_BOOKMARK; 636260183Sdelphij 637260183Sdelphij if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { 638260183Sdelphij nvlist_free(zhp->zfs_props); 639260183Sdelphij free(zhp); 640260183Sdelphij return (NULL); 641260183Sdelphij } 642260183Sdelphij 643260183Sdelphij return (zhp); 644260183Sdelphij} 645260183Sdelphij 646168404Spjd/* 647168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 648168404Spjd * argument is a mask of acceptable types. The function will print an 649168404Spjd * appropriate error message and return NULL if it can't be opened. 650168404Spjd */ 651168404Spjdzfs_handle_t * 652168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 653168404Spjd{ 654168404Spjd zfs_handle_t *zhp; 655168404Spjd char errbuf[1024]; 656168404Spjd 657168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 658168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 659168404Spjd 660168404Spjd /* 661168404Spjd * Validate the name before we even try to open it. 662168404Spjd */ 663185029Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { 664168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 665168404Spjd "invalid dataset name")); 666168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 667168404Spjd return (NULL); 668168404Spjd } 669168404Spjd 670168404Spjd /* 671168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 672168404Spjd */ 673168404Spjd errno = 0; 674168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 675168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 676168404Spjd return (NULL); 677168404Spjd } 678168404Spjd 679240870Spjd if (zhp == NULL) { 680240870Spjd char *at = strchr(path, '@'); 681240870Spjd 682240870Spjd if (at != NULL) 683240870Spjd *at = '\0'; 684240870Spjd errno = 0; 685240870Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 686240870Spjd (void) zfs_standard_error(hdl, errno, errbuf); 687240870Spjd return (NULL); 688240870Spjd } 689240870Spjd if (at != NULL) 690240870Spjd *at = '@'; 691240870Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 692240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 693240870Spjd } 694240870Spjd 695168404Spjd if (!(types & zhp->zfs_type)) { 696168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 697168404Spjd zfs_close(zhp); 698168404Spjd return (NULL); 699168404Spjd } 700168404Spjd 701168404Spjd return (zhp); 702168404Spjd} 703168404Spjd 704168404Spjd/* 705168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 706168404Spjd */ 707168404Spjdvoid 708168404Spjdzfs_close(zfs_handle_t *zhp) 709168404Spjd{ 710168404Spjd if (zhp->zfs_mntopts) 711168404Spjd free(zhp->zfs_mntopts); 712168404Spjd nvlist_free(zhp->zfs_props); 713168404Spjd nvlist_free(zhp->zfs_user_props); 714219089Spjd nvlist_free(zhp->zfs_recvd_props); 715168404Spjd free(zhp); 716168404Spjd} 717168404Spjd 718209962Smmtypedef struct mnttab_node { 719209962Smm struct mnttab mtn_mt; 720209962Smm avl_node_t mtn_node; 721209962Smm} mnttab_node_t; 722209962Smm 723209962Smmstatic int 724209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2) 725209962Smm{ 726209962Smm const mnttab_node_t *mtn1 = arg1; 727209962Smm const mnttab_node_t *mtn2 = arg2; 728209962Smm int rv; 729209962Smm 730209962Smm rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); 731209962Smm 732209962Smm if (rv == 0) 733209962Smm return (0); 734209962Smm return (rv > 0 ? 1 : -1); 735209962Smm} 736209962Smm 737209962Smmvoid 738209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl) 739209962Smm{ 740209962Smm assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0); 741209962Smm avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, 742209962Smm sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); 743209962Smm} 744209962Smm 745209962Smmvoid 746209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl) 747209962Smm{ 748209962Smm struct mnttab entry; 749209962Smm 750209962Smm rewind(hdl->libzfs_mnttab); 751209962Smm while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 752209962Smm mnttab_node_t *mtn; 753209962Smm 754209962Smm if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 755209962Smm continue; 756209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 757209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special); 758209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp); 759209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype); 760209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts); 761209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 762209962Smm } 763209962Smm} 764209962Smm 765209962Smmvoid 766209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl) 767209962Smm{ 768209962Smm void *cookie = NULL; 769209962Smm mnttab_node_t *mtn; 770209962Smm 771209962Smm while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { 772209962Smm free(mtn->mtn_mt.mnt_special); 773209962Smm free(mtn->mtn_mt.mnt_mountp); 774209962Smm free(mtn->mtn_mt.mnt_fstype); 775209962Smm free(mtn->mtn_mt.mnt_mntopts); 776209962Smm free(mtn); 777209962Smm } 778209962Smm avl_destroy(&hdl->libzfs_mnttab_cache); 779209962Smm} 780209962Smm 781209962Smmvoid 782209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) 783209962Smm{ 784209962Smm hdl->libzfs_mnttab_enable = enable; 785209962Smm} 786209962Smm 787185029Spjdint 788209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, 789209962Smm struct mnttab *entry) 790209962Smm{ 791209962Smm mnttab_node_t find; 792209962Smm mnttab_node_t *mtn; 793209962Smm 794209962Smm if (!hdl->libzfs_mnttab_enable) { 795209962Smm struct mnttab srch = { 0 }; 796209962Smm 797209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache)) 798209962Smm libzfs_mnttab_fini(hdl); 799209962Smm rewind(hdl->libzfs_mnttab); 800209962Smm srch.mnt_special = (char *)fsname; 801209962Smm srch.mnt_fstype = MNTTYPE_ZFS; 802209962Smm if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0) 803209962Smm return (0); 804209962Smm else 805209962Smm return (ENOENT); 806209962Smm } 807209962Smm 808209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 809209962Smm libzfs_mnttab_update(hdl); 810209962Smm 811209962Smm find.mtn_mt.mnt_special = (char *)fsname; 812209962Smm mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); 813209962Smm if (mtn) { 814209962Smm *entry = mtn->mtn_mt; 815209962Smm return (0); 816209962Smm } 817209962Smm return (ENOENT); 818209962Smm} 819209962Smm 820209962Smmvoid 821209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, 822209962Smm const char *mountp, const char *mntopts) 823209962Smm{ 824209962Smm mnttab_node_t *mtn; 825209962Smm 826209962Smm if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) 827209962Smm return; 828209962Smm mtn = zfs_alloc(hdl, sizeof (mnttab_node_t)); 829209962Smm mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special); 830209962Smm mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp); 831209962Smm mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS); 832209962Smm mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts); 833209962Smm avl_add(&hdl->libzfs_mnttab_cache, mtn); 834209962Smm} 835209962Smm 836209962Smmvoid 837209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) 838209962Smm{ 839209962Smm mnttab_node_t find; 840209962Smm mnttab_node_t *ret; 841209962Smm 842209962Smm find.mtn_mt.mnt_special = (char *)fsname; 843209962Smm if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { 844209962Smm avl_remove(&hdl->libzfs_mnttab_cache, ret); 845209962Smm free(ret->mtn_mt.mnt_special); 846209962Smm free(ret->mtn_mt.mnt_mountp); 847209962Smm free(ret->mtn_mt.mnt_fstype); 848209962Smm free(ret->mtn_mt.mnt_mntopts); 849209962Smm free(ret); 850209962Smm } 851209962Smm} 852209962Smm 853209962Smmint 854185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version) 855168404Spjd{ 856185029Spjd zpool_handle_t *zpool_handle = zhp->zpool_hdl; 857168404Spjd 858185029Spjd if (zpool_handle == NULL) 859168404Spjd return (-1); 860168404Spjd 861185029Spjd *spa_version = zpool_get_prop_int(zpool_handle, 862185029Spjd ZPOOL_PROP_VERSION, NULL); 863168404Spjd return (0); 864168404Spjd} 865168404Spjd 866168404Spjd/* 867185029Spjd * The choice of reservation property depends on the SPA version. 868168404Spjd */ 869168404Spjdstatic int 870185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) 871168404Spjd{ 872185029Spjd int spa_version; 873168404Spjd 874185029Spjd if (zfs_spa_version(zhp, &spa_version) < 0) 875168404Spjd return (-1); 876168404Spjd 877185029Spjd if (spa_version >= SPA_VERSION_REFRESERVATION) 878185029Spjd *resv_prop = ZFS_PROP_REFRESERVATION; 879185029Spjd else 880185029Spjd *resv_prop = ZFS_PROP_RESERVATION; 881168404Spjd 882168404Spjd return (0); 883168404Spjd} 884168404Spjd 885168404Spjd/* 886168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 887168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 888168404Spjd * strings. 889168404Spjd */ 890168404Spjdnvlist_t * 891185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 892185029Spjd uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 893168404Spjd{ 894168404Spjd nvpair_t *elem; 895168404Spjd uint64_t intval; 896168404Spjd char *strval; 897185029Spjd zfs_prop_t prop; 898168404Spjd nvlist_t *ret; 899185029Spjd int chosen_normal = -1; 900185029Spjd int chosen_utf = -1; 901168404Spjd 902168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 903168404Spjd (void) no_memory(hdl); 904168404Spjd return (NULL); 905168404Spjd } 906168404Spjd 907209962Smm /* 908209962Smm * Make sure this property is valid and applies to this type. 909209962Smm */ 910209962Smm 911168404Spjd elem = NULL; 912168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 913185029Spjd const char *propname = nvpair_name(elem); 914168404Spjd 915209962Smm prop = zfs_name_to_prop(propname); 916209962Smm if (prop == ZPROP_INVAL && zfs_prop_user(propname)) { 917185029Spjd /* 918209962Smm * This is a user property: make sure it's a 919185029Spjd * string, and that it's less than ZAP_MAXNAMELEN. 920185029Spjd */ 921185029Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 922185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 923185029Spjd "'%s' must be a string"), propname); 924185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 925185029Spjd goto error; 926168404Spjd } 927168404Spjd 928185029Spjd if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 929185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 930185029Spjd "property name '%s' is too long"), 931185029Spjd propname); 932185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 933185029Spjd goto error; 934185029Spjd } 935185029Spjd 936168404Spjd (void) nvpair_value_string(elem, &strval); 937168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 938168404Spjd (void) no_memory(hdl); 939168404Spjd goto error; 940168404Spjd } 941168404Spjd continue; 942168404Spjd } 943168404Spjd 944209962Smm /* 945209962Smm * Currently, only user properties can be modified on 946209962Smm * snapshots. 947209962Smm */ 948185029Spjd if (type == ZFS_TYPE_SNAPSHOT) { 949185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 950185029Spjd "this property can not be modified for snapshots")); 951185029Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 952185029Spjd goto error; 953185029Spjd } 954168404Spjd 955209962Smm if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) { 956209962Smm zfs_userquota_prop_t uqtype; 957209962Smm char newpropname[128]; 958209962Smm char domain[128]; 959209962Smm uint64_t rid; 960209962Smm uint64_t valary[3]; 961209962Smm 962209962Smm if (userquota_propname_decode(propname, zoned, 963209962Smm &uqtype, domain, sizeof (domain), &rid) != 0) { 964209962Smm zfs_error_aux(hdl, 965209962Smm dgettext(TEXT_DOMAIN, 966209962Smm "'%s' has an invalid user/group name"), 967209962Smm propname); 968209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 969209962Smm goto error; 970209962Smm } 971209962Smm 972209962Smm if (uqtype != ZFS_PROP_USERQUOTA && 973209962Smm uqtype != ZFS_PROP_GROUPQUOTA) { 974209962Smm zfs_error_aux(hdl, 975209962Smm dgettext(TEXT_DOMAIN, "'%s' is readonly"), 976209962Smm propname); 977209962Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, 978209962Smm errbuf); 979209962Smm goto error; 980209962Smm } 981209962Smm 982209962Smm if (nvpair_type(elem) == DATA_TYPE_STRING) { 983209962Smm (void) nvpair_value_string(elem, &strval); 984209962Smm if (strcmp(strval, "none") == 0) { 985209962Smm intval = 0; 986209962Smm } else if (zfs_nicestrtonum(hdl, 987209962Smm strval, &intval) != 0) { 988209962Smm (void) zfs_error(hdl, 989209962Smm EZFS_BADPROP, errbuf); 990209962Smm goto error; 991209962Smm } 992209962Smm } else if (nvpair_type(elem) == 993209962Smm DATA_TYPE_UINT64) { 994209962Smm (void) nvpair_value_uint64(elem, &intval); 995209962Smm if (intval == 0) { 996209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 997209962Smm "use 'none' to disable " 998209962Smm "userquota/groupquota")); 999209962Smm goto error; 1000209962Smm } 1001209962Smm } else { 1002209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1003209962Smm "'%s' must be a number"), propname); 1004209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1005209962Smm goto error; 1006209962Smm } 1007209962Smm 1008219089Spjd /* 1009219089Spjd * Encode the prop name as 1010219089Spjd * userquota@<hex-rid>-domain, to make it easy 1011219089Spjd * for the kernel to decode. 1012219089Spjd */ 1013209962Smm (void) snprintf(newpropname, sizeof (newpropname), 1014219089Spjd "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], 1015219089Spjd (longlong_t)rid, domain); 1016209962Smm valary[0] = uqtype; 1017209962Smm valary[1] = rid; 1018209962Smm valary[2] = intval; 1019209962Smm if (nvlist_add_uint64_array(ret, newpropname, 1020209962Smm valary, 3) != 0) { 1021209962Smm (void) no_memory(hdl); 1022209962Smm goto error; 1023209962Smm } 1024209962Smm continue; 1025228103Smm } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { 1026228103Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1027228103Smm "'%s' is readonly"), 1028228103Smm propname); 1029228103Smm (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1030228103Smm goto error; 1031209962Smm } 1032209962Smm 1033209962Smm if (prop == ZPROP_INVAL) { 1034209962Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1035209962Smm "invalid property '%s'"), propname); 1036209962Smm (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1037209962Smm goto error; 1038209962Smm } 1039209962Smm 1040168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 1041168404Spjd zfs_error_aux(hdl, 1042168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 1043168404Spjd "apply to datasets of this type"), propname); 1044168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 1045168404Spjd goto error; 1046168404Spjd } 1047168404Spjd 1048168404Spjd if (zfs_prop_readonly(prop) && 1049185029Spjd (!zfs_prop_setonce(prop) || zhp != NULL)) { 1050168404Spjd zfs_error_aux(hdl, 1051168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 1052168404Spjd propname); 1053168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 1054168404Spjd goto error; 1055168404Spjd } 1056168404Spjd 1057185029Spjd if (zprop_parse_value(hdl, elem, prop, type, ret, 1058185029Spjd &strval, &intval, errbuf) != 0) 1059185029Spjd goto error; 1060185029Spjd 1061168404Spjd /* 1062185029Spjd * Perform some additional checks for specific properties. 1063168404Spjd */ 1064185029Spjd switch (prop) { 1065185029Spjd case ZFS_PROP_VERSION: 1066185029Spjd { 1067185029Spjd int version; 1068168404Spjd 1069185029Spjd if (zhp == NULL) 1070185029Spjd break; 1071185029Spjd version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1072185029Spjd if (intval < version) { 1073168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1074185029Spjd "Can not downgrade; already at version %u"), 1075185029Spjd version); 1076168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1077168404Spjd goto error; 1078168404Spjd } 1079168404Spjd break; 1080168404Spjd } 1081168404Spjd 1082168404Spjd case ZFS_PROP_RECORDSIZE: 1083168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 1084168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 1085168404Spjd if (intval < SPA_MINBLOCKSIZE || 1086168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 1087168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1088168404Spjd "'%s' must be power of 2 from %u " 1089168404Spjd "to %uk"), propname, 1090168404Spjd (uint_t)SPA_MINBLOCKSIZE, 1091168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 1092168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1093168404Spjd goto error; 1094168404Spjd } 1095168404Spjd break; 1096168404Spjd 1097219089Spjd case ZFS_PROP_MLSLABEL: 1098219089Spjd { 1099219089Spjd#ifdef sun 1100219089Spjd /* 1101219089Spjd * Verify the mlslabel string and convert to 1102219089Spjd * internal hex label string. 1103219089Spjd */ 1104219089Spjd 1105219089Spjd m_label_t *new_sl; 1106219089Spjd char *hex = NULL; /* internal label string */ 1107219089Spjd 1108219089Spjd /* Default value is already OK. */ 1109219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 1110219089Spjd break; 1111219089Spjd 1112219089Spjd /* Verify the label can be converted to binary form */ 1113219089Spjd if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) || 1114219089Spjd (str_to_label(strval, &new_sl, MAC_LABEL, 1115219089Spjd L_NO_CORRECTION, NULL) == -1)) { 1116219089Spjd goto badlabel; 1117168404Spjd } 1118168404Spjd 1119219089Spjd /* Now translate to hex internal label string */ 1120219089Spjd if (label_to_str(new_sl, &hex, M_INTERNAL, 1121219089Spjd DEF_NAMES) != 0) { 1122219089Spjd if (hex) 1123219089Spjd free(hex); 1124219089Spjd goto badlabel; 1125219089Spjd } 1126219089Spjd m_label_free(new_sl); 1127219089Spjd 1128219089Spjd /* If string is already in internal form, we're done. */ 1129219089Spjd if (strcmp(strval, hex) == 0) { 1130219089Spjd free(hex); 1131219089Spjd break; 1132219089Spjd } 1133219089Spjd 1134219089Spjd /* Replace the label string with the internal form. */ 1135219089Spjd (void) nvlist_remove(ret, zfs_prop_to_name(prop), 1136219089Spjd DATA_TYPE_STRING); 1137219089Spjd verify(nvlist_add_string(ret, zfs_prop_to_name(prop), 1138219089Spjd hex) == 0); 1139219089Spjd free(hex); 1140219089Spjd 1141168404Spjd break; 1142168404Spjd 1143219089Spjdbadlabel: 1144219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1145219089Spjd "invalid mlslabel '%s'"), strval); 1146219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1147219089Spjd m_label_free(new_sl); /* OK if null */ 1148219089Spjd#else /* !sun */ 1149219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1150219089Spjd "mlslabel is not supported on FreeBSD")); 1151219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1152219089Spjd#endif /* !sun */ 1153219089Spjd goto error; 1154219089Spjd 1155219089Spjd } 1156219089Spjd 1157168404Spjd case ZFS_PROP_MOUNTPOINT: 1158185029Spjd { 1159185029Spjd namecheck_err_t why; 1160185029Spjd 1161168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 1162168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 1163168404Spjd break; 1164168404Spjd 1165185029Spjd if (mountpoint_namecheck(strval, &why)) { 1166185029Spjd switch (why) { 1167185029Spjd case NAME_ERR_LEADING_SLASH: 1168185029Spjd zfs_error_aux(hdl, 1169185029Spjd dgettext(TEXT_DOMAIN, 1170185029Spjd "'%s' must be an absolute path, " 1171185029Spjd "'none', or 'legacy'"), propname); 1172185029Spjd break; 1173185029Spjd case NAME_ERR_TOOLONG: 1174185029Spjd zfs_error_aux(hdl, 1175185029Spjd dgettext(TEXT_DOMAIN, 1176185029Spjd "component of '%s' is too long"), 1177185029Spjd propname); 1178185029Spjd break; 1179185029Spjd } 1180168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1181168404Spjd goto error; 1182168404Spjd } 1183185029Spjd } 1184185029Spjd 1185168404Spjd /*FALLTHRU*/ 1186168404Spjd 1187185029Spjd case ZFS_PROP_SHARESMB: 1188168404Spjd case ZFS_PROP_SHARENFS: 1189168404Spjd /* 1190185029Spjd * For the mountpoint and sharenfs or sharesmb 1191185029Spjd * properties, check if it can be set in a 1192185029Spjd * global/non-global zone based on 1193168404Spjd * the zoned property value: 1194168404Spjd * 1195168404Spjd * global zone non-global zone 1196168404Spjd * -------------------------------------------------- 1197168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 1198168404Spjd * sharenfs (no) sharenfs (no) 1199185029Spjd * sharesmb (no) sharesmb (no) 1200168404Spjd * 1201168404Spjd * zoned=off mountpoint (yes) N/A 1202168404Spjd * sharenfs (yes) 1203185029Spjd * sharesmb (yes) 1204168404Spjd */ 1205168404Spjd if (zoned) { 1206168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 1207168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1208168404Spjd "'%s' cannot be set on " 1209168404Spjd "dataset in a non-global zone"), 1210168404Spjd propname); 1211168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1212168404Spjd errbuf); 1213168404Spjd goto error; 1214185029Spjd } else if (prop == ZFS_PROP_SHARENFS || 1215185029Spjd prop == ZFS_PROP_SHARESMB) { 1216168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1217168404Spjd "'%s' cannot be set in " 1218168404Spjd "a non-global zone"), propname); 1219168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 1220168404Spjd errbuf); 1221168404Spjd goto error; 1222168404Spjd } 1223168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 1224168404Spjd /* 1225168404Spjd * If zoned property is 'off', this must be in 1226209962Smm * a global zone. If not, something is wrong. 1227168404Spjd */ 1228168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1229168404Spjd "'%s' cannot be set while dataset " 1230168404Spjd "'zoned' property is set"), propname); 1231168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 1232168404Spjd goto error; 1233168404Spjd } 1234168404Spjd 1235168404Spjd /* 1236185029Spjd * At this point, it is legitimate to set the 1237185029Spjd * property. Now we want to make sure that the 1238185029Spjd * property value is valid if it is sharenfs. 1239168404Spjd */ 1240185029Spjd if ((prop == ZFS_PROP_SHARENFS || 1241185029Spjd prop == ZFS_PROP_SHARESMB) && 1242185029Spjd strcmp(strval, "on") != 0 && 1243185029Spjd strcmp(strval, "off") != 0) { 1244185029Spjd zfs_share_proto_t proto; 1245168404Spjd 1246185029Spjd if (prop == ZFS_PROP_SHARESMB) 1247185029Spjd proto = PROTO_SMB; 1248185029Spjd else 1249185029Spjd proto = PROTO_NFS; 1250185029Spjd 1251185029Spjd /* 1252185029Spjd * Must be an valid sharing protocol 1253185029Spjd * option string so init the libshare 1254185029Spjd * in order to enable the parser and 1255185029Spjd * then parse the options. We use the 1256185029Spjd * control API since we don't care about 1257185029Spjd * the current configuration and don't 1258185029Spjd * want the overhead of loading it 1259185029Spjd * until we actually do something. 1260185029Spjd */ 1261185029Spjd 1262185029Spjd if (zfs_init_libshare(hdl, 1263185029Spjd SA_INIT_CONTROL_API) != SA_OK) { 1264185029Spjd /* 1265185029Spjd * An error occurred so we can't do 1266185029Spjd * anything 1267185029Spjd */ 1268185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1269185029Spjd "'%s' cannot be set: problem " 1270185029Spjd "in share initialization"), 1271185029Spjd propname); 1272185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1273185029Spjd errbuf); 1274185029Spjd goto error; 1275185029Spjd } 1276185029Spjd 1277185029Spjd if (zfs_parse_options(strval, proto) != SA_OK) { 1278185029Spjd /* 1279185029Spjd * There was an error in parsing so 1280185029Spjd * deal with it by issuing an error 1281185029Spjd * message and leaving after 1282185029Spjd * uninitializing the the libshare 1283185029Spjd * interface. 1284185029Spjd */ 1285185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1286185029Spjd "'%s' cannot be set to invalid " 1287185029Spjd "options"), propname); 1288185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1289185029Spjd errbuf); 1290185029Spjd zfs_uninit_libshare(hdl); 1291185029Spjd goto error; 1292185029Spjd } 1293185029Spjd zfs_uninit_libshare(hdl); 1294168404Spjd } 1295185029Spjd 1296168404Spjd break; 1297185029Spjd case ZFS_PROP_UTF8ONLY: 1298185029Spjd chosen_utf = (int)intval; 1299185029Spjd break; 1300185029Spjd case ZFS_PROP_NORMALIZE: 1301185029Spjd chosen_normal = (int)intval; 1302185029Spjd break; 1303168404Spjd } 1304168404Spjd 1305168404Spjd /* 1306168404Spjd * For changes to existing volumes, we have some additional 1307168404Spjd * checks to enforce. 1308168404Spjd */ 1309168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 1310168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 1311168404Spjd ZFS_PROP_VOLSIZE); 1312168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 1313168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1314168404Spjd char buf[64]; 1315168404Spjd 1316168404Spjd switch (prop) { 1317168404Spjd case ZFS_PROP_RESERVATION: 1318185029Spjd case ZFS_PROP_REFRESERVATION: 1319168404Spjd if (intval > volsize) { 1320168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1321168404Spjd "'%s' is greater than current " 1322168404Spjd "volume size"), propname); 1323168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1324168404Spjd errbuf); 1325168404Spjd goto error; 1326168404Spjd } 1327168404Spjd break; 1328168404Spjd 1329168404Spjd case ZFS_PROP_VOLSIZE: 1330168404Spjd if (intval % blocksize != 0) { 1331168404Spjd zfs_nicenum(blocksize, buf, 1332168404Spjd sizeof (buf)); 1333168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1334168404Spjd "'%s' must be a multiple of " 1335168404Spjd "volume block size (%s)"), 1336168404Spjd propname, buf); 1337168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1338168404Spjd errbuf); 1339168404Spjd goto error; 1340168404Spjd } 1341168404Spjd 1342168404Spjd if (intval == 0) { 1343168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1344168404Spjd "'%s' cannot be zero"), 1345168404Spjd propname); 1346168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1347168404Spjd errbuf); 1348168404Spjd goto error; 1349168404Spjd } 1350168404Spjd break; 1351168404Spjd } 1352168404Spjd } 1353168404Spjd } 1354168404Spjd 1355168404Spjd /* 1356185029Spjd * If normalization was chosen, but no UTF8 choice was made, 1357185029Spjd * enforce rejection of non-UTF8 names. 1358185029Spjd * 1359185029Spjd * If normalization was chosen, but rejecting non-UTF8 names 1360185029Spjd * was explicitly not chosen, it is an error. 1361185029Spjd */ 1362185029Spjd if (chosen_normal > 0 && chosen_utf < 0) { 1363185029Spjd if (nvlist_add_uint64(ret, 1364185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 1365185029Spjd (void) no_memory(hdl); 1366185029Spjd goto error; 1367185029Spjd } 1368185029Spjd } else if (chosen_normal > 0 && chosen_utf == 0) { 1369185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1370185029Spjd "'%s' must be set 'on' if normalization chosen"), 1371185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1372185029Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1373185029Spjd goto error; 1374185029Spjd } 1375219089Spjd return (ret); 1376185029Spjd 1377219089Spjderror: 1378219089Spjd nvlist_free(ret); 1379219089Spjd return (NULL); 1380219089Spjd} 1381219089Spjd 1382219089Spjdint 1383219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) 1384219089Spjd{ 1385219089Spjd uint64_t old_volsize; 1386219089Spjd uint64_t new_volsize; 1387219089Spjd uint64_t old_reservation; 1388219089Spjd uint64_t new_reservation; 1389219089Spjd zfs_prop_t resv_prop; 1390219089Spjd 1391185029Spjd /* 1392168404Spjd * If this is an existing volume, and someone is setting the volsize, 1393168404Spjd * make sure that it matches the reservation, or add it if necessary. 1394168404Spjd */ 1395219089Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1396219089Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 1397219089Spjd return (-1); 1398219089Spjd old_reservation = zfs_prop_get_int(zhp, resv_prop); 1399219089Spjd if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != 1400219089Spjd old_reservation) || nvlist_lookup_uint64(nvl, 1401219089Spjd zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { 1402219089Spjd return (0); 1403219089Spjd } 1404219089Spjd if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1405219089Spjd &new_volsize) != 0) 1406219089Spjd return (-1); 1407219089Spjd new_reservation = zvol_volsize_to_reservation(new_volsize, 1408219089Spjd zhp->zfs_props); 1409219089Spjd if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), 1410219089Spjd new_reservation) != 0) { 1411219089Spjd (void) no_memory(zhp->zfs_hdl); 1412219089Spjd return (-1); 1413219089Spjd } 1414219089Spjd return (1); 1415219089Spjd} 1416168404Spjd 1417219089Spjdvoid 1418219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, 1419219089Spjd char *errbuf) 1420219089Spjd{ 1421219089Spjd switch (err) { 1422185029Spjd 1423219089Spjd case ENOSPC: 1424219089Spjd /* 1425219089Spjd * For quotas and reservations, ENOSPC indicates 1426219089Spjd * something different; setting a quota or reservation 1427219089Spjd * doesn't use any disk space. 1428219089Spjd */ 1429219089Spjd switch (prop) { 1430219089Spjd case ZFS_PROP_QUOTA: 1431219089Spjd case ZFS_PROP_REFQUOTA: 1432219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1433219089Spjd "size is less than current used or " 1434219089Spjd "reserved space")); 1435219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1436219089Spjd break; 1437219089Spjd 1438219089Spjd case ZFS_PROP_RESERVATION: 1439219089Spjd case ZFS_PROP_REFRESERVATION: 1440219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1441219089Spjd "size is greater than available space")); 1442219089Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1443219089Spjd break; 1444219089Spjd 1445219089Spjd default: 1446219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1447219089Spjd break; 1448168404Spjd } 1449219089Spjd break; 1450219089Spjd 1451219089Spjd case EBUSY: 1452219089Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1453219089Spjd break; 1454219089Spjd 1455219089Spjd case EROFS: 1456219089Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1457219089Spjd break; 1458219089Spjd 1459219089Spjd case ENOTSUP: 1460219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1461219089Spjd "pool and or dataset must be upgraded to set this " 1462219089Spjd "property or value")); 1463219089Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1464219089Spjd break; 1465219089Spjd 1466219089Spjd case ERANGE: 1467219089Spjd if (prop == ZFS_PROP_COMPRESSION) { 1468219089Spjd (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1469219089Spjd "property setting is not allowed on " 1470219089Spjd "bootable datasets")); 1471219089Spjd (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1472219089Spjd } else { 1473219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1474219089Spjd } 1475219089Spjd break; 1476219089Spjd 1477219089Spjd case EINVAL: 1478219089Spjd if (prop == ZPROP_INVAL) { 1479219089Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1480219089Spjd } else { 1481219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1482219089Spjd } 1483219089Spjd break; 1484219089Spjd 1485219089Spjd case EOVERFLOW: 1486219089Spjd /* 1487219089Spjd * This platform can't address a volume this big. 1488219089Spjd */ 1489219089Spjd#ifdef _ILP32 1490219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1491219089Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1492219089Spjd break; 1493219089Spjd } 1494219089Spjd#endif 1495219089Spjd /* FALLTHROUGH */ 1496219089Spjd default: 1497219089Spjd (void) zfs_standard_error(hdl, err, errbuf); 1498168404Spjd } 1499168404Spjd} 1500168404Spjd 1501168404Spjd/* 1502168404Spjd * Given a property name and value, set the property for the given dataset. 1503168404Spjd */ 1504168404Spjdint 1505168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1506168404Spjd{ 1507168404Spjd zfs_cmd_t zc = { 0 }; 1508168404Spjd int ret = -1; 1509168404Spjd prop_changelist_t *cl = NULL; 1510168404Spjd char errbuf[1024]; 1511168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1512168404Spjd nvlist_t *nvl = NULL, *realprops; 1513168404Spjd zfs_prop_t prop; 1514241655Smm boolean_t do_prefix = B_TRUE; 1515219089Spjd int added_resv; 1516168404Spjd 1517168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1518168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1519168404Spjd zhp->zfs_name); 1520168404Spjd 1521168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1522168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1523168404Spjd (void) no_memory(hdl); 1524168404Spjd goto error; 1525168404Spjd } 1526168404Spjd 1527185029Spjd if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, 1528168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1529168404Spjd goto error; 1530185029Spjd 1531168404Spjd nvlist_free(nvl); 1532168404Spjd nvl = realprops; 1533168404Spjd 1534168404Spjd prop = zfs_name_to_prop(propname); 1535168404Spjd 1536168404Spjd /* We don't support those properties on FreeBSD. */ 1537168404Spjd switch (prop) { 1538197867Strasz case ZFS_PROP_DEVICES: 1539168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1540197867Strasz case ZFS_PROP_XATTR: 1541197867Strasz case ZFS_PROP_VSCAN: 1542197867Strasz case ZFS_PROP_NBMAND: 1543219089Spjd case ZFS_PROP_MLSLABEL: 1544168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1545168404Spjd "property '%s' not supported on FreeBSD", propname); 1546168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1547168404Spjd goto error; 1548168404Spjd } 1549168404Spjd 1550219089Spjd if (prop == ZFS_PROP_VOLSIZE) { 1551219089Spjd if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) 1552219089Spjd goto error; 1553219089Spjd } 1554219089Spjd 1555185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1556168404Spjd goto error; 1557168404Spjd 1558168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1559168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1560168404Spjd "child dataset with inherited mountpoint is used " 1561168404Spjd "in a non-global zone")); 1562168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1563168404Spjd goto error; 1564168404Spjd } 1565168404Spjd 1566185029Spjd /* 1567238391Smm * We don't want to unmount & remount the dataset when changing 1568238391Smm * its canmount property to 'on' or 'noauto'. We only use 1569238391Smm * the changelist logic to unmount when setting canmount=off. 1570185029Spjd */ 1571238391Smm if (prop == ZFS_PROP_CANMOUNT) { 1572238391Smm uint64_t idx; 1573238391Smm int err = zprop_string_to_index(prop, propval, &idx, 1574238391Smm ZFS_TYPE_DATASET); 1575238391Smm if (err == 0 && idx != ZFS_CANMOUNT_OFF) 1576238391Smm do_prefix = B_FALSE; 1577238391Smm } 1578185029Spjd 1579185029Spjd if (do_prefix && (ret = changelist_prefix(cl)) != 0) 1580168404Spjd goto error; 1581168404Spjd 1582168404Spjd /* 1583168404Spjd * Execute the corresponding ioctl() to set this property. 1584168404Spjd */ 1585168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1586168404Spjd 1587185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1588168404Spjd goto error; 1589168404Spjd 1590185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1591209962Smm 1592168404Spjd if (ret != 0) { 1593219089Spjd zfs_setprop_error(hdl, prop, errno, errbuf); 1594219089Spjd if (added_resv && errno == ENOSPC) { 1595219089Spjd /* clean up the volsize property we tried to set */ 1596219089Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1597219089Spjd ZFS_PROP_VOLSIZE); 1598219089Spjd nvlist_free(nvl); 1599219089Spjd zcmd_free_nvlists(&zc); 1600219089Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1601219089Spjd goto error; 1602219089Spjd if (nvlist_add_uint64(nvl, 1603219089Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1604219089Spjd old_volsize) != 0) 1605219089Spjd goto error; 1606219089Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) 1607219089Spjd goto error; 1608219089Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); 1609168404Spjd } 1610168404Spjd } else { 1611185029Spjd if (do_prefix) 1612185029Spjd ret = changelist_postfix(cl); 1613185029Spjd 1614168404Spjd /* 1615168404Spjd * Refresh the statistics so the new property value 1616168404Spjd * is reflected. 1617168404Spjd */ 1618185029Spjd if (ret == 0) 1619168404Spjd (void) get_stats(zhp); 1620168404Spjd } 1621168404Spjd 1622168404Spjderror: 1623168404Spjd nvlist_free(nvl); 1624168404Spjd zcmd_free_nvlists(&zc); 1625168404Spjd if (cl) 1626168404Spjd changelist_free(cl); 1627168404Spjd return (ret); 1628168404Spjd} 1629168404Spjd 1630168404Spjd/* 1631219089Spjd * Given a property, inherit the value from the parent dataset, or if received 1632219089Spjd * is TRUE, revert to the received value, if any. 1633168404Spjd */ 1634168404Spjdint 1635219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) 1636168404Spjd{ 1637168404Spjd zfs_cmd_t zc = { 0 }; 1638168404Spjd int ret; 1639168404Spjd prop_changelist_t *cl; 1640168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1641168404Spjd char errbuf[1024]; 1642168404Spjd zfs_prop_t prop; 1643168404Spjd 1644168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1645168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1646168404Spjd 1647219089Spjd zc.zc_cookie = received; 1648185029Spjd if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 1649168404Spjd /* 1650168404Spjd * For user properties, the amount of work we have to do is very 1651168404Spjd * small, so just do it here. 1652168404Spjd */ 1653168404Spjd if (!zfs_prop_user(propname)) { 1654168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1655168404Spjd "invalid property")); 1656168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1657168404Spjd } 1658168404Spjd 1659168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1660168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1661168404Spjd 1662185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) 1663168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1664168404Spjd 1665168404Spjd return (0); 1666168404Spjd } 1667168404Spjd 1668168404Spjd /* 1669168404Spjd * Verify that this property is inheritable. 1670168404Spjd */ 1671168404Spjd if (zfs_prop_readonly(prop)) 1672168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1673168404Spjd 1674219089Spjd if (!zfs_prop_inheritable(prop) && !received) 1675168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1676168404Spjd 1677168404Spjd /* 1678168404Spjd * Check to see if the value applies to this type 1679168404Spjd */ 1680168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1681168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1682168404Spjd 1683168404Spjd /* 1684219089Spjd * Normalize the name, to get rid of shorthand abbreviations. 1685168404Spjd */ 1686168404Spjd propname = zfs_prop_to_name(prop); 1687168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1688168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1689168404Spjd 1690168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1691168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1692168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1693168404Spjd "dataset is used in a non-global zone")); 1694168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1695168404Spjd } 1696168404Spjd 1697168404Spjd /* 1698168404Spjd * Determine datasets which will be affected by this change, if any. 1699168404Spjd */ 1700185029Spjd if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) 1701168404Spjd return (-1); 1702168404Spjd 1703168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1704168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1705168404Spjd "child dataset with inherited mountpoint is used " 1706168404Spjd "in a non-global zone")); 1707168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1708168404Spjd goto error; 1709168404Spjd } 1710168404Spjd 1711168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1712168404Spjd goto error; 1713168404Spjd 1714185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { 1715168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1716168404Spjd } else { 1717168404Spjd 1718168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1719168404Spjd goto error; 1720168404Spjd 1721168404Spjd /* 1722168404Spjd * Refresh the statistics so the new property is reflected. 1723168404Spjd */ 1724168404Spjd (void) get_stats(zhp); 1725168404Spjd } 1726168404Spjd 1727168404Spjderror: 1728168404Spjd changelist_free(cl); 1729168404Spjd return (ret); 1730168404Spjd} 1731168404Spjd 1732168404Spjd/* 1733168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1734168404Spjd * extract them appropriately. 1735168404Spjd */ 1736168404Spjdstatic uint64_t 1737168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1738168404Spjd{ 1739168404Spjd nvlist_t *nv; 1740168404Spjd uint64_t value; 1741168404Spjd 1742168404Spjd *source = NULL; 1743168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1744168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1745185029Spjd verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1746185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1747168404Spjd } else { 1748205198Sdelphij verify(!zhp->zfs_props_table || 1749205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1750168404Spjd value = zfs_prop_default_numeric(prop); 1751168404Spjd *source = ""; 1752168404Spjd } 1753168404Spjd 1754168404Spjd return (value); 1755168404Spjd} 1756168404Spjd 1757168404Spjdstatic char * 1758168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1759168404Spjd{ 1760168404Spjd nvlist_t *nv; 1761168404Spjd char *value; 1762168404Spjd 1763168404Spjd *source = NULL; 1764168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1765168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1766185029Spjd verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1767185029Spjd (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); 1768168404Spjd } else { 1769205198Sdelphij verify(!zhp->zfs_props_table || 1770205198Sdelphij zhp->zfs_props_table[prop] == B_TRUE); 1771168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1772168404Spjd value = ""; 1773168404Spjd *source = ""; 1774168404Spjd } 1775168404Spjd 1776168404Spjd return (value); 1777168404Spjd} 1778168404Spjd 1779219089Spjdstatic boolean_t 1780219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp) 1781219089Spjd{ 1782219089Spjd return (zhp->zfs_props == zhp->zfs_recvd_props); 1783219089Spjd} 1784219089Spjd 1785219089Spjdstatic void 1786219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1787219089Spjd{ 1788219089Spjd *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; 1789219089Spjd zhp->zfs_props = zhp->zfs_recvd_props; 1790219089Spjd} 1791219089Spjd 1792219089Spjdstatic void 1793219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) 1794219089Spjd{ 1795219089Spjd zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; 1796219089Spjd *cookie = 0; 1797219089Spjd} 1798219089Spjd 1799168404Spjd/* 1800168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1801168404Spjd * zfs_prop_get_int() are built using this interface. 1802168404Spjd * 1803168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1804168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1805168404Spjd * If they differ from the on-disk values, report the current values and mark 1806168404Spjd * the source "temporary". 1807168404Spjd */ 1808168404Spjdstatic int 1809185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 1810168404Spjd char **source, uint64_t *val) 1811168404Spjd{ 1812185029Spjd zfs_cmd_t zc = { 0 }; 1813185029Spjd nvlist_t *zplprops = NULL; 1814168404Spjd struct mnttab mnt; 1815168404Spjd char *mntopt_on = NULL; 1816168404Spjd char *mntopt_off = NULL; 1817219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 1818168404Spjd 1819168404Spjd *source = NULL; 1820168404Spjd 1821168404Spjd switch (prop) { 1822168404Spjd case ZFS_PROP_ATIME: 1823168404Spjd mntopt_on = MNTOPT_ATIME; 1824168404Spjd mntopt_off = MNTOPT_NOATIME; 1825168404Spjd break; 1826168404Spjd 1827168404Spjd case ZFS_PROP_DEVICES: 1828168404Spjd mntopt_on = MNTOPT_DEVICES; 1829168404Spjd mntopt_off = MNTOPT_NODEVICES; 1830168404Spjd break; 1831168404Spjd 1832168404Spjd case ZFS_PROP_EXEC: 1833168404Spjd mntopt_on = MNTOPT_EXEC; 1834168404Spjd mntopt_off = MNTOPT_NOEXEC; 1835168404Spjd break; 1836168404Spjd 1837168404Spjd case ZFS_PROP_READONLY: 1838168404Spjd mntopt_on = MNTOPT_RO; 1839168404Spjd mntopt_off = MNTOPT_RW; 1840168404Spjd break; 1841168404Spjd 1842168404Spjd case ZFS_PROP_SETUID: 1843168404Spjd mntopt_on = MNTOPT_SETUID; 1844168404Spjd mntopt_off = MNTOPT_NOSETUID; 1845168404Spjd break; 1846168404Spjd 1847168404Spjd case ZFS_PROP_XATTR: 1848168404Spjd mntopt_on = MNTOPT_XATTR; 1849168404Spjd mntopt_off = MNTOPT_NOXATTR; 1850168404Spjd break; 1851185029Spjd 1852185029Spjd case ZFS_PROP_NBMAND: 1853185029Spjd mntopt_on = MNTOPT_NBMAND; 1854185029Spjd mntopt_off = MNTOPT_NONBMAND; 1855185029Spjd break; 1856168404Spjd } 1857168404Spjd 1858168404Spjd /* 1859168404Spjd * Because looking up the mount options is potentially expensive 1860168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1861168404Spjd * we're looking up a property which requires its presence. 1862168404Spjd */ 1863168404Spjd if (!zhp->zfs_mntcheck && 1864168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1865209962Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 1866209962Smm struct mnttab entry; 1867168404Spjd 1868209962Smm if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) { 1869209962Smm zhp->zfs_mntopts = zfs_strdup(hdl, 1870168404Spjd entry.mnt_mntopts); 1871168404Spjd if (zhp->zfs_mntopts == NULL) 1872168404Spjd return (-1); 1873168404Spjd } 1874168404Spjd 1875168404Spjd zhp->zfs_mntcheck = B_TRUE; 1876168404Spjd } 1877168404Spjd 1878168404Spjd if (zhp->zfs_mntopts == NULL) 1879168404Spjd mnt.mnt_mntopts = ""; 1880168404Spjd else 1881168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1882168404Spjd 1883168404Spjd switch (prop) { 1884168404Spjd case ZFS_PROP_ATIME: 1885168404Spjd case ZFS_PROP_DEVICES: 1886168404Spjd case ZFS_PROP_EXEC: 1887168404Spjd case ZFS_PROP_READONLY: 1888168404Spjd case ZFS_PROP_SETUID: 1889168404Spjd case ZFS_PROP_XATTR: 1890185029Spjd case ZFS_PROP_NBMAND: 1891168404Spjd *val = getprop_uint64(zhp, prop, source); 1892168404Spjd 1893219089Spjd if (received) 1894219089Spjd break; 1895219089Spjd 1896168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1897168404Spjd *val = B_TRUE; 1898168404Spjd if (src) 1899185029Spjd *src = ZPROP_SRC_TEMPORARY; 1900168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1901168404Spjd *val = B_FALSE; 1902168404Spjd if (src) 1903185029Spjd *src = ZPROP_SRC_TEMPORARY; 1904168404Spjd } 1905168404Spjd break; 1906168404Spjd 1907168404Spjd case ZFS_PROP_CANMOUNT: 1908219089Spjd case ZFS_PROP_VOLSIZE: 1909168404Spjd case ZFS_PROP_QUOTA: 1910185029Spjd case ZFS_PROP_REFQUOTA: 1911168404Spjd case ZFS_PROP_RESERVATION: 1912185029Spjd case ZFS_PROP_REFRESERVATION: 1913168404Spjd *val = getprop_uint64(zhp, prop, source); 1914219089Spjd 1915219089Spjd if (*source == NULL) { 1916219089Spjd /* not default, must be local */ 1917168404Spjd *source = zhp->zfs_name; 1918219089Spjd } 1919168404Spjd break; 1920168404Spjd 1921168404Spjd case ZFS_PROP_MOUNTED: 1922168404Spjd *val = (zhp->zfs_mntopts != NULL); 1923168404Spjd break; 1924168404Spjd 1925168404Spjd case ZFS_PROP_NUMCLONES: 1926168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1927168404Spjd break; 1928168404Spjd 1929185029Spjd case ZFS_PROP_VERSION: 1930185029Spjd case ZFS_PROP_NORMALIZE: 1931185029Spjd case ZFS_PROP_UTF8ONLY: 1932185029Spjd case ZFS_PROP_CASE: 1933185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 1934185029Spjd zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1935185029Spjd return (-1); 1936185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1937185029Spjd if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 1938185029Spjd zcmd_free_nvlists(&zc); 1939219089Spjd return (-1); 1940185029Spjd } 1941185029Spjd if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 1942185029Spjd nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 1943185029Spjd val) != 0) { 1944185029Spjd zcmd_free_nvlists(&zc); 1945219089Spjd return (-1); 1946185029Spjd } 1947185029Spjd if (zplprops) 1948185029Spjd nvlist_free(zplprops); 1949185029Spjd zcmd_free_nvlists(&zc); 1950185029Spjd break; 1951185029Spjd 1952253819Sdelphij case ZFS_PROP_INCONSISTENT: 1953253819Sdelphij *val = zhp->zfs_dmustats.dds_inconsistent; 1954253819Sdelphij break; 1955253819Sdelphij 1956168404Spjd default: 1957185029Spjd switch (zfs_prop_get_type(prop)) { 1958185029Spjd case PROP_TYPE_NUMBER: 1959185029Spjd case PROP_TYPE_INDEX: 1960185029Spjd *val = getprop_uint64(zhp, prop, source); 1961185029Spjd /* 1962209962Smm * If we tried to use a default value for a 1963185029Spjd * readonly property, it means that it was not 1964219089Spjd * present. 1965185029Spjd */ 1966185029Spjd if (zfs_prop_readonly(prop) && 1967219089Spjd *source != NULL && (*source)[0] == '\0') { 1968219089Spjd *source = NULL; 1969185029Spjd } 1970185029Spjd break; 1971185029Spjd 1972185029Spjd case PROP_TYPE_STRING: 1973185029Spjd default: 1974185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1975185029Spjd "cannot get non-numeric property")); 1976185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1977185029Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1978185029Spjd } 1979168404Spjd } 1980168404Spjd 1981168404Spjd return (0); 1982168404Spjd} 1983168404Spjd 1984168404Spjd/* 1985168404Spjd * Calculate the source type, given the raw source string. 1986168404Spjd */ 1987168404Spjdstatic void 1988185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, 1989168404Spjd char *statbuf, size_t statlen) 1990168404Spjd{ 1991185029Spjd if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) 1992168404Spjd return; 1993168404Spjd 1994168404Spjd if (source == NULL) { 1995185029Spjd *srctype = ZPROP_SRC_NONE; 1996168404Spjd } else if (source[0] == '\0') { 1997185029Spjd *srctype = ZPROP_SRC_DEFAULT; 1998219089Spjd } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) { 1999219089Spjd *srctype = ZPROP_SRC_RECEIVED; 2000168404Spjd } else { 2001168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 2002185029Spjd *srctype = ZPROP_SRC_LOCAL; 2003168404Spjd } else { 2004168404Spjd (void) strlcpy(statbuf, source, statlen); 2005185029Spjd *srctype = ZPROP_SRC_INHERITED; 2006168404Spjd } 2007168404Spjd } 2008168404Spjd 2009168404Spjd} 2010168404Spjd 2011219089Spjdint 2012219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, 2013219089Spjd size_t proplen, boolean_t literal) 2014219089Spjd{ 2015219089Spjd zfs_prop_t prop; 2016219089Spjd int err = 0; 2017219089Spjd 2018219089Spjd if (zhp->zfs_recvd_props == NULL) 2019219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 2020219089Spjd return (-1); 2021219089Spjd 2022219089Spjd prop = zfs_name_to_prop(propname); 2023219089Spjd 2024219089Spjd if (prop != ZPROP_INVAL) { 2025219089Spjd uint64_t cookie; 2026219089Spjd if (!nvlist_exists(zhp->zfs_recvd_props, propname)) 2027219089Spjd return (-1); 2028219089Spjd zfs_set_recvd_props_mode(zhp, &cookie); 2029219089Spjd err = zfs_prop_get(zhp, prop, propbuf, proplen, 2030219089Spjd NULL, NULL, 0, literal); 2031219089Spjd zfs_unset_recvd_props_mode(zhp, &cookie); 2032219089Spjd } else { 2033219089Spjd nvlist_t *propval; 2034219089Spjd char *recvdval; 2035219089Spjd if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, 2036219089Spjd propname, &propval) != 0) 2037219089Spjd return (-1); 2038219089Spjd verify(nvlist_lookup_string(propval, ZPROP_VALUE, 2039219089Spjd &recvdval) == 0); 2040219089Spjd (void) strlcpy(propbuf, recvdval, proplen); 2041219089Spjd } 2042219089Spjd 2043219089Spjd return (err == 0 ? 0 : -1); 2044219089Spjd} 2045219089Spjd 2046228103Smmstatic int 2047228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) 2048228103Smm{ 2049228103Smm nvlist_t *value; 2050228103Smm nvpair_t *pair; 2051228103Smm 2052228103Smm value = zfs_get_clones_nvl(zhp); 2053228103Smm if (value == NULL) 2054228103Smm return (-1); 2055228103Smm 2056228103Smm propbuf[0] = '\0'; 2057228103Smm for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; 2058228103Smm pair = nvlist_next_nvpair(value, pair)) { 2059228103Smm if (propbuf[0] != '\0') 2060228103Smm (void) strlcat(propbuf, ",", proplen); 2061228103Smm (void) strlcat(propbuf, nvpair_name(pair), proplen); 2062228103Smm } 2063228103Smm 2064228103Smm return (0); 2065228103Smm} 2066228103Smm 2067228103Smmstruct get_clones_arg { 2068228103Smm uint64_t numclones; 2069228103Smm nvlist_t *value; 2070228103Smm const char *origin; 2071228103Smm char buf[ZFS_MAXNAMELEN]; 2072228103Smm}; 2073228103Smm 2074228103Smmint 2075228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg) 2076228103Smm{ 2077228103Smm struct get_clones_arg *gca = arg; 2078228103Smm 2079228103Smm if (gca->numclones == 0) { 2080228103Smm zfs_close(zhp); 2081228103Smm return (0); 2082228103Smm } 2083228103Smm 2084228103Smm if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), 2085228103Smm NULL, NULL, 0, B_TRUE) != 0) 2086228103Smm goto out; 2087228103Smm if (strcmp(gca->buf, gca->origin) == 0) { 2088248571Smm fnvlist_add_boolean(gca->value, zfs_get_name(zhp)); 2089228103Smm gca->numclones--; 2090228103Smm } 2091228103Smm 2092228103Smmout: 2093228103Smm (void) zfs_iter_children(zhp, get_clones_cb, gca); 2094228103Smm zfs_close(zhp); 2095228103Smm return (0); 2096228103Smm} 2097228103Smm 2098228103Smmnvlist_t * 2099228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp) 2100228103Smm{ 2101228103Smm nvlist_t *nv, *value; 2102228103Smm 2103228103Smm if (nvlist_lookup_nvlist(zhp->zfs_props, 2104228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { 2105228103Smm struct get_clones_arg gca; 2106228103Smm 2107228103Smm /* 2108228103Smm * if this is a snapshot, then the kernel wasn't able 2109228103Smm * to get the clones. Do it by slowly iterating. 2110228103Smm */ 2111228103Smm if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) 2112228103Smm return (NULL); 2113228103Smm if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) 2114228103Smm return (NULL); 2115228103Smm if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { 2116228103Smm nvlist_free(nv); 2117228103Smm return (NULL); 2118228103Smm } 2119228103Smm 2120228103Smm gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); 2121228103Smm gca.value = value; 2122228103Smm gca.origin = zhp->zfs_name; 2123228103Smm 2124228103Smm if (gca.numclones != 0) { 2125228103Smm zfs_handle_t *root; 2126228103Smm char pool[ZFS_MAXNAMELEN]; 2127228103Smm char *cp = pool; 2128228103Smm 2129228103Smm /* get the pool name */ 2130228103Smm (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); 2131228103Smm (void) strsep(&cp, "/@"); 2132228103Smm root = zfs_open(zhp->zfs_hdl, pool, 2133228103Smm ZFS_TYPE_FILESYSTEM); 2134228103Smm 2135228103Smm (void) get_clones_cb(root, &gca); 2136228103Smm } 2137228103Smm 2138228103Smm if (gca.numclones != 0 || 2139228103Smm nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || 2140228103Smm nvlist_add_nvlist(zhp->zfs_props, 2141228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { 2142228103Smm nvlist_free(nv); 2143228103Smm nvlist_free(value); 2144228103Smm return (NULL); 2145228103Smm } 2146228103Smm nvlist_free(nv); 2147228103Smm nvlist_free(value); 2148228103Smm verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, 2149228103Smm zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); 2150228103Smm } 2151228103Smm 2152228103Smm verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); 2153228103Smm 2154228103Smm return (value); 2155228103Smm} 2156228103Smm 2157168404Spjd/* 2158168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 2159168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 2160168404Spjd * human-readable form. 2161168404Spjd * 2162168404Spjd * Returns 0 on success, or -1 on error. 2163168404Spjd */ 2164168404Spjdint 2165168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 2166185029Spjd zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 2167168404Spjd{ 2168168404Spjd char *source = NULL; 2169168404Spjd uint64_t val; 2170168404Spjd char *str; 2171168404Spjd const char *strval; 2172219089Spjd boolean_t received = zfs_is_recvd_props_mode(zhp); 2173168404Spjd 2174168404Spjd /* 2175168404Spjd * Check to see if this property applies to our object 2176168404Spjd */ 2177168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2178168404Spjd return (-1); 2179168404Spjd 2180219089Spjd if (received && zfs_prop_readonly(prop)) 2181219089Spjd return (-1); 2182219089Spjd 2183168404Spjd if (src) 2184185029Spjd *src = ZPROP_SRC_NONE; 2185168404Spjd 2186168404Spjd switch (prop) { 2187168404Spjd case ZFS_PROP_CREATION: 2188168404Spjd /* 2189168404Spjd * 'creation' is a time_t stored in the statistics. We convert 2190168404Spjd * this into a string unless 'literal' is specified. 2191168404Spjd */ 2192168404Spjd { 2193168404Spjd val = getprop_uint64(zhp, prop, &source); 2194168404Spjd time_t time = (time_t)val; 2195168404Spjd struct tm t; 2196168404Spjd 2197168404Spjd if (literal || 2198168404Spjd localtime_r(&time, &t) == NULL || 2199168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 2200168404Spjd &t) == 0) 2201168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 2202168404Spjd } 2203168404Spjd break; 2204168404Spjd 2205168404Spjd case ZFS_PROP_MOUNTPOINT: 2206168404Spjd /* 2207168404Spjd * Getting the precise mountpoint can be tricky. 2208168404Spjd * 2209168404Spjd * - for 'none' or 'legacy', return those values. 2210168404Spjd * - for inherited mountpoints, we want to take everything 2211168404Spjd * after our ancestor and append it to the inherited value. 2212168404Spjd * 2213168404Spjd * If the pool has an alternate root, we want to prepend that 2214168404Spjd * root to any values we return. 2215168404Spjd */ 2216185029Spjd 2217168404Spjd str = getprop_string(zhp, prop, &source); 2218168404Spjd 2219185029Spjd if (str[0] == '/') { 2220185029Spjd char buf[MAXPATHLEN]; 2221185029Spjd char *root = buf; 2222219089Spjd const char *relpath; 2223168404Spjd 2224219089Spjd /* 2225219089Spjd * If we inherit the mountpoint, even from a dataset 2226219089Spjd * with a received value, the source will be the path of 2227219089Spjd * the dataset we inherit from. If source is 2228219089Spjd * ZPROP_SOURCE_VAL_RECVD, the received value is not 2229219089Spjd * inherited. 2230219089Spjd */ 2231219089Spjd if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { 2232219089Spjd relpath = ""; 2233219089Spjd } else { 2234219089Spjd relpath = zhp->zfs_name + strlen(source); 2235219089Spjd if (relpath[0] == '/') 2236219089Spjd relpath++; 2237219089Spjd } 2238185029Spjd 2239185029Spjd if ((zpool_get_prop(zhp->zpool_hdl, 2240185029Spjd ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 2241185029Spjd (strcmp(root, "-") == 0)) 2242185029Spjd root[0] = '\0'; 2243185029Spjd /* 2244185029Spjd * Special case an alternate root of '/'. This will 2245185029Spjd * avoid having multiple leading slashes in the 2246185029Spjd * mountpoint path. 2247185029Spjd */ 2248185029Spjd if (strcmp(root, "/") == 0) 2249185029Spjd root++; 2250185029Spjd 2251185029Spjd /* 2252185029Spjd * If the mountpoint is '/' then skip over this 2253185029Spjd * if we are obtaining either an alternate root or 2254185029Spjd * an inherited mountpoint. 2255185029Spjd */ 2256185029Spjd if (str[1] == '\0' && (root[0] != '\0' || 2257185029Spjd relpath[0] != '\0')) 2258168404Spjd str++; 2259168404Spjd 2260168404Spjd if (relpath[0] == '\0') 2261168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 2262168404Spjd root, str); 2263168404Spjd else 2264168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 2265168404Spjd root, str, relpath[0] == '@' ? "" : "/", 2266168404Spjd relpath); 2267168404Spjd } else { 2268168404Spjd /* 'legacy' or 'none' */ 2269168404Spjd (void) strlcpy(propbuf, str, proplen); 2270168404Spjd } 2271168404Spjd 2272168404Spjd break; 2273168404Spjd 2274168404Spjd case ZFS_PROP_ORIGIN: 2275168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2276168404Spjd proplen); 2277168404Spjd /* 2278168404Spjd * If there is no parent at all, return failure to indicate that 2279168404Spjd * it doesn't apply to this dataset. 2280168404Spjd */ 2281168404Spjd if (propbuf[0] == '\0') 2282168404Spjd return (-1); 2283168404Spjd break; 2284168404Spjd 2285228103Smm case ZFS_PROP_CLONES: 2286228103Smm if (get_clones_string(zhp, propbuf, proplen) != 0) 2287228103Smm return (-1); 2288228103Smm break; 2289228103Smm 2290168404Spjd case ZFS_PROP_QUOTA: 2291185029Spjd case ZFS_PROP_REFQUOTA: 2292168404Spjd case ZFS_PROP_RESERVATION: 2293185029Spjd case ZFS_PROP_REFRESERVATION: 2294185029Spjd 2295168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2296168404Spjd return (-1); 2297168404Spjd 2298168404Spjd /* 2299168404Spjd * If quota or reservation is 0, we translate this into 'none' 2300168404Spjd * (unless literal is set), and indicate that it's the default 2301168404Spjd * value. Otherwise, we print the number nicely and indicate 2302168404Spjd * that its set locally. 2303168404Spjd */ 2304168404Spjd if (val == 0) { 2305168404Spjd if (literal) 2306168404Spjd (void) strlcpy(propbuf, "0", proplen); 2307168404Spjd else 2308168404Spjd (void) strlcpy(propbuf, "none", proplen); 2309168404Spjd } else { 2310168404Spjd if (literal) 2311168404Spjd (void) snprintf(propbuf, proplen, "%llu", 2312168404Spjd (u_longlong_t)val); 2313168404Spjd else 2314168404Spjd zfs_nicenum(val, propbuf, proplen); 2315168404Spjd } 2316168404Spjd break; 2317168404Spjd 2318223623Smm case ZFS_PROP_REFRATIO: 2319168404Spjd case ZFS_PROP_COMPRESSRATIO: 2320168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2321168404Spjd return (-1); 2322219089Spjd (void) snprintf(propbuf, proplen, "%llu.%02llux", 2323219089Spjd (u_longlong_t)(val / 100), 2324219089Spjd (u_longlong_t)(val % 100)); 2325168404Spjd break; 2326168404Spjd 2327168404Spjd case ZFS_PROP_TYPE: 2328168404Spjd switch (zhp->zfs_type) { 2329168404Spjd case ZFS_TYPE_FILESYSTEM: 2330168404Spjd str = "filesystem"; 2331168404Spjd break; 2332168404Spjd case ZFS_TYPE_VOLUME: 2333168404Spjd str = "volume"; 2334168404Spjd break; 2335168404Spjd case ZFS_TYPE_SNAPSHOT: 2336168404Spjd str = "snapshot"; 2337168404Spjd break; 2338260183Sdelphij case ZFS_TYPE_BOOKMARK: 2339260183Sdelphij str = "bookmark"; 2340260183Sdelphij break; 2341168404Spjd default: 2342168404Spjd abort(); 2343168404Spjd } 2344168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 2345168404Spjd break; 2346168404Spjd 2347168404Spjd case ZFS_PROP_MOUNTED: 2348168404Spjd /* 2349168404Spjd * The 'mounted' property is a pseudo-property that described 2350168404Spjd * whether the filesystem is currently mounted. Even though 2351168404Spjd * it's a boolean value, the typical values of "on" and "off" 2352168404Spjd * don't make sense, so we translate to "yes" and "no". 2353168404Spjd */ 2354168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 2355168404Spjd src, &source, &val) != 0) 2356168404Spjd return (-1); 2357168404Spjd if (val) 2358168404Spjd (void) strlcpy(propbuf, "yes", proplen); 2359168404Spjd else 2360168404Spjd (void) strlcpy(propbuf, "no", proplen); 2361168404Spjd break; 2362168404Spjd 2363168404Spjd case ZFS_PROP_NAME: 2364168404Spjd /* 2365168404Spjd * The 'name' property is a pseudo-property derived from the 2366168404Spjd * dataset name. It is presented as a real property to simplify 2367168404Spjd * consumers. 2368168404Spjd */ 2369168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2370168404Spjd break; 2371168404Spjd 2372219089Spjd case ZFS_PROP_MLSLABEL: 2373219089Spjd { 2374219089Spjd#ifdef sun 2375219089Spjd m_label_t *new_sl = NULL; 2376219089Spjd char *ascii = NULL; /* human readable label */ 2377219089Spjd 2378219089Spjd (void) strlcpy(propbuf, 2379219089Spjd getprop_string(zhp, prop, &source), proplen); 2380219089Spjd 2381219089Spjd if (literal || (strcasecmp(propbuf, 2382219089Spjd ZFS_MLSLABEL_DEFAULT) == 0)) 2383219089Spjd break; 2384219089Spjd 2385219089Spjd /* 2386219089Spjd * Try to translate the internal hex string to 2387219089Spjd * human-readable output. If there are any 2388219089Spjd * problems just use the hex string. 2389219089Spjd */ 2390219089Spjd 2391219089Spjd if (str_to_label(propbuf, &new_sl, MAC_LABEL, 2392219089Spjd L_NO_CORRECTION, NULL) == -1) { 2393219089Spjd m_label_free(new_sl); 2394219089Spjd break; 2395219089Spjd } 2396219089Spjd 2397219089Spjd if (label_to_str(new_sl, &ascii, M_LABEL, 2398219089Spjd DEF_NAMES) != 0) { 2399219089Spjd if (ascii) 2400219089Spjd free(ascii); 2401219089Spjd m_label_free(new_sl); 2402219089Spjd break; 2403219089Spjd } 2404219089Spjd m_label_free(new_sl); 2405219089Spjd 2406219089Spjd (void) strlcpy(propbuf, ascii, proplen); 2407219089Spjd free(ascii); 2408219089Spjd#else /* !sun */ 2409219089Spjd propbuf[0] = '\0'; 2410219089Spjd#endif /* !sun */ 2411219089Spjd } 2412219089Spjd break; 2413219089Spjd 2414236705Smm case ZFS_PROP_GUID: 2415236705Smm /* 2416236705Smm * GUIDs are stored as numbers, but they are identifiers. 2417236705Smm * We don't want them to be pretty printed, because pretty 2418236705Smm * printing mangles the ID into a truncated and useless value. 2419236705Smm */ 2420236705Smm if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2421236705Smm return (-1); 2422236705Smm (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); 2423236705Smm break; 2424236705Smm 2425168404Spjd default: 2426185029Spjd switch (zfs_prop_get_type(prop)) { 2427185029Spjd case PROP_TYPE_NUMBER: 2428185029Spjd if (get_numeric_property(zhp, prop, src, 2429185029Spjd &source, &val) != 0) 2430185029Spjd return (-1); 2431185029Spjd if (literal) 2432185029Spjd (void) snprintf(propbuf, proplen, "%llu", 2433185029Spjd (u_longlong_t)val); 2434185029Spjd else 2435185029Spjd zfs_nicenum(val, propbuf, proplen); 2436185029Spjd break; 2437185029Spjd 2438185029Spjd case PROP_TYPE_STRING: 2439185029Spjd (void) strlcpy(propbuf, 2440185029Spjd getprop_string(zhp, prop, &source), proplen); 2441185029Spjd break; 2442185029Spjd 2443185029Spjd case PROP_TYPE_INDEX: 2444185029Spjd if (get_numeric_property(zhp, prop, src, 2445185029Spjd &source, &val) != 0) 2446185029Spjd return (-1); 2447185029Spjd if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2448185029Spjd return (-1); 2449185029Spjd (void) strlcpy(propbuf, strval, proplen); 2450185029Spjd break; 2451185029Spjd 2452185029Spjd default: 2453185029Spjd abort(); 2454185029Spjd } 2455168404Spjd } 2456168404Spjd 2457168404Spjd get_source(zhp, src, source, statbuf, statlen); 2458168404Spjd 2459168404Spjd return (0); 2460168404Spjd} 2461168404Spjd 2462168404Spjd/* 2463168404Spjd * Utility function to get the given numeric property. Does no validation that 2464168404Spjd * the given property is the appropriate type; should only be used with 2465168404Spjd * hard-coded property types. 2466168404Spjd */ 2467168404Spjduint64_t 2468168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2469168404Spjd{ 2470168404Spjd char *source; 2471168404Spjd uint64_t val; 2472168404Spjd 2473185029Spjd (void) get_numeric_property(zhp, prop, NULL, &source, &val); 2474168404Spjd 2475168404Spjd return (val); 2476168404Spjd} 2477168404Spjd 2478185029Spjdint 2479185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2480185029Spjd{ 2481185029Spjd char buf[64]; 2482185029Spjd 2483209962Smm (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); 2484185029Spjd return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2485185029Spjd} 2486185029Spjd 2487168404Spjd/* 2488168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 2489168404Spjd */ 2490168404Spjdint 2491168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 2492185029Spjd zprop_source_t *src, char *statbuf, size_t statlen) 2493168404Spjd{ 2494168404Spjd char *source; 2495168404Spjd 2496168404Spjd /* 2497168404Spjd * Check to see if this property applies to our object 2498168404Spjd */ 2499185029Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 2500168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2501168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2502168404Spjd zfs_prop_to_name(prop))); 2503185029Spjd } 2504168404Spjd 2505168404Spjd if (src) 2506185029Spjd *src = ZPROP_SRC_NONE; 2507168404Spjd 2508168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2509168404Spjd return (-1); 2510168404Spjd 2511168404Spjd get_source(zhp, src, source, statbuf, statlen); 2512168404Spjd 2513168404Spjd return (0); 2514168404Spjd} 2515168404Spjd 2516209962Smmstatic int 2517209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, 2518209962Smm char **domainp, idmap_rid_t *ridp) 2519209962Smm{ 2520209962Smm#ifdef sun 2521209962Smm idmap_get_handle_t *get_hdl = NULL; 2522209962Smm idmap_stat status; 2523209962Smm int err = EINVAL; 2524209962Smm 2525219089Spjd if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 2526209962Smm goto out; 2527209962Smm 2528209962Smm if (isuser) { 2529209962Smm err = idmap_get_sidbyuid(get_hdl, id, 2530209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2531209962Smm } else { 2532209962Smm err = idmap_get_sidbygid(get_hdl, id, 2533209962Smm IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); 2534209962Smm } 2535209962Smm if (err == IDMAP_SUCCESS && 2536209962Smm idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && 2537209962Smm status == IDMAP_SUCCESS) 2538209962Smm err = 0; 2539209962Smm else 2540209962Smm err = EINVAL; 2541209962Smmout: 2542209962Smm if (get_hdl) 2543209962Smm idmap_get_destroy(get_hdl); 2544209962Smm return (err); 2545209962Smm#else /* !sun */ 2546209962Smm assert(!"invalid code path"); 2547209962Smm#endif /* !sun */ 2548209962Smm} 2549209962Smm 2550168404Spjd/* 2551209962Smm * convert the propname into parameters needed by kernel 2552209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 2553209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 2554209962Smm */ 2555209962Smmstatic int 2556209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned, 2557209962Smm zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) 2558209962Smm{ 2559209962Smm zfs_userquota_prop_t type; 2560209962Smm char *cp, *end; 2561209962Smm char *numericsid = NULL; 2562209962Smm boolean_t isuser; 2563209962Smm 2564209962Smm domain[0] = '\0'; 2565209962Smm 2566209962Smm /* Figure out the property type ({user|group}{quota|space}) */ 2567209962Smm for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 2568209962Smm if (strncmp(propname, zfs_userquota_prop_prefixes[type], 2569209962Smm strlen(zfs_userquota_prop_prefixes[type])) == 0) 2570209962Smm break; 2571209962Smm } 2572209962Smm if (type == ZFS_NUM_USERQUOTA_PROPS) 2573209962Smm return (EINVAL); 2574209962Smm *typep = type; 2575209962Smm 2576209962Smm isuser = (type == ZFS_PROP_USERQUOTA || 2577209962Smm type == ZFS_PROP_USERUSED); 2578209962Smm 2579209962Smm cp = strchr(propname, '@') + 1; 2580209962Smm 2581209962Smm if (strchr(cp, '@')) { 2582209962Smm#ifdef sun 2583209962Smm /* 2584209962Smm * It's a SID name (eg "user@domain") that needs to be 2585209962Smm * turned into S-1-domainID-RID. 2586209962Smm */ 2587209962Smm directory_error_t e; 2588209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2589209962Smm return (ENOENT); 2590209962Smm if (isuser) { 2591209962Smm e = directory_sid_from_user_name(NULL, 2592209962Smm cp, &numericsid); 2593209962Smm } else { 2594209962Smm e = directory_sid_from_group_name(NULL, 2595209962Smm cp, &numericsid); 2596209962Smm } 2597209962Smm if (e != NULL) { 2598209962Smm directory_error_free(e); 2599209962Smm return (ENOENT); 2600209962Smm } 2601209962Smm if (numericsid == NULL) 2602209962Smm return (ENOENT); 2603209962Smm cp = numericsid; 2604209962Smm /* will be further decoded below */ 2605209962Smm#else /* !sun */ 2606219089Spjd return (ENOENT); 2607209962Smm#endif /* !sun */ 2608209962Smm } 2609209962Smm 2610209962Smm if (strncmp(cp, "S-1-", 4) == 0) { 2611209962Smm /* It's a numeric SID (eg "S-1-234-567-89") */ 2612209962Smm (void) strlcpy(domain, cp, domainlen); 2613209962Smm cp = strrchr(domain, '-'); 2614209962Smm *cp = '\0'; 2615209962Smm cp++; 2616209962Smm 2617209962Smm errno = 0; 2618209962Smm *ridp = strtoull(cp, &end, 10); 2619209962Smm if (numericsid) { 2620209962Smm free(numericsid); 2621209962Smm numericsid = NULL; 2622209962Smm } 2623209962Smm if (errno != 0 || *end != '\0') 2624209962Smm return (EINVAL); 2625209962Smm } else if (!isdigit(*cp)) { 2626209962Smm /* 2627209962Smm * It's a user/group name (eg "user") that needs to be 2628209962Smm * turned into a uid/gid 2629209962Smm */ 2630209962Smm if (zoned && getzoneid() == GLOBAL_ZONEID) 2631209962Smm return (ENOENT); 2632209962Smm if (isuser) { 2633209962Smm struct passwd *pw; 2634209962Smm pw = getpwnam(cp); 2635209962Smm if (pw == NULL) 2636209962Smm return (ENOENT); 2637209962Smm *ridp = pw->pw_uid; 2638209962Smm } else { 2639209962Smm struct group *gr; 2640209962Smm gr = getgrnam(cp); 2641209962Smm if (gr == NULL) 2642209962Smm return (ENOENT); 2643209962Smm *ridp = gr->gr_gid; 2644209962Smm } 2645209962Smm } else { 2646209962Smm /* It's a user/group ID (eg "12345"). */ 2647209962Smm uid_t id = strtoul(cp, &end, 10); 2648209962Smm idmap_rid_t rid; 2649209962Smm char *mapdomain; 2650209962Smm 2651209962Smm if (*end != '\0') 2652209962Smm return (EINVAL); 2653209962Smm if (id > MAXUID) { 2654209962Smm /* It's an ephemeral ID. */ 2655209962Smm if (idmap_id_to_numeric_domain_rid(id, isuser, 2656209962Smm &mapdomain, &rid) != 0) 2657209962Smm return (ENOENT); 2658209962Smm (void) strlcpy(domain, mapdomain, domainlen); 2659209962Smm *ridp = rid; 2660209962Smm } else { 2661209962Smm *ridp = id; 2662209962Smm } 2663209962Smm } 2664209962Smm 2665209962Smm ASSERT3P(numericsid, ==, NULL); 2666209962Smm return (0); 2667209962Smm} 2668209962Smm 2669209962Smmstatic int 2670209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, 2671209962Smm uint64_t *propvalue, zfs_userquota_prop_t *typep) 2672209962Smm{ 2673209962Smm int err; 2674209962Smm zfs_cmd_t zc = { 0 }; 2675209962Smm 2676228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2677209962Smm 2678209962Smm err = userquota_propname_decode(propname, 2679209962Smm zfs_prop_get_int(zhp, ZFS_PROP_ZONED), 2680209962Smm typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); 2681209962Smm zc.zc_objset_type = *typep; 2682209962Smm if (err) 2683209962Smm return (err); 2684209962Smm 2685209962Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); 2686209962Smm if (err) 2687209962Smm return (err); 2688209962Smm 2689209962Smm *propvalue = zc.zc_cookie; 2690209962Smm return (0); 2691209962Smm} 2692209962Smm 2693209962Smmint 2694209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, 2695209962Smm uint64_t *propvalue) 2696209962Smm{ 2697209962Smm zfs_userquota_prop_t type; 2698209962Smm 2699209962Smm return (zfs_prop_get_userquota_common(zhp, propname, propvalue, 2700209962Smm &type)); 2701209962Smm} 2702209962Smm 2703209962Smmint 2704209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, 2705209962Smm char *propbuf, int proplen, boolean_t literal) 2706209962Smm{ 2707209962Smm int err; 2708209962Smm uint64_t propvalue; 2709209962Smm zfs_userquota_prop_t type; 2710209962Smm 2711209962Smm err = zfs_prop_get_userquota_common(zhp, propname, &propvalue, 2712209962Smm &type); 2713209962Smm 2714209962Smm if (err) 2715209962Smm return (err); 2716209962Smm 2717209962Smm if (literal) { 2718209962Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2719209962Smm } else if (propvalue == 0 && 2720209962Smm (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { 2721209962Smm (void) strlcpy(propbuf, "none", proplen); 2722209962Smm } else { 2723209962Smm zfs_nicenum(propvalue, propbuf, proplen); 2724209962Smm } 2725209962Smm return (0); 2726209962Smm} 2727209962Smm 2728228103Smmint 2729228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, 2730228103Smm uint64_t *propvalue) 2731168404Spjd{ 2732228103Smm int err; 2733228103Smm zfs_cmd_t zc = { 0 }; 2734228103Smm const char *snapname; 2735168404Spjd 2736228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2737168404Spjd 2738228103Smm snapname = strchr(propname, '@') + 1; 2739228103Smm if (strchr(snapname, '@')) { 2740228103Smm (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2741228103Smm } else { 2742228103Smm /* snapname is the short name, append it to zhp's fsname */ 2743228103Smm char *cp; 2744209962Smm 2745228103Smm (void) strlcpy(zc.zc_value, zhp->zfs_name, 2746228103Smm sizeof (zc.zc_value)); 2747228103Smm cp = strchr(zc.zc_value, '@'); 2748228103Smm if (cp != NULL) 2749228103Smm *cp = '\0'; 2750228103Smm (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); 2751228103Smm (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); 2752228103Smm } 2753209962Smm 2754228103Smm err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); 2755228103Smm if (err) 2756228103Smm return (err); 2757228103Smm 2758228103Smm *propvalue = zc.zc_cookie; 2759228103Smm return (0); 2760209962Smm} 2761209962Smm 2762168404Spjdint 2763228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname, 2764228103Smm char *propbuf, int proplen, boolean_t literal) 2765168404Spjd{ 2766228103Smm int err; 2767228103Smm uint64_t propvalue; 2768168404Spjd 2769228103Smm err = zfs_prop_get_written_int(zhp, propname, &propvalue); 2770185029Spjd 2771228103Smm if (err) 2772228103Smm return (err); 2773209962Smm 2774228103Smm if (literal) { 2775228103Smm (void) snprintf(propbuf, proplen, "%llu", propvalue); 2776228103Smm } else { 2777228103Smm zfs_nicenum(propvalue, propbuf, proplen); 2778168404Spjd } 2779228103Smm return (0); 2780168404Spjd} 2781168404Spjd 2782168404Spjd/* 2783228103Smm * Returns the name of the given zfs handle. 2784168404Spjd */ 2785228103Smmconst char * 2786228103Smmzfs_get_name(const zfs_handle_t *zhp) 2787168404Spjd{ 2788228103Smm return (zhp->zfs_name); 2789228103Smm} 2790168404Spjd 2791228103Smm/* 2792228103Smm * Returns the type of the given zfs handle. 2793228103Smm */ 2794228103Smmzfs_type_t 2795228103Smmzfs_get_type(const zfs_handle_t *zhp) 2796228103Smm{ 2797228103Smm return (zhp->zfs_type); 2798168404Spjd} 2799168404Spjd 2800168404Spjd/* 2801219089Spjd * Is one dataset name a child dataset of another? 2802219089Spjd * 2803219089Spjd * Needs to handle these cases: 2804219089Spjd * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" 2805219089Spjd * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" 2806219089Spjd * Descendant? No. No. No. Yes. 2807219089Spjd */ 2808219089Spjdstatic boolean_t 2809219089Spjdis_descendant(const char *ds1, const char *ds2) 2810219089Spjd{ 2811219089Spjd size_t d1len = strlen(ds1); 2812219089Spjd 2813219089Spjd /* ds2 can't be a descendant if it's smaller */ 2814219089Spjd if (strlen(ds2) < d1len) 2815219089Spjd return (B_FALSE); 2816219089Spjd 2817219089Spjd /* otherwise, compare strings and verify that there's a '/' char */ 2818219089Spjd return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0)); 2819219089Spjd} 2820219089Spjd 2821219089Spjd/* 2822168404Spjd * Given a complete name, return just the portion that refers to the parent. 2823228103Smm * Will return -1 if there is no parent (path is just the name of the 2824228103Smm * pool). 2825168404Spjd */ 2826168404Spjdstatic int 2827168404Spjdparent_name(const char *path, char *buf, size_t buflen) 2828168404Spjd{ 2829228103Smm char *slashp; 2830168404Spjd 2831228103Smm (void) strlcpy(buf, path, buflen); 2832228103Smm 2833228103Smm if ((slashp = strrchr(buf, '/')) == NULL) 2834168404Spjd return (-1); 2835228103Smm *slashp = '\0'; 2836168404Spjd 2837168404Spjd return (0); 2838168404Spjd} 2839168404Spjd 2840168404Spjd/* 2841185029Spjd * If accept_ancestor is false, then check to make sure that the given path has 2842185029Spjd * a parent, and that it exists. If accept_ancestor is true, then find the 2843185029Spjd * closest existing ancestor for the given path. In prefixlen return the 2844185029Spjd * length of already existing prefix of the given path. We also fetch the 2845185029Spjd * 'zoned' property, which is used to validate property settings when creating 2846185029Spjd * new datasets. 2847168404Spjd */ 2848168404Spjdstatic int 2849185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2850185029Spjd boolean_t accept_ancestor, int *prefixlen) 2851168404Spjd{ 2852168404Spjd zfs_cmd_t zc = { 0 }; 2853168404Spjd char parent[ZFS_MAXNAMELEN]; 2854168404Spjd char *slash; 2855168404Spjd zfs_handle_t *zhp; 2856168404Spjd char errbuf[1024]; 2857219089Spjd uint64_t is_zoned; 2858168404Spjd 2859209962Smm (void) snprintf(errbuf, sizeof (errbuf), 2860209962Smm dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); 2861168404Spjd 2862168404Spjd /* get parent, and check to see if this is just a pool */ 2863168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 2864168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2865168404Spjd "missing dataset name")); 2866168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2867168404Spjd } 2868168404Spjd 2869168404Spjd /* check to see if the pool exists */ 2870168404Spjd if ((slash = strchr(parent, '/')) == NULL) 2871168404Spjd slash = parent + strlen(parent); 2872168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 2873168404Spjd zc.zc_name[slash - parent] = '\0'; 2874168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2875168404Spjd errno == ENOENT) { 2876168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2877168404Spjd "no such pool '%s'"), zc.zc_name); 2878168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2879168404Spjd } 2880168404Spjd 2881168404Spjd /* check to see if the parent dataset exists */ 2882185029Spjd while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2883185029Spjd if (errno == ENOENT && accept_ancestor) { 2884185029Spjd /* 2885185029Spjd * Go deeper to find an ancestor, give up on top level. 2886185029Spjd */ 2887185029Spjd if (parent_name(parent, parent, sizeof (parent)) != 0) { 2888185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2889185029Spjd "no such pool '%s'"), zc.zc_name); 2890185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2891185029Spjd } 2892185029Spjd } else if (errno == ENOENT) { 2893168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2894168404Spjd "parent does not exist")); 2895168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2896185029Spjd } else 2897168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2898168404Spjd } 2899168404Spjd 2900219089Spjd is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2901219089Spjd if (zoned != NULL) 2902219089Spjd *zoned = is_zoned; 2903219089Spjd 2904168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2905219089Spjd if (getzoneid() != GLOBAL_ZONEID && !is_zoned) { 2906168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2907168404Spjd zfs_close(zhp); 2908168404Spjd return (-1); 2909168404Spjd } 2910168404Spjd 2911168404Spjd /* make sure parent is a filesystem */ 2912168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2913168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2914168404Spjd "parent is not a filesystem")); 2915168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2916168404Spjd zfs_close(zhp); 2917168404Spjd return (-1); 2918168404Spjd } 2919168404Spjd 2920168404Spjd zfs_close(zhp); 2921185029Spjd if (prefixlen != NULL) 2922185029Spjd *prefixlen = strlen(parent); 2923168404Spjd return (0); 2924168404Spjd} 2925168404Spjd 2926168404Spjd/* 2927185029Spjd * Finds whether the dataset of the given type(s) exists. 2928185029Spjd */ 2929185029Spjdboolean_t 2930185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2931185029Spjd{ 2932185029Spjd zfs_handle_t *zhp; 2933185029Spjd 2934185029Spjd if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2935185029Spjd return (B_FALSE); 2936185029Spjd 2937185029Spjd /* 2938185029Spjd * Try to get stats for the dataset, which will tell us if it exists. 2939185029Spjd */ 2940185029Spjd if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2941185029Spjd int ds_type = zhp->zfs_type; 2942185029Spjd 2943185029Spjd zfs_close(zhp); 2944185029Spjd if (types & ds_type) 2945185029Spjd return (B_TRUE); 2946185029Spjd } 2947185029Spjd return (B_FALSE); 2948185029Spjd} 2949185029Spjd 2950185029Spjd/* 2951185029Spjd * Given a path to 'target', create all the ancestors between 2952185029Spjd * the prefixlen portion of the path, and the target itself. 2953185029Spjd * Fail if the initial prefixlen-ancestor does not already exist. 2954185029Spjd */ 2955185029Spjdint 2956185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2957185029Spjd{ 2958185029Spjd zfs_handle_t *h; 2959185029Spjd char *cp; 2960185029Spjd const char *opname; 2961185029Spjd 2962185029Spjd /* make sure prefix exists */ 2963185029Spjd cp = target + prefixlen; 2964185029Spjd if (*cp != '/') { 2965185029Spjd assert(strchr(cp, '/') == NULL); 2966185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2967185029Spjd } else { 2968185029Spjd *cp = '\0'; 2969185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2970185029Spjd *cp = '/'; 2971185029Spjd } 2972185029Spjd if (h == NULL) 2973185029Spjd return (-1); 2974185029Spjd zfs_close(h); 2975185029Spjd 2976185029Spjd /* 2977185029Spjd * Attempt to create, mount, and share any ancestor filesystems, 2978185029Spjd * up to the prefixlen-long one. 2979185029Spjd */ 2980185029Spjd for (cp = target + prefixlen + 1; 2981185029Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2982185029Spjd 2983185029Spjd *cp = '\0'; 2984185029Spjd 2985185029Spjd h = make_dataset_handle(hdl, target); 2986185029Spjd if (h) { 2987185029Spjd /* it already exists, nothing to do here */ 2988185029Spjd zfs_close(h); 2989185029Spjd continue; 2990185029Spjd } 2991185029Spjd 2992185029Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2993185029Spjd NULL) != 0) { 2994185029Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2995185029Spjd goto ancestorerr; 2996185029Spjd } 2997185029Spjd 2998185029Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2999185029Spjd if (h == NULL) { 3000185029Spjd opname = dgettext(TEXT_DOMAIN, "open"); 3001185029Spjd goto ancestorerr; 3002185029Spjd } 3003185029Spjd 3004185029Spjd if (zfs_mount(h, NULL, 0) != 0) { 3005185029Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 3006185029Spjd goto ancestorerr; 3007185029Spjd } 3008185029Spjd 3009185029Spjd if (zfs_share(h) != 0) { 3010185029Spjd opname = dgettext(TEXT_DOMAIN, "share"); 3011185029Spjd goto ancestorerr; 3012185029Spjd } 3013185029Spjd 3014185029Spjd zfs_close(h); 3015185029Spjd } 3016185029Spjd 3017185029Spjd return (0); 3018185029Spjd 3019185029Spjdancestorerr: 3020185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3021185029Spjd "failed to %s ancestor '%s'"), opname, target); 3022185029Spjd return (-1); 3023185029Spjd} 3024185029Spjd 3025185029Spjd/* 3026185029Spjd * Creates non-existing ancestors of the given path. 3027185029Spjd */ 3028185029Spjdint 3029185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 3030185029Spjd{ 3031185029Spjd int prefix; 3032185029Spjd char *path_copy; 3033185029Spjd int rc; 3034185029Spjd 3035219089Spjd if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0) 3036185029Spjd return (-1); 3037185029Spjd 3038185029Spjd if ((path_copy = strdup(path)) != NULL) { 3039185029Spjd rc = create_parents(hdl, path_copy, prefix); 3040185029Spjd free(path_copy); 3041185029Spjd } 3042185029Spjd if (path_copy == NULL || rc != 0) 3043185029Spjd return (-1); 3044185029Spjd 3045185029Spjd return (0); 3046185029Spjd} 3047185029Spjd 3048185029Spjd/* 3049168404Spjd * Create a new filesystem or volume. 3050168404Spjd */ 3051168404Spjdint 3052168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 3053168404Spjd nvlist_t *props) 3054168404Spjd{ 3055168404Spjd int ret; 3056168404Spjd uint64_t size = 0; 3057168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 3058168404Spjd char errbuf[1024]; 3059168404Spjd uint64_t zoned; 3060248571Smm dmu_objset_type_t ost; 3061168404Spjd 3062168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3063168404Spjd "cannot create '%s'"), path); 3064168404Spjd 3065168404Spjd /* validate the path, taking care to note the extended error message */ 3066185029Spjd if (!zfs_validate_name(hdl, path, type, B_TRUE)) 3067168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3068168404Spjd 3069168404Spjd /* validate parents exist */ 3070185029Spjd if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) 3071168404Spjd return (-1); 3072168404Spjd 3073168404Spjd /* 3074168404Spjd * The failure modes when creating a dataset of a different type over 3075168404Spjd * one that already exists is a little strange. In particular, if you 3076168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 3077168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 3078168404Spjd * first try to see if the dataset exists. 3079168404Spjd */ 3080248571Smm if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { 3081168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3082168404Spjd "dataset already exists")); 3083168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3084168404Spjd } 3085168404Spjd 3086168404Spjd if (type == ZFS_TYPE_VOLUME) 3087248571Smm ost = DMU_OST_ZVOL; 3088168404Spjd else 3089248571Smm ost = DMU_OST_ZFS; 3090168404Spjd 3091185029Spjd if (props && (props = zfs_valid_proplist(hdl, type, props, 3092168404Spjd zoned, NULL, errbuf)) == 0) 3093168404Spjd return (-1); 3094168404Spjd 3095168404Spjd if (type == ZFS_TYPE_VOLUME) { 3096168404Spjd /* 3097168404Spjd * If we are creating a volume, the size and block size must 3098168404Spjd * satisfy a few restraints. First, the blocksize must be a 3099168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 3100168404Spjd * volsize must be a multiple of the block size, and cannot be 3101168404Spjd * zero. 3102168404Spjd */ 3103168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 3104168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 3105168404Spjd nvlist_free(props); 3106168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3107168404Spjd "missing volume size")); 3108168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3109168404Spjd } 3110168404Spjd 3111168404Spjd if ((ret = nvlist_lookup_uint64(props, 3112168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3113168404Spjd &blocksize)) != 0) { 3114168404Spjd if (ret == ENOENT) { 3115168404Spjd blocksize = zfs_prop_default_numeric( 3116168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3117168404Spjd } else { 3118168404Spjd nvlist_free(props); 3119168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3120168404Spjd "missing volume block size")); 3121168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3122168404Spjd } 3123168404Spjd } 3124168404Spjd 3125168404Spjd if (size == 0) { 3126168404Spjd nvlist_free(props); 3127168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3128168404Spjd "volume size cannot be zero")); 3129168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3130168404Spjd } 3131168404Spjd 3132168404Spjd if (size % blocksize != 0) { 3133168404Spjd nvlist_free(props); 3134168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3135168404Spjd "volume size must be a multiple of volume block " 3136168404Spjd "size")); 3137168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3138168404Spjd } 3139168404Spjd } 3140168404Spjd 3141248571Smm /* create the dataset */ 3142248571Smm ret = lzc_create(path, ost, props); 3143168404Spjd nvlist_free(props); 3144168404Spjd 3145168404Spjd /* check for failure */ 3146168404Spjd if (ret != 0) { 3147168404Spjd char parent[ZFS_MAXNAMELEN]; 3148168404Spjd (void) parent_name(path, parent, sizeof (parent)); 3149168404Spjd 3150168404Spjd switch (errno) { 3151168404Spjd case ENOENT: 3152168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3153168404Spjd "no such parent '%s'"), parent); 3154168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 3155168404Spjd 3156168404Spjd case EINVAL: 3157168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3158168404Spjd "parent '%s' is not a filesystem"), parent); 3159168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3160168404Spjd 3161168404Spjd case EDOM: 3162168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3163168404Spjd "volume block size must be power of 2 from " 3164168404Spjd "%u to %uk"), 3165168404Spjd (uint_t)SPA_MINBLOCKSIZE, 3166168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 3167168404Spjd 3168168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3169168404Spjd 3170185029Spjd case ENOTSUP: 3171185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3172185029Spjd "pool must be upgraded to set this " 3173185029Spjd "property or value")); 3174185029Spjd return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); 3175168404Spjd#ifdef _ILP32 3176168404Spjd case EOVERFLOW: 3177168404Spjd /* 3178168404Spjd * This platform can't address a volume this big. 3179168404Spjd */ 3180168404Spjd if (type == ZFS_TYPE_VOLUME) 3181168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 3182168404Spjd errbuf)); 3183168404Spjd#endif 3184168404Spjd /* FALLTHROUGH */ 3185168404Spjd default: 3186168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 3187168404Spjd } 3188168404Spjd } 3189168404Spjd 3190168404Spjd return (0); 3191168404Spjd} 3192168404Spjd 3193168404Spjd/* 3194168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 3195238422Smm * isn't mounted, and that there are no active dependents. If the file system 3196238422Smm * does not exist this function does nothing. 3197168404Spjd */ 3198168404Spjdint 3199219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer) 3200168404Spjd{ 3201168404Spjd zfs_cmd_t zc = { 0 }; 3202168404Spjd 3203260183Sdelphij if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { 3204260183Sdelphij nvlist_t *nv = fnvlist_alloc(); 3205260183Sdelphij fnvlist_add_boolean(nv, zhp->zfs_name); 3206260183Sdelphij int error = lzc_destroy_bookmarks(nv, NULL); 3207260183Sdelphij fnvlist_free(nv); 3208260183Sdelphij if (error != 0) { 3209260183Sdelphij return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3210260183Sdelphij dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3211260183Sdelphij zhp->zfs_name)); 3212260183Sdelphij } 3213260183Sdelphij return (0); 3214260183Sdelphij } 3215260183Sdelphij 3216168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3217168404Spjd 3218168404Spjd if (ZFS_IS_VOLUME(zhp)) { 3219168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3220168404Spjd } else { 3221168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3222168404Spjd } 3223168404Spjd 3224219089Spjd zc.zc_defer_destroy = defer; 3225238422Smm if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && 3226238422Smm errno != ENOENT) { 3227168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3228168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3229168404Spjd zhp->zfs_name)); 3230168404Spjd } 3231168404Spjd 3232168404Spjd remove_mountpoint(zhp); 3233168404Spjd 3234168404Spjd return (0); 3235168404Spjd} 3236168404Spjd 3237168404Spjdstruct destroydata { 3238228103Smm nvlist_t *nvl; 3239228103Smm const char *snapname; 3240168404Spjd}; 3241168404Spjd 3242168404Spjdstatic int 3243219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg) 3244168404Spjd{ 3245168404Spjd struct destroydata *dd = arg; 3246168404Spjd char name[ZFS_MAXNAMELEN]; 3247219089Spjd int rv = 0; 3248168404Spjd 3249228103Smm (void) snprintf(name, sizeof (name), 3250228103Smm "%s@%s", zhp->zfs_name, dd->snapname); 3251168404Spjd 3252251646Sdelphij if (lzc_exists(name)) 3253228103Smm verify(nvlist_add_boolean(dd->nvl, name) == 0); 3254168404Spjd 3255228103Smm rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); 3256228103Smm zfs_close(zhp); 3257168404Spjd return (rv); 3258168404Spjd} 3259168404Spjd 3260168404Spjd/* 3261168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 3262168404Spjd */ 3263168404Spjdint 3264219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) 3265168404Spjd{ 3266168404Spjd int ret; 3267168404Spjd struct destroydata dd = { 0 }; 3268168404Spjd 3269168404Spjd dd.snapname = snapname; 3270228103Smm verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); 3271228103Smm (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); 3272168404Spjd 3273251646Sdelphij if (nvlist_empty(dd.nvl)) { 3274228103Smm ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3275168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3276228103Smm zhp->zfs_name, snapname); 3277228103Smm } else { 3278248571Smm ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer); 3279168404Spjd } 3280228103Smm nvlist_free(dd.nvl); 3281228103Smm return (ret); 3282228103Smm} 3283168404Spjd 3284228103Smm/* 3285248571Smm * Destroys all the snapshots named in the nvlist. 3286228103Smm */ 3287228103Smmint 3288248571Smmzfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer) 3289228103Smm{ 3290228103Smm int ret; 3291248571Smm nvlist_t *errlist; 3292228103Smm 3293248571Smm ret = lzc_destroy_snaps(snaps, defer, &errlist); 3294168404Spjd 3295248571Smm if (ret == 0) 3296248571Smm return (0); 3297248571Smm 3298251646Sdelphij if (nvlist_empty(errlist)) { 3299168404Spjd char errbuf[1024]; 3300248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3301248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshots")); 3302168404Spjd 3303248571Smm ret = zfs_standard_error(hdl, ret, errbuf); 3304248571Smm } 3305248571Smm for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL); 3306248571Smm pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) { 3307248571Smm char errbuf[1024]; 3308248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3309248571Smm dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"), 3310248571Smm nvpair_name(pair)); 3311168404Spjd 3312248571Smm switch (fnvpair_value_int32(pair)) { 3313168404Spjd case EEXIST: 3314248571Smm zfs_error_aux(hdl, 3315248571Smm dgettext(TEXT_DOMAIN, "snapshot is cloned")); 3316248571Smm ret = zfs_error(hdl, EZFS_EXISTS, errbuf); 3317248571Smm break; 3318168404Spjd default: 3319248571Smm ret = zfs_standard_error(hdl, errno, errbuf); 3320248571Smm break; 3321168404Spjd } 3322168404Spjd } 3323168404Spjd 3324248571Smm return (ret); 3325168404Spjd} 3326168404Spjd 3327168404Spjd/* 3328168404Spjd * Clones the given dataset. The target must be of the same type as the source. 3329168404Spjd */ 3330168404Spjdint 3331168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 3332168404Spjd{ 3333168404Spjd char parent[ZFS_MAXNAMELEN]; 3334168404Spjd int ret; 3335168404Spjd char errbuf[1024]; 3336168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3337168404Spjd uint64_t zoned; 3338168404Spjd 3339168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3340168404Spjd 3341168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3342168404Spjd "cannot create '%s'"), target); 3343168404Spjd 3344228103Smm /* validate the target/clone name */ 3345185029Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) 3346168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3347168404Spjd 3348168404Spjd /* validate parents exist */ 3349185029Spjd if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) 3350168404Spjd return (-1); 3351168404Spjd 3352168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3353168404Spjd 3354168404Spjd /* do the clone */ 3355168404Spjd 3356168404Spjd if (props) { 3357248571Smm zfs_type_t type; 3358248571Smm if (ZFS_IS_VOLUME(zhp)) { 3359248571Smm type = ZFS_TYPE_VOLUME; 3360248571Smm } else { 3361248571Smm type = ZFS_TYPE_FILESYSTEM; 3362248571Smm } 3363185029Spjd if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3364185029Spjd zhp, errbuf)) == NULL) 3365168404Spjd return (-1); 3366168404Spjd } 3367168404Spjd 3368248571Smm ret = lzc_clone(target, zhp->zfs_name, props); 3369248571Smm nvlist_free(props); 3370168404Spjd 3371168404Spjd if (ret != 0) { 3372168404Spjd switch (errno) { 3373168404Spjd 3374168404Spjd case ENOENT: 3375168404Spjd /* 3376168404Spjd * The parent doesn't exist. We should have caught this 3377168404Spjd * above, but there may a race condition that has since 3378168404Spjd * destroyed the parent. 3379168404Spjd * 3380168404Spjd * At this point, we don't know whether it's the source 3381168404Spjd * that doesn't exist anymore, or whether the target 3382168404Spjd * dataset doesn't exist. 3383168404Spjd */ 3384168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3385168404Spjd "no such parent '%s'"), parent); 3386168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 3387168404Spjd 3388168404Spjd case EXDEV: 3389168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 3390168404Spjd "source and target pools differ")); 3391168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 3392168404Spjd errbuf)); 3393168404Spjd 3394168404Spjd default: 3395168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 3396168404Spjd errbuf)); 3397168404Spjd } 3398168404Spjd } 3399168404Spjd 3400168404Spjd return (ret); 3401168404Spjd} 3402168404Spjd 3403168404Spjd/* 3404168404Spjd * Promotes the given clone fs to be the clone parent. 3405168404Spjd */ 3406168404Spjdint 3407168404Spjdzfs_promote(zfs_handle_t *zhp) 3408168404Spjd{ 3409168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3410168404Spjd zfs_cmd_t zc = { 0 }; 3411168404Spjd char parent[MAXPATHLEN]; 3412168404Spjd int ret; 3413168404Spjd char errbuf[1024]; 3414168404Spjd 3415168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3416168404Spjd "cannot promote '%s'"), zhp->zfs_name); 3417168404Spjd 3418168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3419168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3420168404Spjd "snapshots can not be promoted")); 3421168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3422168404Spjd } 3423168404Spjd 3424185029Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); 3425168404Spjd if (parent[0] == '\0') { 3426168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3427168404Spjd "not a cloned filesystem")); 3428168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3429168404Spjd } 3430168404Spjd 3431185029Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, 3432168404Spjd sizeof (zc.zc_value)); 3433168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3434185029Spjd ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 3435168404Spjd 3436168404Spjd if (ret != 0) { 3437168404Spjd int save_errno = errno; 3438168404Spjd 3439168404Spjd switch (save_errno) { 3440168404Spjd case EEXIST: 3441219089Spjd /* There is a conflicting snapshot name. */ 3442168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3443219089Spjd "conflicting snapshot '%s' from parent '%s'"), 3444219089Spjd zc.zc_string, parent); 3445168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 3446168404Spjd 3447168404Spjd default: 3448168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 3449168404Spjd } 3450168404Spjd } 3451168404Spjd return (ret); 3452168404Spjd} 3453168404Spjd 3454248571Smmtypedef struct snapdata { 3455248571Smm nvlist_t *sd_nvl; 3456248571Smm const char *sd_snapname; 3457248571Smm} snapdata_t; 3458248571Smm 3459248571Smmstatic int 3460248571Smmzfs_snapshot_cb(zfs_handle_t *zhp, void *arg) 3461248571Smm{ 3462248571Smm snapdata_t *sd = arg; 3463248571Smm char name[ZFS_MAXNAMELEN]; 3464248571Smm int rv = 0; 3465248571Smm 3466253819Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { 3467253819Sdelphij (void) snprintf(name, sizeof (name), 3468253819Sdelphij "%s@%s", zfs_get_name(zhp), sd->sd_snapname); 3469248571Smm 3470253819Sdelphij fnvlist_add_boolean(sd->sd_nvl, name); 3471248571Smm 3472253819Sdelphij rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); 3473253819Sdelphij } 3474248571Smm zfs_close(zhp); 3475253819Sdelphij 3476248571Smm return (rv); 3477248571Smm} 3478248571Smm 3479168404Spjd/* 3480248571Smm * Creates snapshots. The keys in the snaps nvlist are the snapshots to be 3481248571Smm * created. 3482168404Spjd */ 3483168404Spjdint 3484248571Smmzfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) 3485168404Spjd{ 3486168404Spjd int ret; 3487168404Spjd char errbuf[1024]; 3488248571Smm nvpair_t *elem; 3489248571Smm nvlist_t *errors; 3490168404Spjd 3491168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3492248571Smm "cannot create snapshots ")); 3493168404Spjd 3494248571Smm elem = NULL; 3495248571Smm while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) { 3496248571Smm const char *snapname = nvpair_name(elem); 3497168404Spjd 3498248571Smm /* validate the target name */ 3499248571Smm if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT, 3500248571Smm B_TRUE)) { 3501248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3502248571Smm dgettext(TEXT_DOMAIN, 3503248571Smm "cannot create snapshot '%s'"), snapname); 3504248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3505248571Smm } 3506248571Smm } 3507185029Spjd 3508248571Smm if (props != NULL && 3509248571Smm (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3510248571Smm props, B_FALSE, NULL, errbuf)) == NULL) { 3511248571Smm return (-1); 3512248571Smm } 3513248571Smm 3514248571Smm ret = lzc_snapshot(snaps, props, &errors); 3515248571Smm 3516248571Smm if (ret != 0) { 3517248571Smm boolean_t printed = B_FALSE; 3518248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 3519248571Smm elem != NULL; 3520248571Smm elem = nvlist_next_nvpair(errors, elem)) { 3521248571Smm (void) snprintf(errbuf, sizeof (errbuf), 3522248571Smm dgettext(TEXT_DOMAIN, 3523248571Smm "cannot create snapshot '%s'"), nvpair_name(elem)); 3524248571Smm (void) zfs_standard_error(hdl, 3525248571Smm fnvpair_value_int32(elem), errbuf); 3526248571Smm printed = B_TRUE; 3527185029Spjd } 3528248571Smm if (!printed) { 3529248571Smm switch (ret) { 3530248571Smm case EXDEV: 3531248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3532248571Smm "multiple snapshots of same " 3533248571Smm "fs not allowed")); 3534248571Smm (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3535185029Spjd 3536248571Smm break; 3537248571Smm default: 3538248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 3539248571Smm } 3540248571Smm } 3541185029Spjd } 3542185029Spjd 3543248571Smm nvlist_free(props); 3544248571Smm nvlist_free(errors); 3545248571Smm return (ret); 3546248571Smm} 3547168404Spjd 3548248571Smmint 3549248571Smmzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3550248571Smm nvlist_t *props) 3551248571Smm{ 3552248571Smm int ret; 3553248571Smm snapdata_t sd = { 0 }; 3554248571Smm char fsname[ZFS_MAXNAMELEN]; 3555248571Smm char *cp; 3556248571Smm zfs_handle_t *zhp; 3557248571Smm char errbuf[1024]; 3558248571Smm 3559248571Smm (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3560248571Smm "cannot snapshot %s"), path); 3561248571Smm 3562248571Smm if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) 3563248571Smm return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3564248571Smm 3565248571Smm (void) strlcpy(fsname, path, sizeof (fsname)); 3566248571Smm cp = strchr(fsname, '@'); 3567248571Smm *cp = '\0'; 3568248571Smm sd.sd_snapname = cp + 1; 3569248571Smm 3570248571Smm if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | 3571168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 3572168404Spjd return (-1); 3573168404Spjd } 3574168404Spjd 3575248571Smm verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); 3576248571Smm if (recursive) { 3577248571Smm (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); 3578248571Smm } else { 3579248571Smm fnvlist_add_boolean(sd.sd_nvl, path); 3580168404Spjd } 3581168404Spjd 3582248571Smm ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props); 3583248571Smm nvlist_free(sd.sd_nvl); 3584168404Spjd zfs_close(zhp); 3585168404Spjd return (ret); 3586168404Spjd} 3587168404Spjd 3588168404Spjd/* 3589168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3590168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3591168404Spjd * is a dependent and we should just destroy it without checking the transaction 3592168404Spjd * group. 3593168404Spjd */ 3594168404Spjdtypedef struct rollback_data { 3595168404Spjd const char *cb_target; /* the snapshot */ 3596168404Spjd uint64_t cb_create; /* creation time reference */ 3597185029Spjd boolean_t cb_error; 3598185029Spjd boolean_t cb_force; 3599168404Spjd} rollback_data_t; 3600168404Spjd 3601168404Spjdstatic int 3602260183Sdelphijrollback_destroy_dependent(zfs_handle_t *zhp, void *data) 3603168404Spjd{ 3604168404Spjd rollback_data_t *cbp = data; 3605260183Sdelphij prop_changelist_t *clp; 3606168404Spjd 3607260183Sdelphij /* We must destroy this clone; first unmount it */ 3608260183Sdelphij clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3609260183Sdelphij cbp->cb_force ? MS_FORCE: 0); 3610260183Sdelphij if (clp == NULL || changelist_prefix(clp) != 0) { 3611260183Sdelphij cbp->cb_error = B_TRUE; 3612260183Sdelphij zfs_close(zhp); 3613260183Sdelphij return (0); 3614260183Sdelphij } 3615260183Sdelphij if (zfs_destroy(zhp, B_FALSE) != 0) 3616260183Sdelphij cbp->cb_error = B_TRUE; 3617260183Sdelphij else 3618260183Sdelphij changelist_remove(clp, zhp->zfs_name); 3619260183Sdelphij (void) changelist_postfix(clp); 3620260183Sdelphij changelist_free(clp); 3621168404Spjd 3622260183Sdelphij zfs_close(zhp); 3623260183Sdelphij return (0); 3624260183Sdelphij} 3625168404Spjd 3626260183Sdelphijstatic int 3627260183Sdelphijrollback_destroy(zfs_handle_t *zhp, void *data) 3628260183Sdelphij{ 3629260183Sdelphij rollback_data_t *cbp = data; 3630185029Spjd 3631260183Sdelphij if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { 3632260183Sdelphij cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3633260183Sdelphij rollback_destroy_dependent, cbp); 3634260183Sdelphij 3635260183Sdelphij cbp->cb_error |= zfs_destroy(zhp, B_FALSE); 3636168404Spjd } 3637168404Spjd 3638168404Spjd zfs_close(zhp); 3639168404Spjd return (0); 3640168404Spjd} 3641168404Spjd 3642168404Spjd/* 3643168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3644168404Spjd * data changes since then and making it the active dataset. 3645168404Spjd * 3646260183Sdelphij * Any snapshots and bookmarks more recent than the target are 3647260183Sdelphij * destroyed, along with their dependents (i.e. clones). 3648168404Spjd */ 3649168404Spjdint 3650185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) 3651168404Spjd{ 3652168404Spjd rollback_data_t cb = { 0 }; 3653185029Spjd int err; 3654185029Spjd boolean_t restore_resv = 0; 3655185029Spjd uint64_t old_volsize, new_volsize; 3656185029Spjd zfs_prop_t resv_prop; 3657168404Spjd 3658185029Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3659185029Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3660168404Spjd 3661168404Spjd /* 3662239774Smm * Destroy all recent snapshots and their dependents. 3663168404Spjd */ 3664185029Spjd cb.cb_force = force; 3665168404Spjd cb.cb_target = snap->zfs_name; 3666168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3667260183Sdelphij (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb); 3668260183Sdelphij (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); 3669168404Spjd 3670185029Spjd if (cb.cb_error) 3671185029Spjd return (-1); 3672168404Spjd 3673168404Spjd /* 3674168404Spjd * Now that we have verified that the snapshot is the latest, 3675168404Spjd * rollback to the given snapshot. 3676168404Spjd */ 3677168404Spjd 3678185029Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3679185029Spjd if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3680185029Spjd return (-1); 3681185029Spjd old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3682185029Spjd restore_resv = 3683185029Spjd (old_volsize == zfs_prop_get_int(zhp, resv_prop)); 3684168404Spjd } 3685168404Spjd 3686168404Spjd /* 3687185029Spjd * We rely on zfs_iter_children() to verify that there are no 3688185029Spjd * newer snapshots for the given dataset. Therefore, we can 3689185029Spjd * simply pass the name on to the ioctl() call. There is still 3690185029Spjd * an unlikely race condition where the user has taken a 3691185029Spjd * snapshot since we verified that this was the most recent. 3692168404Spjd */ 3693254587Sdelphij err = lzc_rollback(zhp->zfs_name, NULL, 0); 3694254587Sdelphij if (err != 0) { 3695185029Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3696185029Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3697185029Spjd zhp->zfs_name); 3698185029Spjd return (err); 3699185029Spjd } 3700168404Spjd 3701185029Spjd /* 3702185029Spjd * For volumes, if the pre-rollback volsize matched the pre- 3703185029Spjd * rollback reservation and the volsize has changed then set 3704185029Spjd * the reservation property to the post-rollback volsize. 3705185029Spjd * Make a new handle since the rollback closed the dataset. 3706185029Spjd */ 3707185029Spjd if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3708185029Spjd (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3709185029Spjd if (restore_resv) { 3710185029Spjd new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3711185029Spjd if (old_volsize != new_volsize) 3712185029Spjd err = zfs_prop_set_int(zhp, resv_prop, 3713185029Spjd new_volsize); 3714185029Spjd } 3715185029Spjd zfs_close(zhp); 3716185029Spjd } 3717185029Spjd return (err); 3718168404Spjd} 3719168404Spjd 3720168404Spjd/* 3721168404Spjd * Renames the given dataset. 3722168404Spjd */ 3723168404Spjdint 3724240870Spjdzfs_rename(zfs_handle_t *zhp, const char *source, const char *target, 3725240870Spjd renameflags_t flags) 3726168404Spjd{ 3727168404Spjd int ret; 3728168404Spjd zfs_cmd_t zc = { 0 }; 3729168404Spjd char *delim; 3730168676Spjd prop_changelist_t *cl = NULL; 3731168676Spjd zfs_handle_t *zhrp = NULL; 3732168676Spjd char *parentname = NULL; 3733168404Spjd char parent[ZFS_MAXNAMELEN]; 3734226676Spjd char property[ZFS_MAXPROPLEN]; 3735168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3736168404Spjd char errbuf[1024]; 3737168404Spjd 3738168404Spjd /* if we have the same exact name, just return success */ 3739168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3740168404Spjd return (0); 3741168404Spjd 3742168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3743168404Spjd "cannot rename to '%s'"), target); 3744168404Spjd 3745240870Spjd if (source != NULL) { 3746240870Spjd /* 3747240870Spjd * This is recursive snapshots rename, put snapshot name 3748240870Spjd * (that might not exist) into zfs_name. 3749240870Spjd */ 3750240870Spjd assert(flags.recurse); 3751240870Spjd 3752240870Spjd (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name)); 3753240870Spjd (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name)); 3754240870Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 3755240870Spjd } 3756240870Spjd 3757168404Spjd /* 3758168404Spjd * Make sure the target name is valid 3759168404Spjd */ 3760168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3761168404Spjd if ((strchr(target, '@') == NULL) || 3762168404Spjd *target == '@') { 3763168404Spjd /* 3764168404Spjd * Snapshot target name is abbreviated, 3765168404Spjd * reconstruct full dataset name 3766168404Spjd */ 3767168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3768168404Spjd sizeof (parent)); 3769168404Spjd delim = strchr(parent, '@'); 3770168404Spjd if (strchr(target, '@') == NULL) 3771168404Spjd *(++delim) = '\0'; 3772168404Spjd else 3773168404Spjd *delim = '\0'; 3774168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3775168404Spjd target = parent; 3776168404Spjd } else { 3777168404Spjd /* 3778168404Spjd * Make sure we're renaming within the same dataset. 3779168404Spjd */ 3780168404Spjd delim = strchr(target, '@'); 3781168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3782168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3783168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3784168404Spjd "snapshots must be part of same " 3785168404Spjd "dataset")); 3786168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3787168404Spjd errbuf)); 3788168404Spjd } 3789168404Spjd } 3790185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3791168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3792168404Spjd } else { 3793226705Spjd if (flags.recurse) { 3794168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3795168676Spjd "recursive rename must be a snapshot")); 3796168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3797168676Spjd } 3798168676Spjd 3799185029Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) 3800168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3801168404Spjd 3802168404Spjd /* validate parents */ 3803219089Spjd if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0) 3804168404Spjd return (-1); 3805168404Spjd 3806168404Spjd /* make sure we're in the same pool */ 3807168404Spjd verify((delim = strchr(target, '/')) != NULL); 3808168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3809168404Spjd zhp->zfs_name[delim - target] != '/') { 3810168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3811168404Spjd "datasets must be within same pool")); 3812168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3813168404Spjd } 3814168404Spjd 3815168404Spjd /* new name cannot be a child of the current dataset name */ 3816219089Spjd if (is_descendant(zhp->zfs_name, target)) { 3817168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3818219089Spjd "New dataset name cannot be a descendant of " 3819168404Spjd "current dataset name")); 3820168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3821168404Spjd } 3822168404Spjd } 3823168404Spjd 3824168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3825168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3826168404Spjd 3827168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3828168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3829168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3830168404Spjd "dataset is used in a non-global zone")); 3831168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3832168404Spjd } 3833168404Spjd 3834226705Spjd /* 3835226705Spjd * Avoid unmounting file systems with mountpoint property set to 3836226705Spjd * 'legacy' or 'none' even if -u option is not given. 3837226705Spjd */ 3838226705Spjd if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 3839226705Spjd !flags.recurse && !flags.nounmount && 3840226705Spjd zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, 3841226705Spjd sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && 3842226705Spjd (strcmp(property, "legacy") == 0 || 3843226705Spjd strcmp(property, "none") == 0)) { 3844226705Spjd flags.nounmount = B_TRUE; 3845226705Spjd } 3846168404Spjd 3847226705Spjd if (flags.recurse) { 3848226705Spjd 3849185029Spjd parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3850185029Spjd if (parentname == NULL) { 3851185029Spjd ret = -1; 3852185029Spjd goto error; 3853185029Spjd } 3854168676Spjd delim = strchr(parentname, '@'); 3855168676Spjd *delim = '\0'; 3856185029Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); 3857168676Spjd if (zhrp == NULL) { 3858185029Spjd ret = -1; 3859185029Spjd goto error; 3860168676Spjd } 3861168676Spjd 3862168676Spjd } else { 3863226676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 3864235216Smm flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 3865235216Smm flags.forceunmount ? MS_FORCE : 0)) == NULL) { 3866168676Spjd return (-1); 3867226676Spjd } 3868168676Spjd 3869168676Spjd if (changelist_haszonedchild(cl)) { 3870168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3871168676Spjd "child dataset with inherited mountpoint is used " 3872168676Spjd "in a non-global zone")); 3873168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3874168676Spjd goto error; 3875168676Spjd } 3876168676Spjd 3877168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3878168676Spjd goto error; 3879168404Spjd } 3880168404Spjd 3881168404Spjd if (ZFS_IS_VOLUME(zhp)) 3882168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3883168404Spjd else 3884168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3885168404Spjd 3886168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3887168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3888168404Spjd 3889226705Spjd zc.zc_cookie = flags.recurse ? 1 : 0; 3890226705Spjd if (flags.nounmount) 3891226676Spjd zc.zc_cookie |= 2; 3892168676Spjd 3893185029Spjd if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { 3894168676Spjd /* 3895168676Spjd * if it was recursive, the one that actually failed will 3896168676Spjd * be in zc.zc_name 3897168676Spjd */ 3898168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3899185029Spjd "cannot rename '%s'"), zc.zc_name); 3900168404Spjd 3901226705Spjd if (flags.recurse && errno == EEXIST) { 3902168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3903168676Spjd "a child dataset already has a snapshot " 3904168676Spjd "with the new name")); 3905185029Spjd (void) zfs_error(hdl, EZFS_EXISTS, errbuf); 3906168676Spjd } else { 3907168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3908168676Spjd } 3909168676Spjd 3910168404Spjd /* 3911168404Spjd * On failure, we still want to remount any filesystems that 3912168404Spjd * were previously mounted, so we don't alter the system state. 3913168404Spjd */ 3914226705Spjd if (!flags.recurse) 3915168676Spjd (void) changelist_postfix(cl); 3916168404Spjd } else { 3917226705Spjd if (!flags.recurse) { 3918168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3919168676Spjd ret = changelist_postfix(cl); 3920168676Spjd } 3921168404Spjd } 3922168404Spjd 3923168404Spjderror: 3924168676Spjd if (parentname) { 3925168676Spjd free(parentname); 3926168676Spjd } 3927168676Spjd if (zhrp) { 3928168676Spjd zfs_close(zhrp); 3929168676Spjd } 3930168676Spjd if (cl) { 3931168676Spjd changelist_free(cl); 3932168676Spjd } 3933168404Spjd return (ret); 3934168404Spjd} 3935168404Spjd 3936219089Spjdnvlist_t * 3937219089Spjdzfs_get_user_props(zfs_handle_t *zhp) 3938168404Spjd{ 3939219089Spjd return (zhp->zfs_user_props); 3940168676Spjd} 3941168676Spjd 3942168404Spjdnvlist_t * 3943219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp) 3944168404Spjd{ 3945219089Spjd if (zhp->zfs_recvd_props == NULL) 3946219089Spjd if (get_recvd_props_ioctl(zhp) != 0) 3947219089Spjd return (NULL); 3948219089Spjd return (zhp->zfs_recvd_props); 3949168404Spjd} 3950168404Spjd 3951168404Spjd/* 3952168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3953168404Spjd * display, and their maximum widths. This does two main things: 3954168404Spjd * 3955168404Spjd * - If this is a list of all properties, then expand the list to include 3956168404Spjd * all native properties, and set a flag so that for each dataset we look 3957168404Spjd * for new unique user properties and add them to the list. 3958168404Spjd * 3959168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3960219089Spjd * so that we can size the column appropriately. If the user has 3961219089Spjd * requested received property values, we also need to compute the width 3962219089Spjd * of the RECEIVED column. 3963168404Spjd */ 3964168404Spjdint 3965259850Sdelphijzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received, 3966259850Sdelphij boolean_t literal) 3967168404Spjd{ 3968168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3969185029Spjd zprop_list_t *entry; 3970185029Spjd zprop_list_t **last, **start; 3971168404Spjd nvlist_t *userprops, *propval; 3972168404Spjd nvpair_t *elem; 3973168404Spjd char *strval; 3974168404Spjd char buf[ZFS_MAXPROPLEN]; 3975168404Spjd 3976185029Spjd if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) 3977168404Spjd return (-1); 3978168404Spjd 3979168404Spjd userprops = zfs_get_user_props(zhp); 3980168404Spjd 3981168404Spjd entry = *plp; 3982168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3983168404Spjd /* 3984168404Spjd * Go through and add any user properties as necessary. We 3985168404Spjd * start by incrementing our list pointer to the first 3986168404Spjd * non-native property. 3987168404Spjd */ 3988168404Spjd start = plp; 3989168404Spjd while (*start != NULL) { 3990185029Spjd if ((*start)->pl_prop == ZPROP_INVAL) 3991168404Spjd break; 3992168404Spjd start = &(*start)->pl_next; 3993168404Spjd } 3994168404Spjd 3995168404Spjd elem = NULL; 3996168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3997168404Spjd /* 3998168404Spjd * See if we've already found this property in our list. 3999168404Spjd */ 4000168404Spjd for (last = start; *last != NULL; 4001168404Spjd last = &(*last)->pl_next) { 4002168404Spjd if (strcmp((*last)->pl_user_prop, 4003168404Spjd nvpair_name(elem)) == 0) 4004168404Spjd break; 4005168404Spjd } 4006168404Spjd 4007168404Spjd if (*last == NULL) { 4008168404Spjd if ((entry = zfs_alloc(hdl, 4009185029Spjd sizeof (zprop_list_t))) == NULL || 4010168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 4011168404Spjd nvpair_name(elem)))) == NULL) { 4012168404Spjd free(entry); 4013168404Spjd return (-1); 4014168404Spjd } 4015168404Spjd 4016185029Spjd entry->pl_prop = ZPROP_INVAL; 4017168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 4018168404Spjd entry->pl_all = B_TRUE; 4019168404Spjd *last = entry; 4020168404Spjd } 4021168404Spjd } 4022168404Spjd } 4023168404Spjd 4024168404Spjd /* 4025168404Spjd * Now go through and check the width of any non-fixed columns 4026168404Spjd */ 4027168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4028259850Sdelphij if (entry->pl_fixed && !literal) 4029168404Spjd continue; 4030168404Spjd 4031185029Spjd if (entry->pl_prop != ZPROP_INVAL) { 4032168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 4033259850Sdelphij buf, sizeof (buf), NULL, NULL, 0, literal) == 0) { 4034168404Spjd if (strlen(buf) > entry->pl_width) 4035168404Spjd entry->pl_width = strlen(buf); 4036168404Spjd } 4037219089Spjd if (received && zfs_prop_get_recvd(zhp, 4038219089Spjd zfs_prop_to_name(entry->pl_prop), 4039259850Sdelphij buf, sizeof (buf), literal) == 0) 4040219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4041219089Spjd entry->pl_recvd_width = strlen(buf); 4042219089Spjd } else { 4043219089Spjd if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, 4044219089Spjd &propval) == 0) { 4045219089Spjd verify(nvlist_lookup_string(propval, 4046219089Spjd ZPROP_VALUE, &strval) == 0); 4047219089Spjd if (strlen(strval) > entry->pl_width) 4048219089Spjd entry->pl_width = strlen(strval); 4049219089Spjd } 4050219089Spjd if (received && zfs_prop_get_recvd(zhp, 4051219089Spjd entry->pl_user_prop, 4052259850Sdelphij buf, sizeof (buf), literal) == 0) 4053219089Spjd if (strlen(buf) > entry->pl_recvd_width) 4054219089Spjd entry->pl_recvd_width = strlen(buf); 4055168404Spjd } 4056168404Spjd } 4057168404Spjd 4058168404Spjd return (0); 4059168404Spjd} 4060168404Spjd 4061185029Spjdint 4062185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4063209962Smm char *resource, void *export, void *sharetab, 4064209962Smm int sharemax, zfs_share_op_t operation) 4065185029Spjd{ 4066185029Spjd zfs_cmd_t zc = { 0 }; 4067185029Spjd int error; 4068185029Spjd 4069185029Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4070185029Spjd (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4071209962Smm if (resource) 4072209962Smm (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); 4073185029Spjd zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4074185029Spjd zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4075185029Spjd zc.zc_share.z_sharetype = operation; 4076185029Spjd zc.zc_share.z_sharemax = sharemax; 4077185029Spjd error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4078185029Spjd return (error); 4079185029Spjd} 4080185029Spjd 4081205198Sdelphijvoid 4082205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) 4083205198Sdelphij{ 4084205198Sdelphij nvpair_t *curr; 4085205198Sdelphij 4086205198Sdelphij /* 4087205198Sdelphij * Keep a reference to the props-table against which we prune the 4088205198Sdelphij * properties. 4089205198Sdelphij */ 4090205198Sdelphij zhp->zfs_props_table = props; 4091205198Sdelphij 4092205198Sdelphij curr = nvlist_next_nvpair(zhp->zfs_props, NULL); 4093205198Sdelphij 4094205198Sdelphij while (curr) { 4095205198Sdelphij zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr)); 4096205198Sdelphij nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr); 4097205198Sdelphij 4098206199Sdelphij /* 4099219089Spjd * User properties will result in ZPROP_INVAL, and since we 4100219089Spjd * only know how to prune standard ZFS properties, we always 4101219089Spjd * leave these in the list. This can also happen if we 4102219089Spjd * encounter an unknown DSL property (when running older 4103219089Spjd * software, for example). 4104206199Sdelphij */ 4105206199Sdelphij if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE) 4106205198Sdelphij (void) nvlist_remove(zhp->zfs_props, 4107205198Sdelphij nvpair_name(curr), nvpair_type(curr)); 4108205198Sdelphij curr = next; 4109205198Sdelphij } 4110205198Sdelphij} 4111205198Sdelphij 4112209962Smm#ifdef sun 4113209962Smmstatic int 4114209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, 4115209962Smm zfs_smb_acl_op_t cmd, char *resource1, char *resource2) 4116209962Smm{ 4117209962Smm zfs_cmd_t zc = { 0 }; 4118209962Smm nvlist_t *nvlist = NULL; 4119209962Smm int error; 4120209962Smm 4121209962Smm (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4122209962Smm (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4123209962Smm zc.zc_cookie = (uint64_t)cmd; 4124209962Smm 4125209962Smm if (cmd == ZFS_SMB_ACL_RENAME) { 4126209962Smm if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) { 4127209962Smm (void) no_memory(hdl); 4128209962Smm return (NULL); 4129209962Smm } 4130209962Smm } 4131209962Smm 4132209962Smm switch (cmd) { 4133209962Smm case ZFS_SMB_ACL_ADD: 4134209962Smm case ZFS_SMB_ACL_REMOVE: 4135209962Smm (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); 4136209962Smm break; 4137209962Smm case ZFS_SMB_ACL_RENAME: 4138209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, 4139209962Smm resource1) != 0) { 4140209962Smm (void) no_memory(hdl); 4141209962Smm return (-1); 4142209962Smm } 4143209962Smm if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, 4144209962Smm resource2) != 0) { 4145209962Smm (void) no_memory(hdl); 4146209962Smm return (-1); 4147209962Smm } 4148209962Smm if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) { 4149209962Smm nvlist_free(nvlist); 4150209962Smm return (-1); 4151209962Smm } 4152209962Smm break; 4153209962Smm case ZFS_SMB_ACL_PURGE: 4154209962Smm break; 4155209962Smm default: 4156209962Smm return (-1); 4157209962Smm } 4158209962Smm error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); 4159209962Smm if (nvlist) 4160209962Smm nvlist_free(nvlist); 4161209962Smm return (error); 4162209962Smm} 4163209962Smm 4164209962Smmint 4165209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, 4166209962Smm char *path, char *resource) 4167209962Smm{ 4168209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, 4169209962Smm resource, NULL)); 4170209962Smm} 4171209962Smm 4172209962Smmint 4173209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, 4174209962Smm char *path, char *resource) 4175209962Smm{ 4176209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, 4177209962Smm resource, NULL)); 4178209962Smm} 4179209962Smm 4180209962Smmint 4181209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) 4182209962Smm{ 4183209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, 4184209962Smm NULL, NULL)); 4185209962Smm} 4186209962Smm 4187209962Smmint 4188209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, 4189209962Smm char *oldname, char *newname) 4190209962Smm{ 4191209962Smm return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, 4192209962Smm oldname, newname)); 4193209962Smm} 4194209962Smm#endif /* sun */ 4195209962Smm 4196209962Smmint 4197209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, 4198209962Smm zfs_userspace_cb_t func, void *arg) 4199209962Smm{ 4200209962Smm zfs_cmd_t zc = { 0 }; 4201209962Smm zfs_useracct_t buf[100]; 4202240415Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4203240415Smm int ret; 4204209962Smm 4205228103Smm (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4206209962Smm 4207209962Smm zc.zc_objset_type = type; 4208209962Smm zc.zc_nvlist_dst = (uintptr_t)buf; 4209209962Smm 4210240415Smm for (;;) { 4211209962Smm zfs_useracct_t *zua = buf; 4212209962Smm 4213209962Smm zc.zc_nvlist_dst_size = sizeof (buf); 4214240415Smm if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { 4215248571Smm char errbuf[1024]; 4216240415Smm 4217240415Smm (void) snprintf(errbuf, sizeof (errbuf), 4218240415Smm dgettext(TEXT_DOMAIN, 4219240415Smm "cannot get used/quota for %s"), zc.zc_name); 4220240415Smm return (zfs_standard_error_fmt(hdl, errno, errbuf)); 4221240415Smm } 4222240415Smm if (zc.zc_nvlist_dst_size == 0) 4223209962Smm break; 4224209962Smm 4225209962Smm while (zc.zc_nvlist_dst_size > 0) { 4226240415Smm if ((ret = func(arg, zua->zu_domain, zua->zu_rid, 4227240415Smm zua->zu_space)) != 0) 4228240415Smm return (ret); 4229209962Smm zua++; 4230209962Smm zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t); 4231209962Smm } 4232209962Smm } 4233209962Smm 4234240415Smm return (0); 4235209962Smm} 4236209962Smm 4237248571Smmstruct holdarg { 4238248571Smm nvlist_t *nvl; 4239248571Smm const char *snapname; 4240248571Smm const char *tag; 4241248571Smm boolean_t recursive; 4242252219Sdelphij int error; 4243248571Smm}; 4244248571Smm 4245248571Smmstatic int 4246248571Smmzfs_hold_one(zfs_handle_t *zhp, void *arg) 4247248571Smm{ 4248248571Smm struct holdarg *ha = arg; 4249248571Smm char name[ZFS_MAXNAMELEN]; 4250248571Smm int rv = 0; 4251248571Smm 4252248571Smm (void) snprintf(name, sizeof (name), 4253248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4254248571Smm 4255251646Sdelphij if (lzc_exists(name)) 4256248571Smm fnvlist_add_string(ha->nvl, name, ha->tag); 4257248571Smm 4258248571Smm if (ha->recursive) 4259248571Smm rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); 4260248571Smm zfs_close(zhp); 4261248571Smm return (rv); 4262248571Smm} 4263248571Smm 4264219089Spjdint 4265219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, 4266251646Sdelphij boolean_t recursive, int cleanup_fd) 4267219089Spjd{ 4268248571Smm int ret; 4269248571Smm struct holdarg ha; 4270219089Spjd 4271248571Smm ha.nvl = fnvlist_alloc(); 4272248571Smm ha.snapname = snapname; 4273248571Smm ha.tag = tag; 4274248571Smm ha.recursive = recursive; 4275248571Smm (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); 4276249357Smm 4277251646Sdelphij if (nvlist_empty(ha.nvl)) { 4278251646Sdelphij char errbuf[1024]; 4279251646Sdelphij 4280249357Smm fnvlist_free(ha.nvl); 4281249357Smm ret = ENOENT; 4282251646Sdelphij (void) snprintf(errbuf, sizeof (errbuf), 4283251646Sdelphij dgettext(TEXT_DOMAIN, 4284251646Sdelphij "cannot hold snapshot '%s@%s'"), 4285251646Sdelphij zhp->zfs_name, snapname); 4286251646Sdelphij (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); 4287249357Smm return (ret); 4288249357Smm } 4289249357Smm 4290251646Sdelphij ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); 4291248571Smm fnvlist_free(ha.nvl); 4292219089Spjd 4293251646Sdelphij return (ret); 4294251646Sdelphij} 4295251646Sdelphij 4296251646Sdelphijint 4297251646Sdelphijzfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) 4298251646Sdelphij{ 4299251646Sdelphij int ret; 4300251646Sdelphij nvlist_t *errors; 4301251646Sdelphij libzfs_handle_t *hdl = zhp->zfs_hdl; 4302251646Sdelphij char errbuf[1024]; 4303251646Sdelphij nvpair_t *elem; 4304251646Sdelphij 4305251646Sdelphij errors = NULL; 4306251646Sdelphij ret = lzc_hold(holds, cleanup_fd, &errors); 4307251646Sdelphij 4308251646Sdelphij if (ret == 0) { 4309251646Sdelphij /* There may be errors even in the success case. */ 4310251646Sdelphij fnvlist_free(errors); 4311248571Smm return (0); 4312251646Sdelphij } 4313219089Spjd 4314251646Sdelphij if (nvlist_empty(errors)) { 4315248571Smm /* no hold-specific errors */ 4316248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4317248571Smm dgettext(TEXT_DOMAIN, "cannot hold")); 4318248571Smm switch (ret) { 4319248571Smm case ENOTSUP: 4320248571Smm zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4321248571Smm "pool must be upgraded")); 4322248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4323248571Smm break; 4324248571Smm case EINVAL: 4325248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4326248571Smm break; 4327248571Smm default: 4328248571Smm (void) zfs_standard_error(hdl, ret, errbuf); 4329248571Smm } 4330248571Smm } 4331219089Spjd 4332248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4333248571Smm elem != NULL; 4334248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4335248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4336248571Smm dgettext(TEXT_DOMAIN, 4337248571Smm "cannot hold snapshot '%s'"), nvpair_name(elem)); 4338248571Smm switch (fnvpair_value_int32(elem)) { 4339219089Spjd case E2BIG: 4340219089Spjd /* 4341219089Spjd * Temporary tags wind up having the ds object id 4342219089Spjd * prepended. So even if we passed the length check 4343219089Spjd * above, it's still possible for the tag to wind 4344219089Spjd * up being slightly too long. 4345219089Spjd */ 4346248571Smm (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf); 4347248571Smm break; 4348219089Spjd case EINVAL: 4349248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4350248571Smm break; 4351219089Spjd case EEXIST: 4352248571Smm (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); 4353248571Smm break; 4354219089Spjd default: 4355248571Smm (void) zfs_standard_error(hdl, 4356248571Smm fnvpair_value_int32(elem), errbuf); 4357219089Spjd } 4358219089Spjd } 4359219089Spjd 4360248571Smm fnvlist_free(errors); 4361248571Smm return (ret); 4362219089Spjd} 4363219089Spjd 4364248571Smmstatic int 4365248571Smmzfs_release_one(zfs_handle_t *zhp, void *arg) 4366248571Smm{ 4367248571Smm struct holdarg *ha = arg; 4368248571Smm char name[ZFS_MAXNAMELEN]; 4369248571Smm int rv = 0; 4370252219Sdelphij nvlist_t *existing_holds; 4371248571Smm 4372248571Smm (void) snprintf(name, sizeof (name), 4373248571Smm "%s@%s", zhp->zfs_name, ha->snapname); 4374248571Smm 4375252219Sdelphij if (lzc_get_holds(name, &existing_holds) != 0) { 4376252219Sdelphij ha->error = ENOENT; 4377252219Sdelphij } else if (!nvlist_exists(existing_holds, ha->tag)) { 4378252219Sdelphij ha->error = ESRCH; 4379252219Sdelphij } else { 4380252219Sdelphij nvlist_t *torelease = fnvlist_alloc(); 4381252219Sdelphij fnvlist_add_boolean(torelease, ha->tag); 4382252219Sdelphij fnvlist_add_nvlist(ha->nvl, name, torelease); 4383252219Sdelphij fnvlist_free(torelease); 4384248571Smm } 4385248571Smm 4386248571Smm if (ha->recursive) 4387248571Smm rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); 4388248571Smm zfs_close(zhp); 4389248571Smm return (rv); 4390248571Smm} 4391248571Smm 4392219089Spjdint 4393219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, 4394219089Spjd boolean_t recursive) 4395219089Spjd{ 4396248571Smm int ret; 4397248571Smm struct holdarg ha; 4398251646Sdelphij nvlist_t *errors = NULL; 4399248571Smm nvpair_t *elem; 4400219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4401249357Smm char errbuf[1024]; 4402219089Spjd 4403248571Smm ha.nvl = fnvlist_alloc(); 4404248571Smm ha.snapname = snapname; 4405248571Smm ha.tag = tag; 4406248571Smm ha.recursive = recursive; 4407252219Sdelphij ha.error = 0; 4408248571Smm (void) zfs_release_one(zfs_handle_dup(zhp), &ha); 4409249357Smm 4410251646Sdelphij if (nvlist_empty(ha.nvl)) { 4411249357Smm fnvlist_free(ha.nvl); 4412252219Sdelphij ret = ha.error; 4413249357Smm (void) snprintf(errbuf, sizeof (errbuf), 4414249357Smm dgettext(TEXT_DOMAIN, 4415249357Smm "cannot release hold from snapshot '%s@%s'"), 4416249357Smm zhp->zfs_name, snapname); 4417252219Sdelphij if (ret == ESRCH) { 4418252219Sdelphij (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4419252219Sdelphij } else { 4420252219Sdelphij (void) zfs_standard_error(hdl, ret, errbuf); 4421252219Sdelphij } 4422249357Smm return (ret); 4423249357Smm } 4424249357Smm 4425248571Smm ret = lzc_release(ha.nvl, &errors); 4426248571Smm fnvlist_free(ha.nvl); 4427219089Spjd 4428251646Sdelphij if (ret == 0) { 4429251646Sdelphij /* There may be errors even in the success case. */ 4430251646Sdelphij fnvlist_free(errors); 4431248571Smm return (0); 4432251646Sdelphij } 4433219089Spjd 4434251646Sdelphij if (nvlist_empty(errors)) { 4435248571Smm /* no hold-specific errors */ 4436219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4437248571Smm "cannot release")); 4438219089Spjd switch (errno) { 4439219089Spjd case ENOTSUP: 4440219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4441219089Spjd "pool must be upgraded")); 4442248571Smm (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4443248571Smm break; 4444248571Smm default: 4445248571Smm (void) zfs_standard_error_fmt(hdl, errno, errbuf); 4446248571Smm } 4447248571Smm } 4448248571Smm 4449248571Smm for (elem = nvlist_next_nvpair(errors, NULL); 4450248571Smm elem != NULL; 4451248571Smm elem = nvlist_next_nvpair(errors, elem)) { 4452248571Smm (void) snprintf(errbuf, sizeof (errbuf), 4453248571Smm dgettext(TEXT_DOMAIN, 4454248571Smm "cannot release hold from snapshot '%s'"), 4455248571Smm nvpair_name(elem)); 4456248571Smm switch (fnvpair_value_int32(elem)) { 4457248571Smm case ESRCH: 4458248571Smm (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); 4459248571Smm break; 4460219089Spjd case EINVAL: 4461248571Smm (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4462248571Smm break; 4463219089Spjd default: 4464248571Smm (void) zfs_standard_error_fmt(hdl, 4465248571Smm fnvpair_value_int32(elem), errbuf); 4466219089Spjd } 4467219089Spjd } 4468219089Spjd 4469248571Smm fnvlist_free(errors); 4470248571Smm return (ret); 4471219089Spjd} 4472219089Spjd 4473219089Spjdint 4474219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) 4475219089Spjd{ 4476219089Spjd zfs_cmd_t zc = { 0 }; 4477219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4478219089Spjd int nvsz = 2048; 4479219089Spjd void *nvbuf; 4480219089Spjd int err = 0; 4481248571Smm char errbuf[1024]; 4482219089Spjd 4483219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4484219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4485219089Spjd 4486219089Spjdtryagain: 4487219089Spjd 4488219089Spjd nvbuf = malloc(nvsz); 4489219089Spjd if (nvbuf == NULL) { 4490219089Spjd err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); 4491219089Spjd goto out; 4492219089Spjd } 4493219089Spjd 4494219089Spjd zc.zc_nvlist_dst_size = nvsz; 4495219089Spjd zc.zc_nvlist_dst = (uintptr_t)nvbuf; 4496219089Spjd 4497219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); 4498219089Spjd 4499230514Smm if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 4500219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4501219089Spjd dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), 4502219089Spjd zc.zc_name); 4503219089Spjd switch (errno) { 4504219089Spjd case ENOMEM: 4505219089Spjd free(nvbuf); 4506219089Spjd nvsz = zc.zc_nvlist_dst_size; 4507219089Spjd goto tryagain; 4508219089Spjd 4509219089Spjd case ENOTSUP: 4510219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4511219089Spjd "pool must be upgraded")); 4512219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4513219089Spjd break; 4514219089Spjd case EINVAL: 4515219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4516219089Spjd break; 4517219089Spjd case ENOENT: 4518219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4519219089Spjd break; 4520219089Spjd default: 4521219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4522219089Spjd break; 4523219089Spjd } 4524219089Spjd } else { 4525219089Spjd /* success */ 4526219089Spjd int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); 4527219089Spjd if (rc) { 4528219089Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext( 4529219089Spjd TEXT_DOMAIN, "cannot get permissions on '%s'"), 4530219089Spjd zc.zc_name); 4531219089Spjd err = zfs_standard_error_fmt(hdl, rc, errbuf); 4532219089Spjd } 4533219089Spjd } 4534219089Spjd 4535219089Spjd free(nvbuf); 4536219089Spjdout: 4537219089Spjd return (err); 4538219089Spjd} 4539219089Spjd 4540219089Spjdint 4541219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) 4542219089Spjd{ 4543219089Spjd zfs_cmd_t zc = { 0 }; 4544219089Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4545219089Spjd char *nvbuf; 4546248571Smm char errbuf[1024]; 4547219089Spjd size_t nvsz; 4548219089Spjd int err; 4549219089Spjd 4550219089Spjd assert(zhp->zfs_type == ZFS_TYPE_VOLUME || 4551219089Spjd zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4552219089Spjd 4553219089Spjd err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); 4554219089Spjd assert(err == 0); 4555219089Spjd 4556219089Spjd nvbuf = malloc(nvsz); 4557219089Spjd 4558219089Spjd err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); 4559219089Spjd assert(err == 0); 4560219089Spjd 4561219089Spjd zc.zc_nvlist_src_size = nvsz; 4562219089Spjd zc.zc_nvlist_src = (uintptr_t)nvbuf; 4563219089Spjd zc.zc_perm_action = un; 4564219089Spjd 4565219089Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4566219089Spjd 4567219089Spjd if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { 4568219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4569219089Spjd dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), 4570219089Spjd zc.zc_name); 4571219089Spjd switch (errno) { 4572219089Spjd case ENOTSUP: 4573219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4574219089Spjd "pool must be upgraded")); 4575219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4576219089Spjd break; 4577219089Spjd case EINVAL: 4578219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4579219089Spjd break; 4580219089Spjd case ENOENT: 4581219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4582219089Spjd break; 4583219089Spjd default: 4584219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4585219089Spjd break; 4586219089Spjd } 4587219089Spjd } 4588219089Spjd 4589219089Spjd free(nvbuf); 4590219089Spjd 4591219089Spjd return (err); 4592219089Spjd} 4593219089Spjd 4594219089Spjdint 4595219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) 4596219089Spjd{ 4597248571Smm int err; 4598248571Smm char errbuf[1024]; 4599219089Spjd 4600248571Smm err = lzc_get_holds(zhp->zfs_name, nvl); 4601219089Spjd 4602248571Smm if (err != 0) { 4603248571Smm libzfs_handle_t *hdl = zhp->zfs_hdl; 4604219089Spjd 4605219089Spjd (void) snprintf(errbuf, sizeof (errbuf), 4606219089Spjd dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), 4607248571Smm zhp->zfs_name); 4608248571Smm switch (err) { 4609219089Spjd case ENOTSUP: 4610219089Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4611219089Spjd "pool must be upgraded")); 4612219089Spjd err = zfs_error(hdl, EZFS_BADVERSION, errbuf); 4613219089Spjd break; 4614219089Spjd case EINVAL: 4615219089Spjd err = zfs_error(hdl, EZFS_BADTYPE, errbuf); 4616219089Spjd break; 4617219089Spjd case ENOENT: 4618219089Spjd err = zfs_error(hdl, EZFS_NOENT, errbuf); 4619219089Spjd break; 4620219089Spjd default: 4621219089Spjd err = zfs_standard_error_fmt(hdl, errno, errbuf); 4622219089Spjd break; 4623219089Spjd } 4624219089Spjd } 4625219089Spjd 4626219089Spjd return (err); 4627219089Spjd} 4628219089Spjd 4629251629Sdelphij/* 4630251629Sdelphij * Convert the zvol's volume size to an appropriate reservation. 4631251629Sdelphij * Note: If this routine is updated, it is necessary to update the ZFS test 4632251629Sdelphij * suite's shell version in reservation.kshlib. 4633251629Sdelphij */ 4634219089Spjduint64_t 4635219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) 4636219089Spjd{ 4637219089Spjd uint64_t numdb; 4638219089Spjd uint64_t nblocks, volblocksize; 4639219089Spjd int ncopies; 4640219089Spjd char *strval; 4641219089Spjd 4642219089Spjd if (nvlist_lookup_string(props, 4643219089Spjd zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0) 4644219089Spjd ncopies = atoi(strval); 4645219089Spjd else 4646219089Spjd ncopies = 1; 4647219089Spjd if (nvlist_lookup_uint64(props, 4648219089Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 4649219089Spjd &volblocksize) != 0) 4650219089Spjd volblocksize = ZVOL_DEFAULT_BLOCKSIZE; 4651219089Spjd nblocks = volsize/volblocksize; 4652219089Spjd /* start with metadnode L0-L6 */ 4653219089Spjd numdb = 7; 4654219089Spjd /* calculate number of indirects */ 4655219089Spjd while (nblocks > 1) { 4656219089Spjd nblocks += DNODES_PER_LEVEL - 1; 4657219089Spjd nblocks /= DNODES_PER_LEVEL; 4658219089Spjd numdb += nblocks; 4659219089Spjd } 4660219089Spjd numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1); 4661219089Spjd volsize *= ncopies; 4662219089Spjd /* 4663219089Spjd * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't 4664219089Spjd * compressed, but in practice they compress down to about 4665219089Spjd * 1100 bytes 4666219089Spjd */ 4667219089Spjd numdb *= 1ULL << DN_MAX_INDBLKSHIFT; 4668219089Spjd volsize += numdb; 4669219089Spjd return (volsize); 4670219089Spjd} 4671219089Spjd 4672168404Spjd/* 4673168404Spjd * Attach/detach the given filesystem to/from the given jail. 4674168404Spjd */ 4675168404Spjdint 4676168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4677168404Spjd{ 4678168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 4679168404Spjd zfs_cmd_t zc = { 0 }; 4680168404Spjd char errbuf[1024]; 4681224525Smm unsigned long cmd; 4682224525Smm int ret; 4683168404Spjd 4684168404Spjd if (attach) { 4685168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4686168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 4687168404Spjd } else { 4688168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 4689249547Spjd dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name); 4690168404Spjd } 4691168404Spjd 4692168404Spjd switch (zhp->zfs_type) { 4693168404Spjd case ZFS_TYPE_VOLUME: 4694168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4695168404Spjd "volumes can not be jailed")); 4696168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4697168404Spjd case ZFS_TYPE_SNAPSHOT: 4698168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4699168404Spjd "snapshots can not be jailed")); 4700168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 4701168404Spjd } 4702168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 4703168404Spjd 4704168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 4705168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 4706168404Spjd zc.zc_jailid = jailid; 4707168404Spjd 4708168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 4709168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 4710168404Spjd zfs_standard_error(hdl, errno, errbuf); 4711168404Spjd 4712168404Spjd return (ret); 4713168404Spjd} 4714