libzfs_dataset.c revision 168676
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/* 23168404Spjd * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24168404Spjd * Use is subject to license terms. 25168404Spjd */ 26168404Spjd 27168404Spjd#pragma ident "%Z%%M% %I% %E% SMI" 28168404Spjd 29168404Spjd#include <assert.h> 30168404Spjd#include <ctype.h> 31168404Spjd#include <errno.h> 32168404Spjd#include <libintl.h> 33168404Spjd#include <math.h> 34168404Spjd#include <stdio.h> 35168404Spjd#include <stdlib.h> 36168404Spjd#include <strings.h> 37168404Spjd#include <unistd.h> 38168404Spjd#include <zone.h> 39168404Spjd#include <fcntl.h> 40168404Spjd#include <sys/mntent.h> 41168404Spjd#include <sys/mnttab.h> 42168404Spjd#include <sys/mount.h> 43168404Spjd 44168404Spjd#include <sys/spa.h> 45168404Spjd#include <sys/zio.h> 46168404Spjd#include <sys/zap.h> 47168404Spjd#include <libzfs.h> 48168404Spjd 49168404Spjd#include "zfs_namecheck.h" 50168404Spjd#include "zfs_prop.h" 51168404Spjd#include "libzfs_impl.h" 52168404Spjd 53168676Spjdstatic int zvol_create_link_common(libzfs_handle_t *, const char *, int); 54168676Spjd 55168404Spjd/* 56168404Spjd * Given a single type (not a mask of types), return the type in a human 57168404Spjd * readable form. 58168404Spjd */ 59168404Spjdconst char * 60168404Spjdzfs_type_to_name(zfs_type_t type) 61168404Spjd{ 62168404Spjd switch (type) { 63168404Spjd case ZFS_TYPE_FILESYSTEM: 64168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 65168404Spjd case ZFS_TYPE_SNAPSHOT: 66168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 67168404Spjd case ZFS_TYPE_VOLUME: 68168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 69168404Spjd } 70168404Spjd 71168404Spjd return (NULL); 72168404Spjd} 73168404Spjd 74168404Spjd/* 75168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset. 76168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type. 77168404Spjd * We guess what the type would have been based on the path and the mask of 78168404Spjd * acceptable types. 79168404Spjd */ 80168404Spjdstatic const char * 81168404Spjdpath_to_str(const char *path, int types) 82168404Spjd{ 83168404Spjd /* 84168404Spjd * When given a single type, always report the exact type. 85168404Spjd */ 86168404Spjd if (types == ZFS_TYPE_SNAPSHOT) 87168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 88168404Spjd if (types == ZFS_TYPE_FILESYSTEM) 89168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 90168404Spjd if (types == ZFS_TYPE_VOLUME) 91168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 92168404Spjd 93168404Spjd /* 94168404Spjd * The user is requesting more than one type of dataset. If this is the 95168404Spjd * case, consult the path itself. If we're looking for a snapshot, and 96168404Spjd * a '@' is found, then report it as "snapshot". Otherwise, remove the 97168404Spjd * snapshot attribute and try again. 98168404Spjd */ 99168404Spjd if (types & ZFS_TYPE_SNAPSHOT) { 100168404Spjd if (strchr(path, '@') != NULL) 101168404Spjd return (dgettext(TEXT_DOMAIN, "snapshot")); 102168404Spjd return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 103168404Spjd } 104168404Spjd 105168404Spjd 106168404Spjd /* 107168404Spjd * The user has requested either filesystems or volumes. 108168404Spjd * We have no way of knowing a priori what type this would be, so always 109168404Spjd * report it as "filesystem" or "volume", our two primitive types. 110168404Spjd */ 111168404Spjd if (types & ZFS_TYPE_FILESYSTEM) 112168404Spjd return (dgettext(TEXT_DOMAIN, "filesystem")); 113168404Spjd 114168404Spjd assert(types & ZFS_TYPE_VOLUME); 115168404Spjd return (dgettext(TEXT_DOMAIN, "volume")); 116168404Spjd} 117168404Spjd 118168404Spjd/* 119168404Spjd * Validate a ZFS path. This is used even before trying to open the dataset, to 120168404Spjd * provide a more meaningful error message. We place a more useful message in 121168404Spjd * 'buf' detailing exactly why the name was not valid. 122168404Spjd */ 123168404Spjdstatic int 124168404Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 125168404Spjd{ 126168404Spjd namecheck_err_t why; 127168404Spjd char what; 128168404Spjd 129168404Spjd if (dataset_namecheck(path, &why, &what) != 0) { 130168404Spjd if (hdl != NULL) { 131168404Spjd switch (why) { 132168404Spjd case NAME_ERR_TOOLONG: 133168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 134168404Spjd "name is too long")); 135168404Spjd break; 136168404Spjd 137168404Spjd case NAME_ERR_LEADING_SLASH: 138168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 139168404Spjd "leading slash in name")); 140168404Spjd break; 141168404Spjd 142168404Spjd case NAME_ERR_EMPTY_COMPONENT: 143168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 144168404Spjd "empty component in name")); 145168404Spjd break; 146168404Spjd 147168404Spjd case NAME_ERR_TRAILING_SLASH: 148168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 149168404Spjd "trailing slash in name")); 150168404Spjd break; 151168404Spjd 152168404Spjd case NAME_ERR_INVALCHAR: 153168404Spjd zfs_error_aux(hdl, 154168404Spjd dgettext(TEXT_DOMAIN, "invalid character " 155168404Spjd "'%c' in name"), what); 156168404Spjd break; 157168404Spjd 158168404Spjd case NAME_ERR_MULTIPLE_AT: 159168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 160168404Spjd "multiple '@' delimiters in name")); 161168404Spjd break; 162168404Spjd 163168404Spjd case NAME_ERR_NOLETTER: 164168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 165168404Spjd "pool doesn't begin with a letter")); 166168404Spjd break; 167168404Spjd 168168404Spjd case NAME_ERR_RESERVED: 169168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 170168404Spjd "name is reserved")); 171168404Spjd break; 172168404Spjd 173168404Spjd case NAME_ERR_DISKLIKE: 174168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 175168404Spjd "reserved disk name")); 176168404Spjd break; 177168404Spjd } 178168404Spjd } 179168404Spjd 180168404Spjd return (0); 181168404Spjd } 182168404Spjd 183168404Spjd if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 184168404Spjd if (hdl != NULL) 185168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 186168404Spjd "snapshot delimiter '@' in filesystem name")); 187168404Spjd return (0); 188168404Spjd } 189168404Spjd 190168404Spjd if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 191168404Spjd if (hdl != NULL) 192168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 193168404Spjd "missing '@' delimiter in snapshot name")); 194168404Spjd return (0); 195168404Spjd } 196168404Spjd 197168404Spjd return (-1); 198168404Spjd} 199168404Spjd 200168404Spjdint 201168404Spjdzfs_name_valid(const char *name, zfs_type_t type) 202168404Spjd{ 203168404Spjd return (zfs_validate_name(NULL, name, type)); 204168404Spjd} 205168404Spjd 206168404Spjd/* 207168404Spjd * This function takes the raw DSL properties, and filters out the user-defined 208168404Spjd * properties into a separate nvlist. 209168404Spjd */ 210168404Spjdstatic int 211168404Spjdprocess_user_props(zfs_handle_t *zhp) 212168404Spjd{ 213168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 214168404Spjd nvpair_t *elem; 215168404Spjd nvlist_t *propval; 216168404Spjd 217168404Spjd nvlist_free(zhp->zfs_user_props); 218168404Spjd 219168404Spjd if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 220168404Spjd return (no_memory(hdl)); 221168404Spjd 222168404Spjd elem = NULL; 223168404Spjd while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 224168404Spjd if (!zfs_prop_user(nvpair_name(elem))) 225168404Spjd continue; 226168404Spjd 227168404Spjd verify(nvpair_value_nvlist(elem, &propval) == 0); 228168404Spjd if (nvlist_add_nvlist(zhp->zfs_user_props, 229168404Spjd nvpair_name(elem), propval) != 0) 230168404Spjd return (no_memory(hdl)); 231168404Spjd } 232168404Spjd 233168404Spjd return (0); 234168404Spjd} 235168404Spjd 236168404Spjd/* 237168404Spjd * Utility function to gather stats (objset and zpl) for the given object. 238168404Spjd */ 239168404Spjdstatic int 240168404Spjdget_stats(zfs_handle_t *zhp) 241168404Spjd{ 242168404Spjd zfs_cmd_t zc = { 0 }; 243168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 244168404Spjd 245168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 246168404Spjd 247168404Spjd if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 248168404Spjd return (-1); 249168404Spjd 250168404Spjd while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 251168404Spjd if (errno == ENOMEM) { 252168404Spjd if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 253168404Spjd zcmd_free_nvlists(&zc); 254168404Spjd return (-1); 255168404Spjd } 256168404Spjd } else { 257168404Spjd zcmd_free_nvlists(&zc); 258168404Spjd return (-1); 259168404Spjd } 260168404Spjd } 261168404Spjd 262168404Spjd zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 263168404Spjd 264168404Spjd (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 265168404Spjd 266168404Spjd if (zhp->zfs_props) { 267168404Spjd nvlist_free(zhp->zfs_props); 268168404Spjd zhp->zfs_props = NULL; 269168404Spjd } 270168404Spjd 271168404Spjd if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 272168404Spjd zcmd_free_nvlists(&zc); 273168404Spjd return (-1); 274168404Spjd } 275168404Spjd 276168404Spjd zcmd_free_nvlists(&zc); 277168404Spjd 278168404Spjd if (process_user_props(zhp) != 0) 279168404Spjd return (-1); 280168404Spjd 281168404Spjd return (0); 282168404Spjd} 283168404Spjd 284168404Spjd/* 285168404Spjd * Refresh the properties currently stored in the handle. 286168404Spjd */ 287168404Spjdvoid 288168404Spjdzfs_refresh_properties(zfs_handle_t *zhp) 289168404Spjd{ 290168404Spjd (void) get_stats(zhp); 291168404Spjd} 292168404Spjd 293168404Spjd/* 294168404Spjd * Makes a handle from the given dataset name. Used by zfs_open() and 295168404Spjd * zfs_iter_* to create child handles on the fly. 296168404Spjd */ 297168404Spjdzfs_handle_t * 298168404Spjdmake_dataset_handle(libzfs_handle_t *hdl, const char *path) 299168404Spjd{ 300168404Spjd zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 301168404Spjd 302168404Spjd if (zhp == NULL) 303168404Spjd return (NULL); 304168404Spjd 305168404Spjd zhp->zfs_hdl = hdl; 306168404Spjd 307168404Spjdtop: 308168404Spjd (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 309168404Spjd 310168404Spjd if (get_stats(zhp) != 0) { 311168404Spjd free(zhp); 312168404Spjd return (NULL); 313168404Spjd } 314168404Spjd 315168404Spjd if (zhp->zfs_dmustats.dds_inconsistent) { 316168404Spjd zfs_cmd_t zc = { 0 }; 317168404Spjd 318168404Spjd /* 319168404Spjd * If it is dds_inconsistent, then we've caught it in 320168404Spjd * the middle of a 'zfs receive' or 'zfs destroy', and 321168404Spjd * it is inconsistent from the ZPL's point of view, so 322168404Spjd * can't be mounted. However, it could also be that we 323168404Spjd * have crashed in the middle of one of those 324168404Spjd * operations, in which case we need to get rid of the 325168404Spjd * inconsistent state. We do that by either rolling 326168404Spjd * back to the previous snapshot (which will fail if 327168404Spjd * there is none), or destroying the filesystem. Note 328168404Spjd * that if we are still in the middle of an active 329168404Spjd * 'receive' or 'destroy', then the rollback and destroy 330168404Spjd * will fail with EBUSY and we will drive on as usual. 331168404Spjd */ 332168404Spjd 333168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 334168404Spjd 335168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 336168404Spjd (void) zvol_remove_link(hdl, zhp->zfs_name); 337168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 338168404Spjd } else { 339168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 340168404Spjd } 341168404Spjd 342168404Spjd /* If we can successfully roll it back, reget the stats */ 343168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 344168404Spjd goto top; 345168404Spjd /* 346168404Spjd * If we can sucessfully destroy it, pretend that it 347168404Spjd * never existed. 348168404Spjd */ 349168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 350168404Spjd free(zhp); 351168404Spjd errno = ENOENT; 352168404Spjd return (NULL); 353168404Spjd } 354168404Spjd } 355168404Spjd 356168404Spjd /* 357168404Spjd * We've managed to open the dataset and gather statistics. Determine 358168404Spjd * the high-level type. 359168404Spjd */ 360168404Spjd if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 361168404Spjd zhp->zfs_head_type = ZFS_TYPE_VOLUME; 362168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 363168404Spjd zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 364168404Spjd else 365168404Spjd abort(); 366168404Spjd 367168404Spjd if (zhp->zfs_dmustats.dds_is_snapshot) 368168404Spjd zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 369168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 370168404Spjd zhp->zfs_type = ZFS_TYPE_VOLUME; 371168404Spjd else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 372168404Spjd zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 373168404Spjd else 374168404Spjd abort(); /* we should never see any other types */ 375168404Spjd 376168404Spjd return (zhp); 377168404Spjd} 378168404Spjd 379168404Spjd/* 380168404Spjd * Opens the given snapshot, filesystem, or volume. The 'types' 381168404Spjd * argument is a mask of acceptable types. The function will print an 382168404Spjd * appropriate error message and return NULL if it can't be opened. 383168404Spjd */ 384168404Spjdzfs_handle_t * 385168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types) 386168404Spjd{ 387168404Spjd zfs_handle_t *zhp; 388168404Spjd char errbuf[1024]; 389168404Spjd 390168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 391168404Spjd dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 392168404Spjd 393168404Spjd /* 394168404Spjd * Validate the name before we even try to open it. 395168404Spjd */ 396168404Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 397168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 398168404Spjd "invalid dataset name")); 399168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 400168404Spjd return (NULL); 401168404Spjd } 402168404Spjd 403168404Spjd /* 404168404Spjd * Try to get stats for the dataset, which will tell us if it exists. 405168404Spjd */ 406168404Spjd errno = 0; 407168404Spjd if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 408168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 409168404Spjd return (NULL); 410168404Spjd } 411168404Spjd 412168404Spjd if (!(types & zhp->zfs_type)) { 413168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 414168404Spjd zfs_close(zhp); 415168404Spjd return (NULL); 416168404Spjd } 417168404Spjd 418168404Spjd return (zhp); 419168404Spjd} 420168404Spjd 421168404Spjd/* 422168404Spjd * Release a ZFS handle. Nothing to do but free the associated memory. 423168404Spjd */ 424168404Spjdvoid 425168404Spjdzfs_close(zfs_handle_t *zhp) 426168404Spjd{ 427168404Spjd if (zhp->zfs_mntopts) 428168404Spjd free(zhp->zfs_mntopts); 429168404Spjd nvlist_free(zhp->zfs_props); 430168404Spjd nvlist_free(zhp->zfs_user_props); 431168404Spjd free(zhp); 432168404Spjd} 433168404Spjd 434168404Spjd/* 435168404Spjd * Given a numeric suffix, convert the value into a number of bits that the 436168404Spjd * resulting value must be shifted. 437168404Spjd */ 438168404Spjdstatic int 439168404Spjdstr2shift(libzfs_handle_t *hdl, const char *buf) 440168404Spjd{ 441168404Spjd const char *ends = "BKMGTPEZ"; 442168404Spjd int i; 443168404Spjd 444168404Spjd if (buf[0] == '\0') 445168404Spjd return (0); 446168404Spjd for (i = 0; i < strlen(ends); i++) { 447168404Spjd if (toupper(buf[0]) == ends[i]) 448168404Spjd break; 449168404Spjd } 450168404Spjd if (i == strlen(ends)) { 451168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 452168404Spjd "invalid numeric suffix '%s'"), buf); 453168404Spjd return (-1); 454168404Spjd } 455168404Spjd 456168404Spjd /* 457168404Spjd * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 458168404Spjd * allow 'BB' - that's just weird. 459168404Spjd */ 460168404Spjd if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 461168404Spjd toupper(buf[0]) != 'B')) 462168404Spjd return (10*i); 463168404Spjd 464168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 465168404Spjd "invalid numeric suffix '%s'"), buf); 466168404Spjd return (-1); 467168404Spjd} 468168404Spjd 469168404Spjd/* 470168404Spjd * Convert a string of the form '100G' into a real number. Used when setting 471168404Spjd * properties or creating a volume. 'buf' is used to place an extended error 472168404Spjd * message for the caller to use. 473168404Spjd */ 474168404Spjdstatic int 475168404Spjdnicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 476168404Spjd{ 477168404Spjd char *end; 478168404Spjd int shift; 479168404Spjd 480168404Spjd *num = 0; 481168404Spjd 482168404Spjd /* Check to see if this looks like a number. */ 483168404Spjd if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 484168404Spjd if (hdl) 485168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 486168404Spjd "bad numeric value '%s'"), value); 487168404Spjd return (-1); 488168404Spjd } 489168404Spjd 490168404Spjd /* Rely on stroll() to process the numeric portion. */ 491168404Spjd errno = 0; 492168404Spjd *num = strtoll(value, &end, 10); 493168404Spjd 494168404Spjd /* 495168404Spjd * Check for ERANGE, which indicates that the value is too large to fit 496168404Spjd * in a 64-bit value. 497168404Spjd */ 498168404Spjd if (errno == ERANGE) { 499168404Spjd if (hdl) 500168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 501168404Spjd "numeric value is too large")); 502168404Spjd return (-1); 503168404Spjd } 504168404Spjd 505168404Spjd /* 506168404Spjd * If we have a decimal value, then do the computation with floating 507168404Spjd * point arithmetic. Otherwise, use standard arithmetic. 508168404Spjd */ 509168404Spjd if (*end == '.') { 510168404Spjd double fval = strtod(value, &end); 511168404Spjd 512168404Spjd if ((shift = str2shift(hdl, end)) == -1) 513168404Spjd return (-1); 514168404Spjd 515168404Spjd fval *= pow(2, shift); 516168404Spjd 517168404Spjd if (fval > UINT64_MAX) { 518168404Spjd if (hdl) 519168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 520168404Spjd "numeric value is too large")); 521168404Spjd return (-1); 522168404Spjd } 523168404Spjd 524168404Spjd *num = (uint64_t)fval; 525168404Spjd } else { 526168404Spjd if ((shift = str2shift(hdl, end)) == -1) 527168404Spjd return (-1); 528168404Spjd 529168404Spjd /* Check for overflow */ 530168404Spjd if (shift >= 64 || (*num << shift) >> shift != *num) { 531168404Spjd if (hdl) 532168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 533168404Spjd "numeric value is too large")); 534168404Spjd return (-1); 535168404Spjd } 536168404Spjd 537168404Spjd *num <<= shift; 538168404Spjd } 539168404Spjd 540168404Spjd return (0); 541168404Spjd} 542168404Spjd 543168404Spjdint 544168404Spjdzfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 545168404Spjd{ 546168404Spjd return (nicestrtonum(hdl, str, val)); 547168404Spjd} 548168404Spjd 549168404Spjd/* 550168404Spjd * The prop_parse_*() functions are designed to allow flexibility in callers 551168404Spjd * when setting properties. At the DSL layer, all properties are either 64-bit 552168404Spjd * numbers or strings. We want the user to be able to ignore this fact and 553168404Spjd * specify properties as native values (boolean, for example) or as strings (to 554168404Spjd * simplify command line utilities). This also handles converting index types 555168404Spjd * (compression, checksum, etc) from strings to their on-disk index. 556168404Spjd */ 557168404Spjd 558168404Spjdstatic int 559168404Spjdprop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 560168404Spjd{ 561168404Spjd uint64_t ret; 562168404Spjd 563168404Spjd switch (nvpair_type(elem)) { 564168404Spjd case DATA_TYPE_STRING: 565168404Spjd { 566168404Spjd char *value; 567168404Spjd verify(nvpair_value_string(elem, &value) == 0); 568168404Spjd 569168404Spjd if (strcmp(value, "on") == 0) { 570168404Spjd ret = 1; 571168404Spjd } else if (strcmp(value, "off") == 0) { 572168404Spjd ret = 0; 573168404Spjd } else { 574168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 575168404Spjd "property '%s' must be 'on' or 'off'"), 576168404Spjd nvpair_name(elem)); 577168404Spjd return (-1); 578168404Spjd } 579168404Spjd break; 580168404Spjd } 581168404Spjd 582168404Spjd case DATA_TYPE_UINT64: 583168404Spjd { 584168404Spjd verify(nvpair_value_uint64(elem, &ret) == 0); 585168404Spjd if (ret > 1) { 586168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 587168404Spjd "'%s' must be a boolean value"), 588168404Spjd nvpair_name(elem)); 589168404Spjd return (-1); 590168404Spjd } 591168404Spjd break; 592168404Spjd } 593168404Spjd 594168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 595168404Spjd { 596168404Spjd boolean_t value; 597168404Spjd verify(nvpair_value_boolean_value(elem, &value) == 0); 598168404Spjd ret = value; 599168404Spjd break; 600168404Spjd } 601168404Spjd 602168404Spjd default: 603168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 604168404Spjd "'%s' must be a boolean value"), 605168404Spjd nvpair_name(elem)); 606168404Spjd return (-1); 607168404Spjd } 608168404Spjd 609168404Spjd *val = ret; 610168404Spjd return (0); 611168404Spjd} 612168404Spjd 613168404Spjdstatic int 614168404Spjdprop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 615168404Spjd uint64_t *val) 616168404Spjd{ 617168404Spjd uint64_t ret; 618168404Spjd boolean_t isnone = B_FALSE; 619168404Spjd 620168404Spjd switch (nvpair_type(elem)) { 621168404Spjd case DATA_TYPE_STRING: 622168404Spjd { 623168404Spjd char *value; 624168404Spjd (void) nvpair_value_string(elem, &value); 625168404Spjd if (strcmp(value, "none") == 0) { 626168404Spjd isnone = B_TRUE; 627168404Spjd ret = 0; 628168404Spjd } else if (nicestrtonum(hdl, value, &ret) != 0) { 629168404Spjd return (-1); 630168404Spjd } 631168404Spjd break; 632168404Spjd } 633168404Spjd 634168404Spjd case DATA_TYPE_UINT64: 635168404Spjd (void) nvpair_value_uint64(elem, &ret); 636168404Spjd break; 637168404Spjd 638168404Spjd default: 639168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 640168404Spjd "'%s' must be a number"), 641168404Spjd nvpair_name(elem)); 642168404Spjd return (-1); 643168404Spjd } 644168404Spjd 645168404Spjd /* 646168404Spjd * Quota special: force 'none' and don't allow 0. 647168404Spjd */ 648168404Spjd if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 649168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 650168404Spjd "use 'none' to disable quota")); 651168404Spjd return (-1); 652168404Spjd } 653168404Spjd 654168404Spjd *val = ret; 655168404Spjd return (0); 656168404Spjd} 657168404Spjd 658168404Spjdstatic int 659168404Spjdprop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 660168404Spjd uint64_t *val) 661168404Spjd{ 662168404Spjd char *propname = nvpair_name(elem); 663168404Spjd char *value; 664168404Spjd 665168404Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 666168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 667168404Spjd "'%s' must be a string"), propname); 668168404Spjd return (-1); 669168404Spjd } 670168404Spjd 671168404Spjd (void) nvpair_value_string(elem, &value); 672168404Spjd 673168404Spjd if (zfs_prop_string_to_index(prop, value, val) != 0) { 674168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 675168404Spjd "'%s' must be one of '%s'"), propname, 676168404Spjd zfs_prop_values(prop)); 677168404Spjd return (-1); 678168404Spjd } 679168404Spjd 680168404Spjd return (0); 681168404Spjd} 682168404Spjd 683168404Spjd/* 684168404Spjd * Check if the bootfs name has the same pool name as it is set to. 685168404Spjd * Assuming bootfs is a valid dataset name. 686168404Spjd */ 687168404Spjdstatic boolean_t 688168404Spjdbootfs_poolname_valid(char *pool, char *bootfs) 689168404Spjd{ 690168404Spjd char ch, *pname; 691168404Spjd 692168404Spjd /* get the pool name from the bootfs name */ 693168404Spjd pname = bootfs; 694168404Spjd while (*bootfs && !isspace(*bootfs) && *bootfs != '/') 695168404Spjd bootfs++; 696168404Spjd 697168404Spjd ch = *bootfs; 698168404Spjd *bootfs = 0; 699168404Spjd 700168404Spjd if (strcmp(pool, pname) == 0) { 701168404Spjd *bootfs = ch; 702168404Spjd return (B_TRUE); 703168404Spjd } 704168404Spjd 705168404Spjd *bootfs = ch; 706168404Spjd return (B_FALSE); 707168404Spjd} 708168404Spjd 709168404Spjd/* 710168404Spjd * Given an nvlist of properties to set, validates that they are correct, and 711168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as 712168404Spjd * strings. 713168404Spjd */ 714168404Spjdnvlist_t * 715168404Spjdzfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, 716168404Spjd nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 717168404Spjd{ 718168404Spjd nvpair_t *elem; 719168404Spjd const char *propname; 720168404Spjd zfs_prop_t prop; 721168404Spjd uint64_t intval; 722168404Spjd char *strval; 723168404Spjd nvlist_t *ret; 724168404Spjd int isuser; 725168404Spjd 726168404Spjd if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 727168404Spjd (void) no_memory(hdl); 728168404Spjd return (NULL); 729168404Spjd } 730168404Spjd 731168404Spjd if (type == ZFS_TYPE_SNAPSHOT) { 732168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 733168404Spjd "snapshot properties cannot be modified")); 734168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 735168404Spjd goto error; 736168404Spjd } 737168404Spjd 738168404Spjd elem = NULL; 739168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 740168404Spjd propname = nvpair_name(elem); 741168404Spjd 742168404Spjd /* 743168404Spjd * Make sure this property is valid and applies to this type. 744168404Spjd */ 745168404Spjd if ((prop = zfs_name_to_prop_common(propname, type)) 746168404Spjd == ZFS_PROP_INVAL) { 747168404Spjd isuser = zfs_prop_user(propname); 748168404Spjd if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) { 749168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 750168404Spjd "invalid property '%s'"), 751168404Spjd propname); 752168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 753168404Spjd goto error; 754168404Spjd } else { 755168404Spjd /* 756168404Spjd * If this is a user property, make sure it's a 757168404Spjd * string, and that it's less than 758168404Spjd * ZAP_MAXNAMELEN. 759168404Spjd */ 760168404Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 761168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 762168404Spjd "'%s' must be a string"), 763168404Spjd propname); 764168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 765168404Spjd errbuf); 766168404Spjd goto error; 767168404Spjd } 768168404Spjd 769168404Spjd if (strlen(nvpair_name(elem)) >= 770168404Spjd ZAP_MAXNAMELEN) { 771168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 772168404Spjd "property name '%s' is too long"), 773168404Spjd propname); 774168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 775168404Spjd errbuf); 776168404Spjd goto error; 777168404Spjd } 778168404Spjd } 779168404Spjd 780168404Spjd (void) nvpair_value_string(elem, &strval); 781168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 782168404Spjd (void) no_memory(hdl); 783168404Spjd goto error; 784168404Spjd } 785168404Spjd continue; 786168404Spjd } 787168404Spjd 788168404Spjd /* 789168404Spjd * Normalize the name, to get rid of shorthand abbrevations. 790168404Spjd */ 791168404Spjd propname = zfs_prop_to_name(prop); 792168404Spjd 793168404Spjd if (!zfs_prop_valid_for_type(prop, type)) { 794168404Spjd zfs_error_aux(hdl, 795168404Spjd dgettext(TEXT_DOMAIN, "'%s' does not " 796168404Spjd "apply to datasets of this type"), propname); 797168404Spjd (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 798168404Spjd goto error; 799168404Spjd } 800168404Spjd 801168404Spjd if (zfs_prop_readonly(prop) && 802168404Spjd (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 803168404Spjd zfs_error_aux(hdl, 804168404Spjd dgettext(TEXT_DOMAIN, "'%s' is readonly"), 805168404Spjd propname); 806168404Spjd (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 807168404Spjd goto error; 808168404Spjd } 809168404Spjd 810168404Spjd /* 811168404Spjd * Convert any properties to the internal DSL value types. 812168404Spjd */ 813168404Spjd strval = NULL; 814168404Spjd switch (zfs_prop_get_type(prop)) { 815168404Spjd case prop_type_boolean: 816168404Spjd if (prop_parse_boolean(hdl, elem, &intval) != 0) { 817168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 818168404Spjd goto error; 819168404Spjd } 820168404Spjd break; 821168404Spjd 822168404Spjd case prop_type_string: 823168404Spjd if (nvpair_type(elem) != DATA_TYPE_STRING) { 824168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 825168404Spjd "'%s' must be a string"), 826168404Spjd propname); 827168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 828168404Spjd goto error; 829168404Spjd } 830168404Spjd (void) nvpair_value_string(elem, &strval); 831168404Spjd if (strlen(strval) >= ZFS_MAXPROPLEN) { 832168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 833168404Spjd "'%s' is too long"), propname); 834168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 835168404Spjd goto error; 836168404Spjd } 837168404Spjd break; 838168404Spjd 839168404Spjd case prop_type_number: 840168404Spjd if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 841168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 842168404Spjd goto error; 843168404Spjd } 844168404Spjd break; 845168404Spjd 846168404Spjd case prop_type_index: 847168404Spjd if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 848168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 849168404Spjd goto error; 850168404Spjd } 851168404Spjd break; 852168404Spjd 853168404Spjd default: 854168404Spjd abort(); 855168404Spjd } 856168404Spjd 857168404Spjd /* 858168404Spjd * Add the result to our return set of properties. 859168404Spjd */ 860168404Spjd if (strval) { 861168404Spjd if (nvlist_add_string(ret, propname, strval) != 0) { 862168404Spjd (void) no_memory(hdl); 863168404Spjd goto error; 864168404Spjd } 865168404Spjd } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 866168404Spjd (void) no_memory(hdl); 867168404Spjd goto error; 868168404Spjd } 869168404Spjd 870168404Spjd /* 871168404Spjd * Perform some additional checks for specific properties. 872168404Spjd */ 873168404Spjd switch (prop) { 874168404Spjd case ZFS_PROP_RECORDSIZE: 875168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 876168404Spjd /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 877168404Spjd if (intval < SPA_MINBLOCKSIZE || 878168404Spjd intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 879168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 880168404Spjd "'%s' must be power of 2 from %u " 881168404Spjd "to %uk"), propname, 882168404Spjd (uint_t)SPA_MINBLOCKSIZE, 883168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 884168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 885168404Spjd goto error; 886168404Spjd } 887168404Spjd break; 888168404Spjd 889168404Spjd case ZFS_PROP_SHAREISCSI: 890168404Spjd if (strcmp(strval, "off") != 0 && 891168404Spjd strcmp(strval, "on") != 0 && 892168404Spjd strcmp(strval, "type=disk") != 0) { 893168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 894168404Spjd "'%s' must be 'on', 'off', or 'type=disk'"), 895168404Spjd propname); 896168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 897168404Spjd goto error; 898168404Spjd } 899168404Spjd 900168404Spjd break; 901168404Spjd 902168404Spjd case ZFS_PROP_MOUNTPOINT: 903168404Spjd if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 904168404Spjd strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 905168404Spjd break; 906168404Spjd 907168404Spjd if (strval[0] != '/') { 908168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 909168404Spjd "'%s' must be an absolute path, " 910168404Spjd "'none', or 'legacy'"), propname); 911168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 912168404Spjd goto error; 913168404Spjd } 914168404Spjd /*FALLTHRU*/ 915168404Spjd 916168404Spjd case ZFS_PROP_SHARENFS: 917168404Spjd /* 918168404Spjd * For the mountpoint and sharenfs properties, check if 919168404Spjd * it can be set in a global/non-global zone based on 920168404Spjd * the zoned property value: 921168404Spjd * 922168404Spjd * global zone non-global zone 923168404Spjd * -------------------------------------------------- 924168404Spjd * zoned=on mountpoint (no) mountpoint (yes) 925168404Spjd * sharenfs (no) sharenfs (no) 926168404Spjd * 927168404Spjd * zoned=off mountpoint (yes) N/A 928168404Spjd * sharenfs (yes) 929168404Spjd */ 930168404Spjd if (zoned) { 931168404Spjd if (getzoneid() == GLOBAL_ZONEID) { 932168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 933168404Spjd "'%s' cannot be set on " 934168404Spjd "dataset in a non-global zone"), 935168404Spjd propname); 936168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 937168404Spjd errbuf); 938168404Spjd goto error; 939168404Spjd } else if (prop == ZFS_PROP_SHARENFS) { 940168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 941168404Spjd "'%s' cannot be set in " 942168404Spjd "a non-global zone"), propname); 943168404Spjd (void) zfs_error(hdl, EZFS_ZONED, 944168404Spjd errbuf); 945168404Spjd goto error; 946168404Spjd } 947168404Spjd } else if (getzoneid() != GLOBAL_ZONEID) { 948168404Spjd /* 949168404Spjd * If zoned property is 'off', this must be in 950168404Spjd * a globle zone. If not, something is wrong. 951168404Spjd */ 952168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 953168404Spjd "'%s' cannot be set while dataset " 954168404Spjd "'zoned' property is set"), propname); 955168404Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 956168404Spjd goto error; 957168404Spjd } 958168404Spjd 959168404Spjd break; 960168404Spjd 961168404Spjd case ZFS_PROP_BOOTFS: 962168404Spjd /* 963168404Spjd * bootfs property value has to be a dataset name and 964168404Spjd * the dataset has to be in the same pool as it sets to. 965168404Spjd */ 966168404Spjd if (strval[0] != '\0' && (!zfs_name_valid(strval, 967168404Spjd ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid( 968168404Spjd pool_name, strval))) { 969168404Spjd 970168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 971168404Spjd "is an invalid name"), strval); 972168404Spjd (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 973168404Spjd goto error; 974168404Spjd } 975168404Spjd break; 976168404Spjd } 977168404Spjd 978168404Spjd /* 979168404Spjd * For changes to existing volumes, we have some additional 980168404Spjd * checks to enforce. 981168404Spjd */ 982168404Spjd if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 983168404Spjd uint64_t volsize = zfs_prop_get_int(zhp, 984168404Spjd ZFS_PROP_VOLSIZE); 985168404Spjd uint64_t blocksize = zfs_prop_get_int(zhp, 986168404Spjd ZFS_PROP_VOLBLOCKSIZE); 987168404Spjd char buf[64]; 988168404Spjd 989168404Spjd switch (prop) { 990168404Spjd case ZFS_PROP_RESERVATION: 991168404Spjd if (intval > volsize) { 992168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 993168404Spjd "'%s' is greater than current " 994168404Spjd "volume size"), propname); 995168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 996168404Spjd errbuf); 997168404Spjd goto error; 998168404Spjd } 999168404Spjd break; 1000168404Spjd 1001168404Spjd case ZFS_PROP_VOLSIZE: 1002168404Spjd if (intval % blocksize != 0) { 1003168404Spjd zfs_nicenum(blocksize, buf, 1004168404Spjd sizeof (buf)); 1005168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1006168404Spjd "'%s' must be a multiple of " 1007168404Spjd "volume block size (%s)"), 1008168404Spjd propname, buf); 1009168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1010168404Spjd errbuf); 1011168404Spjd goto error; 1012168404Spjd } 1013168404Spjd 1014168404Spjd if (intval == 0) { 1015168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1016168404Spjd "'%s' cannot be zero"), 1017168404Spjd propname); 1018168404Spjd (void) zfs_error(hdl, EZFS_BADPROP, 1019168404Spjd errbuf); 1020168404Spjd goto error; 1021168404Spjd } 1022168404Spjd break; 1023168404Spjd } 1024168404Spjd } 1025168404Spjd } 1026168404Spjd 1027168404Spjd /* 1028168404Spjd * If this is an existing volume, and someone is setting the volsize, 1029168404Spjd * make sure that it matches the reservation, or add it if necessary. 1030168404Spjd */ 1031168404Spjd if (zhp != NULL && type == ZFS_TYPE_VOLUME && 1032168404Spjd nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1033168404Spjd &intval) == 0) { 1034168404Spjd uint64_t old_volsize = zfs_prop_get_int(zhp, 1035168404Spjd ZFS_PROP_VOLSIZE); 1036168404Spjd uint64_t old_reservation = zfs_prop_get_int(zhp, 1037168404Spjd ZFS_PROP_RESERVATION); 1038168404Spjd uint64_t new_reservation; 1039168404Spjd 1040168404Spjd if (old_volsize == old_reservation && 1041168404Spjd nvlist_lookup_uint64(ret, 1042168404Spjd zfs_prop_to_name(ZFS_PROP_RESERVATION), 1043168404Spjd &new_reservation) != 0) { 1044168404Spjd if (nvlist_add_uint64(ret, 1045168404Spjd zfs_prop_to_name(ZFS_PROP_RESERVATION), 1046168404Spjd intval) != 0) { 1047168404Spjd (void) no_memory(hdl); 1048168404Spjd goto error; 1049168404Spjd } 1050168404Spjd } 1051168404Spjd } 1052168404Spjd 1053168404Spjd return (ret); 1054168404Spjd 1055168404Spjderror: 1056168404Spjd nvlist_free(ret); 1057168404Spjd return (NULL); 1058168404Spjd} 1059168404Spjd 1060168404Spjd/* 1061168404Spjd * Given a property name and value, set the property for the given dataset. 1062168404Spjd */ 1063168404Spjdint 1064168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1065168404Spjd{ 1066168404Spjd zfs_cmd_t zc = { 0 }; 1067168404Spjd int ret = -1; 1068168404Spjd prop_changelist_t *cl = NULL; 1069168404Spjd char errbuf[1024]; 1070168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1071168404Spjd nvlist_t *nvl = NULL, *realprops; 1072168404Spjd zfs_prop_t prop; 1073168404Spjd 1074168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1075168404Spjd dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1076168404Spjd zhp->zfs_name); 1077168404Spjd 1078168404Spjd if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1079168404Spjd nvlist_add_string(nvl, propname, propval) != 0) { 1080168404Spjd (void) no_memory(hdl); 1081168404Spjd goto error; 1082168404Spjd } 1083168404Spjd 1084168404Spjd if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl, 1085168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1086168404Spjd goto error; 1087168404Spjd nvlist_free(nvl); 1088168404Spjd nvl = realprops; 1089168404Spjd 1090168404Spjd prop = zfs_name_to_prop(propname); 1091168404Spjd 1092168404Spjd /* We don't support those properties on FreeBSD. */ 1093168404Spjd switch (prop) { 1094168404Spjd case ZFS_PROP_SHAREISCSI: 1095168404Spjd case ZFS_PROP_DEVICES: 1096168404Spjd case ZFS_PROP_ACLMODE: 1097168404Spjd case ZFS_PROP_ACLINHERIT: 1098168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1099168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 1100168404Spjd "property '%s' not supported on FreeBSD", propname); 1101168404Spjd ret = zfs_error(hdl, EZFS_PERM, errbuf); 1102168404Spjd goto error; 1103168404Spjd } 1104168404Spjd 1105168404Spjd if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1106168404Spjd goto error; 1107168404Spjd 1108168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1109168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1110168404Spjd "child dataset with inherited mountpoint is used " 1111168404Spjd "in a non-global zone")); 1112168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1113168404Spjd goto error; 1114168404Spjd } 1115168404Spjd 1116168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1117168404Spjd goto error; 1118168404Spjd 1119168404Spjd /* 1120168404Spjd * Execute the corresponding ioctl() to set this property. 1121168404Spjd */ 1122168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1123168404Spjd 1124168404Spjd if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 1125168404Spjd goto error; 1126168404Spjd 1127168404Spjd ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1128168404Spjd 1129168404Spjd if (ret != 0) { 1130168404Spjd switch (errno) { 1131168404Spjd 1132168404Spjd case ENOSPC: 1133168404Spjd /* 1134168404Spjd * For quotas and reservations, ENOSPC indicates 1135168404Spjd * something different; setting a quota or reservation 1136168404Spjd * doesn't use any disk space. 1137168404Spjd */ 1138168404Spjd switch (prop) { 1139168404Spjd case ZFS_PROP_QUOTA: 1140168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1141168404Spjd "size is less than current used or " 1142168404Spjd "reserved space")); 1143168404Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1144168404Spjd break; 1145168404Spjd 1146168404Spjd case ZFS_PROP_RESERVATION: 1147168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1148168404Spjd "size is greater than available space")); 1149168404Spjd (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1150168404Spjd break; 1151168404Spjd 1152168404Spjd default: 1153168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 1154168404Spjd break; 1155168404Spjd } 1156168404Spjd break; 1157168404Spjd 1158168404Spjd case EBUSY: 1159168404Spjd if (prop == ZFS_PROP_VOLBLOCKSIZE) 1160168404Spjd (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 1161168404Spjd else 1162168404Spjd (void) zfs_standard_error(hdl, EBUSY, errbuf); 1163168404Spjd break; 1164168404Spjd 1165168404Spjd case EROFS: 1166168404Spjd (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1167168404Spjd break; 1168168404Spjd 1169168404Spjd case ENOTSUP: 1170168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1171168404Spjd "pool must be upgraded to allow gzip compression")); 1172168404Spjd (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1173168404Spjd break; 1174168404Spjd 1175168404Spjd case EOVERFLOW: 1176168404Spjd /* 1177168404Spjd * This platform can't address a volume this big. 1178168404Spjd */ 1179168404Spjd#ifdef _ILP32 1180168404Spjd if (prop == ZFS_PROP_VOLSIZE) { 1181168404Spjd (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1182168404Spjd break; 1183168404Spjd } 1184168404Spjd#endif 1185168404Spjd /* FALLTHROUGH */ 1186168404Spjd default: 1187168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 1188168404Spjd } 1189168404Spjd } else { 1190168404Spjd /* 1191168404Spjd * Refresh the statistics so the new property value 1192168404Spjd * is reflected. 1193168404Spjd */ 1194168404Spjd if ((ret = changelist_postfix(cl)) == 0) 1195168404Spjd (void) get_stats(zhp); 1196168404Spjd } 1197168404Spjd 1198168404Spjderror: 1199168404Spjd nvlist_free(nvl); 1200168404Spjd zcmd_free_nvlists(&zc); 1201168404Spjd if (cl) 1202168404Spjd changelist_free(cl); 1203168404Spjd return (ret); 1204168404Spjd} 1205168404Spjd 1206168404Spjd/* 1207168404Spjd * Given a property, inherit the value from the parent dataset. 1208168404Spjd */ 1209168404Spjdint 1210168404Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1211168404Spjd{ 1212168404Spjd zfs_cmd_t zc = { 0 }; 1213168404Spjd int ret; 1214168404Spjd prop_changelist_t *cl; 1215168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 1216168404Spjd char errbuf[1024]; 1217168404Spjd zfs_prop_t prop; 1218168404Spjd 1219168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1220168404Spjd "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1221168404Spjd 1222168404Spjd if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 1223168404Spjd /* 1224168404Spjd * For user properties, the amount of work we have to do is very 1225168404Spjd * small, so just do it here. 1226168404Spjd */ 1227168404Spjd if (!zfs_prop_user(propname)) { 1228168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1229168404Spjd "invalid property")); 1230168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1231168404Spjd } 1232168404Spjd 1233168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1234168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1235168404Spjd 1236168404Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, 1237168404Spjd ZFS_IOC_SET_PROP, &zc) != 0) 1238168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1239168404Spjd 1240168404Spjd return (0); 1241168404Spjd } 1242168404Spjd 1243168404Spjd /* 1244168404Spjd * Verify that this property is inheritable. 1245168404Spjd */ 1246168404Spjd if (zfs_prop_readonly(prop)) 1247168404Spjd return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1248168404Spjd 1249168404Spjd if (!zfs_prop_inheritable(prop)) 1250168404Spjd return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1251168404Spjd 1252168404Spjd /* 1253168404Spjd * Check to see if the value applies to this type 1254168404Spjd */ 1255168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1256168404Spjd return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1257168404Spjd 1258168404Spjd /* 1259168404Spjd * Normalize the name, to get rid of shorthand abbrevations. 1260168404Spjd */ 1261168404Spjd propname = zfs_prop_to_name(prop); 1262168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1263168404Spjd (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1264168404Spjd 1265168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1266168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1267168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1268168404Spjd "dataset is used in a non-global zone")); 1269168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1270168404Spjd } 1271168404Spjd 1272168404Spjd /* 1273168404Spjd * Determine datasets which will be affected by this change, if any. 1274168404Spjd */ 1275168404Spjd if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1276168404Spjd return (-1); 1277168404Spjd 1278168404Spjd if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1279168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1280168404Spjd "child dataset with inherited mountpoint is used " 1281168404Spjd "in a non-global zone")); 1282168404Spjd ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1283168404Spjd goto error; 1284168404Spjd } 1285168404Spjd 1286168404Spjd if ((ret = changelist_prefix(cl)) != 0) 1287168404Spjd goto error; 1288168404Spjd 1289168404Spjd if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 1290168404Spjd ZFS_IOC_SET_PROP, &zc)) != 0) { 1291168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1292168404Spjd } else { 1293168404Spjd 1294168404Spjd if ((ret = changelist_postfix(cl)) != 0) 1295168404Spjd goto error; 1296168404Spjd 1297168404Spjd /* 1298168404Spjd * Refresh the statistics so the new property is reflected. 1299168404Spjd */ 1300168404Spjd (void) get_stats(zhp); 1301168404Spjd } 1302168404Spjd 1303168404Spjderror: 1304168404Spjd changelist_free(cl); 1305168404Spjd return (ret); 1306168404Spjd} 1307168404Spjd 1308168404Spjdvoid 1309168404Spjdnicebool(int value, char *buf, size_t buflen) 1310168404Spjd{ 1311168404Spjd if (value) 1312168404Spjd (void) strlcpy(buf, "on", buflen); 1313168404Spjd else 1314168404Spjd (void) strlcpy(buf, "off", buflen); 1315168404Spjd} 1316168404Spjd 1317168404Spjd/* 1318168404Spjd * True DSL properties are stored in an nvlist. The following two functions 1319168404Spjd * extract them appropriately. 1320168404Spjd */ 1321168404Spjdstatic uint64_t 1322168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1323168404Spjd{ 1324168404Spjd nvlist_t *nv; 1325168404Spjd uint64_t value; 1326168404Spjd 1327168404Spjd *source = NULL; 1328168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1329168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1330168404Spjd verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 1331168404Spjd (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 1332168404Spjd } else { 1333168404Spjd value = zfs_prop_default_numeric(prop); 1334168404Spjd *source = ""; 1335168404Spjd } 1336168404Spjd 1337168404Spjd return (value); 1338168404Spjd} 1339168404Spjd 1340168404Spjdstatic char * 1341168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1342168404Spjd{ 1343168404Spjd nvlist_t *nv; 1344168404Spjd char *value; 1345168404Spjd 1346168404Spjd *source = NULL; 1347168404Spjd if (nvlist_lookup_nvlist(zhp->zfs_props, 1348168404Spjd zfs_prop_to_name(prop), &nv) == 0) { 1349168404Spjd verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 1350168404Spjd (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 1351168404Spjd } else { 1352168404Spjd if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1353168404Spjd value = ""; 1354168404Spjd *source = ""; 1355168404Spjd } 1356168404Spjd 1357168404Spjd return (value); 1358168404Spjd} 1359168404Spjd 1360168404Spjd/* 1361168404Spjd * Internal function for getting a numeric property. Both zfs_prop_get() and 1362168404Spjd * zfs_prop_get_int() are built using this interface. 1363168404Spjd * 1364168404Spjd * Certain properties can be overridden using 'mount -o'. In this case, scan 1365168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options. 1366168404Spjd * If they differ from the on-disk values, report the current values and mark 1367168404Spjd * the source "temporary". 1368168404Spjd */ 1369168404Spjdstatic int 1370168404Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 1371168404Spjd char **source, uint64_t *val) 1372168404Spjd{ 1373168404Spjd struct mnttab mnt; 1374168404Spjd char *mntopt_on = NULL; 1375168404Spjd char *mntopt_off = NULL; 1376168404Spjd 1377168404Spjd *source = NULL; 1378168404Spjd 1379168404Spjd switch (prop) { 1380168404Spjd case ZFS_PROP_ATIME: 1381168404Spjd mntopt_on = MNTOPT_ATIME; 1382168404Spjd mntopt_off = MNTOPT_NOATIME; 1383168404Spjd break; 1384168404Spjd 1385168404Spjd case ZFS_PROP_DEVICES: 1386168404Spjd mntopt_on = MNTOPT_DEVICES; 1387168404Spjd mntopt_off = MNTOPT_NODEVICES; 1388168404Spjd break; 1389168404Spjd 1390168404Spjd case ZFS_PROP_EXEC: 1391168404Spjd mntopt_on = MNTOPT_EXEC; 1392168404Spjd mntopt_off = MNTOPT_NOEXEC; 1393168404Spjd break; 1394168404Spjd 1395168404Spjd case ZFS_PROP_READONLY: 1396168404Spjd mntopt_on = MNTOPT_RO; 1397168404Spjd mntopt_off = MNTOPT_RW; 1398168404Spjd break; 1399168404Spjd 1400168404Spjd case ZFS_PROP_SETUID: 1401168404Spjd mntopt_on = MNTOPT_SETUID; 1402168404Spjd mntopt_off = MNTOPT_NOSETUID; 1403168404Spjd break; 1404168404Spjd 1405168404Spjd case ZFS_PROP_XATTR: 1406168404Spjd mntopt_on = MNTOPT_XATTR; 1407168404Spjd mntopt_off = MNTOPT_NOXATTR; 1408168404Spjd break; 1409168404Spjd } 1410168404Spjd 1411168404Spjd /* 1412168404Spjd * Because looking up the mount options is potentially expensive 1413168404Spjd * (iterating over all of /etc/mnttab), we defer its calculation until 1414168404Spjd * we're looking up a property which requires its presence. 1415168404Spjd */ 1416168404Spjd if (!zhp->zfs_mntcheck && 1417168404Spjd (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 1418168404Spjd struct mnttab entry, search = { 0 }; 1419168404Spjd FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 1420168404Spjd 1421168404Spjd search.mnt_special = (char *)zhp->zfs_name; 1422168404Spjd search.mnt_fstype = MNTTYPE_ZFS; 1423168404Spjd rewind(mnttab); 1424168404Spjd 1425168404Spjd if (getmntany(mnttab, &entry, &search) == 0) { 1426168404Spjd zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 1427168404Spjd entry.mnt_mntopts); 1428168404Spjd if (zhp->zfs_mntopts == NULL) 1429168404Spjd return (-1); 1430168404Spjd } 1431168404Spjd 1432168404Spjd zhp->zfs_mntcheck = B_TRUE; 1433168404Spjd } 1434168404Spjd 1435168404Spjd if (zhp->zfs_mntopts == NULL) 1436168404Spjd mnt.mnt_mntopts = ""; 1437168404Spjd else 1438168404Spjd mnt.mnt_mntopts = zhp->zfs_mntopts; 1439168404Spjd 1440168404Spjd switch (prop) { 1441168404Spjd case ZFS_PROP_ATIME: 1442168404Spjd case ZFS_PROP_DEVICES: 1443168404Spjd case ZFS_PROP_EXEC: 1444168404Spjd case ZFS_PROP_READONLY: 1445168404Spjd case ZFS_PROP_SETUID: 1446168404Spjd case ZFS_PROP_XATTR: 1447168404Spjd *val = getprop_uint64(zhp, prop, source); 1448168404Spjd 1449168404Spjd if (hasmntopt(&mnt, mntopt_on) && !*val) { 1450168404Spjd *val = B_TRUE; 1451168404Spjd if (src) 1452168404Spjd *src = ZFS_SRC_TEMPORARY; 1453168404Spjd } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1454168404Spjd *val = B_FALSE; 1455168404Spjd if (src) 1456168404Spjd *src = ZFS_SRC_TEMPORARY; 1457168404Spjd } 1458168404Spjd break; 1459168404Spjd 1460168404Spjd case ZFS_PROP_RECORDSIZE: 1461168404Spjd case ZFS_PROP_COMPRESSION: 1462168404Spjd case ZFS_PROP_ZONED: 1463168404Spjd case ZFS_PROP_CREATION: 1464168404Spjd case ZFS_PROP_COMPRESSRATIO: 1465168404Spjd case ZFS_PROP_REFERENCED: 1466168404Spjd case ZFS_PROP_USED: 1467168404Spjd case ZFS_PROP_CREATETXG: 1468168404Spjd case ZFS_PROP_AVAILABLE: 1469168404Spjd case ZFS_PROP_VOLSIZE: 1470168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 1471168404Spjd *val = getprop_uint64(zhp, prop, source); 1472168404Spjd break; 1473168404Spjd 1474168404Spjd case ZFS_PROP_CANMOUNT: 1475168404Spjd *val = getprop_uint64(zhp, prop, source); 1476168404Spjd if (*val == 0) 1477168404Spjd *source = zhp->zfs_name; 1478168404Spjd else 1479168404Spjd *source = ""; /* default */ 1480168404Spjd break; 1481168404Spjd 1482168404Spjd case ZFS_PROP_QUOTA: 1483168404Spjd case ZFS_PROP_RESERVATION: 1484168404Spjd *val = getprop_uint64(zhp, prop, source); 1485168404Spjd if (*val == 0) 1486168404Spjd *source = ""; /* default */ 1487168404Spjd else 1488168404Spjd *source = zhp->zfs_name; 1489168404Spjd break; 1490168404Spjd 1491168404Spjd case ZFS_PROP_MOUNTED: 1492168404Spjd *val = (zhp->zfs_mntopts != NULL); 1493168404Spjd break; 1494168404Spjd 1495168404Spjd case ZFS_PROP_NUMCLONES: 1496168404Spjd *val = zhp->zfs_dmustats.dds_num_clones; 1497168404Spjd break; 1498168404Spjd 1499168404Spjd default: 1500168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1501168404Spjd "cannot get non-numeric property")); 1502168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1503168404Spjd dgettext(TEXT_DOMAIN, "internal error"))); 1504168404Spjd } 1505168404Spjd 1506168404Spjd return (0); 1507168404Spjd} 1508168404Spjd 1509168404Spjd/* 1510168404Spjd * Calculate the source type, given the raw source string. 1511168404Spjd */ 1512168404Spjdstatic void 1513168404Spjdget_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1514168404Spjd char *statbuf, size_t statlen) 1515168404Spjd{ 1516168404Spjd if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1517168404Spjd return; 1518168404Spjd 1519168404Spjd if (source == NULL) { 1520168404Spjd *srctype = ZFS_SRC_NONE; 1521168404Spjd } else if (source[0] == '\0') { 1522168404Spjd *srctype = ZFS_SRC_DEFAULT; 1523168404Spjd } else { 1524168404Spjd if (strcmp(source, zhp->zfs_name) == 0) { 1525168404Spjd *srctype = ZFS_SRC_LOCAL; 1526168404Spjd } else { 1527168404Spjd (void) strlcpy(statbuf, source, statlen); 1528168404Spjd *srctype = ZFS_SRC_INHERITED; 1529168404Spjd } 1530168404Spjd } 1531168404Spjd 1532168404Spjd} 1533168404Spjd 1534168404Spjd/* 1535168404Spjd * Retrieve a property from the given object. If 'literal' is specified, then 1536168404Spjd * numbers are left as exact values. Otherwise, numbers are converted to a 1537168404Spjd * human-readable form. 1538168404Spjd * 1539168404Spjd * Returns 0 on success, or -1 on error. 1540168404Spjd */ 1541168404Spjdint 1542168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1543168404Spjd zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1544168404Spjd{ 1545168404Spjd char *source = NULL; 1546168404Spjd uint64_t val; 1547168404Spjd char *str; 1548168404Spjd const char *root; 1549168404Spjd const char *strval; 1550168404Spjd 1551168404Spjd /* 1552168404Spjd * Check to see if this property applies to our object 1553168404Spjd */ 1554168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1555168404Spjd return (-1); 1556168404Spjd 1557168404Spjd if (src) 1558168404Spjd *src = ZFS_SRC_NONE; 1559168404Spjd 1560168404Spjd switch (prop) { 1561168404Spjd case ZFS_PROP_ATIME: 1562168404Spjd case ZFS_PROP_READONLY: 1563168404Spjd case ZFS_PROP_SETUID: 1564168404Spjd case ZFS_PROP_ZONED: 1565168404Spjd case ZFS_PROP_DEVICES: 1566168404Spjd case ZFS_PROP_EXEC: 1567168404Spjd case ZFS_PROP_CANMOUNT: 1568168404Spjd case ZFS_PROP_XATTR: 1569168404Spjd /* 1570168404Spjd * Basic boolean values are built on top of 1571168404Spjd * get_numeric_property(). 1572168404Spjd */ 1573168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1574168404Spjd return (-1); 1575168404Spjd nicebool(val, propbuf, proplen); 1576168404Spjd 1577168404Spjd break; 1578168404Spjd 1579168404Spjd case ZFS_PROP_AVAILABLE: 1580168404Spjd case ZFS_PROP_RECORDSIZE: 1581168404Spjd case ZFS_PROP_CREATETXG: 1582168404Spjd case ZFS_PROP_REFERENCED: 1583168404Spjd case ZFS_PROP_USED: 1584168404Spjd case ZFS_PROP_VOLSIZE: 1585168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 1586168404Spjd case ZFS_PROP_NUMCLONES: 1587168404Spjd /* 1588168404Spjd * Basic numeric values are built on top of 1589168404Spjd * get_numeric_property(). 1590168404Spjd */ 1591168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1592168404Spjd return (-1); 1593168404Spjd if (literal) 1594168404Spjd (void) snprintf(propbuf, proplen, "%llu", 1595168404Spjd (u_longlong_t)val); 1596168404Spjd else 1597168404Spjd zfs_nicenum(val, propbuf, proplen); 1598168404Spjd break; 1599168404Spjd 1600168404Spjd case ZFS_PROP_COMPRESSION: 1601168404Spjd case ZFS_PROP_CHECKSUM: 1602168404Spjd case ZFS_PROP_SNAPDIR: 1603168404Spjd#ifdef ZFS_NO_ACL 1604168404Spjd case ZFS_PROP_ACLMODE: 1605168404Spjd case ZFS_PROP_ACLINHERIT: 1606168404Spjd case ZFS_PROP_COPIES: 1607168404Spjd val = getprop_uint64(zhp, prop, &source); 1608168404Spjd verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 1609168404Spjd (void) strlcpy(propbuf, strval, proplen); 1610168404Spjd break; 1611168404Spjd#else /* ZFS_NO_ACL */ 1612168404Spjd case ZFS_PROP_ACLMODE: 1613168404Spjd case ZFS_PROP_ACLINHERIT: 1614168404Spjd (void) strlcpy(propbuf, "<unsupported>", proplen); 1615168404Spjd break; 1616168404Spjd#endif /* ZFS_NO_ACL */ 1617168404Spjd 1618168404Spjd case ZFS_PROP_CREATION: 1619168404Spjd /* 1620168404Spjd * 'creation' is a time_t stored in the statistics. We convert 1621168404Spjd * this into a string unless 'literal' is specified. 1622168404Spjd */ 1623168404Spjd { 1624168404Spjd val = getprop_uint64(zhp, prop, &source); 1625168404Spjd time_t time = (time_t)val; 1626168404Spjd struct tm t; 1627168404Spjd 1628168404Spjd if (literal || 1629168404Spjd localtime_r(&time, &t) == NULL || 1630168404Spjd strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1631168404Spjd &t) == 0) 1632168404Spjd (void) snprintf(propbuf, proplen, "%llu", val); 1633168404Spjd } 1634168404Spjd break; 1635168404Spjd 1636168404Spjd case ZFS_PROP_MOUNTPOINT: 1637168404Spjd /* 1638168404Spjd * Getting the precise mountpoint can be tricky. 1639168404Spjd * 1640168404Spjd * - for 'none' or 'legacy', return those values. 1641168404Spjd * - for default mountpoints, construct it as /zfs/<dataset> 1642168404Spjd * - for inherited mountpoints, we want to take everything 1643168404Spjd * after our ancestor and append it to the inherited value. 1644168404Spjd * 1645168404Spjd * If the pool has an alternate root, we want to prepend that 1646168404Spjd * root to any values we return. 1647168404Spjd */ 1648168404Spjd root = zhp->zfs_root; 1649168404Spjd str = getprop_string(zhp, prop, &source); 1650168404Spjd 1651168404Spjd if (str[0] == '\0') { 1652168404Spjd (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1653168404Spjd root, zhp->zfs_name); 1654168404Spjd } else if (str[0] == '/') { 1655168404Spjd const char *relpath = zhp->zfs_name + strlen(source); 1656168404Spjd 1657168404Spjd if (relpath[0] == '/') 1658168404Spjd relpath++; 1659168404Spjd if (str[1] == '\0') 1660168404Spjd str++; 1661168404Spjd 1662168404Spjd if (relpath[0] == '\0') 1663168404Spjd (void) snprintf(propbuf, proplen, "%s%s", 1664168404Spjd root, str); 1665168404Spjd else 1666168404Spjd (void) snprintf(propbuf, proplen, "%s%s%s%s", 1667168404Spjd root, str, relpath[0] == '@' ? "" : "/", 1668168404Spjd relpath); 1669168404Spjd } else { 1670168404Spjd /* 'legacy' or 'none' */ 1671168404Spjd (void) strlcpy(propbuf, str, proplen); 1672168404Spjd } 1673168404Spjd 1674168404Spjd break; 1675168404Spjd 1676168404Spjd case ZFS_PROP_SHARENFS: 1677168404Spjd case ZFS_PROP_SHAREISCSI: 1678168404Spjd case ZFS_PROP_ISCSIOPTIONS: 1679168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1680168404Spjd proplen); 1681168404Spjd break; 1682168404Spjd 1683168404Spjd case ZFS_PROP_ORIGIN: 1684168404Spjd (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1685168404Spjd proplen); 1686168404Spjd /* 1687168404Spjd * If there is no parent at all, return failure to indicate that 1688168404Spjd * it doesn't apply to this dataset. 1689168404Spjd */ 1690168404Spjd if (propbuf[0] == '\0') 1691168404Spjd return (-1); 1692168404Spjd break; 1693168404Spjd 1694168404Spjd case ZFS_PROP_QUOTA: 1695168404Spjd case ZFS_PROP_RESERVATION: 1696168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1697168404Spjd return (-1); 1698168404Spjd 1699168404Spjd /* 1700168404Spjd * If quota or reservation is 0, we translate this into 'none' 1701168404Spjd * (unless literal is set), and indicate that it's the default 1702168404Spjd * value. Otherwise, we print the number nicely and indicate 1703168404Spjd * that its set locally. 1704168404Spjd */ 1705168404Spjd if (val == 0) { 1706168404Spjd if (literal) 1707168404Spjd (void) strlcpy(propbuf, "0", proplen); 1708168404Spjd else 1709168404Spjd (void) strlcpy(propbuf, "none", proplen); 1710168404Spjd } else { 1711168404Spjd if (literal) 1712168404Spjd (void) snprintf(propbuf, proplen, "%llu", 1713168404Spjd (u_longlong_t)val); 1714168404Spjd else 1715168404Spjd zfs_nicenum(val, propbuf, proplen); 1716168404Spjd } 1717168404Spjd break; 1718168404Spjd 1719168404Spjd case ZFS_PROP_COMPRESSRATIO: 1720168404Spjd if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1721168404Spjd return (-1); 1722168404Spjd (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 1723168404Spjd val / 100, (longlong_t)val % 100); 1724168404Spjd break; 1725168404Spjd 1726168404Spjd case ZFS_PROP_TYPE: 1727168404Spjd switch (zhp->zfs_type) { 1728168404Spjd case ZFS_TYPE_FILESYSTEM: 1729168404Spjd str = "filesystem"; 1730168404Spjd break; 1731168404Spjd case ZFS_TYPE_VOLUME: 1732168404Spjd str = "volume"; 1733168404Spjd break; 1734168404Spjd case ZFS_TYPE_SNAPSHOT: 1735168404Spjd str = "snapshot"; 1736168404Spjd break; 1737168404Spjd default: 1738168404Spjd abort(); 1739168404Spjd } 1740168404Spjd (void) snprintf(propbuf, proplen, "%s", str); 1741168404Spjd break; 1742168404Spjd 1743168404Spjd case ZFS_PROP_MOUNTED: 1744168404Spjd /* 1745168404Spjd * The 'mounted' property is a pseudo-property that described 1746168404Spjd * whether the filesystem is currently mounted. Even though 1747168404Spjd * it's a boolean value, the typical values of "on" and "off" 1748168404Spjd * don't make sense, so we translate to "yes" and "no". 1749168404Spjd */ 1750168404Spjd if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 1751168404Spjd src, &source, &val) != 0) 1752168404Spjd return (-1); 1753168404Spjd if (val) 1754168404Spjd (void) strlcpy(propbuf, "yes", proplen); 1755168404Spjd else 1756168404Spjd (void) strlcpy(propbuf, "no", proplen); 1757168404Spjd break; 1758168404Spjd 1759168404Spjd case ZFS_PROP_NAME: 1760168404Spjd /* 1761168404Spjd * The 'name' property is a pseudo-property derived from the 1762168404Spjd * dataset name. It is presented as a real property to simplify 1763168404Spjd * consumers. 1764168404Spjd */ 1765168404Spjd (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1766168404Spjd break; 1767168404Spjd 1768168404Spjd default: 1769168404Spjd abort(); 1770168404Spjd } 1771168404Spjd 1772168404Spjd get_source(zhp, src, source, statbuf, statlen); 1773168404Spjd 1774168404Spjd return (0); 1775168404Spjd} 1776168404Spjd 1777168404Spjd/* 1778168404Spjd * Utility function to get the given numeric property. Does no validation that 1779168404Spjd * the given property is the appropriate type; should only be used with 1780168404Spjd * hard-coded property types. 1781168404Spjd */ 1782168404Spjduint64_t 1783168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1784168404Spjd{ 1785168404Spjd char *source; 1786168404Spjd zfs_source_t sourcetype = ZFS_SRC_NONE; 1787168404Spjd uint64_t val; 1788168404Spjd 1789168404Spjd (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 1790168404Spjd 1791168404Spjd return (val); 1792168404Spjd} 1793168404Spjd 1794168404Spjd/* 1795168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer. 1796168404Spjd */ 1797168404Spjdint 1798168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1799168404Spjd zfs_source_t *src, char *statbuf, size_t statlen) 1800168404Spjd{ 1801168404Spjd char *source; 1802168404Spjd 1803168404Spjd /* 1804168404Spjd * Check to see if this property applies to our object 1805168404Spjd */ 1806168404Spjd if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1807168404Spjd return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 1808168404Spjd dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 1809168404Spjd zfs_prop_to_name(prop))); 1810168404Spjd 1811168404Spjd if (src) 1812168404Spjd *src = ZFS_SRC_NONE; 1813168404Spjd 1814168404Spjd if (get_numeric_property(zhp, prop, src, &source, value) != 0) 1815168404Spjd return (-1); 1816168404Spjd 1817168404Spjd get_source(zhp, src, source, statbuf, statlen); 1818168404Spjd 1819168404Spjd return (0); 1820168404Spjd} 1821168404Spjd 1822168404Spjd/* 1823168404Spjd * Returns the name of the given zfs handle. 1824168404Spjd */ 1825168404Spjdconst char * 1826168404Spjdzfs_get_name(const zfs_handle_t *zhp) 1827168404Spjd{ 1828168404Spjd return (zhp->zfs_name); 1829168404Spjd} 1830168404Spjd 1831168404Spjd/* 1832168404Spjd * Returns the type of the given zfs handle. 1833168404Spjd */ 1834168404Spjdzfs_type_t 1835168404Spjdzfs_get_type(const zfs_handle_t *zhp) 1836168404Spjd{ 1837168404Spjd return (zhp->zfs_type); 1838168404Spjd} 1839168404Spjd 1840168404Spjd/* 1841168404Spjd * Iterate over all child filesystems 1842168404Spjd */ 1843168404Spjdint 1844168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1845168404Spjd{ 1846168404Spjd zfs_cmd_t zc = { 0 }; 1847168404Spjd zfs_handle_t *nzhp; 1848168404Spjd int ret; 1849168404Spjd 1850168404Spjd for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1851168404Spjd ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1852168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1853168404Spjd /* 1854168404Spjd * Ignore private dataset names. 1855168404Spjd */ 1856168404Spjd if (dataset_name_hidden(zc.zc_name)) 1857168404Spjd continue; 1858168404Spjd 1859168404Spjd /* 1860168404Spjd * Silently ignore errors, as the only plausible explanation is 1861168404Spjd * that the pool has since been removed. 1862168404Spjd */ 1863168404Spjd if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 1864168404Spjd zc.zc_name)) == NULL) 1865168404Spjd continue; 1866168404Spjd 1867168404Spjd if ((ret = func(nzhp, data)) != 0) 1868168404Spjd return (ret); 1869168404Spjd } 1870168404Spjd 1871168404Spjd /* 1872168404Spjd * An errno value of ESRCH indicates normal completion. If ENOENT is 1873168404Spjd * returned, then the underlying dataset has been removed since we 1874168404Spjd * obtained the handle. 1875168404Spjd */ 1876168404Spjd if (errno != ESRCH && errno != ENOENT) 1877168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 1878168404Spjd dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1879168404Spjd 1880168404Spjd return (0); 1881168404Spjd} 1882168404Spjd 1883168404Spjd/* 1884168404Spjd * Iterate over all snapshots 1885168404Spjd */ 1886168404Spjdint 1887168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1888168404Spjd{ 1889168404Spjd zfs_cmd_t zc = { 0 }; 1890168404Spjd zfs_handle_t *nzhp; 1891168404Spjd int ret; 1892168404Spjd 1893168404Spjd for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1894168404Spjd ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 1895168404Spjd &zc) == 0; 1896168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1897168404Spjd 1898168404Spjd if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 1899168404Spjd zc.zc_name)) == NULL) 1900168404Spjd continue; 1901168404Spjd 1902168404Spjd if ((ret = func(nzhp, data)) != 0) 1903168404Spjd return (ret); 1904168404Spjd } 1905168404Spjd 1906168404Spjd /* 1907168404Spjd * An errno value of ESRCH indicates normal completion. If ENOENT is 1908168404Spjd * returned, then the underlying dataset has been removed since we 1909168404Spjd * obtained the handle. Silently ignore this case, and return success. 1910168404Spjd */ 1911168404Spjd if (errno != ESRCH && errno != ENOENT) 1912168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 1913168404Spjd dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1914168404Spjd 1915168404Spjd return (0); 1916168404Spjd} 1917168404Spjd 1918168404Spjd/* 1919168404Spjd * Iterate over all children, snapshots and filesystems 1920168404Spjd */ 1921168404Spjdint 1922168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1923168404Spjd{ 1924168404Spjd int ret; 1925168404Spjd 1926168404Spjd if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 1927168404Spjd return (ret); 1928168404Spjd 1929168404Spjd return (zfs_iter_snapshots(zhp, func, data)); 1930168404Spjd} 1931168404Spjd 1932168404Spjd/* 1933168404Spjd * Given a complete name, return just the portion that refers to the parent. 1934168404Spjd * Can return NULL if this is a pool. 1935168404Spjd */ 1936168404Spjdstatic int 1937168404Spjdparent_name(const char *path, char *buf, size_t buflen) 1938168404Spjd{ 1939168404Spjd char *loc; 1940168404Spjd 1941168404Spjd if ((loc = strrchr(path, '/')) == NULL) 1942168404Spjd return (-1); 1943168404Spjd 1944168404Spjd (void) strncpy(buf, path, MIN(buflen, loc - path)); 1945168404Spjd buf[loc - path] = '\0'; 1946168404Spjd 1947168404Spjd return (0); 1948168404Spjd} 1949168404Spjd 1950168404Spjd/* 1951168404Spjd * Checks to make sure that the given path has a parent, and that it exists. We 1952168404Spjd * also fetch the 'zoned' property, which is used to validate property settings 1953168404Spjd * when creating new datasets. 1954168404Spjd */ 1955168404Spjdstatic int 1956168404Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1957168404Spjd{ 1958168404Spjd zfs_cmd_t zc = { 0 }; 1959168404Spjd char parent[ZFS_MAXNAMELEN]; 1960168404Spjd char *slash; 1961168404Spjd zfs_handle_t *zhp; 1962168404Spjd char errbuf[1024]; 1963168404Spjd 1964168404Spjd (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 1965168404Spjd path); 1966168404Spjd 1967168404Spjd /* get parent, and check to see if this is just a pool */ 1968168404Spjd if (parent_name(path, parent, sizeof (parent)) != 0) { 1969168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1970168404Spjd "missing dataset name")); 1971168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1972168404Spjd } 1973168404Spjd 1974168404Spjd /* check to see if the pool exists */ 1975168404Spjd if ((slash = strchr(parent, '/')) == NULL) 1976168404Spjd slash = parent + strlen(parent); 1977168404Spjd (void) strncpy(zc.zc_name, parent, slash - parent); 1978168404Spjd zc.zc_name[slash - parent] = '\0'; 1979168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1980168404Spjd errno == ENOENT) { 1981168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1982168404Spjd "no such pool '%s'"), zc.zc_name); 1983168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1984168404Spjd } 1985168404Spjd 1986168404Spjd /* check to see if the parent dataset exists */ 1987168404Spjd if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1988168404Spjd switch (errno) { 1989168404Spjd case ENOENT: 1990168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1991168404Spjd "parent does not exist")); 1992168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1993168404Spjd 1994168404Spjd default: 1995168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 1996168404Spjd } 1997168404Spjd } 1998168404Spjd 1999168404Spjd *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2000168404Spjd /* we are in a non-global zone, but parent is in the global zone */ 2001168404Spjd if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 2002168404Spjd (void) zfs_standard_error(hdl, EPERM, errbuf); 2003168404Spjd zfs_close(zhp); 2004168404Spjd return (-1); 2005168404Spjd } 2006168404Spjd 2007168404Spjd /* make sure parent is a filesystem */ 2008168404Spjd if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2009168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2010168404Spjd "parent is not a filesystem")); 2011168404Spjd (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2012168404Spjd zfs_close(zhp); 2013168404Spjd return (-1); 2014168404Spjd } 2015168404Spjd 2016168404Spjd zfs_close(zhp); 2017168404Spjd return (0); 2018168404Spjd} 2019168404Spjd 2020168404Spjd/* 2021168404Spjd * Create a new filesystem or volume. 2022168404Spjd */ 2023168404Spjdint 2024168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2025168404Spjd nvlist_t *props) 2026168404Spjd{ 2027168404Spjd zfs_cmd_t zc = { 0 }; 2028168404Spjd int ret; 2029168404Spjd uint64_t size = 0; 2030168404Spjd uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2031168404Spjd char errbuf[1024]; 2032168404Spjd uint64_t zoned; 2033168404Spjd 2034168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2035168404Spjd "cannot create '%s'"), path); 2036168404Spjd 2037168404Spjd /* validate the path, taking care to note the extended error message */ 2038168404Spjd if (!zfs_validate_name(hdl, path, type)) 2039168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2040168404Spjd 2041168404Spjd /* validate parents exist */ 2042168404Spjd if (check_parents(hdl, path, &zoned) != 0) 2043168404Spjd return (-1); 2044168404Spjd 2045168404Spjd /* 2046168404Spjd * The failure modes when creating a dataset of a different type over 2047168404Spjd * one that already exists is a little strange. In particular, if you 2048168404Spjd * try to create a dataset on top of an existing dataset, the ioctl() 2049168404Spjd * will return ENOENT, not EEXIST. To prevent this from happening, we 2050168404Spjd * first try to see if the dataset exists. 2051168404Spjd */ 2052168404Spjd (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2053168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2054168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2055168404Spjd "dataset already exists")); 2056168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2057168404Spjd } 2058168404Spjd 2059168404Spjd if (type == ZFS_TYPE_VOLUME) 2060168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2061168404Spjd else 2062168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2063168404Spjd 2064168404Spjd if (props && (props = zfs_validate_properties(hdl, type, NULL, props, 2065168404Spjd zoned, NULL, errbuf)) == 0) 2066168404Spjd return (-1); 2067168404Spjd 2068168404Spjd if (type == ZFS_TYPE_VOLUME) { 2069168404Spjd /* 2070168404Spjd * If we are creating a volume, the size and block size must 2071168404Spjd * satisfy a few restraints. First, the blocksize must be a 2072168404Spjd * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 2073168404Spjd * volsize must be a multiple of the block size, and cannot be 2074168404Spjd * zero. 2075168404Spjd */ 2076168404Spjd if (props == NULL || nvlist_lookup_uint64(props, 2077168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2078168404Spjd nvlist_free(props); 2079168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2080168404Spjd "missing volume size")); 2081168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2082168404Spjd } 2083168404Spjd 2084168404Spjd if ((ret = nvlist_lookup_uint64(props, 2085168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2086168404Spjd &blocksize)) != 0) { 2087168404Spjd if (ret == ENOENT) { 2088168404Spjd blocksize = zfs_prop_default_numeric( 2089168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2090168404Spjd } else { 2091168404Spjd nvlist_free(props); 2092168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2093168404Spjd "missing volume block size")); 2094168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2095168404Spjd } 2096168404Spjd } 2097168404Spjd 2098168404Spjd if (size == 0) { 2099168404Spjd nvlist_free(props); 2100168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2101168404Spjd "volume size cannot be zero")); 2102168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2103168404Spjd } 2104168404Spjd 2105168404Spjd if (size % blocksize != 0) { 2106168404Spjd nvlist_free(props); 2107168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2108168404Spjd "volume size must be a multiple of volume block " 2109168404Spjd "size")); 2110168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2111168404Spjd } 2112168404Spjd } 2113168404Spjd 2114168404Spjd if (props && 2115168404Spjd zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 2116168404Spjd return (-1); 2117168404Spjd nvlist_free(props); 2118168404Spjd 2119168404Spjd /* create the dataset */ 2120168404Spjd ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2121168404Spjd 2122168404Spjd if (ret == 0 && type == ZFS_TYPE_VOLUME) { 2123168404Spjd ret = zvol_create_link(hdl, path); 2124168404Spjd if (ret) { 2125168404Spjd (void) zfs_standard_error(hdl, errno, 2126168404Spjd dgettext(TEXT_DOMAIN, 2127168404Spjd "Volume successfully created, but device links " 2128168404Spjd "were not created")); 2129168404Spjd zcmd_free_nvlists(&zc); 2130168404Spjd return (-1); 2131168404Spjd } 2132168404Spjd } 2133168404Spjd 2134168404Spjd zcmd_free_nvlists(&zc); 2135168404Spjd 2136168404Spjd /* check for failure */ 2137168404Spjd if (ret != 0) { 2138168404Spjd char parent[ZFS_MAXNAMELEN]; 2139168404Spjd (void) parent_name(path, parent, sizeof (parent)); 2140168404Spjd 2141168404Spjd switch (errno) { 2142168404Spjd case ENOENT: 2143168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2144168404Spjd "no such parent '%s'"), parent); 2145168404Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2146168404Spjd 2147168404Spjd case EINVAL: 2148168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2149168404Spjd "parent '%s' is not a filesystem"), parent); 2150168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2151168404Spjd 2152168404Spjd case EDOM: 2153168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2154168404Spjd "volume block size must be power of 2 from " 2155168404Spjd "%u to %uk"), 2156168404Spjd (uint_t)SPA_MINBLOCKSIZE, 2157168404Spjd (uint_t)SPA_MAXBLOCKSIZE >> 10); 2158168404Spjd 2159168404Spjd return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2160168404Spjd 2161168404Spjd#ifdef _ILP32 2162168404Spjd case EOVERFLOW: 2163168404Spjd /* 2164168404Spjd * This platform can't address a volume this big. 2165168404Spjd */ 2166168404Spjd if (type == ZFS_TYPE_VOLUME) 2167168404Spjd return (zfs_error(hdl, EZFS_VOLTOOBIG, 2168168404Spjd errbuf)); 2169168404Spjd#endif 2170168404Spjd /* FALLTHROUGH */ 2171168404Spjd default: 2172168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2173168404Spjd } 2174168404Spjd } 2175168404Spjd 2176168404Spjd return (0); 2177168404Spjd} 2178168404Spjd 2179168404Spjd/* 2180168404Spjd * Destroys the given dataset. The caller must make sure that the filesystem 2181168404Spjd * isn't mounted, and that there are no active dependents. 2182168404Spjd */ 2183168404Spjdint 2184168404Spjdzfs_destroy(zfs_handle_t *zhp) 2185168404Spjd{ 2186168404Spjd zfs_cmd_t zc = { 0 }; 2187168404Spjd 2188168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2189168404Spjd 2190168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2191168404Spjd /* 2192168404Spjd * Unconditionally unshare this zvol ignoring failure as it 2193168404Spjd * indicates only that the volume wasn't shared initially. 2194168404Spjd */ 2195168404Spjd (void) zfs_unshare_iscsi(zhp); 2196168404Spjd 2197168404Spjd if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2198168404Spjd return (-1); 2199168404Spjd 2200168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2201168404Spjd } else { 2202168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2203168404Spjd } 2204168404Spjd 2205168404Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 2206168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 2207168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 2208168404Spjd zhp->zfs_name)); 2209168404Spjd } 2210168404Spjd 2211168404Spjd remove_mountpoint(zhp); 2212168404Spjd 2213168404Spjd return (0); 2214168404Spjd} 2215168404Spjd 2216168404Spjdstruct destroydata { 2217168404Spjd char *snapname; 2218168404Spjd boolean_t gotone; 2219168404Spjd boolean_t closezhp; 2220168404Spjd}; 2221168404Spjd 2222168404Spjdstatic int 2223168404Spjdzfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 2224168404Spjd{ 2225168404Spjd struct destroydata *dd = arg; 2226168404Spjd zfs_handle_t *szhp; 2227168404Spjd char name[ZFS_MAXNAMELEN]; 2228168404Spjd boolean_t closezhp = dd->closezhp; 2229168404Spjd int rv; 2230168404Spjd 2231168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2232168404Spjd (void) strlcat(name, "@", sizeof (name)); 2233168404Spjd (void) strlcat(name, dd->snapname, sizeof (name)); 2234168404Spjd 2235168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, name); 2236168404Spjd if (szhp) { 2237168404Spjd dd->gotone = B_TRUE; 2238168404Spjd zfs_close(szhp); 2239168404Spjd } 2240168404Spjd 2241168404Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2242168404Spjd (void) zvol_remove_link(zhp->zfs_hdl, name); 2243168404Spjd /* 2244168404Spjd * NB: this is simply a best-effort. We don't want to 2245168404Spjd * return an error, because then we wouldn't visit all 2246168404Spjd * the volumes. 2247168404Spjd */ 2248168404Spjd } 2249168404Spjd 2250168404Spjd dd->closezhp = B_TRUE; 2251168404Spjd rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 2252168404Spjd if (closezhp) 2253168404Spjd zfs_close(zhp); 2254168404Spjd return (rv); 2255168404Spjd} 2256168404Spjd 2257168404Spjd/* 2258168404Spjd * Destroys all snapshots with the given name in zhp & descendants. 2259168404Spjd */ 2260168404Spjdint 2261168404Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 2262168404Spjd{ 2263168404Spjd zfs_cmd_t zc = { 0 }; 2264168404Spjd int ret; 2265168404Spjd struct destroydata dd = { 0 }; 2266168404Spjd 2267168404Spjd dd.snapname = snapname; 2268168404Spjd (void) zfs_remove_link_cb(zhp, &dd); 2269168404Spjd 2270168404Spjd if (!dd.gotone) { 2271168404Spjd return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 2272168404Spjd dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 2273168404Spjd zhp->zfs_name, snapname)); 2274168404Spjd } 2275168404Spjd 2276168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2277168404Spjd (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2278168404Spjd 2279168404Spjd ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 2280168404Spjd if (ret != 0) { 2281168404Spjd char errbuf[1024]; 2282168404Spjd 2283168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2284168404Spjd "cannot destroy '%s@%s'"), zc.zc_name, snapname); 2285168404Spjd 2286168404Spjd switch (errno) { 2287168404Spjd case EEXIST: 2288168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2289168404Spjd "snapshot is cloned")); 2290168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 2291168404Spjd 2292168404Spjd default: 2293168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 2294168404Spjd errbuf)); 2295168404Spjd } 2296168404Spjd } 2297168404Spjd 2298168404Spjd return (0); 2299168404Spjd} 2300168404Spjd 2301168404Spjd/* 2302168404Spjd * Clones the given dataset. The target must be of the same type as the source. 2303168404Spjd */ 2304168404Spjdint 2305168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2306168404Spjd{ 2307168404Spjd zfs_cmd_t zc = { 0 }; 2308168404Spjd char parent[ZFS_MAXNAMELEN]; 2309168404Spjd int ret; 2310168404Spjd char errbuf[1024]; 2311168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 2312168404Spjd zfs_type_t type; 2313168404Spjd uint64_t zoned; 2314168404Spjd 2315168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2316168404Spjd 2317168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2318168404Spjd "cannot create '%s'"), target); 2319168404Spjd 2320168404Spjd /* validate the target name */ 2321168404Spjd if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 2322168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2323168404Spjd 2324168404Spjd /* validate parents exist */ 2325168404Spjd if (check_parents(hdl, target, &zoned) != 0) 2326168404Spjd return (-1); 2327168404Spjd 2328168404Spjd (void) parent_name(target, parent, sizeof (parent)); 2329168404Spjd 2330168404Spjd /* do the clone */ 2331168404Spjd if (ZFS_IS_VOLUME(zhp)) { 2332168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 2333168404Spjd type = ZFS_TYPE_VOLUME; 2334168404Spjd } else { 2335168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 2336168404Spjd type = ZFS_TYPE_FILESYSTEM; 2337168404Spjd } 2338168404Spjd 2339168404Spjd if (props) { 2340168404Spjd if ((props = zfs_validate_properties(hdl, type, NULL, props, 2341168404Spjd zoned, zhp, errbuf)) == NULL) 2342168404Spjd return (-1); 2343168404Spjd 2344168404Spjd if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 2345168404Spjd nvlist_free(props); 2346168404Spjd return (-1); 2347168404Spjd } 2348168404Spjd 2349168404Spjd nvlist_free(props); 2350168404Spjd } 2351168404Spjd 2352168404Spjd (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2353168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 2354168404Spjd ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2355168404Spjd 2356168404Spjd zcmd_free_nvlists(&zc); 2357168404Spjd 2358168404Spjd if (ret != 0) { 2359168404Spjd switch (errno) { 2360168404Spjd 2361168404Spjd case ENOENT: 2362168404Spjd /* 2363168404Spjd * The parent doesn't exist. We should have caught this 2364168404Spjd * above, but there may a race condition that has since 2365168404Spjd * destroyed the parent. 2366168404Spjd * 2367168404Spjd * At this point, we don't know whether it's the source 2368168404Spjd * that doesn't exist anymore, or whether the target 2369168404Spjd * dataset doesn't exist. 2370168404Spjd */ 2371168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2372168404Spjd "no such parent '%s'"), parent); 2373168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 2374168404Spjd 2375168404Spjd case EXDEV: 2376168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2377168404Spjd "source and target pools differ")); 2378168404Spjd return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 2379168404Spjd errbuf)); 2380168404Spjd 2381168404Spjd default: 2382168404Spjd return (zfs_standard_error(zhp->zfs_hdl, errno, 2383168404Spjd errbuf)); 2384168404Spjd } 2385168404Spjd } else if (ZFS_IS_VOLUME(zhp)) { 2386168404Spjd ret = zvol_create_link(zhp->zfs_hdl, target); 2387168404Spjd } 2388168404Spjd 2389168404Spjd return (ret); 2390168404Spjd} 2391168404Spjd 2392168404Spjdtypedef struct promote_data { 2393168404Spjd char cb_mountpoint[MAXPATHLEN]; 2394168404Spjd const char *cb_target; 2395168404Spjd const char *cb_errbuf; 2396168404Spjd uint64_t cb_pivot_txg; 2397168404Spjd} promote_data_t; 2398168404Spjd 2399168404Spjdstatic int 2400168404Spjdpromote_snap_cb(zfs_handle_t *zhp, void *data) 2401168404Spjd{ 2402168404Spjd promote_data_t *pd = data; 2403168404Spjd zfs_handle_t *szhp; 2404168404Spjd char snapname[MAXPATHLEN]; 2405168404Spjd int rv = 0; 2406168404Spjd 2407168404Spjd /* We don't care about snapshots after the pivot point */ 2408168404Spjd if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 2409168404Spjd zfs_close(zhp); 2410168404Spjd return (0); 2411168404Spjd } 2412168404Spjd 2413168404Spjd /* Remove the device link if it's a zvol. */ 2414168404Spjd if (ZFS_IS_VOLUME(zhp)) 2415168404Spjd (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 2416168404Spjd 2417168404Spjd /* Check for conflicting names */ 2418168404Spjd (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 2419168404Spjd (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 2420168404Spjd szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 2421168404Spjd if (szhp != NULL) { 2422168404Spjd zfs_close(szhp); 2423168404Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2424168404Spjd "snapshot name '%s' from origin \n" 2425168404Spjd "conflicts with '%s' from target"), 2426168404Spjd zhp->zfs_name, snapname); 2427168404Spjd rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 2428168404Spjd } 2429168404Spjd zfs_close(zhp); 2430168404Spjd return (rv); 2431168404Spjd} 2432168404Spjd 2433168404Spjdstatic int 2434168404Spjdpromote_snap_done_cb(zfs_handle_t *zhp, void *data) 2435168404Spjd{ 2436168404Spjd promote_data_t *pd = data; 2437168404Spjd 2438168404Spjd /* We don't care about snapshots after the pivot point */ 2439168404Spjd if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 2440168404Spjd /* Create the device link if it's a zvol. */ 2441168404Spjd if (ZFS_IS_VOLUME(zhp)) 2442168404Spjd (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2443168404Spjd } 2444168404Spjd 2445168404Spjd zfs_close(zhp); 2446168404Spjd return (0); 2447168404Spjd} 2448168404Spjd 2449168404Spjd/* 2450168404Spjd * Promotes the given clone fs to be the clone parent. 2451168404Spjd */ 2452168404Spjdint 2453168404Spjdzfs_promote(zfs_handle_t *zhp) 2454168404Spjd{ 2455168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 2456168404Spjd zfs_cmd_t zc = { 0 }; 2457168404Spjd char parent[MAXPATHLEN]; 2458168404Spjd char *cp; 2459168404Spjd int ret; 2460168404Spjd zfs_handle_t *pzhp; 2461168404Spjd promote_data_t pd; 2462168404Spjd char errbuf[1024]; 2463168404Spjd 2464168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2465168404Spjd "cannot promote '%s'"), zhp->zfs_name); 2466168404Spjd 2467168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2468168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2469168404Spjd "snapshots can not be promoted")); 2470168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2471168404Spjd } 2472168404Spjd 2473168404Spjd (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 2474168404Spjd if (parent[0] == '\0') { 2475168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2476168404Spjd "not a cloned filesystem")); 2477168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2478168404Spjd } 2479168404Spjd cp = strchr(parent, '@'); 2480168404Spjd *cp = '\0'; 2481168404Spjd 2482168404Spjd /* Walk the snapshots we will be moving */ 2483168404Spjd pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 2484168404Spjd if (pzhp == NULL) 2485168404Spjd return (-1); 2486168404Spjd pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 2487168404Spjd zfs_close(pzhp); 2488168404Spjd pd.cb_target = zhp->zfs_name; 2489168404Spjd pd.cb_errbuf = errbuf; 2490168404Spjd pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 2491168404Spjd if (pzhp == NULL) 2492168404Spjd return (-1); 2493168404Spjd (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 2494168404Spjd sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 2495168404Spjd ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 2496168404Spjd if (ret != 0) { 2497168404Spjd zfs_close(pzhp); 2498168404Spjd return (-1); 2499168404Spjd } 2500168404Spjd 2501168404Spjd /* issue the ioctl */ 2502168404Spjd (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 2503168404Spjd sizeof (zc.zc_value)); 2504168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2505168404Spjd ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 2506168404Spjd 2507168404Spjd if (ret != 0) { 2508168404Spjd int save_errno = errno; 2509168404Spjd 2510168404Spjd (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 2511168404Spjd zfs_close(pzhp); 2512168404Spjd 2513168404Spjd switch (save_errno) { 2514168404Spjd case EEXIST: 2515168404Spjd /* 2516168404Spjd * There is a conflicting snapshot name. We 2517168404Spjd * should have caught this above, but they could 2518168404Spjd * have renamed something in the mean time. 2519168404Spjd */ 2520168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2521168404Spjd "conflicting snapshot name from parent '%s'"), 2522168404Spjd parent); 2523168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2524168404Spjd 2525168404Spjd default: 2526168404Spjd return (zfs_standard_error(hdl, save_errno, errbuf)); 2527168404Spjd } 2528168404Spjd } else { 2529168404Spjd (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2530168404Spjd } 2531168404Spjd 2532168404Spjd zfs_close(pzhp); 2533168404Spjd return (ret); 2534168404Spjd} 2535168404Spjd 2536168676Spjdstruct createdata { 2537168676Spjd const char *cd_snapname; 2538168676Spjd int cd_ifexists; 2539168676Spjd}; 2540168676Spjd 2541168404Spjdstatic int 2542168404Spjdzfs_create_link_cb(zfs_handle_t *zhp, void *arg) 2543168404Spjd{ 2544168676Spjd struct createdata *cd = arg; 2545168404Spjd int ret; 2546168404Spjd 2547168404Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2548168404Spjd char name[MAXPATHLEN]; 2549168404Spjd 2550168404Spjd (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2551168404Spjd (void) strlcat(name, "@", sizeof (name)); 2552168676Spjd (void) strlcat(name, cd->cd_snapname, sizeof (name)); 2553168676Spjd (void) zvol_create_link_common(zhp->zfs_hdl, name, 2554168676Spjd cd->cd_ifexists); 2555168404Spjd /* 2556168404Spjd * NB: this is simply a best-effort. We don't want to 2557168404Spjd * return an error, because then we wouldn't visit all 2558168404Spjd * the volumes. 2559168404Spjd */ 2560168404Spjd } 2561168404Spjd 2562168676Spjd ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd); 2563168404Spjd 2564168404Spjd zfs_close(zhp); 2565168404Spjd 2566168404Spjd return (ret); 2567168404Spjd} 2568168404Spjd 2569168404Spjd/* 2570168404Spjd * Takes a snapshot of the given dataset. 2571168404Spjd */ 2572168404Spjdint 2573168404Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2574168404Spjd{ 2575168404Spjd const char *delim; 2576168404Spjd char *parent; 2577168404Spjd zfs_handle_t *zhp; 2578168404Spjd zfs_cmd_t zc = { 0 }; 2579168404Spjd int ret; 2580168404Spjd char errbuf[1024]; 2581168404Spjd 2582168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2583168404Spjd "cannot snapshot '%s'"), path); 2584168404Spjd 2585168404Spjd /* validate the target name */ 2586168404Spjd if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 2587168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2588168404Spjd 2589168404Spjd /* make sure the parent exists and is of the appropriate type */ 2590168404Spjd delim = strchr(path, '@'); 2591168404Spjd if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 2592168404Spjd return (-1); 2593168404Spjd (void) strncpy(parent, path, delim - path); 2594168404Spjd parent[delim - path] = '\0'; 2595168404Spjd 2596168404Spjd if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2597168404Spjd ZFS_TYPE_VOLUME)) == NULL) { 2598168404Spjd free(parent); 2599168404Spjd return (-1); 2600168404Spjd } 2601168404Spjd 2602168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2603168404Spjd (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 2604168404Spjd zc.zc_cookie = recursive; 2605168404Spjd ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 2606168404Spjd 2607168404Spjd /* 2608168404Spjd * if it was recursive, the one that actually failed will be in 2609168404Spjd * zc.zc_name. 2610168404Spjd */ 2611168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2612168404Spjd "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 2613168404Spjd if (ret == 0 && recursive) { 2614168676Spjd struct createdata cd; 2615168676Spjd 2616168676Spjd cd.cd_snapname = delim + 1; 2617168676Spjd cd.cd_ifexists = B_FALSE; 2618168676Spjd (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 2619168404Spjd } 2620168404Spjd if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 2621168404Spjd ret = zvol_create_link(zhp->zfs_hdl, path); 2622168404Spjd if (ret != 0) { 2623168404Spjd (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 2624168404Spjd &zc); 2625168404Spjd } 2626168404Spjd } 2627168404Spjd 2628168404Spjd if (ret != 0) 2629168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 2630168404Spjd 2631168404Spjd free(parent); 2632168404Spjd zfs_close(zhp); 2633168404Spjd 2634168404Spjd return (ret); 2635168404Spjd} 2636168404Spjd 2637168404Spjd/* 2638168404Spjd * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 2639168404Spjd * NULL) to the file descriptor specified by outfd. 2640168404Spjd */ 2641168404Spjdint 2642168404Spjdzfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2643168404Spjd{ 2644168404Spjd zfs_cmd_t zc = { 0 }; 2645168404Spjd char errbuf[1024]; 2646168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 2647168404Spjd 2648168404Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2649168404Spjd 2650168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2651168404Spjd if (fromsnap) 2652168404Spjd (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 2653168404Spjd zc.zc_cookie = outfd; 2654168404Spjd 2655168404Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 2656168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2657168404Spjd "cannot send '%s'"), zhp->zfs_name); 2658168404Spjd 2659168404Spjd switch (errno) { 2660168404Spjd 2661168404Spjd case EXDEV: 2662168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2663168404Spjd "not an earlier snapshot from the same fs")); 2664168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2665168404Spjd 2666168404Spjd case EDQUOT: 2667168404Spjd case EFBIG: 2668168404Spjd case EIO: 2669168404Spjd case ENOLINK: 2670168404Spjd case ENOSPC: 2671168404Spjd case ENXIO: 2672168404Spjd case EPIPE: 2673168404Spjd case ERANGE: 2674168404Spjd case EFAULT: 2675168404Spjd case EROFS: 2676168404Spjd zfs_error_aux(hdl, strerror(errno)); 2677168404Spjd return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2678168404Spjd 2679168404Spjd default: 2680168404Spjd return (zfs_standard_error(hdl, errno, errbuf)); 2681168404Spjd } 2682168404Spjd } 2683168404Spjd 2684168404Spjd return (0); 2685168404Spjd} 2686168404Spjd 2687168404Spjd/* 2688168404Spjd * Create ancestors of 'target', but not target itself, and not 2689168404Spjd * ancestors whose names are shorter than prefixlen. Die if 2690168404Spjd * prefixlen-ancestor does not exist. 2691168404Spjd */ 2692168404Spjdstatic int 2693168404Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2694168404Spjd{ 2695168404Spjd zfs_handle_t *h; 2696168404Spjd char *cp; 2697168404Spjd 2698168404Spjd /* make sure prefix exists */ 2699168404Spjd cp = strchr(target + prefixlen, '/'); 2700168404Spjd *cp = '\0'; 2701168404Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2702168404Spjd *cp = '/'; 2703168404Spjd if (h == NULL) 2704168404Spjd return (-1); 2705168404Spjd zfs_close(h); 2706168404Spjd 2707168404Spjd /* 2708168404Spjd * Attempt to create, mount, and share any ancestor filesystems, 2709168404Spjd * up to the prefixlen-long one. 2710168404Spjd */ 2711168404Spjd for (cp = target + prefixlen + 1; 2712168404Spjd cp = strchr(cp, '/'); *cp = '/', cp++) { 2713168404Spjd const char *opname; 2714168404Spjd 2715168404Spjd *cp = '\0'; 2716168404Spjd 2717168404Spjd h = make_dataset_handle(hdl, target); 2718168404Spjd if (h) { 2719168404Spjd /* it already exists, nothing to do here */ 2720168404Spjd zfs_close(h); 2721168404Spjd continue; 2722168404Spjd } 2723168404Spjd 2724168404Spjd opname = dgettext(TEXT_DOMAIN, "create"); 2725168404Spjd if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2726168404Spjd NULL) != 0) 2727168404Spjd goto ancestorerr; 2728168404Spjd 2729168404Spjd opname = dgettext(TEXT_DOMAIN, "open"); 2730168404Spjd h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2731168404Spjd if (h == NULL) 2732168404Spjd goto ancestorerr; 2733168404Spjd 2734168404Spjd opname = dgettext(TEXT_DOMAIN, "mount"); 2735168404Spjd if (zfs_mount(h, NULL, 0) != 0) 2736168404Spjd goto ancestorerr; 2737168404Spjd 2738168404Spjd opname = dgettext(TEXT_DOMAIN, "share"); 2739168404Spjd if (zfs_share(h) != 0) 2740168404Spjd goto ancestorerr; 2741168404Spjd 2742168404Spjd zfs_close(h); 2743168404Spjd 2744168404Spjd continue; 2745168404Spjdancestorerr: 2746168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2747168404Spjd "failed to %s ancestor '%s'"), opname, target); 2748168404Spjd return (-1); 2749168404Spjd } 2750168404Spjd 2751168404Spjd return (0); 2752168404Spjd} 2753168404Spjd 2754168404Spjd/* 2755168404Spjd * Restores a backup of tosnap from the file descriptor specified by infd. 2756168404Spjd */ 2757168404Spjdint 2758168404Spjdzfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 2759168404Spjd int verbose, int dryrun, boolean_t force, int infd) 2760168404Spjd{ 2761168404Spjd zfs_cmd_t zc = { 0 }; 2762168404Spjd time_t begin_time; 2763168404Spjd int ioctl_err, err, bytes, size, choplen; 2764168404Spjd char *cp; 2765168404Spjd dmu_replay_record_t drr; 2766168404Spjd struct drr_begin *drrb = &zc.zc_begin_record; 2767168404Spjd char errbuf[1024]; 2768168404Spjd prop_changelist_t *clp; 2769168404Spjd char chopprefix[ZFS_MAXNAMELEN]; 2770168404Spjd 2771168404Spjd begin_time = time(NULL); 2772168404Spjd 2773168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2774168404Spjd "cannot receive")); 2775168404Spjd 2776168404Spjd /* read in the BEGIN record */ 2777168404Spjd cp = (char *)&drr; 2778168404Spjd bytes = 0; 2779168404Spjd do { 2780168404Spjd size = read(infd, cp, sizeof (drr) - bytes); 2781168404Spjd cp += size; 2782168404Spjd bytes += size; 2783168404Spjd } while (size > 0); 2784168404Spjd 2785168404Spjd if (size < 0 || bytes != sizeof (drr)) { 2786168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2787168404Spjd "stream (failed to read first record)")); 2788168404Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2789168404Spjd } 2790168404Spjd 2791168404Spjd zc.zc_begin_record = drr.drr_u.drr_begin; 2792168404Spjd 2793168404Spjd if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2794168404Spjd drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 2795168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2796168404Spjd "stream (bad magic number)")); 2797168404Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2798168404Spjd } 2799168404Spjd 2800168404Spjd if (drrb->drr_version != DMU_BACKUP_VERSION && 2801168404Spjd drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 2802168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 2803168404Spjd "0x%llx is supported (stream is version 0x%llx)"), 2804168404Spjd DMU_BACKUP_VERSION, drrb->drr_version); 2805168404Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2806168404Spjd } 2807168404Spjd 2808168404Spjd if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 2809168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2810168404Spjd "stream (bad snapshot name)")); 2811168404Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2812168404Spjd } 2813168404Spjd /* 2814168404Spjd * Determine how much of the snapshot name stored in the stream 2815168404Spjd * we are going to tack on to the name they specified on the 2816168404Spjd * command line, and how much we are going to chop off. 2817168404Spjd * 2818168404Spjd * If they specified a snapshot, chop the entire name stored in 2819168404Spjd * the stream. 2820168404Spjd */ 2821168404Spjd (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2822168404Spjd if (isprefix) { 2823168404Spjd /* 2824168404Spjd * They specified a fs with -d, we want to tack on 2825168404Spjd * everything but the pool name stored in the stream 2826168404Spjd */ 2827168404Spjd if (strchr(tosnap, '@')) { 2828168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2829168404Spjd "argument - snapshot not allowed with -d")); 2830168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2831168404Spjd } 2832168404Spjd cp = strchr(chopprefix, '/'); 2833168404Spjd if (cp == NULL) 2834168404Spjd cp = strchr(chopprefix, '@'); 2835168404Spjd *cp = '\0'; 2836168404Spjd } else if (strchr(tosnap, '@') == NULL) { 2837168404Spjd /* 2838168404Spjd * If they specified a filesystem without -d, we want to 2839168404Spjd * tack on everything after the fs specified in the 2840168404Spjd * first name from the stream. 2841168404Spjd */ 2842168404Spjd cp = strchr(chopprefix, '@'); 2843168404Spjd *cp = '\0'; 2844168404Spjd } 2845168404Spjd choplen = strlen(chopprefix); 2846168404Spjd 2847168404Spjd /* 2848168404Spjd * Determine name of destination snapshot, store in zc_value. 2849168404Spjd */ 2850168404Spjd (void) strcpy(zc.zc_value, tosnap); 2851168404Spjd (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 2852168404Spjd sizeof (zc.zc_value)); 2853168404Spjd if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 2854168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2855168404Spjd 2856168404Spjd (void) strcpy(zc.zc_name, zc.zc_value); 2857168404Spjd if (drrb->drr_fromguid) { 2858168404Spjd /* incremental backup stream */ 2859168404Spjd zfs_handle_t *h; 2860168404Spjd 2861168404Spjd /* do the recvbackup ioctl to the containing fs */ 2862168404Spjd *strchr(zc.zc_name, '@') = '\0'; 2863168404Spjd 2864168404Spjd /* make sure destination fs exists */ 2865168404Spjd h = zfs_open(hdl, zc.zc_name, 2866168404Spjd ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2867168404Spjd if (h == NULL) 2868168404Spjd return (-1); 2869168404Spjd if (!dryrun) { 2870168404Spjd /* 2871168404Spjd * We need to unmount all the dependents of the dataset 2872168404Spjd * and the dataset itself. If it's a volume 2873168404Spjd * then remove device link. 2874168404Spjd */ 2875168404Spjd if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2876168404Spjd clp = changelist_gather(h, ZFS_PROP_NAME, 0); 2877168404Spjd if (clp == NULL) 2878168404Spjd return (-1); 2879168404Spjd if (changelist_prefix(clp) != 0) { 2880168404Spjd changelist_free(clp); 2881168404Spjd return (-1); 2882168404Spjd } 2883168404Spjd } else { 2884168404Spjd (void) zvol_remove_link(hdl, h->zfs_name); 2885168404Spjd } 2886168404Spjd } 2887168404Spjd zfs_close(h); 2888168404Spjd } else { 2889168404Spjd /* full backup stream */ 2890168404Spjd 2891168404Spjd /* Make sure destination fs does not exist */ 2892168404Spjd *strchr(zc.zc_name, '@') = '\0'; 2893168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2894168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2895168404Spjd "destination '%s' exists"), zc.zc_name); 2896168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2897168404Spjd } 2898168404Spjd 2899168404Spjd if (strchr(zc.zc_name, '/') == NULL) { 2900168404Spjd /* 2901168404Spjd * they're trying to do a recv into a 2902168404Spjd * nonexistant topmost filesystem. 2903168404Spjd */ 2904168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2905168404Spjd "destination does not exist"), zc.zc_name); 2906168404Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2907168404Spjd } 2908168404Spjd 2909168404Spjd /* Do the recvbackup ioctl to the fs's parent. */ 2910168404Spjd *strrchr(zc.zc_name, '/') = '\0'; 2911168404Spjd 2912168404Spjd if (isprefix && (err = create_parents(hdl, 2913168404Spjd zc.zc_value, strlen(tosnap))) != 0) { 2914168404Spjd return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 2915168404Spjd } 2916168404Spjd 2917168404Spjd } 2918168404Spjd 2919168404Spjd zc.zc_cookie = infd; 2920168404Spjd zc.zc_guid = force; 2921168404Spjd if (verbose) { 2922168404Spjd (void) printf("%s %s stream of %s into %s\n", 2923168404Spjd dryrun ? "would receive" : "receiving", 2924168404Spjd drrb->drr_fromguid ? "incremental" : "full", 2925168404Spjd drr.drr_u.drr_begin.drr_toname, 2926168404Spjd zc.zc_value); 2927168404Spjd (void) fflush(stdout); 2928168404Spjd } 2929168404Spjd if (dryrun) 2930168404Spjd return (0); 2931168404Spjd err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2932168404Spjd if (ioctl_err != 0) { 2933168404Spjd switch (errno) { 2934168404Spjd case ENODEV: 2935168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2936168404Spjd "most recent snapshot does not match incremental " 2937168404Spjd "source")); 2938168404Spjd (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2939168404Spjd break; 2940168404Spjd case ETXTBSY: 2941168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2942168404Spjd "destination has been modified since most recent " 2943168404Spjd "snapshot")); 2944168404Spjd (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2945168404Spjd break; 2946168404Spjd case EEXIST: 2947168404Spjd if (drrb->drr_fromguid == 0) { 2948168404Spjd /* it's the containing fs that exists */ 2949168404Spjd cp = strchr(zc.zc_value, '@'); 2950168404Spjd *cp = '\0'; 2951168404Spjd } 2952168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2953168404Spjd "destination already exists")); 2954168404Spjd (void) zfs_error_fmt(hdl, EZFS_EXISTS, 2955168404Spjd dgettext(TEXT_DOMAIN, "cannot restore to %s"), 2956168404Spjd zc.zc_value); 2957168404Spjd break; 2958168404Spjd case EINVAL: 2959168404Spjd (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2960168404Spjd break; 2961168404Spjd case ECKSUM: 2962168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2963168404Spjd "invalid stream (checksum mismatch)")); 2964168404Spjd (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2965168404Spjd break; 2966168404Spjd default: 2967168404Spjd (void) zfs_standard_error(hdl, errno, errbuf); 2968168404Spjd } 2969168404Spjd } 2970168404Spjd 2971168404Spjd /* 2972168404Spjd * Mount or recreate the /dev links for the target filesystem 2973168404Spjd * (if created, or if we tore them down to do an incremental 2974168404Spjd * restore), and the /dev links for the new snapshot (if 2975168404Spjd * created). Also mount any children of the target filesystem 2976168404Spjd * if we did an incremental receive. 2977168404Spjd */ 2978168404Spjd cp = strchr(zc.zc_value, '@'); 2979168404Spjd if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2980168404Spjd zfs_handle_t *h; 2981168404Spjd 2982168404Spjd *cp = '\0'; 2983168404Spjd h = zfs_open(hdl, zc.zc_value, 2984168404Spjd ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2985168404Spjd *cp = '@'; 2986168404Spjd if (h) { 2987168404Spjd if (h->zfs_type == ZFS_TYPE_VOLUME) { 2988168404Spjd err = zvol_create_link(hdl, h->zfs_name); 2989168404Spjd if (err == 0 && ioctl_err == 0) 2990168404Spjd err = zvol_create_link(hdl, 2991168404Spjd zc.zc_value); 2992168404Spjd } else { 2993168404Spjd if (drrb->drr_fromguid) { 2994168404Spjd err = changelist_postfix(clp); 2995168404Spjd changelist_free(clp); 2996168404Spjd } else { 2997168404Spjd err = zfs_mount(h, NULL, 0); 2998168404Spjd } 2999168404Spjd } 3000168404Spjd zfs_close(h); 3001168404Spjd } 3002168404Spjd } 3003168404Spjd 3004168404Spjd if (err || ioctl_err) 3005168404Spjd return (-1); 3006168404Spjd 3007168404Spjd if (verbose) { 3008168404Spjd char buf1[64]; 3009168404Spjd char buf2[64]; 3010168404Spjd uint64_t bytes = zc.zc_cookie; 3011168404Spjd time_t delta = time(NULL) - begin_time; 3012168404Spjd if (delta == 0) 3013168404Spjd delta = 1; 3014168404Spjd zfs_nicenum(bytes, buf1, sizeof (buf1)); 3015168404Spjd zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 3016168404Spjd 3017168404Spjd (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 3018168404Spjd buf1, delta, buf2); 3019168404Spjd } 3020168404Spjd 3021168404Spjd return (0); 3022168404Spjd} 3023168404Spjd 3024168404Spjd/* 3025168404Spjd * Destroy any more recent snapshots. We invoke this callback on any dependents 3026168404Spjd * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3027168404Spjd * is a dependent and we should just destroy it without checking the transaction 3028168404Spjd * group. 3029168404Spjd */ 3030168404Spjdtypedef struct rollback_data { 3031168404Spjd const char *cb_target; /* the snapshot */ 3032168404Spjd uint64_t cb_create; /* creation time reference */ 3033168404Spjd prop_changelist_t *cb_clp; /* changelist pointer */ 3034168404Spjd int cb_error; 3035168404Spjd boolean_t cb_dependent; 3036168404Spjd} rollback_data_t; 3037168404Spjd 3038168404Spjdstatic int 3039168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data) 3040168404Spjd{ 3041168404Spjd rollback_data_t *cbp = data; 3042168404Spjd 3043168404Spjd if (!cbp->cb_dependent) { 3044168404Spjd if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3045168404Spjd zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3046168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3047168404Spjd cbp->cb_create) { 3048168404Spjd 3049168404Spjd cbp->cb_dependent = B_TRUE; 3050168404Spjd if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 3051168404Spjd cbp) != 0) 3052168404Spjd cbp->cb_error = 1; 3053168404Spjd cbp->cb_dependent = B_FALSE; 3054168404Spjd 3055168404Spjd if (zfs_destroy(zhp) != 0) 3056168404Spjd cbp->cb_error = 1; 3057168404Spjd else 3058168404Spjd changelist_remove(zhp, cbp->cb_clp); 3059168404Spjd } 3060168404Spjd } else { 3061168404Spjd if (zfs_destroy(zhp) != 0) 3062168404Spjd cbp->cb_error = 1; 3063168404Spjd else 3064168404Spjd changelist_remove(zhp, cbp->cb_clp); 3065168404Spjd } 3066168404Spjd 3067168404Spjd zfs_close(zhp); 3068168404Spjd return (0); 3069168404Spjd} 3070168404Spjd 3071168404Spjd/* 3072168404Spjd * Rollback the dataset to its latest snapshot. 3073168404Spjd */ 3074168404Spjdstatic int 3075168404Spjddo_rollback(zfs_handle_t *zhp) 3076168404Spjd{ 3077168404Spjd int ret; 3078168404Spjd zfs_cmd_t zc = { 0 }; 3079168404Spjd 3080168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3081168404Spjd zhp->zfs_type == ZFS_TYPE_VOLUME); 3082168404Spjd 3083168404Spjd if (zhp->zfs_type == ZFS_TYPE_VOLUME && 3084168404Spjd zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3085168404Spjd return (-1); 3086168404Spjd 3087168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3088168404Spjd 3089168404Spjd if (ZFS_IS_VOLUME(zhp)) 3090168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3091168404Spjd else 3092168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3093168404Spjd 3094168404Spjd /* 3095168404Spjd * We rely on the consumer to verify that there are no newer snapshots 3096168404Spjd * for the given dataset. Given these constraints, we can simply pass 3097168404Spjd * the name on to the ioctl() call. There is still an unlikely race 3098168404Spjd * condition where the user has taken a snapshot since we verified that 3099168404Spjd * this was the most recent. 3100168404Spjd */ 3101168404Spjd if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 3102168404Spjd &zc)) != 0) { 3103168404Spjd (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3104168404Spjd dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3105168404Spjd zhp->zfs_name); 3106168404Spjd } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3107168404Spjd ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3108168404Spjd } 3109168404Spjd 3110168404Spjd return (ret); 3111168404Spjd} 3112168404Spjd 3113168404Spjd/* 3114168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any 3115168404Spjd * data changes since then and making it the active dataset. 3116168404Spjd * 3117168404Spjd * Any snapshots more recent than the target are destroyed, along with 3118168404Spjd * their dependents. 3119168404Spjd */ 3120168404Spjdint 3121168404Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 3122168404Spjd{ 3123168404Spjd int ret; 3124168404Spjd rollback_data_t cb = { 0 }; 3125168404Spjd prop_changelist_t *clp; 3126168404Spjd 3127168404Spjd /* 3128168404Spjd * Unmount all dependendents of the dataset and the dataset itself. 3129168404Spjd * The list we need to gather is the same as for doing rename 3130168404Spjd */ 3131168404Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 3132168404Spjd if (clp == NULL) 3133168404Spjd return (-1); 3134168404Spjd 3135168404Spjd if ((ret = changelist_prefix(clp)) != 0) 3136168404Spjd goto out; 3137168404Spjd 3138168404Spjd /* 3139168404Spjd * Destroy all recent snapshots and its dependends. 3140168404Spjd */ 3141168404Spjd cb.cb_target = snap->zfs_name; 3142168404Spjd cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3143168404Spjd cb.cb_clp = clp; 3144168404Spjd (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3145168404Spjd 3146168404Spjd if ((ret = cb.cb_error) != 0) { 3147168404Spjd (void) changelist_postfix(clp); 3148168404Spjd goto out; 3149168404Spjd } 3150168404Spjd 3151168404Spjd /* 3152168404Spjd * Now that we have verified that the snapshot is the latest, 3153168404Spjd * rollback to the given snapshot. 3154168404Spjd */ 3155168404Spjd ret = do_rollback(zhp); 3156168404Spjd 3157168404Spjd if (ret != 0) { 3158168404Spjd (void) changelist_postfix(clp); 3159168404Spjd goto out; 3160168404Spjd } 3161168404Spjd 3162168404Spjd /* 3163168404Spjd * We only want to re-mount the filesystem if it was mounted in the 3164168404Spjd * first place. 3165168404Spjd */ 3166168404Spjd ret = changelist_postfix(clp); 3167168404Spjd 3168168404Spjdout: 3169168404Spjd changelist_free(clp); 3170168404Spjd return (ret); 3171168404Spjd} 3172168404Spjd 3173168404Spjd/* 3174168404Spjd * Iterate over all dependents for a given dataset. This includes both 3175168404Spjd * hierarchical dependents (children) and data dependents (snapshots and 3176168404Spjd * clones). The bulk of the processing occurs in get_dependents() in 3177168404Spjd * libzfs_graph.c. 3178168404Spjd */ 3179168404Spjdint 3180168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 3181168404Spjd zfs_iter_f func, void *data) 3182168404Spjd{ 3183168404Spjd char **dependents; 3184168404Spjd size_t count; 3185168404Spjd int i; 3186168404Spjd zfs_handle_t *child; 3187168404Spjd int ret = 0; 3188168404Spjd 3189168404Spjd if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 3190168404Spjd &dependents, &count) != 0) 3191168404Spjd return (-1); 3192168404Spjd 3193168404Spjd for (i = 0; i < count; i++) { 3194168404Spjd if ((child = make_dataset_handle(zhp->zfs_hdl, 3195168404Spjd dependents[i])) == NULL) 3196168404Spjd continue; 3197168404Spjd 3198168404Spjd if ((ret = func(child, data)) != 0) 3199168404Spjd break; 3200168404Spjd } 3201168404Spjd 3202168404Spjd for (i = 0; i < count; i++) 3203168404Spjd free(dependents[i]); 3204168404Spjd free(dependents); 3205168404Spjd 3206168404Spjd return (ret); 3207168404Spjd} 3208168404Spjd 3209168404Spjd/* 3210168404Spjd * Renames the given dataset. 3211168404Spjd */ 3212168404Spjdint 3213168676Spjdzfs_rename(zfs_handle_t *zhp, const char *target, int recursive) 3214168404Spjd{ 3215168404Spjd int ret; 3216168404Spjd zfs_cmd_t zc = { 0 }; 3217168404Spjd char *delim; 3218168676Spjd prop_changelist_t *cl = NULL; 3219168676Spjd zfs_handle_t *zhrp = NULL; 3220168676Spjd char *parentname = NULL; 3221168404Spjd char parent[ZFS_MAXNAMELEN]; 3222168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3223168404Spjd char errbuf[1024]; 3224168404Spjd 3225168404Spjd /* if we have the same exact name, just return success */ 3226168404Spjd if (strcmp(zhp->zfs_name, target) == 0) 3227168404Spjd return (0); 3228168404Spjd 3229168404Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3230168404Spjd "cannot rename to '%s'"), target); 3231168404Spjd 3232168404Spjd /* 3233168404Spjd * Make sure the target name is valid 3234168404Spjd */ 3235168404Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3236168404Spjd if ((strchr(target, '@') == NULL) || 3237168404Spjd *target == '@') { 3238168404Spjd /* 3239168404Spjd * Snapshot target name is abbreviated, 3240168404Spjd * reconstruct full dataset name 3241168404Spjd */ 3242168404Spjd (void) strlcpy(parent, zhp->zfs_name, 3243168404Spjd sizeof (parent)); 3244168404Spjd delim = strchr(parent, '@'); 3245168404Spjd if (strchr(target, '@') == NULL) 3246168404Spjd *(++delim) = '\0'; 3247168404Spjd else 3248168404Spjd *delim = '\0'; 3249168404Spjd (void) strlcat(parent, target, sizeof (parent)); 3250168404Spjd target = parent; 3251168404Spjd } else { 3252168404Spjd /* 3253168404Spjd * Make sure we're renaming within the same dataset. 3254168404Spjd */ 3255168404Spjd delim = strchr(target, '@'); 3256168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) 3257168404Spjd != 0 || zhp->zfs_name[delim - target] != '@') { 3258168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3259168404Spjd "snapshots must be part of same " 3260168404Spjd "dataset")); 3261168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, 3262168404Spjd errbuf)); 3263168404Spjd } 3264168404Spjd } 3265168404Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 3266168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3267168404Spjd } else { 3268168676Spjd if (recursive) { 3269168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3270168676Spjd "recursive rename must be a snapshot")); 3271168676Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3272168676Spjd } 3273168676Spjd 3274168404Spjd if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 3275168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3276168404Spjd uint64_t unused; 3277168404Spjd 3278168404Spjd /* validate parents */ 3279168404Spjd if (check_parents(hdl, target, &unused) != 0) 3280168404Spjd return (-1); 3281168404Spjd 3282168404Spjd (void) parent_name(target, parent, sizeof (parent)); 3283168404Spjd 3284168404Spjd /* make sure we're in the same pool */ 3285168404Spjd verify((delim = strchr(target, '/')) != NULL); 3286168404Spjd if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3287168404Spjd zhp->zfs_name[delim - target] != '/') { 3288168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3289168404Spjd "datasets must be within same pool")); 3290168404Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3291168404Spjd } 3292168404Spjd 3293168404Spjd /* new name cannot be a child of the current dataset name */ 3294168404Spjd if (strncmp(parent, zhp->zfs_name, 3295168404Spjd strlen(zhp->zfs_name)) == 0) { 3296168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3297168404Spjd "New dataset name cannot be a descendent of " 3298168404Spjd "current dataset name")); 3299168404Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3300168404Spjd } 3301168404Spjd } 3302168404Spjd 3303168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3304168404Spjd dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 3305168404Spjd 3306168404Spjd if (getzoneid() == GLOBAL_ZONEID && 3307168404Spjd zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 3308168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3309168404Spjd "dataset is used in a non-global zone")); 3310168404Spjd return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3311168404Spjd } 3312168404Spjd 3313168676Spjd if (recursive) { 3314168676Spjd struct destroydata dd; 3315168404Spjd 3316168676Spjd parentname = strdup(zhp->zfs_name); 3317168676Spjd delim = strchr(parentname, '@'); 3318168676Spjd *delim = '\0'; 3319168676Spjd zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY); 3320168676Spjd if (zhrp == NULL) { 3321168676Spjd return (-1); 3322168676Spjd } 3323168676Spjd 3324168676Spjd dd.snapname = delim + 1; 3325168676Spjd dd.gotone = B_FALSE; 3326168676Spjd dd.closezhp = B_FALSE; 3327168676Spjd 3328168676Spjd /* We remove any zvol links prior to renaming them */ 3329168676Spjd ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3330168676Spjd if (ret) { 3331168676Spjd goto error; 3332168676Spjd } 3333168676Spjd } else { 3334168676Spjd if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 3335168676Spjd return (-1); 3336168676Spjd 3337168676Spjd if (changelist_haszonedchild(cl)) { 3338168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3339168676Spjd "child dataset with inherited mountpoint is used " 3340168676Spjd "in a non-global zone")); 3341168676Spjd (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3342168676Spjd goto error; 3343168676Spjd } 3344168676Spjd 3345168676Spjd if ((ret = changelist_prefix(cl)) != 0) 3346168676Spjd goto error; 3347168404Spjd } 3348168404Spjd 3349168404Spjd if (ZFS_IS_VOLUME(zhp)) 3350168404Spjd zc.zc_objset_type = DMU_OST_ZVOL; 3351168404Spjd else 3352168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3353168404Spjd 3354168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3355168404Spjd (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3356168404Spjd 3357168676Spjd zc.zc_cookie = recursive; 3358168676Spjd 3359168404Spjd if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 3360168676Spjd /* 3361168676Spjd * if it was recursive, the one that actually failed will 3362168676Spjd * be in zc.zc_name 3363168676Spjd */ 3364168676Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3365168676Spjd "cannot rename to '%s'"), zc.zc_name); 3366168404Spjd 3367168676Spjd if (recursive && errno == EEXIST) { 3368168676Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3369168676Spjd "a child dataset already has a snapshot " 3370168676Spjd "with the new name")); 3371168676Spjd (void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf); 3372168676Spjd } else { 3373168676Spjd (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3374168676Spjd } 3375168676Spjd 3376168404Spjd /* 3377168404Spjd * On failure, we still want to remount any filesystems that 3378168404Spjd * were previously mounted, so we don't alter the system state. 3379168404Spjd */ 3380168676Spjd if (recursive) { 3381168676Spjd struct createdata cd; 3382168676Spjd 3383168676Spjd /* only create links for datasets that had existed */ 3384168676Spjd cd.cd_snapname = delim + 1; 3385168676Spjd cd.cd_ifexists = B_TRUE; 3386168676Spjd (void) zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3387168676Spjd &cd); 3388168676Spjd } else { 3389168676Spjd (void) changelist_postfix(cl); 3390168676Spjd } 3391168404Spjd } else { 3392168676Spjd if (recursive) { 3393168676Spjd struct createdata cd; 3394168404Spjd 3395168676Spjd /* only create links for datasets that had existed */ 3396168676Spjd cd.cd_snapname = strchr(target, '@') + 1; 3397168676Spjd cd.cd_ifexists = B_TRUE; 3398168676Spjd ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3399168676Spjd &cd); 3400168676Spjd } else { 3401168676Spjd changelist_rename(cl, zfs_get_name(zhp), target); 3402168676Spjd ret = changelist_postfix(cl); 3403168676Spjd } 3404168404Spjd } 3405168404Spjd 3406168404Spjderror: 3407168676Spjd if (parentname) { 3408168676Spjd free(parentname); 3409168676Spjd } 3410168676Spjd if (zhrp) { 3411168676Spjd zfs_close(zhrp); 3412168676Spjd } 3413168676Spjd if (cl) { 3414168676Spjd changelist_free(cl); 3415168676Spjd } 3416168404Spjd return (ret); 3417168404Spjd} 3418168404Spjd 3419168404Spjd/* 3420168404Spjd * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3421168404Spjd * poke devfsadm to create the /dev link, and then wait for the link to appear. 3422168404Spjd */ 3423168404Spjdint 3424168404Spjdzvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3425168404Spjd{ 3426168676Spjd return (zvol_create_link_common(hdl, dataset, B_FALSE)); 3427168676Spjd} 3428168676Spjd 3429168676Spjdstatic int 3430168676Spjdzvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3431168676Spjd{ 3432168404Spjd zfs_cmd_t zc = { 0 }; 3433168404Spjd#if 0 3434168404Spjd di_devlink_handle_t dhdl; 3435168404Spjd#endif 3436168404Spjd 3437168404Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3438168404Spjd 3439168404Spjd /* 3440168404Spjd * Issue the appropriate ioctl. 3441168404Spjd */ 3442168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3443168404Spjd switch (errno) { 3444168404Spjd case EEXIST: 3445168404Spjd /* 3446168404Spjd * Silently ignore the case where the link already 3447168404Spjd * exists. This allows 'zfs volinit' to be run multiple 3448168404Spjd * times without errors. 3449168404Spjd */ 3450168404Spjd return (0); 3451168404Spjd 3452168676Spjd case ENOENT: 3453168676Spjd /* 3454168676Spjd * Dataset does not exist in the kernel. If we 3455168676Spjd * don't care (see zfs_rename), then ignore the 3456168676Spjd * error quietly. 3457168676Spjd */ 3458168676Spjd if (ifexists) { 3459168676Spjd return (0); 3460168676Spjd } 3461168676Spjd 3462168676Spjd /* FALLTHROUGH */ 3463168676Spjd 3464168404Spjd default: 3465168404Spjd return (zfs_standard_error_fmt(hdl, errno, 3466168404Spjd dgettext(TEXT_DOMAIN, "cannot create device links " 3467168404Spjd "for '%s'"), dataset)); 3468168404Spjd } 3469168404Spjd } 3470168404Spjd 3471168404Spjd#if 0 3472168404Spjd /* 3473168404Spjd * Call devfsadm and wait for the links to magically appear. 3474168404Spjd */ 3475168404Spjd if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 3476168404Spjd zfs_error_aux(hdl, strerror(errno)); 3477168404Spjd (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 3478168404Spjd dgettext(TEXT_DOMAIN, "cannot create device links " 3479168404Spjd "for '%s'"), dataset); 3480168404Spjd (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3481168404Spjd return (-1); 3482168404Spjd } else { 3483168404Spjd (void) di_devlink_fini(&dhdl); 3484168404Spjd } 3485168404Spjd#endif 3486168404Spjd 3487168404Spjd return (0); 3488168404Spjd} 3489168404Spjd 3490168404Spjd/* 3491168404Spjd * Remove a minor node for the given zvol and the associated /dev links. 3492168404Spjd */ 3493168404Spjdint 3494168404Spjdzvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3495168404Spjd{ 3496168404Spjd zfs_cmd_t zc = { 0 }; 3497168404Spjd 3498168404Spjd (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3499168404Spjd 3500168404Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3501168404Spjd switch (errno) { 3502168404Spjd case ENXIO: 3503168404Spjd /* 3504168404Spjd * Silently ignore the case where the link no longer 3505168404Spjd * exists, so that 'zfs volfini' can be run multiple 3506168404Spjd * times without errors. 3507168404Spjd */ 3508168404Spjd return (0); 3509168404Spjd 3510168404Spjd default: 3511168404Spjd return (zfs_standard_error_fmt(hdl, errno, 3512168404Spjd dgettext(TEXT_DOMAIN, "cannot remove device " 3513168404Spjd "links for '%s'"), dataset)); 3514168404Spjd } 3515168404Spjd } 3516168404Spjd 3517168404Spjd return (0); 3518168404Spjd} 3519168404Spjd 3520168404Spjdnvlist_t * 3521168404Spjdzfs_get_user_props(zfs_handle_t *zhp) 3522168404Spjd{ 3523168404Spjd return (zhp->zfs_user_props); 3524168404Spjd} 3525168404Spjd 3526168404Spjd/* 3527168404Spjd * Given a comma-separated list of properties, contruct a property list 3528168404Spjd * containing both user-defined and native properties. This function will 3529168404Spjd * return a NULL list if 'all' is specified, which can later be expanded on a 3530168404Spjd * per-dataset basis by zfs_expand_proplist(). 3531168404Spjd */ 3532168404Spjdint 3533168404Spjdzfs_get_proplist_common(libzfs_handle_t *hdl, char *fields, 3534168404Spjd zfs_proplist_t **listp, zfs_type_t type) 3535168404Spjd{ 3536168404Spjd size_t len; 3537168404Spjd char *s, *p; 3538168404Spjd char c; 3539168404Spjd zfs_prop_t prop; 3540168404Spjd zfs_proplist_t *entry; 3541168404Spjd zfs_proplist_t **last; 3542168404Spjd 3543168404Spjd *listp = NULL; 3544168404Spjd last = listp; 3545168404Spjd 3546168404Spjd /* 3547168404Spjd * If 'all' is specified, return a NULL list. 3548168404Spjd */ 3549168404Spjd if (strcmp(fields, "all") == 0) 3550168404Spjd return (0); 3551168404Spjd 3552168404Spjd /* 3553168404Spjd * If no fields were specified, return an error. 3554168404Spjd */ 3555168404Spjd if (fields[0] == '\0') { 3556168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3557168404Spjd "no properties specified")); 3558168404Spjd return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 3559168404Spjd "bad property list"))); 3560168404Spjd } 3561168404Spjd 3562168404Spjd /* 3563168404Spjd * It would be nice to use getsubopt() here, but the inclusion of column 3564168404Spjd * aliases makes this more effort than it's worth. 3565168404Spjd */ 3566168404Spjd s = fields; 3567168404Spjd while (*s != '\0') { 3568168404Spjd if ((p = strchr(s, ',')) == NULL) { 3569168404Spjd len = strlen(s); 3570168404Spjd p = s + len; 3571168404Spjd } else { 3572168404Spjd len = p - s; 3573168404Spjd } 3574168404Spjd 3575168404Spjd /* 3576168404Spjd * Check for empty options. 3577168404Spjd */ 3578168404Spjd if (len == 0) { 3579168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3580168404Spjd "empty property name")); 3581168404Spjd return (zfs_error(hdl, EZFS_BADPROP, 3582168404Spjd dgettext(TEXT_DOMAIN, "bad property list"))); 3583168404Spjd } 3584168404Spjd 3585168404Spjd /* 3586168404Spjd * Check all regular property names. 3587168404Spjd */ 3588168404Spjd c = s[len]; 3589168404Spjd s[len] = '\0'; 3590168404Spjd prop = zfs_name_to_prop_common(s, type); 3591168404Spjd 3592168404Spjd if (prop != ZFS_PROP_INVAL && 3593168404Spjd !zfs_prop_valid_for_type(prop, type)) 3594168404Spjd prop = ZFS_PROP_INVAL; 3595168404Spjd 3596168404Spjd /* 3597168404Spjd * When no property table entry can be found, return failure if 3598168404Spjd * this is a pool property or if this isn't a user-defined 3599168404Spjd * dataset property, 3600168404Spjd */ 3601168404Spjd if (prop == ZFS_PROP_INVAL && 3602168404Spjd (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) { 3603168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3604168404Spjd "invalid property '%s'"), s); 3605168404Spjd return (zfs_error(hdl, EZFS_BADPROP, 3606168404Spjd dgettext(TEXT_DOMAIN, "bad property list"))); 3607168404Spjd } 3608168404Spjd 3609168404Spjd if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 3610168404Spjd return (-1); 3611168404Spjd 3612168404Spjd entry->pl_prop = prop; 3613168404Spjd if (prop == ZFS_PROP_INVAL) { 3614168404Spjd if ((entry->pl_user_prop = 3615168404Spjd zfs_strdup(hdl, s)) == NULL) { 3616168404Spjd free(entry); 3617168404Spjd return (-1); 3618168404Spjd } 3619168404Spjd entry->pl_width = strlen(s); 3620168404Spjd } else { 3621168404Spjd entry->pl_width = zfs_prop_width(prop, 3622168404Spjd &entry->pl_fixed); 3623168404Spjd } 3624168404Spjd 3625168404Spjd *last = entry; 3626168404Spjd last = &entry->pl_next; 3627168404Spjd 3628168404Spjd s = p; 3629168404Spjd if (c == ',') 3630168404Spjd s++; 3631168404Spjd } 3632168404Spjd 3633168404Spjd return (0); 3634168404Spjd} 3635168404Spjd 3636168404Spjdint 3637168404Spjdzfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 3638168404Spjd{ 3639168404Spjd return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY)); 3640168404Spjd} 3641168404Spjd 3642168404Spjdvoid 3643168404Spjdzfs_free_proplist(zfs_proplist_t *pl) 3644168404Spjd{ 3645168404Spjd zfs_proplist_t *next; 3646168404Spjd 3647168404Spjd while (pl != NULL) { 3648168404Spjd next = pl->pl_next; 3649168404Spjd free(pl->pl_user_prop); 3650168404Spjd free(pl); 3651168404Spjd pl = next; 3652168404Spjd } 3653168404Spjd} 3654168404Spjd 3655168404Spjdtypedef struct expand_data { 3656168404Spjd zfs_proplist_t **last; 3657168404Spjd libzfs_handle_t *hdl; 3658168404Spjd} expand_data_t; 3659168404Spjd 3660168404Spjdstatic zfs_prop_t 3661168404Spjdzfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 3662168404Spjd{ 3663168404Spjd zfs_proplist_t *entry; 3664168404Spjd expand_data_t *edp = cb; 3665168404Spjd 3666168404Spjd if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 3667168404Spjd return (ZFS_PROP_INVAL); 3668168404Spjd 3669168404Spjd entry->pl_prop = prop; 3670168404Spjd entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 3671168404Spjd entry->pl_all = B_TRUE; 3672168404Spjd 3673168404Spjd *(edp->last) = entry; 3674168404Spjd edp->last = &entry->pl_next; 3675168404Spjd 3676168404Spjd return (ZFS_PROP_CONT); 3677168404Spjd} 3678168404Spjd 3679168404Spjdint 3680168404Spjdzfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp, 3681168404Spjd zfs_type_t type) 3682168404Spjd{ 3683168404Spjd zfs_proplist_t *entry; 3684168404Spjd zfs_proplist_t **last; 3685168404Spjd expand_data_t exp; 3686168404Spjd 3687168404Spjd if (*plp == NULL) { 3688168404Spjd /* 3689168404Spjd * If this is the very first time we've been called for an 'all' 3690168404Spjd * specification, expand the list to include all native 3691168404Spjd * properties. 3692168404Spjd */ 3693168404Spjd last = plp; 3694168404Spjd 3695168404Spjd exp.last = last; 3696168404Spjd exp.hdl = hdl; 3697168404Spjd 3698168404Spjd if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type, 3699168404Spjd B_FALSE) == ZFS_PROP_INVAL) 3700168404Spjd return (-1); 3701168404Spjd 3702168404Spjd /* 3703168404Spjd * Add 'name' to the beginning of the list, which is handled 3704168404Spjd * specially. 3705168404Spjd */ 3706168404Spjd if ((entry = zfs_alloc(hdl, 3707168404Spjd sizeof (zfs_proplist_t))) == NULL) 3708168404Spjd return (-1); 3709168404Spjd 3710168404Spjd entry->pl_prop = ZFS_PROP_NAME; 3711168404Spjd entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 3712168404Spjd &entry->pl_fixed); 3713168404Spjd entry->pl_all = B_TRUE; 3714168404Spjd entry->pl_next = *plp; 3715168404Spjd *plp = entry; 3716168404Spjd } 3717168404Spjd return (0); 3718168404Spjd} 3719168404Spjd 3720168404Spjd/* 3721168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to 3722168404Spjd * display, and their maximum widths. This does two main things: 3723168404Spjd * 3724168404Spjd * - If this is a list of all properties, then expand the list to include 3725168404Spjd * all native properties, and set a flag so that for each dataset we look 3726168404Spjd * for new unique user properties and add them to the list. 3727168404Spjd * 3728168404Spjd * - For non fixed-width properties, keep track of the maximum width seen 3729168404Spjd * so that we can size the column appropriately. 3730168404Spjd */ 3731168404Spjdint 3732168404Spjdzfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 3733168404Spjd{ 3734168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3735168404Spjd zfs_proplist_t *entry; 3736168404Spjd zfs_proplist_t **last, **start; 3737168404Spjd nvlist_t *userprops, *propval; 3738168404Spjd nvpair_t *elem; 3739168404Spjd char *strval; 3740168404Spjd char buf[ZFS_MAXPROPLEN]; 3741168404Spjd 3742168404Spjd if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0) 3743168404Spjd return (-1); 3744168404Spjd 3745168404Spjd userprops = zfs_get_user_props(zhp); 3746168404Spjd 3747168404Spjd entry = *plp; 3748168404Spjd if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3749168404Spjd /* 3750168404Spjd * Go through and add any user properties as necessary. We 3751168404Spjd * start by incrementing our list pointer to the first 3752168404Spjd * non-native property. 3753168404Spjd */ 3754168404Spjd start = plp; 3755168404Spjd while (*start != NULL) { 3756168404Spjd if ((*start)->pl_prop == ZFS_PROP_INVAL) 3757168404Spjd break; 3758168404Spjd start = &(*start)->pl_next; 3759168404Spjd } 3760168404Spjd 3761168404Spjd elem = NULL; 3762168404Spjd while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3763168404Spjd /* 3764168404Spjd * See if we've already found this property in our list. 3765168404Spjd */ 3766168404Spjd for (last = start; *last != NULL; 3767168404Spjd last = &(*last)->pl_next) { 3768168404Spjd if (strcmp((*last)->pl_user_prop, 3769168404Spjd nvpair_name(elem)) == 0) 3770168404Spjd break; 3771168404Spjd } 3772168404Spjd 3773168404Spjd if (*last == NULL) { 3774168404Spjd if ((entry = zfs_alloc(hdl, 3775168404Spjd sizeof (zfs_proplist_t))) == NULL || 3776168404Spjd ((entry->pl_user_prop = zfs_strdup(hdl, 3777168404Spjd nvpair_name(elem)))) == NULL) { 3778168404Spjd free(entry); 3779168404Spjd return (-1); 3780168404Spjd } 3781168404Spjd 3782168404Spjd entry->pl_prop = ZFS_PROP_INVAL; 3783168404Spjd entry->pl_width = strlen(nvpair_name(elem)); 3784168404Spjd entry->pl_all = B_TRUE; 3785168404Spjd *last = entry; 3786168404Spjd } 3787168404Spjd } 3788168404Spjd } 3789168404Spjd 3790168404Spjd /* 3791168404Spjd * Now go through and check the width of any non-fixed columns 3792168404Spjd */ 3793168404Spjd for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3794168404Spjd if (entry->pl_fixed) 3795168404Spjd continue; 3796168404Spjd 3797168404Spjd if (entry->pl_prop != ZFS_PROP_INVAL) { 3798168404Spjd if (zfs_prop_get(zhp, entry->pl_prop, 3799168404Spjd buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3800168404Spjd if (strlen(buf) > entry->pl_width) 3801168404Spjd entry->pl_width = strlen(buf); 3802168404Spjd } 3803168404Spjd } else if (nvlist_lookup_nvlist(userprops, 3804168404Spjd entry->pl_user_prop, &propval) == 0) { 3805168404Spjd verify(nvlist_lookup_string(propval, 3806168404Spjd ZFS_PROP_VALUE, &strval) == 0); 3807168404Spjd if (strlen(strval) > entry->pl_width) 3808168404Spjd entry->pl_width = strlen(strval); 3809168404Spjd } 3810168404Spjd } 3811168404Spjd 3812168404Spjd return (0); 3813168404Spjd} 3814168404Spjd 3815168404Spjd/* 3816168404Spjd * Attach/detach the given filesystem to/from the given jail. 3817168404Spjd */ 3818168404Spjdint 3819168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach) 3820168404Spjd{ 3821168404Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 3822168404Spjd zfs_cmd_t zc = { 0 }; 3823168404Spjd char errbuf[1024]; 3824168404Spjd int cmd, ret; 3825168404Spjd 3826168404Spjd if (attach) { 3827168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3828168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 3829168404Spjd } else { 3830168404Spjd (void) snprintf(errbuf, sizeof (errbuf), 3831168404Spjd dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); 3832168404Spjd } 3833168404Spjd 3834168404Spjd switch (zhp->zfs_type) { 3835168404Spjd case ZFS_TYPE_VOLUME: 3836168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3837168404Spjd "volumes can not be jailed")); 3838168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3839168404Spjd case ZFS_TYPE_SNAPSHOT: 3840168404Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3841168404Spjd "snapshots can not be jailed")); 3842168404Spjd return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3843168404Spjd } 3844168404Spjd assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM); 3845168404Spjd 3846168404Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3847168404Spjd zc.zc_objset_type = DMU_OST_ZFS; 3848168404Spjd zc.zc_jailid = jailid; 3849168404Spjd 3850168404Spjd cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; 3851168404Spjd if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0) 3852168404Spjd zfs_standard_error(hdl, errno, errbuf); 3853168404Spjd 3854168404Spjd return (ret); 3855168404Spjd} 3856