1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221294Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <assert.h> 29789Sahrens #include <ctype.h> 30789Sahrens #include <errno.h> 31789Sahrens #include <libdevinfo.h> 32789Sahrens #include <libintl.h> 33789Sahrens #include <math.h> 34789Sahrens #include <stdio.h> 35789Sahrens #include <stdlib.h> 36789Sahrens #include <strings.h> 37789Sahrens #include <unistd.h> 38789Sahrens #include <zone.h> 392082Seschrock #include <fcntl.h> 40789Sahrens #include <sys/mntent.h> 41789Sahrens #include <sys/mnttab.h> 421294Slling #include <sys/mount.h> 43789Sahrens 44789Sahrens #include <sys/spa.h> 45789Sahrens #include <sys/zio.h> 46789Sahrens #include <libzfs.h> 47789Sahrens 48789Sahrens #include "zfs_namecheck.h" 49789Sahrens #include "zfs_prop.h" 50789Sahrens #include "libzfs_impl.h" 51789Sahrens 52789Sahrens /* 53789Sahrens * Given a single type (not a mask of types), return the type in a human 54789Sahrens * readable form. 55789Sahrens */ 56789Sahrens const char * 57789Sahrens zfs_type_to_name(zfs_type_t type) 58789Sahrens { 59789Sahrens switch (type) { 60789Sahrens case ZFS_TYPE_FILESYSTEM: 61789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 62789Sahrens case ZFS_TYPE_SNAPSHOT: 63789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 64789Sahrens case ZFS_TYPE_VOLUME: 65789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 66789Sahrens } 67789Sahrens 68789Sahrens return (NULL); 69789Sahrens } 70789Sahrens 71789Sahrens /* 72789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 73789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 74789Sahrens * We guess what the type would have been based on the path and the mask of 75789Sahrens * acceptable types. 76789Sahrens */ 77789Sahrens static const char * 78789Sahrens path_to_str(const char *path, int types) 79789Sahrens { 80789Sahrens /* 81789Sahrens * When given a single type, always report the exact type. 82789Sahrens */ 83789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 84789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 85789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 86789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 87789Sahrens if (types == ZFS_TYPE_VOLUME) 88789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 89789Sahrens 90789Sahrens /* 91789Sahrens * The user is requesting more than one type of dataset. If this is the 92789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 93789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 94789Sahrens * snapshot attribute and try again. 95789Sahrens */ 96789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 97789Sahrens if (strchr(path, '@') != NULL) 98789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 99789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 100789Sahrens } 101789Sahrens 102789Sahrens 103789Sahrens /* 104789Sahrens * The user has requested either filesystems or volumes. 105789Sahrens * We have no way of knowing a priori what type this would be, so always 106789Sahrens * report it as "filesystem" or "volume", our two primitive types. 107789Sahrens */ 108789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 109789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 110789Sahrens 111789Sahrens assert(types & ZFS_TYPE_VOLUME); 112789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 113789Sahrens } 114789Sahrens 115789Sahrens /* 116789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 117789Sahrens * provide a more meaningful error message. We place a more useful message in 118789Sahrens * 'buf' detailing exactly why the name was not valid. 119789Sahrens */ 120789Sahrens static int 1212082Seschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 122789Sahrens { 123789Sahrens namecheck_err_t why; 124789Sahrens char what; 125789Sahrens 126789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 1272082Seschrock if (hdl != NULL) { 128789Sahrens switch (why) { 1291003Slling case NAME_ERR_TOOLONG: 1302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1312082Seschrock "name is too long")); 1321003Slling break; 1331003Slling 134789Sahrens case NAME_ERR_LEADING_SLASH: 1352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1362082Seschrock "leading slash in name")); 137789Sahrens break; 138789Sahrens 139789Sahrens case NAME_ERR_EMPTY_COMPONENT: 1402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1412082Seschrock "empty component in name")); 142789Sahrens break; 143789Sahrens 144789Sahrens case NAME_ERR_TRAILING_SLASH: 1452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1462082Seschrock "trailing slash in name")); 147789Sahrens break; 148789Sahrens 149789Sahrens case NAME_ERR_INVALCHAR: 1502082Seschrock zfs_error_aux(hdl, 151789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 1522082Seschrock "'%c' in name"), what); 153789Sahrens break; 154789Sahrens 155789Sahrens case NAME_ERR_MULTIPLE_AT: 1562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1572082Seschrock "multiple '@' delimiters in name")); 158789Sahrens break; 159789Sahrens } 160789Sahrens } 161789Sahrens 162789Sahrens return (0); 163789Sahrens } 164789Sahrens 165789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 1662082Seschrock if (hdl != NULL) 1672082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1682082Seschrock "snapshot delimiter '@' in filesystem name")); 169789Sahrens return (0); 170789Sahrens } 171789Sahrens 1722199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1732199Sahrens if (hdl != NULL) 1742199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1752199Sahrens "missing '@' delimeter in snapshot name")); 1762199Sahrens return (0); 1772199Sahrens } 1782199Sahrens 1792082Seschrock return (-1); 180789Sahrens } 181789Sahrens 182789Sahrens int 183789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 184789Sahrens { 1852082Seschrock return (zfs_validate_name(NULL, name, type)); 186789Sahrens } 187789Sahrens 188789Sahrens /* 189789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 190789Sahrens */ 191789Sahrens static int 192789Sahrens get_stats(zfs_handle_t *zhp) 193789Sahrens { 194789Sahrens zfs_cmd_t zc = { 0 }; 195789Sahrens 196789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 197789Sahrens 1982082Seschrock if ((zc.zc_config_src = (uint64_t)(uintptr_t)malloc(1024)) == NULL) 1992082Seschrock return (-1); 2001356Seschrock zc.zc_config_src_size = 1024; 2011356Seschrock 2022082Seschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2031356Seschrock if (errno == ENOMEM) { 2042082Seschrock free((void *)(uintptr_t)zc.zc_config_src); 2052082Seschrock if ((zc.zc_config_src = (uint64_t)(uintptr_t) 2062082Seschrock malloc(zc.zc_config_src_size)) == NULL) 2072082Seschrock return (-1); 2081356Seschrock } else { 2091356Seschrock free((void *)(uintptr_t)zc.zc_config_src); 2101356Seschrock return (-1); 2111356Seschrock } 2121356Seschrock } 213789Sahrens 214789Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 215789Sahrens sizeof (zc.zc_objset_stats)); 216789Sahrens 2171544Seschrock (void) strcpy(zhp->zfs_root, zc.zc_root); 2181544Seschrock 2192082Seschrock if (zhp->zfs_props) { 2202082Seschrock nvlist_free(zhp->zfs_props); 2212082Seschrock zhp->zfs_props = NULL; 2222082Seschrock } 2232082Seschrock 2242082Seschrock if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_src, 2252082Seschrock zc.zc_config_src_size, &zhp->zfs_props, 0) != 0) { 2262082Seschrock free((void *)(uintptr_t)zc.zc_config_src); 2272082Seschrock return (-1); 2282082Seschrock } 229789Sahrens 230789Sahrens zhp->zfs_volsize = zc.zc_volsize; 231789Sahrens zhp->zfs_volblocksize = zc.zc_volblocksize; 232789Sahrens 2332082Seschrock free((void *)(uintptr_t)zc.zc_config_src); 2342082Seschrock 235789Sahrens return (0); 236789Sahrens } 237789Sahrens 238789Sahrens /* 239789Sahrens * Refresh the properties currently stored in the handle. 240789Sahrens */ 241789Sahrens void 242789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 243789Sahrens { 244789Sahrens (void) get_stats(zhp); 245789Sahrens } 246789Sahrens 247789Sahrens /* 248789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 249789Sahrens * zfs_iter_* to create child handles on the fly. 250789Sahrens */ 251789Sahrens zfs_handle_t * 2522082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 253789Sahrens { 2542082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 2552082Seschrock 2562082Seschrock if (zhp == NULL) 2572082Seschrock return (NULL); 2582082Seschrock 2592082Seschrock zhp->zfs_hdl = hdl; 260789Sahrens 2611758Sahrens top: 262789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 263789Sahrens 264789Sahrens if (get_stats(zhp) != 0) { 265789Sahrens free(zhp); 266789Sahrens return (NULL); 267789Sahrens } 268789Sahrens 2691758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 2701758Sahrens zfs_cmd_t zc = { 0 }; 2711758Sahrens 2721758Sahrens /* 2731758Sahrens * If it is dds_inconsistent, then we've caught it in 2741758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 2751758Sahrens * it is inconsistent from the ZPL's point of view, so 2761758Sahrens * can't be mounted. However, it could also be that we 2771758Sahrens * have crashed in the middle of one of those 2781758Sahrens * operations, in which case we need to get rid of the 2791758Sahrens * inconsistent state. We do that by either rolling 2801758Sahrens * back to the previous snapshot (which will fail if 2811758Sahrens * there is none), or destroying the filesystem. Note 2821758Sahrens * that if we are still in the middle of an active 2831758Sahrens * 'receive' or 'destroy', then the rollback and destroy 2841758Sahrens * will fail with EBUSY and we will drive on as usual. 2851758Sahrens */ 2861758Sahrens 2871758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2881758Sahrens 2891758Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2902082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 2911758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2921758Sahrens } else { 2931758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2941758Sahrens } 2951758Sahrens 2961758Sahrens /* If we can successfully roll it back, reget the stats */ 2972082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 2981758Sahrens goto top; 2991758Sahrens /* 3001758Sahrens * If we can sucessfully destroy it, pretend that it 3011758Sahrens * never existed. 3021758Sahrens */ 3032082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3041758Sahrens free(zhp); 3051758Sahrens errno = ENOENT; 3061758Sahrens return (NULL); 3071758Sahrens } 3081758Sahrens } 3091758Sahrens 310789Sahrens /* 311789Sahrens * We've managed to open the dataset and gather statistics. Determine 312789Sahrens * the high-level type. 313789Sahrens */ 314789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 315789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 316789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 317789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 318789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 319789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 320789Sahrens else 3212082Seschrock abort(); /* we should never see any other types */ 322789Sahrens 323789Sahrens return (zhp); 324789Sahrens } 325789Sahrens 326789Sahrens /* 327789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 328789Sahrens * argument is a mask of acceptable types. The function will print an 329789Sahrens * appropriate error message and return NULL if it can't be opened. 330789Sahrens */ 331789Sahrens zfs_handle_t * 3322082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 333789Sahrens { 334789Sahrens zfs_handle_t *zhp; 3352082Seschrock char errbuf[1024]; 3362082Seschrock 3372082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3382082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 339789Sahrens 340789Sahrens /* 3412082Seschrock * Validate the name before we even try to open it. 342789Sahrens */ 3432082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3452082Seschrock "invalid dataset name")); 3462082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 347789Sahrens return (NULL); 348789Sahrens } 349789Sahrens 350789Sahrens /* 351789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 352789Sahrens */ 353789Sahrens errno = 0; 3542082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 3552082Seschrock (void) zfs_standard_error(hdl, errno, errbuf, path); 356789Sahrens return (NULL); 357789Sahrens } 358789Sahrens 359789Sahrens if (!(types & zhp->zfs_type)) { 3602082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3612142Seschrock zfs_close(zhp); 362789Sahrens return (NULL); 363789Sahrens } 364789Sahrens 365789Sahrens return (zhp); 366789Sahrens } 367789Sahrens 368789Sahrens /* 369789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 370789Sahrens */ 371789Sahrens void 372789Sahrens zfs_close(zfs_handle_t *zhp) 373789Sahrens { 374789Sahrens if (zhp->zfs_mntopts) 375789Sahrens free(zhp->zfs_mntopts); 3762082Seschrock if (zhp->zfs_props) 3772082Seschrock nvlist_free(zhp->zfs_props); 378789Sahrens free(zhp); 379789Sahrens } 380789Sahrens 381789Sahrens struct { 382789Sahrens const char *name; 383789Sahrens uint64_t value; 384789Sahrens } checksum_table[] = { 385789Sahrens { "on", ZIO_CHECKSUM_ON }, 386789Sahrens { "off", ZIO_CHECKSUM_OFF }, 387789Sahrens { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 }, 388789Sahrens { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 }, 389789Sahrens { "sha256", ZIO_CHECKSUM_SHA256 }, 390789Sahrens { NULL } 391789Sahrens }; 392789Sahrens 393789Sahrens struct { 394789Sahrens const char *name; 395789Sahrens uint64_t value; 396789Sahrens } compress_table[] = { 397789Sahrens { "on", ZIO_COMPRESS_ON }, 398789Sahrens { "off", ZIO_COMPRESS_OFF }, 399789Sahrens { "lzjb", ZIO_COMPRESS_LZJB }, 400789Sahrens { NULL } 401789Sahrens }; 402789Sahrens 403789Sahrens struct { 404789Sahrens const char *name; 405789Sahrens uint64_t value; 406789Sahrens } snapdir_table[] = { 407849Sbonwick { "hidden", ZFS_SNAPDIR_HIDDEN }, 408849Sbonwick { "visible", ZFS_SNAPDIR_VISIBLE }, 409789Sahrens { NULL } 410789Sahrens }; 411789Sahrens 412789Sahrens struct { 413789Sahrens const char *name; 414789Sahrens uint64_t value; 415789Sahrens } acl_mode_table[] = { 416789Sahrens { "discard", DISCARD }, 417789Sahrens { "groupmask", GROUPMASK }, 418789Sahrens { "passthrough", PASSTHROUGH }, 419789Sahrens { NULL } 420789Sahrens }; 421789Sahrens 422789Sahrens struct { 423789Sahrens const char *name; 424789Sahrens uint64_t value; 425789Sahrens } acl_inherit_table[] = { 426789Sahrens { "discard", DISCARD }, 427789Sahrens { "noallow", NOALLOW }, 428789Sahrens { "secure", SECURE }, 429789Sahrens { "passthrough", PASSTHROUGH }, 430789Sahrens { NULL } 431789Sahrens }; 432789Sahrens 433789Sahrens 434789Sahrens /* 435789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 436789Sahrens * resulting value must be shifted. 437789Sahrens */ 438789Sahrens static int 4392082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 440789Sahrens { 441789Sahrens const char *ends = "BKMGTPEZ"; 442789Sahrens int i; 443789Sahrens 444789Sahrens if (buf[0] == '\0') 445789Sahrens return (0); 446789Sahrens for (i = 0; i < strlen(ends); i++) { 447789Sahrens if (toupper(buf[0]) == ends[i]) 448789Sahrens break; 449789Sahrens } 450789Sahrens if (i == strlen(ends)) { 4512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4522082Seschrock "invalid numeric suffix '%s'"), buf); 453789Sahrens return (-1); 454789Sahrens } 455789Sahrens 456789Sahrens /* 457789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 458789Sahrens * allow 'BB' - that's just weird. 459789Sahrens */ 460789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4612082Seschrock toupper(buf[0]) != 'B')) 462789Sahrens return (10*i); 4632082Seschrock 4642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4652082Seschrock "invalid numeric suffix '%s'"), buf); 466789Sahrens return (-1); 467789Sahrens } 468789Sahrens 469789Sahrens /* 470789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 471789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 472789Sahrens * message for the caller to use. 473789Sahrens */ 474789Sahrens static int 4752082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 476789Sahrens { 477789Sahrens char *end; 478789Sahrens int shift; 479789Sahrens 480789Sahrens *num = 0; 481789Sahrens 482789Sahrens /* Check to see if this looks like a number. */ 483789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4842082Seschrock if (hdl) 4852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4862082Seschrock "bad numeric value '%s'"), value); 487789Sahrens return (-1); 488789Sahrens } 489789Sahrens 490789Sahrens /* Rely on stroll() to process the numeric portion. */ 491789Sahrens errno = 0; 492789Sahrens *num = strtoll(value, &end, 10); 493789Sahrens 494789Sahrens /* 495789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 496789Sahrens * in a 64-bit value. 497789Sahrens */ 498789Sahrens if (errno == ERANGE) { 4992082Seschrock if (hdl) 5002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5012082Seschrock "numeric value is too large")); 502789Sahrens return (-1); 503789Sahrens } 504789Sahrens 505789Sahrens /* 506789Sahrens * If we have a decimal value, then do the computation with floating 507789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 508789Sahrens */ 509789Sahrens if (*end == '.') { 510789Sahrens double fval = strtod(value, &end); 511789Sahrens 5122082Seschrock if ((shift = str2shift(hdl, end)) == -1) 513789Sahrens return (-1); 514789Sahrens 515789Sahrens fval *= pow(2, shift); 516789Sahrens 517789Sahrens if (fval > UINT64_MAX) { 5182082Seschrock if (hdl) 5192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5202082Seschrock "numeric value is too large")); 521789Sahrens return (-1); 522789Sahrens } 523789Sahrens 524789Sahrens *num = (uint64_t)fval; 525789Sahrens } else { 5262082Seschrock if ((shift = str2shift(hdl, end)) == -1) 527789Sahrens return (-1); 528789Sahrens 529789Sahrens /* Check for overflow */ 530789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5312082Seschrock if (hdl) 5322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5332082Seschrock "numeric value is too large")); 534789Sahrens return (-1); 535789Sahrens } 536789Sahrens 537789Sahrens *num <<= shift; 538789Sahrens } 539789Sahrens 540789Sahrens return (0); 541789Sahrens } 542789Sahrens 543789Sahrens int 544789Sahrens zfs_nicestrtonum(const char *str, uint64_t *val) 545789Sahrens { 5462082Seschrock return (nicestrtonum(NULL, str, val)); 547789Sahrens } 548789Sahrens 549789Sahrens /* 550789Sahrens * Given a property type and value, verify that the value is appropriate. Used 551789Sahrens * by zfs_prop_set() and some libzfs consumers. 552789Sahrens */ 553789Sahrens int 5542082Seschrock zfs_prop_validate(libzfs_handle_t *hdl, zfs_prop_t prop, const char *value, 5552082Seschrock uint64_t *intval) 556789Sahrens { 557789Sahrens const char *propname = zfs_prop_to_name(prop); 558789Sahrens uint64_t number; 5592082Seschrock char errbuf[1024]; 560789Sahrens int i; 561789Sahrens 562789Sahrens /* 563789Sahrens * Check to see if this a read-only property. 564789Sahrens */ 5652082Seschrock if (zfs_prop_readonly(prop)) 5662082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, 5672082Seschrock dgettext(TEXT_DOMAIN, "cannot set %s property"), propname)); 5682082Seschrock 5692082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 5702082Seschrock dgettext(TEXT_DOMAIN, "bad %s value '%s'"), propname, value); 571789Sahrens 572789Sahrens /* See if the property value is too long */ 573789Sahrens if (strlen(value) >= ZFS_MAXPROPLEN) { 5742082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "value is too long")); 5752082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 576789Sahrens } 577789Sahrens 578789Sahrens /* Perform basic checking based on property type */ 579789Sahrens switch (zfs_prop_get_type(prop)) { 580789Sahrens case prop_type_boolean: 581789Sahrens if (strcmp(value, "on") == 0) { 582789Sahrens number = 1; 583789Sahrens } else if (strcmp(value, "off") == 0) { 584789Sahrens number = 0; 585789Sahrens } else { 5862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5872082Seschrock "must be 'on' or 'off'")); 5882082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 589789Sahrens } 590789Sahrens break; 591789Sahrens 592789Sahrens case prop_type_number: 593789Sahrens /* treat 'none' as 0 */ 594789Sahrens if (strcmp(value, "none") == 0) { 595789Sahrens number = 0; 596789Sahrens break; 597789Sahrens } 598789Sahrens 5992082Seschrock if (nicestrtonum(hdl, value, &number) != 0) 6002082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 601789Sahrens 602789Sahrens /* don't allow 0 for quota, use 'none' instead */ 603789Sahrens if (prop == ZFS_PROP_QUOTA && number == 0 && 604789Sahrens strcmp(value, "none") != 0) { 6052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6062082Seschrock "use 'quota=none' to disable")); 6072082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 608789Sahrens } 609789Sahrens 610789Sahrens /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 611789Sahrens if (prop == ZFS_PROP_RECORDSIZE || 612789Sahrens prop == ZFS_PROP_VOLBLOCKSIZE) { 613789Sahrens if (number < SPA_MINBLOCKSIZE || 614789Sahrens number > SPA_MAXBLOCKSIZE || !ISP2(number)) { 6152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 616789Sahrens "must be power of 2 from %u to %uk"), 617789Sahrens (uint_t)SPA_MINBLOCKSIZE, 618789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 6192082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 620789Sahrens } 621789Sahrens } 622789Sahrens 623789Sahrens break; 624789Sahrens 625789Sahrens case prop_type_string: 626789Sahrens case prop_type_index: 627789Sahrens /* 628789Sahrens * The two writable string values, 'mountpoint' and 629789Sahrens * 'checksum' need special consideration. The 'index' types are 630789Sahrens * specified as strings by the user, but passed to the kernel as 631789Sahrens * integers. 632789Sahrens */ 633789Sahrens switch (prop) { 634789Sahrens case ZFS_PROP_MOUNTPOINT: 635789Sahrens if (strcmp(value, ZFS_MOUNTPOINT_NONE) == 0 || 636789Sahrens strcmp(value, ZFS_MOUNTPOINT_LEGACY) == 0) 637789Sahrens break; 638789Sahrens 639789Sahrens if (value[0] != '/') { 6402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6412082Seschrock "must be an absolute path, 'none', or " 6422082Seschrock "'legacy'")); 6432082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 644789Sahrens } 645789Sahrens break; 646789Sahrens 647789Sahrens case ZFS_PROP_CHECKSUM: 648789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 649789Sahrens if (strcmp(value, checksum_table[i].name) 650789Sahrens == 0) { 651789Sahrens number = checksum_table[i].value; 652789Sahrens break; 653789Sahrens } 654789Sahrens } 655789Sahrens 656789Sahrens if (checksum_table[i].name == NULL) { 6572082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6582082Seschrock "must be 'on', 'off', 'fletcher2', " 6592082Seschrock "'fletcher4', or 'sha256'")); 6602082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 661789Sahrens } 662789Sahrens break; 663789Sahrens 664789Sahrens case ZFS_PROP_COMPRESSION: 665789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 666789Sahrens if (strcmp(value, compress_table[i].name) 667789Sahrens == 0) { 668789Sahrens number = compress_table[i].value; 669789Sahrens break; 670789Sahrens } 671789Sahrens } 672789Sahrens 673789Sahrens if (compress_table[i].name == NULL) { 6742082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6752082Seschrock "must be 'on', 'off', or 'lzjb'")); 6762082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 677789Sahrens } 678789Sahrens break; 679789Sahrens 680789Sahrens case ZFS_PROP_SNAPDIR: 681789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 682789Sahrens if (strcmp(value, snapdir_table[i].name) == 0) { 683789Sahrens number = snapdir_table[i].value; 684789Sahrens break; 685789Sahrens } 686789Sahrens } 687789Sahrens 688789Sahrens if (snapdir_table[i].name == NULL) { 6892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6902082Seschrock "must be 'hidden' or 'visible'")); 6912082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 692789Sahrens } 693789Sahrens break; 694789Sahrens 695789Sahrens case ZFS_PROP_ACLMODE: 696789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 697789Sahrens if (strcmp(value, acl_mode_table[i].name) 698789Sahrens == 0) { 699789Sahrens number = acl_mode_table[i].value; 700789Sahrens break; 701789Sahrens } 702789Sahrens } 703789Sahrens 704789Sahrens if (acl_mode_table[i].name == NULL) { 7052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7062082Seschrock "must be 'disacard', 'groupmask', or " 7072082Seschrock "'passthrough'")); 7082082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 709789Sahrens } 710789Sahrens break; 711789Sahrens 712789Sahrens case ZFS_PROP_ACLINHERIT: 713789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 714789Sahrens if (strcmp(value, acl_inherit_table[i].name) 715789Sahrens == 0) { 716789Sahrens number = acl_inherit_table[i].value; 717789Sahrens break; 718789Sahrens } 719789Sahrens } 720789Sahrens 721789Sahrens if (acl_inherit_table[i].name == NULL) { 7222082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7232082Seschrock "must be 'discard, 'noallow', 'secure', " 7242082Seschrock "or 'passthrough'")); 7252082Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 726789Sahrens } 727789Sahrens break; 728789Sahrens 729789Sahrens case ZFS_PROP_SHARENFS: 730789Sahrens /* 731789Sahrens * Nothing to do for 'sharenfs', this gets passed on to 732789Sahrens * share(1M) verbatim. 733789Sahrens */ 734789Sahrens break; 735789Sahrens } 736789Sahrens } 737789Sahrens 738789Sahrens if (intval != NULL) 739789Sahrens *intval = number; 740789Sahrens 741789Sahrens return (0); 742789Sahrens } 743789Sahrens 744789Sahrens /* 745789Sahrens * Given a property name and value, set the property for the given dataset. 746789Sahrens */ 747789Sahrens int 748789Sahrens zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval) 749789Sahrens { 750789Sahrens const char *propname = zfs_prop_to_name(prop); 751789Sahrens uint64_t number; 752789Sahrens zfs_cmd_t zc = { 0 }; 753789Sahrens int ret; 754789Sahrens prop_changelist_t *cl; 7552082Seschrock char errbuf[1024]; 7562082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7572082Seschrock 7582082Seschrock if (zfs_prop_validate(zhp->zfs_hdl, prop, propval, &number) != 0) 759789Sahrens return (-1); 760789Sahrens 7612082Seschrock 7622082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 7632082Seschrock dgettext(TEXT_DOMAIN, "cannot set %s for '%s'"), propname, 7642082Seschrock zhp->zfs_name); 7652082Seschrock 766789Sahrens /* 767789Sahrens * Check to see if the value applies to this type 768789Sahrens */ 7692082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 7702082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 771789Sahrens 772789Sahrens /* 773789Sahrens * For the mountpoint and sharenfs properties, check if it can be set 774789Sahrens * in a global/non-global zone based on the zoned property value: 775789Sahrens * 776789Sahrens * global zone non-global zone 777789Sahrens * ----------------------------------------------------- 778789Sahrens * zoned=on mountpoint (no) mountpoint (yes) 779789Sahrens * sharenfs (no) sharenfs (no) 780789Sahrens * 781789Sahrens * zoned=off mountpoint (yes) N/A 782789Sahrens * sharenfs (yes) 783789Sahrens */ 784789Sahrens if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 785789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 786789Sahrens if (getzoneid() == GLOBAL_ZONEID) { 7872082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7882082Seschrock "dataset is used in a non-global zone")); 7892082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 790789Sahrens } else if (prop == ZFS_PROP_SHARENFS) { 7912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7922082Seschrock "filesystems cannot be shared in a " 7932082Seschrock "non-global zone")); 7942082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 795789Sahrens } 796789Sahrens } else if (getzoneid() != GLOBAL_ZONEID) { 797789Sahrens /* 798789Sahrens * If zoned property is 'off', this must be in 799789Sahrens * a globle zone. If not, something is wrong. 800789Sahrens */ 8012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8022082Seschrock "dataset is used in a non-global zone, but " 8032082Seschrock "'zoned' property is not set")); 8042082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 805789Sahrens } 806789Sahrens } 807789Sahrens 808789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 809789Sahrens return (-1); 810789Sahrens 811789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 8122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8132082Seschrock "child dataset with inherited mountpoint is used " 8142082Seschrock "in a non-global zone")); 8152082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 816789Sahrens goto error; 817789Sahrens } 818789Sahrens 819789Sahrens if ((ret = changelist_prefix(cl)) != 0) 820789Sahrens goto error; 821789Sahrens 822789Sahrens /* 823789Sahrens * Execute the corresponding ioctl() to set this property. 824789Sahrens */ 825789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 826789Sahrens 827789Sahrens switch (prop) { 828789Sahrens case ZFS_PROP_QUOTA: 829789Sahrens zc.zc_cookie = number; 8302082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_QUOTA, &zc); 831789Sahrens break; 832789Sahrens case ZFS_PROP_RESERVATION: 833789Sahrens zc.zc_cookie = number; 8342082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_RESERVATION, 8352082Seschrock &zc); 836789Sahrens break; 837789Sahrens case ZFS_PROP_MOUNTPOINT: 838789Sahrens case ZFS_PROP_SHARENFS: 839789Sahrens /* 840789Sahrens * These properties are passed down as real strings. 841789Sahrens */ 842789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 843789Sahrens sizeof (zc.zc_prop_name)); 844789Sahrens (void) strlcpy(zc.zc_prop_value, propval, 845789Sahrens sizeof (zc.zc_prop_value)); 846789Sahrens zc.zc_intsz = 1; 847789Sahrens zc.zc_numints = strlen(propval) + 1; 8482082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 849789Sahrens break; 850789Sahrens case ZFS_PROP_VOLSIZE: 851789Sahrens zc.zc_volsize = number; 8522082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLSIZE, &zc); 853789Sahrens break; 854789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 855789Sahrens zc.zc_volblocksize = number; 8562082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLBLOCKSIZE, 8572082Seschrock &zc); 858789Sahrens break; 859789Sahrens default: 860789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 861789Sahrens sizeof (zc.zc_prop_name)); 862789Sahrens /* LINTED - alignment */ 863789Sahrens *(uint64_t *)zc.zc_prop_value = number; 864789Sahrens zc.zc_intsz = 8; 865789Sahrens zc.zc_numints = 1; 8662082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 867789Sahrens break; 868789Sahrens } 869789Sahrens 870789Sahrens if (ret != 0) { 871789Sahrens switch (errno) { 872789Sahrens 873789Sahrens case ENOSPC: 874789Sahrens /* 875789Sahrens * For quotas and reservations, ENOSPC indicates 876789Sahrens * something different; setting a quota or reservation 877789Sahrens * doesn't use any disk space. 878789Sahrens */ 879789Sahrens switch (prop) { 880789Sahrens case ZFS_PROP_QUOTA: 8812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8822082Seschrock "size is less than current used or " 8832082Seschrock "reserved space")); 8842082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 885789Sahrens break; 886789Sahrens 887789Sahrens case ZFS_PROP_RESERVATION: 8882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8892082Seschrock "size is greater than available space")); 8902082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 891789Sahrens break; 892789Sahrens 893789Sahrens default: 8942082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 895789Sahrens break; 896789Sahrens } 897789Sahrens break; 898789Sahrens 899789Sahrens case EBUSY: 9002082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 9012082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 9022082Seschrock else 9032082Seschrock return (zfs_standard_error(hdl, EBUSY, errbuf)); 904789Sahrens break; 905789Sahrens 9061175Slling case EROFS: 9072082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 9081175Slling break; 9091175Slling 910789Sahrens case EOVERFLOW: 911789Sahrens /* 912789Sahrens * This platform can't address a volume this big. 913789Sahrens */ 914789Sahrens #ifdef _ILP32 915789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 9162082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 917789Sahrens break; 918789Sahrens } 919789Sahrens #endif 9202082Seschrock /* FALLTHROUGH */ 921789Sahrens default: 9222082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 923789Sahrens } 924789Sahrens } else { 925789Sahrens /* 926789Sahrens * Refresh the statistics so the new property value 927789Sahrens * is reflected. 928789Sahrens */ 929789Sahrens if ((ret = changelist_postfix(cl)) != 0) 930789Sahrens goto error; 931789Sahrens 932789Sahrens (void) get_stats(zhp); 933789Sahrens } 934789Sahrens 935789Sahrens error: 936789Sahrens changelist_free(cl); 937789Sahrens return (ret); 938789Sahrens } 939789Sahrens 940789Sahrens /* 941789Sahrens * Given a property, inherit the value from the parent dataset. 942789Sahrens */ 943789Sahrens int 944789Sahrens zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop) 945789Sahrens { 946789Sahrens const char *propname = zfs_prop_to_name(prop); 947789Sahrens zfs_cmd_t zc = { 0 }; 948789Sahrens int ret; 949789Sahrens prop_changelist_t *cl; 9502082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 9512082Seschrock char errbuf[1024]; 9522082Seschrock 9532082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 9542082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 955789Sahrens 956789Sahrens /* 957789Sahrens * Verify that this property is inheritable. 958789Sahrens */ 9592082Seschrock if (zfs_prop_readonly(prop)) 9602082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 9612082Seschrock 9622082Seschrock if (!zfs_prop_inheritable(prop)) 9632082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 964789Sahrens 965789Sahrens /* 966789Sahrens * Check to see if the value applies to this type 967789Sahrens */ 9682082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 9692082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 970789Sahrens 971789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 972789Sahrens (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name)); 973789Sahrens 974789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 975789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 9762082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9772082Seschrock "dataset is used in a non-global zone")); 9782082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 979789Sahrens } 980789Sahrens 981789Sahrens /* 982789Sahrens * Determine datasets which will be affected by this change, if any. 983789Sahrens */ 984789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 985789Sahrens return (-1); 986789Sahrens 987789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 9882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9892082Seschrock "child dataset with inherited mountpoint is used " 9902082Seschrock "in a non-global zone")); 9912082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 992789Sahrens goto error; 993789Sahrens } 994789Sahrens 995789Sahrens if ((ret = changelist_prefix(cl)) != 0) 996789Sahrens goto error; 997789Sahrens 998789Sahrens zc.zc_numints = 0; 999789Sahrens 10002082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 10012082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 10022082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1003789Sahrens } else { 1004789Sahrens 10052169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1006789Sahrens goto error; 1007789Sahrens 1008789Sahrens /* 1009789Sahrens * Refresh the statistics so the new property is reflected. 1010789Sahrens */ 1011789Sahrens (void) get_stats(zhp); 1012789Sahrens } 1013789Sahrens 1014789Sahrens 1015789Sahrens error: 1016789Sahrens changelist_free(cl); 1017789Sahrens return (ret); 1018789Sahrens } 1019789Sahrens 1020789Sahrens static void 1021789Sahrens nicebool(int value, char *buf, size_t buflen) 1022789Sahrens { 1023789Sahrens if (value) 1024789Sahrens (void) strlcpy(buf, "on", buflen); 1025789Sahrens else 1026789Sahrens (void) strlcpy(buf, "off", buflen); 1027789Sahrens } 1028789Sahrens 1029789Sahrens /* 10301356Seschrock * True DSL properties are stored in an nvlist. The following two functions 10311356Seschrock * extract them appropriately. 10321356Seschrock */ 10331356Seschrock static uint64_t 10341356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10351356Seschrock { 10361356Seschrock nvlist_t *nv; 10371356Seschrock uint64_t value; 10381356Seschrock 10391356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10401356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 10411356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 10421356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10431356Seschrock } else { 10441356Seschrock value = zfs_prop_default_numeric(prop); 10451356Seschrock *source = ""; 10461356Seschrock } 10471356Seschrock 10481356Seschrock return (value); 10491356Seschrock } 10501356Seschrock 10511356Seschrock static char * 10521356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10531356Seschrock { 10541356Seschrock nvlist_t *nv; 10551356Seschrock char *value; 10561356Seschrock 10571356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10581356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 10591356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 10601356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10611356Seschrock } else { 10621356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 10631356Seschrock value = ""; 10641356Seschrock *source = ""; 10651356Seschrock } 10661356Seschrock 10671356Seschrock return (value); 10681356Seschrock } 10691356Seschrock 10701356Seschrock /* 1071789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1072789Sahrens * zfs_prop_get_int() are built using this interface. 1073789Sahrens * 1074789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1075789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1076789Sahrens * If they differ from the on-disk values, report the current values and mark 1077789Sahrens * the source "temporary". 1078789Sahrens */ 10792082Seschrock static int 1080789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 10812082Seschrock char **source, uint64_t *val) 1082789Sahrens { 1083789Sahrens struct mnttab mnt; 1084789Sahrens 1085789Sahrens *source = NULL; 1086789Sahrens 10872474Seschrock /* 10882474Seschrock * Because looking up the mount options is potentially expensive 10892474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 10902474Seschrock * we're looking up a property which requires its presence. 10912474Seschrock */ 10922474Seschrock if (!zhp->zfs_mntcheck && 10932474Seschrock (prop == ZFS_PROP_ATIME || 10942474Seschrock prop == ZFS_PROP_DEVICES || 10952474Seschrock prop == ZFS_PROP_EXEC || 10962474Seschrock prop == ZFS_PROP_READONLY || 10972474Seschrock prop == ZFS_PROP_SETUID || 10982474Seschrock prop == ZFS_PROP_MOUNTED)) { 10992474Seschrock struct mnttab search = { 0 }, entry; 11002474Seschrock 11012474Seschrock search.mnt_special = (char *)zhp->zfs_name; 11022474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 11032474Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 11042474Seschrock 11052474Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 11062474Seschrock &search) == 0 && (zhp->zfs_mntopts = 11072474Seschrock zfs_strdup(zhp->zfs_hdl, 11082474Seschrock entry.mnt_mntopts)) == NULL) 11092474Seschrock return (-1); 11102474Seschrock 11112474Seschrock zhp->zfs_mntcheck = B_TRUE; 11122474Seschrock } 11132474Seschrock 1114789Sahrens if (zhp->zfs_mntopts == NULL) 1115789Sahrens mnt.mnt_mntopts = ""; 1116789Sahrens else 1117789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1118789Sahrens 1119789Sahrens switch (prop) { 1120789Sahrens case ZFS_PROP_ATIME: 11212082Seschrock *val = getprop_uint64(zhp, prop, source); 11222082Seschrock 11232082Seschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 11242082Seschrock *val = B_TRUE; 1125789Sahrens if (src) 1126789Sahrens *src = ZFS_SRC_TEMPORARY; 11272082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 11282082Seschrock *val = B_FALSE; 1129789Sahrens if (src) 1130789Sahrens *src = ZFS_SRC_TEMPORARY; 1131789Sahrens } 11322082Seschrock break; 1133789Sahrens 1134789Sahrens case ZFS_PROP_AVAILABLE: 11352082Seschrock *val = zhp->zfs_dmustats.dds_available; 11362082Seschrock break; 1137789Sahrens 1138789Sahrens case ZFS_PROP_DEVICES: 11392082Seschrock *val = getprop_uint64(zhp, prop, source); 11402082Seschrock 11412082Seschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 11422082Seschrock *val = B_TRUE; 1143789Sahrens if (src) 1144789Sahrens *src = ZFS_SRC_TEMPORARY; 11452082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 11462082Seschrock *val = B_FALSE; 1147789Sahrens if (src) 1148789Sahrens *src = ZFS_SRC_TEMPORARY; 1149789Sahrens } 11502082Seschrock break; 1151789Sahrens 1152789Sahrens case ZFS_PROP_EXEC: 11532082Seschrock *val = getprop_uint64(zhp, prop, source); 11542082Seschrock 11552082Seschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 11562082Seschrock *val = B_TRUE; 1157789Sahrens if (src) 1158789Sahrens *src = ZFS_SRC_TEMPORARY; 11592082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 11602082Seschrock *val = B_FALSE; 1161789Sahrens if (src) 1162789Sahrens *src = ZFS_SRC_TEMPORARY; 1163789Sahrens } 11642082Seschrock break; 1165789Sahrens 1166789Sahrens case ZFS_PROP_RECORDSIZE: 1167789Sahrens case ZFS_PROP_COMPRESSION: 11681356Seschrock case ZFS_PROP_ZONED: 11692082Seschrock *val = getprop_uint64(zhp, prop, source); 11702082Seschrock break; 1171789Sahrens 1172789Sahrens case ZFS_PROP_READONLY: 11732082Seschrock *val = getprop_uint64(zhp, prop, source); 11742082Seschrock 11752082Seschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 11762082Seschrock *val = B_TRUE; 1177789Sahrens if (src) 1178789Sahrens *src = ZFS_SRC_TEMPORARY; 11792082Seschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 11802082Seschrock *val = B_FALSE; 1181789Sahrens if (src) 1182789Sahrens *src = ZFS_SRC_TEMPORARY; 1183789Sahrens } 11842082Seschrock break; 1185789Sahrens 11861544Seschrock case ZFS_PROP_CREATION: 11872082Seschrock *val = zhp->zfs_dmustats.dds_creation_time; 11882082Seschrock break; 11891544Seschrock 1190789Sahrens case ZFS_PROP_QUOTA: 1191789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1192789Sahrens *source = ""; /* default */ 1193789Sahrens else 1194789Sahrens *source = zhp->zfs_name; 11952082Seschrock *val = zhp->zfs_dmustats.dds_quota; 11962082Seschrock break; 1197789Sahrens 1198789Sahrens case ZFS_PROP_RESERVATION: 1199789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1200789Sahrens *source = ""; /* default */ 1201789Sahrens else 1202789Sahrens *source = zhp->zfs_name; 12032082Seschrock *val = zhp->zfs_dmustats.dds_reserved; 12042082Seschrock break; 1205789Sahrens 1206789Sahrens case ZFS_PROP_COMPRESSRATIO: 1207789Sahrens /* 1208789Sahrens * Using physical space and logical space, calculate the 1209789Sahrens * compression ratio. We return the number as a multiple of 1210789Sahrens * 100, so '2.5x' would be returned as 250. 1211789Sahrens */ 1212789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 12132082Seschrock *val = 100ULL; 1214789Sahrens else 12152082Seschrock *val = 12162082Seschrock (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1217789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 12182082Seschrock break; 1219789Sahrens 1220789Sahrens case ZFS_PROP_REFERENCED: 1221789Sahrens /* 1222789Sahrens * 'referenced' refers to the amount of physical space 1223789Sahrens * referenced (possibly shared) by this object. 1224789Sahrens */ 12252082Seschrock *val = zhp->zfs_dmustats.dds_space_refd; 12262082Seschrock break; 1227789Sahrens 1228789Sahrens case ZFS_PROP_SETUID: 12292082Seschrock *val = getprop_uint64(zhp, prop, source); 12302082Seschrock 12312082Seschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 12322082Seschrock *val = B_TRUE; 1233789Sahrens if (src) 1234789Sahrens *src = ZFS_SRC_TEMPORARY; 12352082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 12362082Seschrock *val = B_FALSE; 1237789Sahrens if (src) 1238789Sahrens *src = ZFS_SRC_TEMPORARY; 1239789Sahrens } 12402082Seschrock break; 1241789Sahrens 1242789Sahrens case ZFS_PROP_VOLSIZE: 12432082Seschrock *val = zhp->zfs_volsize; 12442082Seschrock break; 1245789Sahrens 1246789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 12472082Seschrock *val = zhp->zfs_volblocksize; 12482082Seschrock break; 1249789Sahrens 1250789Sahrens case ZFS_PROP_USED: 12512082Seschrock *val = zhp->zfs_dmustats.dds_space_used; 12522082Seschrock break; 1253789Sahrens 1254789Sahrens case ZFS_PROP_CREATETXG: 12552082Seschrock *val = zhp->zfs_dmustats.dds_creation_txg; 12562082Seschrock break; 1257789Sahrens 1258789Sahrens case ZFS_PROP_MOUNTED: 12592082Seschrock *val = (zhp->zfs_mntopts != NULL); 12602082Seschrock break; 1261789Sahrens 1262789Sahrens default: 12632082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 12642082Seschrock "cannot get non-numeric property")); 12652082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 12662082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1267789Sahrens } 1268789Sahrens 1269789Sahrens return (0); 1270789Sahrens } 1271789Sahrens 1272789Sahrens /* 1273789Sahrens * Calculate the source type, given the raw source string. 1274789Sahrens */ 1275789Sahrens static void 1276789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1277789Sahrens char *statbuf, size_t statlen) 1278789Sahrens { 1279789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1280789Sahrens return; 1281789Sahrens 1282789Sahrens if (source == NULL) { 1283789Sahrens *srctype = ZFS_SRC_NONE; 1284789Sahrens } else if (source[0] == '\0') { 1285789Sahrens *srctype = ZFS_SRC_DEFAULT; 1286789Sahrens } else { 1287789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1288789Sahrens *srctype = ZFS_SRC_LOCAL; 1289789Sahrens } else { 1290789Sahrens (void) strlcpy(statbuf, source, statlen); 1291789Sahrens *srctype = ZFS_SRC_INHERITED; 1292789Sahrens } 1293789Sahrens } 1294789Sahrens 1295789Sahrens } 1296789Sahrens 1297789Sahrens /* 1298789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1299789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1300789Sahrens * human-readable form. 1301789Sahrens * 1302789Sahrens * Returns 0 on success, or -1 on error. 1303789Sahrens */ 1304789Sahrens int 1305789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 13062082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1307789Sahrens { 1308789Sahrens char *source = NULL; 1309789Sahrens uint64_t val; 1310789Sahrens char *str; 1311789Sahrens int i; 1312789Sahrens const char *root; 1313789Sahrens 1314789Sahrens /* 1315789Sahrens * Check to see if this property applies to our object 1316789Sahrens */ 1317789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1318789Sahrens return (-1); 1319789Sahrens 1320789Sahrens if (src) 1321789Sahrens *src = ZFS_SRC_NONE; 1322789Sahrens 1323789Sahrens switch (prop) { 1324789Sahrens case ZFS_PROP_ATIME: 1325789Sahrens case ZFS_PROP_READONLY: 1326789Sahrens case ZFS_PROP_SETUID: 1327789Sahrens case ZFS_PROP_ZONED: 1328789Sahrens case ZFS_PROP_DEVICES: 1329789Sahrens case ZFS_PROP_EXEC: 1330789Sahrens /* 1331789Sahrens * Basic boolean values are built on top of 1332789Sahrens * get_numeric_property(). 1333789Sahrens */ 13342082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 13352082Seschrock return (-1); 13362082Seschrock nicebool(val, propbuf, proplen); 1337789Sahrens 1338789Sahrens break; 1339789Sahrens 1340789Sahrens case ZFS_PROP_AVAILABLE: 1341789Sahrens case ZFS_PROP_RECORDSIZE: 1342789Sahrens case ZFS_PROP_CREATETXG: 1343789Sahrens case ZFS_PROP_REFERENCED: 1344789Sahrens case ZFS_PROP_USED: 1345789Sahrens case ZFS_PROP_VOLSIZE: 1346789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1347789Sahrens /* 1348789Sahrens * Basic numeric values are built on top of 1349789Sahrens * get_numeric_property(). 1350789Sahrens */ 13512082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 13522082Seschrock return (-1); 1353789Sahrens if (literal) 1354789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1355789Sahrens else 1356789Sahrens zfs_nicenum(val, propbuf, proplen); 1357789Sahrens break; 1358789Sahrens 1359789Sahrens case ZFS_PROP_COMPRESSION: 13601356Seschrock val = getprop_uint64(zhp, prop, &source); 1361789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 13621356Seschrock if (compress_table[i].value == val) 1363789Sahrens break; 1364789Sahrens } 1365789Sahrens assert(compress_table[i].name != NULL); 1366789Sahrens (void) strlcpy(propbuf, compress_table[i].name, proplen); 1367789Sahrens break; 1368789Sahrens 1369789Sahrens case ZFS_PROP_CHECKSUM: 13701356Seschrock val = getprop_uint64(zhp, prop, &source); 1371789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 13721356Seschrock if (checksum_table[i].value == val) 1373789Sahrens break; 1374789Sahrens } 1375789Sahrens assert(checksum_table[i].name != NULL); 1376789Sahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen); 1377789Sahrens break; 1378789Sahrens 1379789Sahrens case ZFS_PROP_SNAPDIR: 13801356Seschrock val = getprop_uint64(zhp, prop, &source); 1381789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 13821356Seschrock if (snapdir_table[i].value == val) 1383789Sahrens break; 1384789Sahrens } 1385789Sahrens assert(snapdir_table[i].name != NULL); 1386789Sahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen); 1387789Sahrens break; 1388789Sahrens 1389789Sahrens case ZFS_PROP_ACLMODE: 13901356Seschrock val = getprop_uint64(zhp, prop, &source); 1391789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 13921356Seschrock if (acl_mode_table[i].value == val) 1393789Sahrens break; 1394789Sahrens } 1395789Sahrens assert(acl_mode_table[i].name != NULL); 1396789Sahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen); 1397789Sahrens break; 1398789Sahrens 1399789Sahrens case ZFS_PROP_ACLINHERIT: 14001356Seschrock val = getprop_uint64(zhp, prop, &source); 1401789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 14021356Seschrock if (acl_inherit_table[i].value == val) 1403789Sahrens break; 1404789Sahrens } 1405789Sahrens assert(acl_inherit_table[i].name != NULL); 1406789Sahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen); 1407789Sahrens break; 1408789Sahrens 1409789Sahrens case ZFS_PROP_CREATION: 1410789Sahrens /* 1411789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1412789Sahrens * this into a string unless 'literal' is specified. 1413789Sahrens */ 1414789Sahrens { 1415789Sahrens time_t time = (time_t) 1416789Sahrens zhp->zfs_dmustats.dds_creation_time; 1417789Sahrens struct tm t; 1418789Sahrens 1419789Sahrens if (literal || 1420789Sahrens localtime_r(&time, &t) == NULL || 1421789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1422789Sahrens &t) == 0) 1423789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1424789Sahrens zhp->zfs_dmustats.dds_creation_time); 1425789Sahrens } 1426789Sahrens break; 1427789Sahrens 1428789Sahrens case ZFS_PROP_MOUNTPOINT: 1429789Sahrens /* 1430789Sahrens * Getting the precise mountpoint can be tricky. 1431789Sahrens * 1432789Sahrens * - for 'none' or 'legacy', return those values. 1433789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1434789Sahrens * - for inherited mountpoints, we want to take everything 1435789Sahrens * after our ancestor and append it to the inherited value. 1436789Sahrens * 1437789Sahrens * If the pool has an alternate root, we want to prepend that 1438789Sahrens * root to any values we return. 1439789Sahrens */ 14401544Seschrock root = zhp->zfs_root; 14411356Seschrock str = getprop_string(zhp, prop, &source); 14421356Seschrock 14431356Seschrock if (str[0] == '\0') { 1444789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1445789Sahrens root, zhp->zfs_name); 14461356Seschrock } else if (str[0] == '/') { 14471356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1448789Sahrens 1449789Sahrens if (relpath[0] == '/') 1450789Sahrens relpath++; 14511356Seschrock if (str[1] == '\0') 14521356Seschrock str++; 1453789Sahrens 1454789Sahrens if (relpath[0] == '\0') 1455789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 14561356Seschrock root, str); 1457789Sahrens else 1458789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 14591356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1460789Sahrens relpath); 1461789Sahrens } else { 1462789Sahrens /* 'legacy' or 'none' */ 14631356Seschrock (void) strlcpy(propbuf, str, proplen); 1464789Sahrens } 1465789Sahrens 1466789Sahrens break; 1467789Sahrens 1468789Sahrens case ZFS_PROP_SHARENFS: 14691356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 14701356Seschrock proplen); 1471789Sahrens break; 1472789Sahrens 1473789Sahrens case ZFS_PROP_ORIGIN: 14741544Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1475789Sahrens proplen); 1476789Sahrens /* 1477789Sahrens * If there is no parent at all, return failure to indicate that 1478789Sahrens * it doesn't apply to this dataset. 1479789Sahrens */ 1480789Sahrens if (propbuf[0] == '\0') 1481789Sahrens return (-1); 1482789Sahrens break; 1483789Sahrens 1484789Sahrens case ZFS_PROP_QUOTA: 1485789Sahrens case ZFS_PROP_RESERVATION: 14862082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 14872082Seschrock return (-1); 1488789Sahrens 1489789Sahrens /* 1490789Sahrens * If quota or reservation is 0, we translate this into 'none' 1491789Sahrens * (unless literal is set), and indicate that it's the default 1492789Sahrens * value. Otherwise, we print the number nicely and indicate 1493789Sahrens * that its set locally. 1494789Sahrens */ 1495789Sahrens if (val == 0) { 1496789Sahrens if (literal) 1497789Sahrens (void) strlcpy(propbuf, "0", proplen); 1498789Sahrens else 1499789Sahrens (void) strlcpy(propbuf, "none", proplen); 1500789Sahrens } else { 1501789Sahrens if (literal) 1502789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1503789Sahrens else 1504789Sahrens zfs_nicenum(val, propbuf, proplen); 1505789Sahrens } 1506789Sahrens break; 1507789Sahrens 1508789Sahrens case ZFS_PROP_COMPRESSRATIO: 15092082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15102082Seschrock return (-1); 1511789Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1512789Sahrens val % 100); 1513789Sahrens break; 1514789Sahrens 1515789Sahrens case ZFS_PROP_TYPE: 1516789Sahrens switch (zhp->zfs_type) { 1517789Sahrens case ZFS_TYPE_FILESYSTEM: 1518789Sahrens str = "filesystem"; 1519789Sahrens break; 1520789Sahrens case ZFS_TYPE_VOLUME: 1521789Sahrens str = "volume"; 1522789Sahrens break; 1523789Sahrens case ZFS_TYPE_SNAPSHOT: 1524789Sahrens str = "snapshot"; 1525789Sahrens break; 1526789Sahrens default: 15272082Seschrock abort(); 1528789Sahrens } 1529789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1530789Sahrens break; 1531789Sahrens 1532789Sahrens case ZFS_PROP_MOUNTED: 1533789Sahrens /* 1534789Sahrens * The 'mounted' property is a pseudo-property that described 1535789Sahrens * whether the filesystem is currently mounted. Even though 1536789Sahrens * it's a boolean value, the typical values of "on" and "off" 1537789Sahrens * don't make sense, so we translate to "yes" and "no". 1538789Sahrens */ 15392082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 15402082Seschrock src, &source, &val) != 0) 15412082Seschrock return (-1); 15422082Seschrock if (val) 1543789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1544789Sahrens else 1545789Sahrens (void) strlcpy(propbuf, "no", proplen); 1546789Sahrens break; 1547789Sahrens 1548789Sahrens case ZFS_PROP_NAME: 1549789Sahrens /* 1550789Sahrens * The 'name' property is a pseudo-property derived from the 1551789Sahrens * dataset name. It is presented as a real property to simplify 1552789Sahrens * consumers. 1553789Sahrens */ 1554789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1555789Sahrens break; 1556789Sahrens 1557789Sahrens default: 15582082Seschrock abort(); 1559789Sahrens } 1560789Sahrens 1561789Sahrens get_source(zhp, src, source, statbuf, statlen); 1562789Sahrens 1563789Sahrens return (0); 1564789Sahrens } 1565789Sahrens 1566789Sahrens /* 1567789Sahrens * Utility function to get the given numeric property. Does no validation that 1568789Sahrens * the given property is the appropriate type; should only be used with 1569789Sahrens * hard-coded property types. 1570789Sahrens */ 1571789Sahrens uint64_t 1572789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1573789Sahrens { 1574789Sahrens char *source; 1575789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 15762082Seschrock uint64_t val; 15772082Seschrock 15782082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 15792082Seschrock 15802082Seschrock return (val); 1581789Sahrens } 1582789Sahrens 1583789Sahrens /* 1584789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1585789Sahrens */ 1586789Sahrens int 1587789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1588789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1589789Sahrens { 1590789Sahrens char *source; 1591789Sahrens 1592789Sahrens /* 1593789Sahrens * Check to see if this property applies to our object 1594789Sahrens */ 1595789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 15962082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 15972082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 15982082Seschrock zfs_prop_to_name(prop))); 1599789Sahrens 1600789Sahrens if (src) 1601789Sahrens *src = ZFS_SRC_NONE; 1602789Sahrens 16032082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 16042082Seschrock return (-1); 1605789Sahrens 1606789Sahrens get_source(zhp, src, source, statbuf, statlen); 1607789Sahrens 1608789Sahrens return (0); 1609789Sahrens } 1610789Sahrens 1611789Sahrens /* 1612789Sahrens * Returns the name of the given zfs handle. 1613789Sahrens */ 1614789Sahrens const char * 1615789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1616789Sahrens { 1617789Sahrens return (zhp->zfs_name); 1618789Sahrens } 1619789Sahrens 1620789Sahrens /* 1621789Sahrens * Returns the type of the given zfs handle. 1622789Sahrens */ 1623789Sahrens zfs_type_t 1624789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1625789Sahrens { 1626789Sahrens return (zhp->zfs_type); 1627789Sahrens } 1628789Sahrens 1629789Sahrens /* 16301356Seschrock * Iterate over all child filesystems 1631789Sahrens */ 1632789Sahrens int 16331356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1634789Sahrens { 1635789Sahrens zfs_cmd_t zc = { 0 }; 1636789Sahrens zfs_handle_t *nzhp; 1637789Sahrens int ret; 1638789Sahrens 1639789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16402082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1641789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1642789Sahrens /* 1643789Sahrens * Ignore private dataset names. 1644789Sahrens */ 1645789Sahrens if (dataset_name_hidden(zc.zc_name)) 1646789Sahrens continue; 1647789Sahrens 1648789Sahrens /* 1649789Sahrens * Silently ignore errors, as the only plausible explanation is 1650789Sahrens * that the pool has since been removed. 1651789Sahrens */ 16522082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 16532082Seschrock zc.zc_name)) == NULL) 1654789Sahrens continue; 1655789Sahrens 1656789Sahrens if ((ret = func(nzhp, data)) != 0) 1657789Sahrens return (ret); 1658789Sahrens } 1659789Sahrens 1660789Sahrens /* 1661789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1662789Sahrens * returned, then the underlying dataset has been removed since we 1663789Sahrens * obtained the handle. 1664789Sahrens */ 1665789Sahrens if (errno != ESRCH && errno != ENOENT) 16662082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 16672082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1668789Sahrens 16691356Seschrock return (0); 16701356Seschrock } 16711356Seschrock 16721356Seschrock /* 16731356Seschrock * Iterate over all snapshots 16741356Seschrock */ 16751356Seschrock int 16761356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 16771356Seschrock { 16781356Seschrock zfs_cmd_t zc = { 0 }; 16791356Seschrock zfs_handle_t *nzhp; 16801356Seschrock int ret; 1681789Sahrens 1682789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16832082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 16842082Seschrock &zc) == 0; 1685789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1686789Sahrens 16872082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 16882082Seschrock zc.zc_name)) == NULL) 1689789Sahrens continue; 1690789Sahrens 1691789Sahrens if ((ret = func(nzhp, data)) != 0) 1692789Sahrens return (ret); 1693789Sahrens } 1694789Sahrens 1695789Sahrens /* 1696789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1697789Sahrens * returned, then the underlying dataset has been removed since we 1698789Sahrens * obtained the handle. Silently ignore this case, and return success. 1699789Sahrens */ 1700789Sahrens if (errno != ESRCH && errno != ENOENT) 17012082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 17022082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1703789Sahrens 1704789Sahrens return (0); 1705789Sahrens } 1706789Sahrens 1707789Sahrens /* 17081356Seschrock * Iterate over all children, snapshots and filesystems 17091356Seschrock */ 17101356Seschrock int 17111356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 17121356Seschrock { 17131356Seschrock int ret; 17141356Seschrock 17151356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 17161356Seschrock return (ret); 17171356Seschrock 17181356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 17191356Seschrock } 17201356Seschrock 17211356Seschrock /* 1722789Sahrens * Given a complete name, return just the portion that refers to the parent. 1723789Sahrens * Can return NULL if this is a pool. 1724789Sahrens */ 1725789Sahrens static int 1726789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1727789Sahrens { 1728789Sahrens char *loc; 1729789Sahrens 1730789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1731789Sahrens return (-1); 1732789Sahrens 1733789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1734789Sahrens buf[loc - path] = '\0'; 1735789Sahrens 1736789Sahrens return (0); 1737789Sahrens } 1738789Sahrens 1739789Sahrens /* 1740789Sahrens * Checks to make sure that the given path has a parent, and that it exists. 1741789Sahrens */ 1742789Sahrens static int 17432082Seschrock check_parents(libzfs_handle_t *hdl, const char *path) 1744789Sahrens { 1745789Sahrens zfs_cmd_t zc = { 0 }; 1746789Sahrens char parent[ZFS_MAXNAMELEN]; 1747789Sahrens char *slash; 17481356Seschrock zfs_handle_t *zhp; 17492082Seschrock char errbuf[1024]; 17502082Seschrock 17512082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 17522082Seschrock path); 1753789Sahrens 1754789Sahrens /* get parent, and check to see if this is just a pool */ 1755789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 17562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17572082Seschrock "missing dataset name")); 17582082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1759789Sahrens } 1760789Sahrens 1761789Sahrens /* check to see if the pool exists */ 1762789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1763789Sahrens slash = parent + strlen(parent); 1764789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1765789Sahrens zc.zc_name[slash - parent] = '\0'; 17662082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1767789Sahrens errno == ENOENT) { 17682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17692082Seschrock "no such pool '%s'"), zc.zc_name); 17702082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1771789Sahrens } 1772789Sahrens 1773789Sahrens /* check to see if the parent dataset exists */ 17742082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1775789Sahrens switch (errno) { 1776789Sahrens case ENOENT: 17772082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17782082Seschrock "parent does not exist")); 17792082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1780789Sahrens 1781789Sahrens default: 17822082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1783789Sahrens } 1784789Sahrens } 1785789Sahrens 1786789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 17871356Seschrock if (getzoneid() != GLOBAL_ZONEID && 17881393Slling !zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 17892082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 17901356Seschrock zfs_close(zhp); 1791789Sahrens return (-1); 1792789Sahrens } 1793789Sahrens 1794789Sahrens /* make sure parent is a filesystem */ 17951356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 17962082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17972082Seschrock "parent is not a filesystem")); 17982082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 17991356Seschrock zfs_close(zhp); 1800789Sahrens return (-1); 1801789Sahrens } 1802789Sahrens 18031356Seschrock zfs_close(zhp); 1804789Sahrens return (0); 1805789Sahrens } 1806789Sahrens 1807789Sahrens /* 1808789Sahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used 1809789Sahrens * only for volumes, and indicate the size and blocksize of the volume. 1810789Sahrens */ 1811789Sahrens int 18122082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 1813789Sahrens const char *sizestr, const char *blocksizestr) 1814789Sahrens { 1815789Sahrens zfs_cmd_t zc = { 0 }; 1816789Sahrens int ret; 1817789Sahrens uint64_t size = 0; 1818789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 18192082Seschrock char errbuf[1024]; 1820789Sahrens 1821789Sahrens /* convert sizestr into integer size */ 18222082Seschrock if (sizestr != NULL && nicestrtonum(hdl, sizestr, &size) != 0) 18232082Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 18242082Seschrock "bad volume size '%s'"), sizestr)); 1825789Sahrens 1826789Sahrens /* convert blocksizestr into integer blocksize */ 18272082Seschrock if (blocksizestr != NULL && nicestrtonum(hdl, blocksizestr, 18282082Seschrock &blocksize) != 0) 18292082Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 18302082Seschrock "bad volume blocksize '%s'"), blocksizestr)); 18312082Seschrock 18322082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 18332082Seschrock "cannot create '%s'"), path); 1834789Sahrens 1835789Sahrens /* validate the path, taking care to note the extended error message */ 18362082Seschrock if (!zfs_validate_name(hdl, path, type)) 18372082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1838789Sahrens 1839789Sahrens /* validate parents exist */ 18402082Seschrock if (check_parents(hdl, path) != 0) 1841789Sahrens return (-1); 1842789Sahrens 1843789Sahrens /* 1844789Sahrens * The failure modes when creating a dataset of a different type over 1845789Sahrens * one that already exists is a little strange. In particular, if you 1846789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1847789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1848789Sahrens * first try to see if the dataset exists. 1849789Sahrens */ 1850789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 18512082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 18522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18532082Seschrock "dataset already exists")); 18542082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1855789Sahrens } 1856789Sahrens 1857789Sahrens if (type == ZFS_TYPE_VOLUME) 1858789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1859789Sahrens else 1860789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1861789Sahrens 1862789Sahrens if (type == ZFS_TYPE_VOLUME) { 18631133Seschrock /* 18641133Seschrock * If we are creating a volume, the size and block size must 18651133Seschrock * satisfy a few restraints. First, the blocksize must be a 18661133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 18671133Seschrock * volsize must be a multiple of the block size, and cannot be 18681133Seschrock * zero. 18691133Seschrock */ 1870789Sahrens if (size == 0) { 18712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18722082Seschrock "cannot be zero")); 18732082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18742082Seschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 18752082Seschrock sizestr)); 1876789Sahrens } 1877789Sahrens 18781133Seschrock if (blocksize < SPA_MINBLOCKSIZE || 18791133Seschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) { 18802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18811133Seschrock "must be power of 2 from %u to %uk"), 18821133Seschrock (uint_t)SPA_MINBLOCKSIZE, 18831133Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 18842082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18852082Seschrock dgettext(TEXT_DOMAIN, 18862082Seschrock "bad volume block size '%s'"), blocksizestr)); 18871133Seschrock } 18881133Seschrock 18891133Seschrock if (size % blocksize != 0) { 18902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18912082Seschrock "must be a multiple of volume block size")); 18922082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18932082Seschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 18942082Seschrock sizestr)); 18951133Seschrock } 18961133Seschrock 1897789Sahrens zc.zc_volsize = size; 1898789Sahrens zc.zc_volblocksize = blocksize; 1899789Sahrens } 1900789Sahrens 1901789Sahrens /* create the dataset */ 19022082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 1903789Sahrens 1904789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 19052082Seschrock ret = zvol_create_link(hdl, path); 1906789Sahrens 1907789Sahrens /* check for failure */ 1908789Sahrens if (ret != 0) { 1909789Sahrens char parent[ZFS_MAXNAMELEN]; 1910789Sahrens (void) parent_name(path, parent, sizeof (parent)); 1911789Sahrens 1912789Sahrens switch (errno) { 1913789Sahrens case ENOENT: 19142082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19152082Seschrock "no such parent '%s'"), parent); 19162082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1917789Sahrens 1918789Sahrens case EINVAL: 19192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19202082Seschrock "parent '%s' is not a filesysem"), parent); 19212082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 1922789Sahrens 1923789Sahrens case EDOM: 19242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1925789Sahrens "must be power of 2 from %u to %uk"), 1926789Sahrens (uint_t)SPA_MINBLOCKSIZE, 1927789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 19282082Seschrock 19292082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 19302082Seschrock dgettext(TEXT_DOMAIN, "bad block size '%s'"), 19312082Seschrock blocksizestr ? blocksizestr : "<unknown>")); 19322082Seschrock 1933789Sahrens #ifdef _ILP32 1934789Sahrens case EOVERFLOW: 1935789Sahrens /* 1936789Sahrens * This platform can't address a volume this big. 1937789Sahrens */ 19382082Seschrock if (type == ZFS_TYPE_VOLUME) 19392082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 19402082Seschrock errbuf)); 1941789Sahrens #endif 19422082Seschrock /* FALLTHROUGH */ 1943789Sahrens default: 19442082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1945789Sahrens } 1946789Sahrens } 1947789Sahrens 1948789Sahrens return (0); 1949789Sahrens } 1950789Sahrens 1951789Sahrens /* 1952789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 1953789Sahrens * isn't mounted, and that there are no active dependents. 1954789Sahrens */ 1955789Sahrens int 1956789Sahrens zfs_destroy(zfs_handle_t *zhp) 1957789Sahrens { 1958789Sahrens zfs_cmd_t zc = { 0 }; 1959789Sahrens int ret; 1960789Sahrens 1961789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1962789Sahrens 1963789Sahrens /* 1964789Sahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME 1965789Sahrens * so that we do the right thing for snapshots of volumes. 1966789Sahrens */ 1967789Sahrens if (zhp->zfs_volblocksize != 0) { 19682082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 1969789Sahrens return (-1); 1970789Sahrens 1971789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1972789Sahrens } else { 1973789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1974789Sahrens } 1975789Sahrens 19762082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 19772199Sahrens if (ret != 0) { 19782082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 19792082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 19802082Seschrock zhp->zfs_name)); 19812199Sahrens } 1982789Sahrens 1983789Sahrens remove_mountpoint(zhp); 1984789Sahrens 1985789Sahrens return (0); 1986789Sahrens } 1987789Sahrens 19882199Sahrens struct destroydata { 19892199Sahrens char *snapname; 19902199Sahrens boolean_t gotone; 19912199Sahrens }; 19922199Sahrens 19932199Sahrens static int 19942199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 19952199Sahrens { 19962199Sahrens struct destroydata *dd = arg; 19972199Sahrens zfs_handle_t *szhp; 19982199Sahrens char name[ZFS_MAXNAMELEN]; 19992199Sahrens 20002199Sahrens (void) strcpy(name, zhp->zfs_name); 20012199Sahrens (void) strcat(name, "@"); 20022199Sahrens (void) strcat(name, dd->snapname); 20032199Sahrens 20042199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 20052199Sahrens if (szhp) { 20062199Sahrens dd->gotone = B_TRUE; 20072199Sahrens zfs_close(szhp); 20082199Sahrens } 20092199Sahrens 20102199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 20112199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 20122199Sahrens /* 20132199Sahrens * NB: this is simply a best-effort. We don't want to 20142199Sahrens * return an error, because then we wouldn't visit all 20152199Sahrens * the volumes. 20162199Sahrens */ 20172199Sahrens } 20182199Sahrens 20192199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 20202199Sahrens } 20212199Sahrens 20222199Sahrens /* 20232199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 20242199Sahrens */ 20252199Sahrens int 20262199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 20272199Sahrens { 20282199Sahrens zfs_cmd_t zc = { 0 }; 20292199Sahrens int ret; 20302199Sahrens struct destroydata dd = { 0 }; 20312199Sahrens 20322199Sahrens dd.snapname = snapname; 20332199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 20342199Sahrens 20352199Sahrens if (!dd.gotone) { 20362199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 20372199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 20382199Sahrens zhp->zfs_name, snapname)); 20392199Sahrens } 20402199Sahrens 20412199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 20422199Sahrens (void) strlcpy(zc.zc_prop_value, snapname, sizeof (zc.zc_prop_value)); 20432199Sahrens 20442199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 20452199Sahrens if (ret != 0) { 20462199Sahrens char errbuf[1024]; 20472199Sahrens 20482199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20492199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 20502199Sahrens 20512199Sahrens switch (errno) { 20522199Sahrens case EEXIST: 20532199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 20542199Sahrens "snapshot is cloned")); 20552199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 20562199Sahrens 20572199Sahrens default: 20582199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 20592199Sahrens errbuf)); 20602199Sahrens } 20612199Sahrens } 20622199Sahrens 20632199Sahrens return (0); 20642199Sahrens } 20652199Sahrens 2066789Sahrens /* 2067789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2068789Sahrens */ 2069789Sahrens int 2070789Sahrens zfs_clone(zfs_handle_t *zhp, const char *target) 2071789Sahrens { 2072789Sahrens zfs_cmd_t zc = { 0 }; 2073789Sahrens char parent[ZFS_MAXNAMELEN]; 2074789Sahrens int ret; 20752082Seschrock char errbuf[1024]; 20762082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2077789Sahrens 2078789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2079789Sahrens 20802082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20812082Seschrock "cannot create '%s'"), target); 20822082Seschrock 2083789Sahrens /* validate the target name */ 20842082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 20852082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2086789Sahrens 2087789Sahrens /* validate parents exist */ 20882082Seschrock if (check_parents(zhp->zfs_hdl, target) != 0) 2089789Sahrens return (-1); 2090789Sahrens 2091789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2092789Sahrens 2093789Sahrens /* do the clone */ 2094789Sahrens if (zhp->zfs_volblocksize != 0) 2095789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2096789Sahrens else 2097789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2098789Sahrens 2099789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2100789Sahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename)); 21012082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2102789Sahrens 2103789Sahrens if (ret != 0) { 2104789Sahrens switch (errno) { 2105789Sahrens 2106789Sahrens case ENOENT: 2107789Sahrens /* 2108789Sahrens * The parent doesn't exist. We should have caught this 2109789Sahrens * above, but there may a race condition that has since 2110789Sahrens * destroyed the parent. 2111789Sahrens * 2112789Sahrens * At this point, we don't know whether it's the source 2113789Sahrens * that doesn't exist anymore, or whether the target 2114789Sahrens * dataset doesn't exist. 2115789Sahrens */ 21162082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21172082Seschrock "no such parent '%s'"), parent); 21182082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 21192082Seschrock 21202082Seschrock case EXDEV: 21212082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21222082Seschrock "source and target pools differ")); 21232082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 21242082Seschrock errbuf)); 21252082Seschrock 21262082Seschrock default: 21272082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 21282082Seschrock errbuf)); 21292082Seschrock } 21302082Seschrock } else if (zhp->zfs_volblocksize != 0) { 21312082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 21322082Seschrock } 21332082Seschrock 21342082Seschrock return (ret); 21352082Seschrock } 21362082Seschrock 21372082Seschrock typedef struct promote_data { 21382082Seschrock char cb_mountpoint[MAXPATHLEN]; 21392082Seschrock const char *cb_target; 21402082Seschrock const char *cb_errbuf; 21412082Seschrock uint64_t cb_pivot_txg; 21422082Seschrock } promote_data_t; 21432082Seschrock 21442082Seschrock static int 21452082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 21462082Seschrock { 21472082Seschrock promote_data_t *pd = data; 21482082Seschrock zfs_handle_t *szhp; 21492082Seschrock char snapname[MAXPATHLEN]; 21502082Seschrock 21512082Seschrock /* We don't care about snapshots after the pivot point */ 21522082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 21532082Seschrock return (0); 21542082Seschrock 21552417Sahrens /* Remove the device link if it's a zvol. */ 21562417Sahrens if (zhp->zfs_volblocksize != 0) 21572417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 21582082Seschrock 21592082Seschrock /* Check for conflicting names */ 21602082Seschrock (void) strcpy(snapname, pd->cb_target); 21612417Sahrens (void) strcat(snapname, strchr(zhp->zfs_name, '@')); 21622082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 21632082Seschrock if (szhp != NULL) { 21642082Seschrock zfs_close(szhp); 21652082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21662082Seschrock "snapshot name '%s' from origin \n" 21672082Seschrock "conflicts with '%s' from target"), 21682082Seschrock zhp->zfs_name, snapname); 21692082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 21702082Seschrock } 21712082Seschrock return (0); 21722082Seschrock } 21732082Seschrock 21742417Sahrens static int 21752417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 21762417Sahrens { 21772417Sahrens promote_data_t *pd = data; 21782417Sahrens 21792417Sahrens /* We don't care about snapshots after the pivot point */ 21802417Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 21812417Sahrens return (0); 21822417Sahrens 21832417Sahrens /* Create the device link if it's a zvol. */ 21842417Sahrens if (zhp->zfs_volblocksize != 0) 21852417Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 21862417Sahrens 21872417Sahrens return (0); 21882417Sahrens } 21892417Sahrens 21902082Seschrock /* 21912082Seschrock * Promotes the given clone fs to be the clone parent. 21922082Seschrock */ 21932082Seschrock int 21942082Seschrock zfs_promote(zfs_handle_t *zhp) 21952082Seschrock { 21962082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 21972082Seschrock zfs_cmd_t zc = { 0 }; 21982082Seschrock char parent[MAXPATHLEN]; 21992082Seschrock char *cp; 22002082Seschrock int ret; 22012082Seschrock zfs_handle_t *pzhp; 22022082Seschrock promote_data_t pd; 22032082Seschrock char errbuf[1024]; 22042082Seschrock 22052082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22062082Seschrock "cannot promote '%s'"), zhp->zfs_name); 22072082Seschrock 22082082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 22092082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22102082Seschrock "snapshots can not be promoted")); 22112082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22122082Seschrock } 22132082Seschrock 22142082Seschrock (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of); 22152082Seschrock if (parent[0] == '\0') { 22162082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22172082Seschrock "not a cloned filesystem")); 22182082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22192082Seschrock } 22202082Seschrock cp = strchr(parent, '@'); 22212082Seschrock *cp = '\0'; 22222082Seschrock 22232082Seschrock /* Walk the snapshots we will be moving */ 22242082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 22252082Seschrock if (pzhp == NULL) 22262082Seschrock return (-1); 22272082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 22282082Seschrock zfs_close(pzhp); 22292082Seschrock pd.cb_target = zhp->zfs_name; 22302082Seschrock pd.cb_errbuf = errbuf; 22312082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 22322082Seschrock if (pzhp == NULL) 22332082Seschrock return (-1); 22342082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 22352082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 22362082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 22372417Sahrens if (ret != 0) { 22382417Sahrens zfs_close(pzhp); 22392082Seschrock return (-1); 22402417Sahrens } 22412082Seschrock 22422082Seschrock /* issue the ioctl */ 22432417Sahrens (void) strlcpy(zc.zc_prop_value, zhp->zfs_dmustats.dds_clone_of, 22442417Sahrens sizeof (zc.zc_prop_value)); 22452082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22462082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 22472082Seschrock 22482082Seschrock if (ret != 0) { 22492417Sahrens int save_errno = errno; 22502417Sahrens 22512417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 22522417Sahrens zfs_close(pzhp); 22532417Sahrens 22542417Sahrens switch (save_errno) { 2255789Sahrens case EEXIST: 2256789Sahrens /* 22572082Seschrock * There is a conflicting snapshot name. We 22582082Seschrock * should have caught this above, but they could 22592082Seschrock * have renamed something in the mean time. 2260789Sahrens */ 22612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22622082Seschrock "conflicting snapshot name from parent '%s'"), 22632082Seschrock parent); 22642082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2265789Sahrens 2266789Sahrens default: 22672417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2268789Sahrens } 22692417Sahrens } else { 22702417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2271789Sahrens } 2272789Sahrens 22732417Sahrens zfs_close(pzhp); 2274789Sahrens return (ret); 2275789Sahrens } 2276789Sahrens 22772199Sahrens static int 22782199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 22792199Sahrens { 22802199Sahrens char *snapname = arg; 22812199Sahrens 22822199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 22832199Sahrens char name[MAXPATHLEN]; 22842199Sahrens 22852199Sahrens (void) strcpy(name, zhp->zfs_name); 22862199Sahrens (void) strcat(name, "@"); 22872199Sahrens (void) strcat(name, snapname); 22882199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 22892199Sahrens /* 22902199Sahrens * NB: this is simply a best-effort. We don't want to 22912199Sahrens * return an error, because then we wouldn't visit all 22922199Sahrens * the volumes. 22932199Sahrens */ 22942199Sahrens } 22952199Sahrens return (zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname)); 22962199Sahrens } 22972199Sahrens 2298789Sahrens /* 2299789Sahrens * Takes a snapshot of the given dataset 2300789Sahrens */ 2301789Sahrens int 23022199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2303789Sahrens { 2304789Sahrens const char *delim; 2305789Sahrens char *parent; 2306789Sahrens zfs_handle_t *zhp; 2307789Sahrens zfs_cmd_t zc = { 0 }; 2308789Sahrens int ret; 23092082Seschrock char errbuf[1024]; 23102082Seschrock 23112082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23122082Seschrock "cannot snapshot '%s'"), path); 23132082Seschrock 23142082Seschrock /* validate the target name */ 23152082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 23162082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2317789Sahrens 2318789Sahrens /* make sure the parent exists and is of the appropriate type */ 23192199Sahrens delim = strchr(path, '@'); 23202082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 23212082Seschrock return (-1); 2322789Sahrens (void) strncpy(parent, path, delim - path); 2323789Sahrens parent[delim - path] = '\0'; 2324789Sahrens 23252082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2326789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2327789Sahrens free(parent); 2328789Sahrens return (-1); 2329789Sahrens } 2330789Sahrens 23312199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 23322199Sahrens (void) strlcpy(zc.zc_prop_value, delim+1, sizeof (zc.zc_prop_value)); 23332199Sahrens zc.zc_cookie = recursive; 23342199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 23352199Sahrens 23362199Sahrens /* 23372199Sahrens * if it was recursive, the one that actually failed will be in 23382199Sahrens * zc.zc_name. 23392199Sahrens */ 23402199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23412199Sahrens "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_prop_value); 23422199Sahrens if (ret == 0 && recursive) { 23432199Sahrens (void) zfs_iter_filesystems(zhp, 23442199Sahrens zfs_create_link_cb, (char *)delim+1); 23452199Sahrens } 2346789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 23472082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 23482199Sahrens if (ret != 0) { 23492082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 23502082Seschrock &zc); 23512199Sahrens } 2352789Sahrens } 2353789Sahrens 23542082Seschrock if (ret != 0) 23552082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2356789Sahrens 2357789Sahrens free(parent); 2358789Sahrens zfs_close(zhp); 2359789Sahrens 2360789Sahrens return (ret); 2361789Sahrens } 2362789Sahrens 2363789Sahrens /* 2364789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2365789Sahrens */ 2366789Sahrens int 23671749Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2368789Sahrens { 2369789Sahrens zfs_cmd_t zc = { 0 }; 2370789Sahrens int ret; 23712082Seschrock char errbuf[1024]; 23722082Seschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 23732082Seschrock 23742082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23752082Seschrock "cannot send '%s'"), zhp_to->zfs_name); 2376789Sahrens 2377789Sahrens /* do the ioctl() */ 2378789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2379789Sahrens if (zhp_from) { 2380789Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2381789Sahrens sizeof (zc.zc_name)); 2382789Sahrens } else { 2383789Sahrens zc.zc_prop_value[0] = '\0'; 2384789Sahrens } 2385789Sahrens zc.zc_cookie = STDOUT_FILENO; 2386789Sahrens 23872082Seschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2388789Sahrens if (ret != 0) { 2389789Sahrens switch (errno) { 2390789Sahrens 2391789Sahrens case EXDEV: 23922082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23932082Seschrock "not an ealier snapshot from the same fs")); 23942082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2395789Sahrens 2396789Sahrens case EDQUOT: 2397789Sahrens case EFBIG: 2398789Sahrens case EIO: 2399789Sahrens case ENOLINK: 2400789Sahrens case ENOSPC: 2401789Sahrens case ENOSTR: 2402789Sahrens case ENXIO: 2403789Sahrens case EPIPE: 2404789Sahrens case ERANGE: 2405789Sahrens case EFAULT: 2406789Sahrens case EROFS: 24072082Seschrock zfs_error_aux(hdl, strerror(errno)); 24082082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2409789Sahrens 2410789Sahrens default: 24112082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2412789Sahrens } 2413789Sahrens } 2414789Sahrens 2415789Sahrens return (ret); 2416789Sahrens } 2417789Sahrens 2418789Sahrens /* 2419789Sahrens * Restores a backup of tosnap from stdin. 2420789Sahrens */ 2421789Sahrens int 24222082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 2423*2665Snd150628 int verbose, int dryrun, boolean_t force) 2424789Sahrens { 2425789Sahrens zfs_cmd_t zc = { 0 }; 2426789Sahrens time_t begin_time; 2427868Sahrens int ioctl_err, err, bytes, size; 2428789Sahrens char *cp; 2429789Sahrens dmu_replay_record_t drr; 2430789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 24312082Seschrock char errbuf[1024]; 2432*2665Snd150628 prop_changelist_t *clp; 2433789Sahrens 2434789Sahrens begin_time = time(NULL); 2435789Sahrens 24362082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24372082Seschrock "cannot receive")); 24382082Seschrock 2439789Sahrens /* trim off snapname, if any */ 2440789Sahrens (void) strcpy(zc.zc_name, tosnap); 2441789Sahrens cp = strchr(zc.zc_name, '@'); 2442789Sahrens if (cp) 2443789Sahrens *cp = '\0'; 2444789Sahrens 2445789Sahrens /* read in the BEGIN record */ 2446789Sahrens cp = (char *)&drr; 2447789Sahrens bytes = 0; 2448789Sahrens do { 2449868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2450868Sahrens cp += size; 2451868Sahrens bytes += size; 2452868Sahrens } while (size > 0); 2453868Sahrens 2454868Sahrens if (size < 0 || bytes != sizeof (drr)) { 24552082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24562082Seschrock "stream (failed to read first record)")); 24572082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2458789Sahrens } 2459789Sahrens 2460789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2461789Sahrens 2462789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2463789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 24642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24652082Seschrock "stream (bad magic number)")); 24662082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2467789Sahrens } 2468789Sahrens 2469789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2470789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 24712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 24722082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2473789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 24742082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2475789Sahrens } 2476789Sahrens 2477789Sahrens /* 2478789Sahrens * Determine name of destination snapshot. 2479789Sahrens */ 24801544Seschrock (void) strcpy(zc.zc_filename, tosnap); 2481789Sahrens if (isprefix) { 2482789Sahrens if (strchr(tosnap, '@') != NULL) { 24832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24842082Seschrock "destination must be a filesystem")); 24852082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2486789Sahrens } 2487789Sahrens 2488789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2489789Sahrens if (cp == NULL) 2490789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2491789Sahrens else 2492789Sahrens cp++; 2493789Sahrens 24941544Seschrock (void) strcat(zc.zc_filename, "/"); 24951544Seschrock (void) strcat(zc.zc_filename, cp); 2496789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2497789Sahrens /* 2498789Sahrens * they specified just a filesystem; tack on the 2499789Sahrens * snapname from the backup. 2500789Sahrens */ 2501789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 25022082Seschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 25032082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 25041544Seschrock (void) strcat(zc.zc_filename, cp); 2505789Sahrens } 2506789Sahrens 2507789Sahrens if (drrb->drr_fromguid) { 2508789Sahrens zfs_handle_t *h; 2509789Sahrens /* incremental backup stream */ 2510789Sahrens 2511789Sahrens /* do the ioctl to the containing fs */ 25121544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2513789Sahrens cp = strchr(zc.zc_name, '@'); 2514789Sahrens *cp = '\0'; 2515789Sahrens 2516789Sahrens /* make sure destination fs exists */ 25172082Seschrock h = zfs_open(hdl, zc.zc_name, 25182082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 25192082Seschrock if (h == NULL) 2520789Sahrens return (-1); 2521868Sahrens if (!dryrun) { 2522*2665Snd150628 /* 2523*2665Snd150628 * We need to unmount all the dependents of the dataset 2524*2665Snd150628 * and the dataset itself. If it's a volume 2525*2665Snd150628 * then remove device link. 2526*2665Snd150628 */ 2527868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2528*2665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 2529*2665Snd150628 if (clp == NULL) 2530*2665Snd150628 return (-1); 2531*2665Snd150628 if (changelist_prefix(clp) != 0) { 2532*2665Snd150628 changelist_free(clp); 2533*2665Snd150628 return (-1); 2534*2665Snd150628 } 2535868Sahrens } else { 25362082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2537868Sahrens } 2538868Sahrens } 2539789Sahrens zfs_close(h); 2540789Sahrens } else { 2541789Sahrens /* full backup stream */ 2542789Sahrens 25431544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2544868Sahrens 25451749Sahrens /* make sure they aren't trying to receive into the root */ 2546868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2547789Sahrens cp = strchr(zc.zc_name, '@'); 2548789Sahrens if (cp) 2549789Sahrens *cp = '\0'; 25502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25512082Seschrock "destination '%s' already exists"), zc.zc_name); 25522082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2553789Sahrens } 2554789Sahrens 2555789Sahrens if (isprefix) { 2556868Sahrens zfs_handle_t *h; 2557868Sahrens 2558789Sahrens /* make sure prefix exists */ 25592082Seschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 25602082Seschrock if (h == NULL) 2561789Sahrens return (-1); 25621544Seschrock zfs_close(h); 2563789Sahrens 2564789Sahrens /* create any necessary ancestors up to prefix */ 2565868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 25661544Seschrock 2567868Sahrens /* 2568868Sahrens * zc.zc_name is now the full name of the snap 25691544Seschrock * we're restoring into. Attempt to create, 25701544Seschrock * mount, and share any ancestor filesystems, up 25711544Seschrock * to the one that was named. 2572868Sahrens */ 25731544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 25741544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 25751544Seschrock const char *opname; 2576789Sahrens *cp = '\0'; 25771544Seschrock 25782082Seschrock opname = dgettext(TEXT_DOMAIN, "create"); 25792082Seschrock if (zfs_create(hdl, zc.zc_name, 25802082Seschrock ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) { 25811544Seschrock if (errno == EEXIST) 25821544Seschrock continue; 25831544Seschrock goto ancestorerr; 2584789Sahrens } 25851544Seschrock 25862082Seschrock opname = dgettext(TEXT_DOMAIN, "open"); 25872082Seschrock h = zfs_open(hdl, zc.zc_name, 25882082Seschrock ZFS_TYPE_FILESYSTEM); 25891544Seschrock if (h == NULL) 25901544Seschrock goto ancestorerr; 25911544Seschrock 25922082Seschrock opname = dgettext(TEXT_DOMAIN, "mount"); 25931544Seschrock if (zfs_mount(h, NULL, 0) != 0) 25941544Seschrock goto ancestorerr; 25951544Seschrock 25962082Seschrock opname = dgettext(TEXT_DOMAIN, "share"); 25971544Seschrock if (zfs_share(h) != 0) 25981544Seschrock goto ancestorerr; 25991544Seschrock 26001544Seschrock zfs_close(h); 26011544Seschrock 26021544Seschrock continue; 26031544Seschrock ancestorerr: 26042082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26052082Seschrock "failed to %s ancestor '%s'"), opname, 26062082Seschrock zc.zc_name); 26072082Seschrock return (zfs_error(hdl, EZFS_BADRESTORE, 26082082Seschrock errbuf)); 2609789Sahrens } 2610789Sahrens } 2611868Sahrens 2612868Sahrens /* Make sure destination fs does not exist */ 2613868Sahrens cp = strchr(zc.zc_name, '@'); 2614868Sahrens *cp = '\0'; 26152082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 26162082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26172082Seschrock "destination '%s' exists"), zc.zc_name); 26182082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2619868Sahrens } 2620868Sahrens 2621868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2622868Sahrens cp = strrchr(zc.zc_name, '/'); 2623868Sahrens *cp = '\0'; 2624789Sahrens } 2625789Sahrens 2626789Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2627789Sahrens zc.zc_cookie = STDIN_FILENO; 2628789Sahrens zc.zc_intsz = isprefix; 2629*2665Snd150628 zc.zc_numints = force; 2630789Sahrens if (verbose) { 26311749Sahrens (void) printf("%s %s stream of %s into %s\n", 26321749Sahrens dryrun ? "would receive" : "receiving", 2633789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2634789Sahrens drr.drr_u.drr_begin.drr_toname, 26351544Seschrock zc.zc_filename); 2636789Sahrens (void) fflush(stdout); 2637789Sahrens } 2638789Sahrens if (dryrun) 2639789Sahrens return (0); 26402082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2641868Sahrens if (ioctl_err != 0) { 2642789Sahrens switch (errno) { 2643789Sahrens case ENODEV: 26442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26452082Seschrock "most recent snapshot does not match incremental " 26462082Seschrock "source")); 26472082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2648789Sahrens break; 2649789Sahrens case ETXTBSY: 26502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26512082Seschrock "destination has been modified since most recent " 26522082Seschrock "snapshot")); 26532082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2654789Sahrens break; 2655789Sahrens case EEXIST: 2656789Sahrens if (drrb->drr_fromguid == 0) { 2657789Sahrens /* it's the containing fs that exists */ 26581544Seschrock cp = strchr(zc.zc_filename, '@'); 2659789Sahrens *cp = '\0'; 2660789Sahrens } 26612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26622082Seschrock "destination already exists")); 26632082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 26642082Seschrock "cannot restore to %s"), zc.zc_filename); 2665789Sahrens break; 2666789Sahrens case EINVAL: 26672082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2668868Sahrens break; 26691544Seschrock case ECKSUM: 26702082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26712082Seschrock "invalid stream (checksum mismatch)")); 26722082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2673789Sahrens break; 2674789Sahrens default: 26752082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2676789Sahrens } 2677789Sahrens } 2678789Sahrens 2679789Sahrens /* 2680868Sahrens * Mount or recreate the /dev links for the target filesystem 2681868Sahrens * (if created, or if we tore them down to do an incremental 2682868Sahrens * restore), and the /dev links for the new snapshot (if 2683*2665Snd150628 * created). Also mount any children of the target filesystem 2684*2665Snd150628 * if we did an incremental receive. 2685789Sahrens */ 26861544Seschrock cp = strchr(zc.zc_filename, '@'); 2687868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2688789Sahrens zfs_handle_t *h; 2689789Sahrens 2690789Sahrens *cp = '\0'; 26912082Seschrock h = zfs_open(hdl, zc.zc_filename, 2692789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2693868Sahrens *cp = '@'; 2694789Sahrens if (h) { 2695*2665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 26962082Seschrock err = zvol_create_link(hdl, h->zfs_name); 26971544Seschrock if (err == 0 && ioctl_err == 0) 26982082Seschrock err = zvol_create_link(hdl, 26992082Seschrock zc.zc_filename); 2700*2665Snd150628 } else { 2701*2665Snd150628 if (drrb->drr_fromguid) { 2702*2665Snd150628 err = changelist_postfix(clp); 2703*2665Snd150628 changelist_free(clp); 2704*2665Snd150628 } else { 2705*2665Snd150628 err = zfs_mount(h, NULL, 0); 2706*2665Snd150628 } 2707868Sahrens } 2708*2665Snd150628 zfs_close(h); 2709789Sahrens } 2710789Sahrens } 2711789Sahrens 2712868Sahrens if (err || ioctl_err) 2713868Sahrens return (-1); 2714789Sahrens 2715789Sahrens if (verbose) { 2716789Sahrens char buf1[64]; 2717789Sahrens char buf2[64]; 2718789Sahrens uint64_t bytes = zc.zc_cookie; 2719789Sahrens time_t delta = time(NULL) - begin_time; 2720789Sahrens if (delta == 0) 2721789Sahrens delta = 1; 2722789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2723789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2724789Sahrens 27251749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2726789Sahrens buf1, delta, buf2); 2727789Sahrens } 2728*2665Snd150628 2729789Sahrens return (0); 2730789Sahrens } 2731789Sahrens 2732789Sahrens /* 27331294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 27341294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 27351294Slling * is a dependent and we should just destroy it without checking the transaction 27361294Slling * group. 2737789Sahrens */ 27381294Slling typedef struct rollback_data { 27391294Slling const char *cb_target; /* the snapshot */ 27401294Slling uint64_t cb_create; /* creation time reference */ 27411294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 27421294Slling int cb_error; 27432082Seschrock boolean_t cb_dependent; 27441294Slling } rollback_data_t; 27451294Slling 27461294Slling static int 27471294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 27481294Slling { 27491294Slling rollback_data_t *cbp = data; 27501294Slling 27511294Slling if (!cbp->cb_dependent) { 27521294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 27531294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 27541294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 27551294Slling cbp->cb_create) { 27561294Slling 27572082Seschrock cbp->cb_dependent = B_TRUE; 27582474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 27592474Seschrock cbp) != 0) 27602474Seschrock cbp->cb_error = 1; 27612082Seschrock cbp->cb_dependent = B_FALSE; 27621294Slling 27631294Slling if (zfs_destroy(zhp) != 0) 27641294Slling cbp->cb_error = 1; 27651294Slling else 27661294Slling changelist_remove(zhp, cbp->cb_clp); 27671294Slling } 27681294Slling } else { 27691294Slling if (zfs_destroy(zhp) != 0) 27701294Slling cbp->cb_error = 1; 27711294Slling else 27721294Slling changelist_remove(zhp, cbp->cb_clp); 27731294Slling } 27741294Slling 27751294Slling zfs_close(zhp); 27761294Slling return (0); 27771294Slling } 27781294Slling 27791294Slling /* 27801294Slling * Rollback the dataset to its latest snapshot. 27811294Slling */ 27821294Slling static int 27831294Slling do_rollback(zfs_handle_t *zhp) 2784789Sahrens { 2785789Sahrens int ret; 2786789Sahrens zfs_cmd_t zc = { 0 }; 2787789Sahrens 2788789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2789789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2790789Sahrens 2791789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 27922082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2793789Sahrens return (-1); 2794789Sahrens 2795789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2796789Sahrens 2797789Sahrens if (zhp->zfs_volblocksize != 0) 2798789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2799789Sahrens else 2800789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2801789Sahrens 2802789Sahrens /* 2803789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2804789Sahrens * for the given dataset. Given these constraints, we can simply pass 2805789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2806789Sahrens * condition where the user has taken a snapshot since we verified that 2807789Sahrens * this was the most recent. 2808789Sahrens */ 28092082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 28102082Seschrock &zc)) != 0) { 28112082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 28122082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 28132082Seschrock zhp->zfs_name); 2814789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 28152082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2816789Sahrens } 2817789Sahrens 2818789Sahrens return (ret); 2819789Sahrens } 2820789Sahrens 2821789Sahrens /* 28221294Slling * Given a dataset, rollback to a specific snapshot, discarding any 28231294Slling * data changes since then and making it the active dataset. 28241294Slling * 28251294Slling * Any snapshots more recent than the target are destroyed, along with 28261294Slling * their dependents. 28271294Slling */ 28281294Slling int 28291294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 28301294Slling { 28311294Slling int ret; 28321294Slling rollback_data_t cb = { 0 }; 28331294Slling prop_changelist_t *clp; 28341294Slling 28351294Slling /* 28361294Slling * Unmount all dependendents of the dataset and the dataset itself. 28371294Slling * The list we need to gather is the same as for doing rename 28381294Slling */ 28391294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 28401294Slling if (clp == NULL) 28411294Slling return (-1); 28421294Slling 28431294Slling if ((ret = changelist_prefix(clp)) != 0) 28441294Slling goto out; 28451294Slling 28461294Slling /* 28471294Slling * Destroy all recent snapshots and its dependends. 28481294Slling */ 28491294Slling cb.cb_target = snap->zfs_name; 28501294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 28511294Slling cb.cb_clp = clp; 28521294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 28531294Slling 28541294Slling if ((ret = cb.cb_error) != 0) { 28551294Slling (void) changelist_postfix(clp); 28561294Slling goto out; 28571294Slling } 28581294Slling 28591294Slling /* 28601294Slling * Now that we have verified that the snapshot is the latest, 28611294Slling * rollback to the given snapshot. 28621294Slling */ 28631294Slling ret = do_rollback(zhp); 28641294Slling 28651294Slling if (ret != 0) { 28661294Slling (void) changelist_postfix(clp); 28671294Slling goto out; 28681294Slling } 28691294Slling 28701294Slling /* 28711294Slling * We only want to re-mount the filesystem if it was mounted in the 28721294Slling * first place. 28731294Slling */ 28741294Slling ret = changelist_postfix(clp); 28751294Slling 28761294Slling out: 28771294Slling changelist_free(clp); 28781294Slling return (ret); 28791294Slling } 28801294Slling 28811294Slling /* 2882789Sahrens * Iterate over all dependents for a given dataset. This includes both 2883789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2884789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2885789Sahrens * libzfs_graph.c. 2886789Sahrens */ 2887789Sahrens int 28882474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 28892474Seschrock zfs_iter_f func, void *data) 2890789Sahrens { 2891789Sahrens char **dependents; 2892789Sahrens size_t count; 2893789Sahrens int i; 2894789Sahrens zfs_handle_t *child; 2895789Sahrens int ret = 0; 2896789Sahrens 28972474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 28982474Seschrock &dependents, &count) != 0) 28992474Seschrock return (-1); 29002474Seschrock 2901789Sahrens for (i = 0; i < count; i++) { 29022082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 29032082Seschrock dependents[i])) == NULL) 2904789Sahrens continue; 2905789Sahrens 2906789Sahrens if ((ret = func(child, data)) != 0) 2907789Sahrens break; 2908789Sahrens } 2909789Sahrens 2910789Sahrens for (i = 0; i < count; i++) 2911789Sahrens free(dependents[i]); 2912789Sahrens free(dependents); 2913789Sahrens 2914789Sahrens return (ret); 2915789Sahrens } 2916789Sahrens 2917789Sahrens /* 2918789Sahrens * Renames the given dataset. 2919789Sahrens */ 2920789Sahrens int 2921789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2922789Sahrens { 2923789Sahrens int ret; 2924789Sahrens zfs_cmd_t zc = { 0 }; 2925789Sahrens char *delim; 2926789Sahrens prop_changelist_t *cl; 2927789Sahrens char parent[ZFS_MAXNAMELEN]; 29282082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 29292082Seschrock char errbuf[1024]; 2930789Sahrens 2931789Sahrens /* if we have the same exact name, just return success */ 2932789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2933789Sahrens return (0); 2934789Sahrens 29352082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 29362082Seschrock "cannot rename to '%s'"), target); 29372082Seschrock 2938789Sahrens /* 2939789Sahrens * Make sure the target name is valid 2940789Sahrens */ 2941789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2942*2665Snd150628 if ((strchr(target, '@') == NULL) || 2943*2665Snd150628 *target == '@') { 2944*2665Snd150628 /* 2945*2665Snd150628 * Snapshot target name is abbreviated, 2946*2665Snd150628 * reconstruct full dataset name 2947*2665Snd150628 */ 2948*2665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 2949*2665Snd150628 sizeof (parent)); 2950*2665Snd150628 delim = strchr(parent, '@'); 2951*2665Snd150628 if (strchr(target, '@') == NULL) 2952*2665Snd150628 *(++delim) = '\0'; 2953*2665Snd150628 else 2954*2665Snd150628 *delim = '\0'; 2955*2665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 2956*2665Snd150628 target = parent; 2957*2665Snd150628 } else { 2958*2665Snd150628 /* 2959*2665Snd150628 * Make sure we're renaming within the same dataset. 2960*2665Snd150628 */ 2961*2665Snd150628 delim = strchr(target, '@'); 2962*2665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 2963*2665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 2964*2665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2965*2665Snd150628 "snapshots must be part of same " 2966*2665Snd150628 "dataset")); 2967*2665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 2968*2665Snd150628 errbuf)); 2969*2665Snd150628 } 2970789Sahrens } 2971*2665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 2972*2665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2973789Sahrens } else { 2974*2665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 2975*2665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2976789Sahrens /* validate parents */ 29772082Seschrock if (check_parents(hdl, target) != 0) 2978789Sahrens return (-1); 2979789Sahrens 2980789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2981789Sahrens 2982789Sahrens /* make sure we're in the same pool */ 2983789Sahrens verify((delim = strchr(target, '/')) != NULL); 2984789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2985789Sahrens zhp->zfs_name[delim - target] != '/') { 29862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29872082Seschrock "datasets must be within same pool")); 29882082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2989789Sahrens } 29902440Snd150628 29912440Snd150628 /* new name cannot be a child of the current dataset name */ 29922440Snd150628 if (strncmp(parent, zhp->zfs_name, 29932440Snd150628 strlen(zhp->zfs_name)) == 0) { 29942440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29952440Snd150628 "New dataset name cannot be a descendent of " 29962440Snd150628 "current dataset name")); 29972440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 29982440Snd150628 } 2999789Sahrens } 3000789Sahrens 30012082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 30022082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 30032082Seschrock 3004789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3005789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 30062082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30072082Seschrock "dataset is used in a non-global zone")); 30082082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3009789Sahrens } 3010789Sahrens 3011789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 30122082Seschrock return (-1); 3013789Sahrens 3014789Sahrens if (changelist_haszonedchild(cl)) { 30152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30162082Seschrock "child dataset with inherited mountpoint is used " 30172082Seschrock "in a non-global zone")); 30182082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 3019789Sahrens goto error; 3020789Sahrens } 3021789Sahrens 3022789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3023789Sahrens goto error; 3024789Sahrens 3025789Sahrens if (zhp->zfs_volblocksize != 0) 3026789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3027789Sahrens else 3028789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3029789Sahrens 3030*2665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3031*2665Snd150628 (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 3032*2665Snd150628 3033*2665Snd150628 30342082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 30352082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3036789Sahrens 3037789Sahrens /* 3038789Sahrens * On failure, we still want to remount any filesystems that 3039789Sahrens * were previously mounted, so we don't alter the system state. 3040789Sahrens */ 3041789Sahrens (void) changelist_postfix(cl); 3042789Sahrens } else { 3043789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3044789Sahrens 3045789Sahrens ret = changelist_postfix(cl); 3046789Sahrens } 3047789Sahrens 3048789Sahrens error: 3049789Sahrens changelist_free(cl); 3050789Sahrens return (ret); 3051789Sahrens } 3052789Sahrens 3053789Sahrens /* 3054789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3055789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3056789Sahrens */ 3057789Sahrens int 30582082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3059789Sahrens { 3060789Sahrens zfs_cmd_t zc = { 0 }; 30612082Seschrock di_devlink_handle_t dhdl; 3062789Sahrens 3063789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3064789Sahrens 3065789Sahrens /* 3066789Sahrens * Issue the appropriate ioctl. 3067789Sahrens */ 30682082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3069789Sahrens switch (errno) { 3070789Sahrens case EEXIST: 3071789Sahrens /* 3072789Sahrens * Silently ignore the case where the link already 3073789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3074789Sahrens * times without errors. 3075789Sahrens */ 3076789Sahrens return (0); 3077789Sahrens 3078789Sahrens default: 30792082Seschrock return (zfs_standard_error(hdl, errno, 30802082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30812082Seschrock "for '%s'"), dataset)); 3082789Sahrens } 3083789Sahrens } 3084789Sahrens 3085789Sahrens /* 3086789Sahrens * Call devfsadm and wait for the links to magically appear. 3087789Sahrens */ 30882082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 30892082Seschrock zfs_error_aux(hdl, strerror(errno)); 30902082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 30912082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30922082Seschrock "for '%s'"), dataset); 30932082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3094789Sahrens return (-1); 3095789Sahrens } else { 30962082Seschrock (void) di_devlink_fini(&dhdl); 3097789Sahrens } 3098789Sahrens 3099789Sahrens return (0); 3100789Sahrens } 3101789Sahrens 3102789Sahrens /* 3103789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3104789Sahrens */ 3105789Sahrens int 31062082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3107789Sahrens { 3108789Sahrens zfs_cmd_t zc = { 0 }; 3109789Sahrens 3110789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3111789Sahrens 31122082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3113789Sahrens switch (errno) { 3114789Sahrens case ENXIO: 3115789Sahrens /* 3116789Sahrens * Silently ignore the case where the link no longer 3117789Sahrens * exists, so that 'zfs volfini' can be run multiple 3118789Sahrens * times without errors. 3119789Sahrens */ 3120789Sahrens return (0); 3121789Sahrens 3122789Sahrens default: 31232082Seschrock return (zfs_standard_error(hdl, errno, 31242082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 31252082Seschrock "links for '%s'"), dataset)); 3126789Sahrens } 3127789Sahrens } 3128789Sahrens 3129789Sahrens return (0); 3130789Sahrens } 3131