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 1087789Sahrens if (zhp->zfs_mntopts == NULL) 1088789Sahrens mnt.mnt_mntopts = ""; 1089789Sahrens else 1090789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1091789Sahrens 1092789Sahrens switch (prop) { 1093789Sahrens case ZFS_PROP_ATIME: 10942082Seschrock *val = getprop_uint64(zhp, prop, source); 10952082Seschrock 10962082Seschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 10972082Seschrock *val = B_TRUE; 1098789Sahrens if (src) 1099789Sahrens *src = ZFS_SRC_TEMPORARY; 11002082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 11012082Seschrock *val = B_FALSE; 1102789Sahrens if (src) 1103789Sahrens *src = ZFS_SRC_TEMPORARY; 1104789Sahrens } 11052082Seschrock break; 1106789Sahrens 1107789Sahrens case ZFS_PROP_AVAILABLE: 11082082Seschrock *val = zhp->zfs_dmustats.dds_available; 11092082Seschrock break; 1110789Sahrens 1111789Sahrens case ZFS_PROP_DEVICES: 11122082Seschrock *val = getprop_uint64(zhp, prop, source); 11132082Seschrock 11142082Seschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 11152082Seschrock *val = B_TRUE; 1116789Sahrens if (src) 1117789Sahrens *src = ZFS_SRC_TEMPORARY; 11182082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 11192082Seschrock *val = B_FALSE; 1120789Sahrens if (src) 1121789Sahrens *src = ZFS_SRC_TEMPORARY; 1122789Sahrens } 11232082Seschrock break; 1124789Sahrens 1125789Sahrens case ZFS_PROP_EXEC: 11262082Seschrock *val = getprop_uint64(zhp, prop, source); 11272082Seschrock 11282082Seschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 11292082Seschrock *val = B_TRUE; 1130789Sahrens if (src) 1131789Sahrens *src = ZFS_SRC_TEMPORARY; 11322082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 11332082Seschrock *val = B_FALSE; 1134789Sahrens if (src) 1135789Sahrens *src = ZFS_SRC_TEMPORARY; 1136789Sahrens } 11372082Seschrock break; 1138789Sahrens 1139789Sahrens case ZFS_PROP_RECORDSIZE: 1140789Sahrens case ZFS_PROP_COMPRESSION: 11411356Seschrock case ZFS_PROP_ZONED: 11422082Seschrock *val = getprop_uint64(zhp, prop, source); 11432082Seschrock break; 1144789Sahrens 1145789Sahrens case ZFS_PROP_READONLY: 11462082Seschrock *val = getprop_uint64(zhp, prop, source); 11472082Seschrock 11482082Seschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 11492082Seschrock *val = B_TRUE; 1150789Sahrens if (src) 1151789Sahrens *src = ZFS_SRC_TEMPORARY; 11522082Seschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 11532082Seschrock *val = B_FALSE; 1154789Sahrens if (src) 1155789Sahrens *src = ZFS_SRC_TEMPORARY; 1156789Sahrens } 11572082Seschrock break; 1158789Sahrens 11591544Seschrock case ZFS_PROP_CREATION: 11602082Seschrock *val = zhp->zfs_dmustats.dds_creation_time; 11612082Seschrock break; 11621544Seschrock 1163789Sahrens case ZFS_PROP_QUOTA: 1164789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1165789Sahrens *source = ""; /* default */ 1166789Sahrens else 1167789Sahrens *source = zhp->zfs_name; 11682082Seschrock *val = zhp->zfs_dmustats.dds_quota; 11692082Seschrock break; 1170789Sahrens 1171789Sahrens case ZFS_PROP_RESERVATION: 1172789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1173789Sahrens *source = ""; /* default */ 1174789Sahrens else 1175789Sahrens *source = zhp->zfs_name; 11762082Seschrock *val = zhp->zfs_dmustats.dds_reserved; 11772082Seschrock break; 1178789Sahrens 1179789Sahrens case ZFS_PROP_COMPRESSRATIO: 1180789Sahrens /* 1181789Sahrens * Using physical space and logical space, calculate the 1182789Sahrens * compression ratio. We return the number as a multiple of 1183789Sahrens * 100, so '2.5x' would be returned as 250. 1184789Sahrens */ 1185789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 11862082Seschrock *val = 100ULL; 1187789Sahrens else 11882082Seschrock *val = 11892082Seschrock (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1190789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 11912082Seschrock break; 1192789Sahrens 1193789Sahrens case ZFS_PROP_REFERENCED: 1194789Sahrens /* 1195789Sahrens * 'referenced' refers to the amount of physical space 1196789Sahrens * referenced (possibly shared) by this object. 1197789Sahrens */ 11982082Seschrock *val = zhp->zfs_dmustats.dds_space_refd; 11992082Seschrock break; 1200789Sahrens 1201789Sahrens case ZFS_PROP_SETUID: 12022082Seschrock *val = getprop_uint64(zhp, prop, source); 12032082Seschrock 12042082Seschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 12052082Seschrock *val = B_TRUE; 1206789Sahrens if (src) 1207789Sahrens *src = ZFS_SRC_TEMPORARY; 12082082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 12092082Seschrock *val = B_FALSE; 1210789Sahrens if (src) 1211789Sahrens *src = ZFS_SRC_TEMPORARY; 1212789Sahrens } 12132082Seschrock break; 1214789Sahrens 1215789Sahrens case ZFS_PROP_VOLSIZE: 12162082Seschrock *val = zhp->zfs_volsize; 12172082Seschrock break; 1218789Sahrens 1219789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 12202082Seschrock *val = zhp->zfs_volblocksize; 12212082Seschrock break; 1222789Sahrens 1223789Sahrens case ZFS_PROP_USED: 12242082Seschrock *val = zhp->zfs_dmustats.dds_space_used; 12252082Seschrock break; 1226789Sahrens 1227789Sahrens case ZFS_PROP_CREATETXG: 12282082Seschrock *val = zhp->zfs_dmustats.dds_creation_txg; 12292082Seschrock break; 1230789Sahrens 1231789Sahrens case ZFS_PROP_MOUNTED: 1232789Sahrens /* 1233789Sahrens * Unlike other properties, we defer calculation of 'MOUNTED' 1234789Sahrens * until actually requested. This is because the getmntany() 1235789Sahrens * call can be extremely expensive on systems with a large 1236789Sahrens * number of filesystems, and the property isn't needed in 1237789Sahrens * normal use cases. 1238789Sahrens */ 1239789Sahrens if (zhp->zfs_mntopts == NULL) { 1240789Sahrens struct mnttab search = { 0 }, entry; 1241789Sahrens 1242789Sahrens search.mnt_special = (char *)zhp->zfs_name; 12431407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 12442082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 12452082Seschrock 12462082Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 12472082Seschrock &search) == 0 && (zhp->zfs_mntopts = 12482082Seschrock zfs_strdup(zhp->zfs_hdl, 12492082Seschrock entry.mnt_mntopts)) == NULL) 12502082Seschrock return (-1); 1251789Sahrens } 12522082Seschrock *val = (zhp->zfs_mntopts != NULL); 12532082Seschrock break; 1254789Sahrens 1255789Sahrens default: 12562082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 12572082Seschrock "cannot get non-numeric property")); 12582082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 12592082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1260789Sahrens } 1261789Sahrens 1262789Sahrens return (0); 1263789Sahrens } 1264789Sahrens 1265789Sahrens /* 1266789Sahrens * Calculate the source type, given the raw source string. 1267789Sahrens */ 1268789Sahrens static void 1269789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1270789Sahrens char *statbuf, size_t statlen) 1271789Sahrens { 1272789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1273789Sahrens return; 1274789Sahrens 1275789Sahrens if (source == NULL) { 1276789Sahrens *srctype = ZFS_SRC_NONE; 1277789Sahrens } else if (source[0] == '\0') { 1278789Sahrens *srctype = ZFS_SRC_DEFAULT; 1279789Sahrens } else { 1280789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1281789Sahrens *srctype = ZFS_SRC_LOCAL; 1282789Sahrens } else { 1283789Sahrens (void) strlcpy(statbuf, source, statlen); 1284789Sahrens *srctype = ZFS_SRC_INHERITED; 1285789Sahrens } 1286789Sahrens } 1287789Sahrens 1288789Sahrens } 1289789Sahrens 1290789Sahrens /* 1291789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1292789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1293789Sahrens * human-readable form. 1294789Sahrens * 1295789Sahrens * Returns 0 on success, or -1 on error. 1296789Sahrens */ 1297789Sahrens int 1298789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 12992082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1300789Sahrens { 1301789Sahrens char *source = NULL; 1302789Sahrens uint64_t val; 1303789Sahrens char *str; 1304789Sahrens int i; 1305789Sahrens const char *root; 1306789Sahrens 1307789Sahrens /* 1308789Sahrens * Check to see if this property applies to our object 1309789Sahrens */ 1310789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1311789Sahrens return (-1); 1312789Sahrens 1313789Sahrens if (src) 1314789Sahrens *src = ZFS_SRC_NONE; 1315789Sahrens 1316789Sahrens switch (prop) { 1317789Sahrens case ZFS_PROP_ATIME: 1318789Sahrens case ZFS_PROP_READONLY: 1319789Sahrens case ZFS_PROP_SETUID: 1320789Sahrens case ZFS_PROP_ZONED: 1321789Sahrens case ZFS_PROP_DEVICES: 1322789Sahrens case ZFS_PROP_EXEC: 1323789Sahrens /* 1324789Sahrens * Basic boolean values are built on top of 1325789Sahrens * get_numeric_property(). 1326789Sahrens */ 13272082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 13282082Seschrock return (-1); 13292082Seschrock nicebool(val, propbuf, proplen); 1330789Sahrens 1331789Sahrens break; 1332789Sahrens 1333789Sahrens case ZFS_PROP_AVAILABLE: 1334789Sahrens case ZFS_PROP_RECORDSIZE: 1335789Sahrens case ZFS_PROP_CREATETXG: 1336789Sahrens case ZFS_PROP_REFERENCED: 1337789Sahrens case ZFS_PROP_USED: 1338789Sahrens case ZFS_PROP_VOLSIZE: 1339789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1340789Sahrens /* 1341789Sahrens * Basic numeric values are built on top of 1342789Sahrens * get_numeric_property(). 1343789Sahrens */ 13442082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 13452082Seschrock return (-1); 1346789Sahrens if (literal) 1347789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1348789Sahrens else 1349789Sahrens zfs_nicenum(val, propbuf, proplen); 1350789Sahrens break; 1351789Sahrens 1352789Sahrens case ZFS_PROP_COMPRESSION: 13531356Seschrock val = getprop_uint64(zhp, prop, &source); 1354789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 13551356Seschrock if (compress_table[i].value == val) 1356789Sahrens break; 1357789Sahrens } 1358789Sahrens assert(compress_table[i].name != NULL); 1359789Sahrens (void) strlcpy(propbuf, compress_table[i].name, proplen); 1360789Sahrens break; 1361789Sahrens 1362789Sahrens case ZFS_PROP_CHECKSUM: 13631356Seschrock val = getprop_uint64(zhp, prop, &source); 1364789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 13651356Seschrock if (checksum_table[i].value == val) 1366789Sahrens break; 1367789Sahrens } 1368789Sahrens assert(checksum_table[i].name != NULL); 1369789Sahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen); 1370789Sahrens break; 1371789Sahrens 1372789Sahrens case ZFS_PROP_SNAPDIR: 13731356Seschrock val = getprop_uint64(zhp, prop, &source); 1374789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 13751356Seschrock if (snapdir_table[i].value == val) 1376789Sahrens break; 1377789Sahrens } 1378789Sahrens assert(snapdir_table[i].name != NULL); 1379789Sahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen); 1380789Sahrens break; 1381789Sahrens 1382789Sahrens case ZFS_PROP_ACLMODE: 13831356Seschrock val = getprop_uint64(zhp, prop, &source); 1384789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 13851356Seschrock if (acl_mode_table[i].value == val) 1386789Sahrens break; 1387789Sahrens } 1388789Sahrens assert(acl_mode_table[i].name != NULL); 1389789Sahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen); 1390789Sahrens break; 1391789Sahrens 1392789Sahrens case ZFS_PROP_ACLINHERIT: 13931356Seschrock val = getprop_uint64(zhp, prop, &source); 1394789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 13951356Seschrock if (acl_inherit_table[i].value == val) 1396789Sahrens break; 1397789Sahrens } 1398789Sahrens assert(acl_inherit_table[i].name != NULL); 1399789Sahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen); 1400789Sahrens break; 1401789Sahrens 1402789Sahrens case ZFS_PROP_CREATION: 1403789Sahrens /* 1404789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1405789Sahrens * this into a string unless 'literal' is specified. 1406789Sahrens */ 1407789Sahrens { 1408789Sahrens time_t time = (time_t) 1409789Sahrens zhp->zfs_dmustats.dds_creation_time; 1410789Sahrens struct tm t; 1411789Sahrens 1412789Sahrens if (literal || 1413789Sahrens localtime_r(&time, &t) == NULL || 1414789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1415789Sahrens &t) == 0) 1416789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1417789Sahrens zhp->zfs_dmustats.dds_creation_time); 1418789Sahrens } 1419789Sahrens break; 1420789Sahrens 1421789Sahrens case ZFS_PROP_MOUNTPOINT: 1422789Sahrens /* 1423789Sahrens * Getting the precise mountpoint can be tricky. 1424789Sahrens * 1425789Sahrens * - for 'none' or 'legacy', return those values. 1426789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1427789Sahrens * - for inherited mountpoints, we want to take everything 1428789Sahrens * after our ancestor and append it to the inherited value. 1429789Sahrens * 1430789Sahrens * If the pool has an alternate root, we want to prepend that 1431789Sahrens * root to any values we return. 1432789Sahrens */ 14331544Seschrock root = zhp->zfs_root; 14341356Seschrock str = getprop_string(zhp, prop, &source); 14351356Seschrock 14361356Seschrock if (str[0] == '\0') { 1437789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1438789Sahrens root, zhp->zfs_name); 14391356Seschrock } else if (str[0] == '/') { 14401356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1441789Sahrens 1442789Sahrens if (relpath[0] == '/') 1443789Sahrens relpath++; 14441356Seschrock if (str[1] == '\0') 14451356Seschrock str++; 1446789Sahrens 1447789Sahrens if (relpath[0] == '\0') 1448789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 14491356Seschrock root, str); 1450789Sahrens else 1451789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 14521356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1453789Sahrens relpath); 1454789Sahrens } else { 1455789Sahrens /* 'legacy' or 'none' */ 14561356Seschrock (void) strlcpy(propbuf, str, proplen); 1457789Sahrens } 1458789Sahrens 1459789Sahrens break; 1460789Sahrens 1461789Sahrens case ZFS_PROP_SHARENFS: 14621356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 14631356Seschrock proplen); 1464789Sahrens break; 1465789Sahrens 1466789Sahrens case ZFS_PROP_ORIGIN: 14671544Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1468789Sahrens proplen); 1469789Sahrens /* 1470789Sahrens * If there is no parent at all, return failure to indicate that 1471789Sahrens * it doesn't apply to this dataset. 1472789Sahrens */ 1473789Sahrens if (propbuf[0] == '\0') 1474789Sahrens return (-1); 1475789Sahrens break; 1476789Sahrens 1477789Sahrens case ZFS_PROP_QUOTA: 1478789Sahrens case ZFS_PROP_RESERVATION: 14792082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 14802082Seschrock return (-1); 1481789Sahrens 1482789Sahrens /* 1483789Sahrens * If quota or reservation is 0, we translate this into 'none' 1484789Sahrens * (unless literal is set), and indicate that it's the default 1485789Sahrens * value. Otherwise, we print the number nicely and indicate 1486789Sahrens * that its set locally. 1487789Sahrens */ 1488789Sahrens if (val == 0) { 1489789Sahrens if (literal) 1490789Sahrens (void) strlcpy(propbuf, "0", proplen); 1491789Sahrens else 1492789Sahrens (void) strlcpy(propbuf, "none", proplen); 1493789Sahrens } else { 1494789Sahrens if (literal) 1495789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1496789Sahrens else 1497789Sahrens zfs_nicenum(val, propbuf, proplen); 1498789Sahrens } 1499789Sahrens break; 1500789Sahrens 1501789Sahrens case ZFS_PROP_COMPRESSRATIO: 15022082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15032082Seschrock return (-1); 1504789Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1505789Sahrens val % 100); 1506789Sahrens break; 1507789Sahrens 1508789Sahrens case ZFS_PROP_TYPE: 1509789Sahrens switch (zhp->zfs_type) { 1510789Sahrens case ZFS_TYPE_FILESYSTEM: 1511789Sahrens str = "filesystem"; 1512789Sahrens break; 1513789Sahrens case ZFS_TYPE_VOLUME: 1514789Sahrens str = "volume"; 1515789Sahrens break; 1516789Sahrens case ZFS_TYPE_SNAPSHOT: 1517789Sahrens str = "snapshot"; 1518789Sahrens break; 1519789Sahrens default: 15202082Seschrock abort(); 1521789Sahrens } 1522789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1523789Sahrens break; 1524789Sahrens 1525789Sahrens case ZFS_PROP_MOUNTED: 1526789Sahrens /* 1527789Sahrens * The 'mounted' property is a pseudo-property that described 1528789Sahrens * whether the filesystem is currently mounted. Even though 1529789Sahrens * it's a boolean value, the typical values of "on" and "off" 1530789Sahrens * don't make sense, so we translate to "yes" and "no". 1531789Sahrens */ 15322082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 15332082Seschrock src, &source, &val) != 0) 15342082Seschrock return (-1); 15352082Seschrock if (val) 1536789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1537789Sahrens else 1538789Sahrens (void) strlcpy(propbuf, "no", proplen); 1539789Sahrens break; 1540789Sahrens 1541789Sahrens case ZFS_PROP_NAME: 1542789Sahrens /* 1543789Sahrens * The 'name' property is a pseudo-property derived from the 1544789Sahrens * dataset name. It is presented as a real property to simplify 1545789Sahrens * consumers. 1546789Sahrens */ 1547789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1548789Sahrens break; 1549789Sahrens 1550789Sahrens default: 15512082Seschrock abort(); 1552789Sahrens } 1553789Sahrens 1554789Sahrens get_source(zhp, src, source, statbuf, statlen); 1555789Sahrens 1556789Sahrens return (0); 1557789Sahrens } 1558789Sahrens 1559789Sahrens /* 1560789Sahrens * Utility function to get the given numeric property. Does no validation that 1561789Sahrens * the given property is the appropriate type; should only be used with 1562789Sahrens * hard-coded property types. 1563789Sahrens */ 1564789Sahrens uint64_t 1565789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1566789Sahrens { 1567789Sahrens char *source; 1568789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 15692082Seschrock uint64_t val; 15702082Seschrock 15712082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 15722082Seschrock 15732082Seschrock return (val); 1574789Sahrens } 1575789Sahrens 1576789Sahrens /* 1577789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1578789Sahrens */ 1579789Sahrens int 1580789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1581789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1582789Sahrens { 1583789Sahrens char *source; 1584789Sahrens 1585789Sahrens /* 1586789Sahrens * Check to see if this property applies to our object 1587789Sahrens */ 1588789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 15892082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 15902082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 15912082Seschrock zfs_prop_to_name(prop))); 1592789Sahrens 1593789Sahrens if (src) 1594789Sahrens *src = ZFS_SRC_NONE; 1595789Sahrens 15962082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 15972082Seschrock return (-1); 1598789Sahrens 1599789Sahrens get_source(zhp, src, source, statbuf, statlen); 1600789Sahrens 1601789Sahrens return (0); 1602789Sahrens } 1603789Sahrens 1604789Sahrens /* 1605789Sahrens * Returns the name of the given zfs handle. 1606789Sahrens */ 1607789Sahrens const char * 1608789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1609789Sahrens { 1610789Sahrens return (zhp->zfs_name); 1611789Sahrens } 1612789Sahrens 1613789Sahrens /* 1614789Sahrens * Returns the type of the given zfs handle. 1615789Sahrens */ 1616789Sahrens zfs_type_t 1617789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1618789Sahrens { 1619789Sahrens return (zhp->zfs_type); 1620789Sahrens } 1621789Sahrens 1622789Sahrens /* 16231356Seschrock * Iterate over all child filesystems 1624789Sahrens */ 1625789Sahrens int 16261356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1627789Sahrens { 1628789Sahrens zfs_cmd_t zc = { 0 }; 1629789Sahrens zfs_handle_t *nzhp; 1630789Sahrens int ret; 1631789Sahrens 1632789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16332082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1634789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1635789Sahrens /* 1636789Sahrens * Ignore private dataset names. 1637789Sahrens */ 1638789Sahrens if (dataset_name_hidden(zc.zc_name)) 1639789Sahrens continue; 1640789Sahrens 1641789Sahrens /* 1642789Sahrens * Silently ignore errors, as the only plausible explanation is 1643789Sahrens * that the pool has since been removed. 1644789Sahrens */ 16452082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 16462082Seschrock zc.zc_name)) == NULL) 1647789Sahrens continue; 1648789Sahrens 1649789Sahrens if ((ret = func(nzhp, data)) != 0) 1650789Sahrens return (ret); 1651789Sahrens } 1652789Sahrens 1653789Sahrens /* 1654789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1655789Sahrens * returned, then the underlying dataset has been removed since we 1656789Sahrens * obtained the handle. 1657789Sahrens */ 1658789Sahrens if (errno != ESRCH && errno != ENOENT) 16592082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 16602082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1661789Sahrens 16621356Seschrock return (0); 16631356Seschrock } 16641356Seschrock 16651356Seschrock /* 16661356Seschrock * Iterate over all snapshots 16671356Seschrock */ 16681356Seschrock int 16691356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 16701356Seschrock { 16711356Seschrock zfs_cmd_t zc = { 0 }; 16721356Seschrock zfs_handle_t *nzhp; 16731356Seschrock int ret; 1674789Sahrens 1675789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16762082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 16772082Seschrock &zc) == 0; 1678789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1679789Sahrens 16802082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 16812082Seschrock zc.zc_name)) == NULL) 1682789Sahrens continue; 1683789Sahrens 1684789Sahrens if ((ret = func(nzhp, data)) != 0) 1685789Sahrens return (ret); 1686789Sahrens } 1687789Sahrens 1688789Sahrens /* 1689789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1690789Sahrens * returned, then the underlying dataset has been removed since we 1691789Sahrens * obtained the handle. Silently ignore this case, and return success. 1692789Sahrens */ 1693789Sahrens if (errno != ESRCH && errno != ENOENT) 16942082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 16952082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1696789Sahrens 1697789Sahrens return (0); 1698789Sahrens } 1699789Sahrens 1700789Sahrens /* 17011356Seschrock * Iterate over all children, snapshots and filesystems 17021356Seschrock */ 17031356Seschrock int 17041356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 17051356Seschrock { 17061356Seschrock int ret; 17071356Seschrock 17081356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 17091356Seschrock return (ret); 17101356Seschrock 17111356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 17121356Seschrock } 17131356Seschrock 17141356Seschrock /* 1715789Sahrens * Given a complete name, return just the portion that refers to the parent. 1716789Sahrens * Can return NULL if this is a pool. 1717789Sahrens */ 1718789Sahrens static int 1719789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1720789Sahrens { 1721789Sahrens char *loc; 1722789Sahrens 1723789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1724789Sahrens return (-1); 1725789Sahrens 1726789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1727789Sahrens buf[loc - path] = '\0'; 1728789Sahrens 1729789Sahrens return (0); 1730789Sahrens } 1731789Sahrens 1732789Sahrens /* 1733789Sahrens * Checks to make sure that the given path has a parent, and that it exists. 1734789Sahrens */ 1735789Sahrens static int 17362082Seschrock check_parents(libzfs_handle_t *hdl, const char *path) 1737789Sahrens { 1738789Sahrens zfs_cmd_t zc = { 0 }; 1739789Sahrens char parent[ZFS_MAXNAMELEN]; 1740789Sahrens char *slash; 17411356Seschrock zfs_handle_t *zhp; 17422082Seschrock char errbuf[1024]; 17432082Seschrock 17442082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 17452082Seschrock path); 1746789Sahrens 1747789Sahrens /* get parent, and check to see if this is just a pool */ 1748789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 17492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17502082Seschrock "missing dataset name")); 17512082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1752789Sahrens } 1753789Sahrens 1754789Sahrens /* check to see if the pool exists */ 1755789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1756789Sahrens slash = parent + strlen(parent); 1757789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1758789Sahrens zc.zc_name[slash - parent] = '\0'; 17592082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1760789Sahrens errno == ENOENT) { 17612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17622082Seschrock "no such pool '%s'"), zc.zc_name); 17632082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1764789Sahrens } 1765789Sahrens 1766789Sahrens /* check to see if the parent dataset exists */ 17672082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1768789Sahrens switch (errno) { 1769789Sahrens case ENOENT: 17702082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17712082Seschrock "parent does not exist")); 17722082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1773789Sahrens 1774789Sahrens default: 17752082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1776789Sahrens } 1777789Sahrens } 1778789Sahrens 1779789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 17801356Seschrock if (getzoneid() != GLOBAL_ZONEID && 17811393Slling !zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 17822082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 17831356Seschrock zfs_close(zhp); 1784789Sahrens return (-1); 1785789Sahrens } 1786789Sahrens 1787789Sahrens /* make sure parent is a filesystem */ 17881356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 17892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 17902082Seschrock "parent is not a filesystem")); 17912082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 17921356Seschrock zfs_close(zhp); 1793789Sahrens return (-1); 1794789Sahrens } 1795789Sahrens 17961356Seschrock zfs_close(zhp); 1797789Sahrens return (0); 1798789Sahrens } 1799789Sahrens 1800789Sahrens /* 1801789Sahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used 1802789Sahrens * only for volumes, and indicate the size and blocksize of the volume. 1803789Sahrens */ 1804789Sahrens int 18052082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 1806789Sahrens const char *sizestr, const char *blocksizestr) 1807789Sahrens { 1808789Sahrens zfs_cmd_t zc = { 0 }; 1809789Sahrens int ret; 1810789Sahrens uint64_t size = 0; 1811789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 18122082Seschrock char errbuf[1024]; 1813789Sahrens 1814789Sahrens /* convert sizestr into integer size */ 18152082Seschrock if (sizestr != NULL && nicestrtonum(hdl, sizestr, &size) != 0) 18162082Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 18172082Seschrock "bad volume size '%s'"), sizestr)); 1818789Sahrens 1819789Sahrens /* convert blocksizestr into integer blocksize */ 18202082Seschrock if (blocksizestr != NULL && nicestrtonum(hdl, blocksizestr, 18212082Seschrock &blocksize) != 0) 18222082Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 18232082Seschrock "bad volume blocksize '%s'"), blocksizestr)); 18242082Seschrock 18252082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 18262082Seschrock "cannot create '%s'"), path); 1827789Sahrens 1828789Sahrens /* validate the path, taking care to note the extended error message */ 18292082Seschrock if (!zfs_validate_name(hdl, path, type)) 18302082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1831789Sahrens 1832789Sahrens /* validate parents exist */ 18332082Seschrock if (check_parents(hdl, path) != 0) 1834789Sahrens return (-1); 1835789Sahrens 1836789Sahrens /* 1837789Sahrens * The failure modes when creating a dataset of a different type over 1838789Sahrens * one that already exists is a little strange. In particular, if you 1839789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1840789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1841789Sahrens * first try to see if the dataset exists. 1842789Sahrens */ 1843789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 18442082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 18452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18462082Seschrock "dataset already exists")); 18472082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1848789Sahrens } 1849789Sahrens 1850789Sahrens if (type == ZFS_TYPE_VOLUME) 1851789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1852789Sahrens else 1853789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1854789Sahrens 1855789Sahrens if (type == ZFS_TYPE_VOLUME) { 18561133Seschrock /* 18571133Seschrock * If we are creating a volume, the size and block size must 18581133Seschrock * satisfy a few restraints. First, the blocksize must be a 18591133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 18601133Seschrock * volsize must be a multiple of the block size, and cannot be 18611133Seschrock * zero. 18621133Seschrock */ 1863789Sahrens if (size == 0) { 18642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18652082Seschrock "cannot be zero")); 18662082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18672082Seschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 18682082Seschrock sizestr)); 1869789Sahrens } 1870789Sahrens 18711133Seschrock if (blocksize < SPA_MINBLOCKSIZE || 18721133Seschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) { 18732082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18741133Seschrock "must be power of 2 from %u to %uk"), 18751133Seschrock (uint_t)SPA_MINBLOCKSIZE, 18761133Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 18772082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18782082Seschrock dgettext(TEXT_DOMAIN, 18792082Seschrock "bad volume block size '%s'"), blocksizestr)); 18801133Seschrock } 18811133Seschrock 18821133Seschrock if (size % blocksize != 0) { 18832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18842082Seschrock "must be a multiple of volume block size")); 18852082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 18862082Seschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 18872082Seschrock sizestr)); 18881133Seschrock } 18891133Seschrock 1890789Sahrens zc.zc_volsize = size; 1891789Sahrens zc.zc_volblocksize = blocksize; 1892789Sahrens } 1893789Sahrens 1894789Sahrens /* create the dataset */ 18952082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 1896789Sahrens 1897789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 18982082Seschrock ret = zvol_create_link(hdl, path); 1899789Sahrens 1900789Sahrens /* check for failure */ 1901789Sahrens if (ret != 0) { 1902789Sahrens char parent[ZFS_MAXNAMELEN]; 1903789Sahrens (void) parent_name(path, parent, sizeof (parent)); 1904789Sahrens 1905789Sahrens switch (errno) { 1906789Sahrens case ENOENT: 19072082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19082082Seschrock "no such parent '%s'"), parent); 19092082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1910789Sahrens 1911789Sahrens case EINVAL: 19122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19132082Seschrock "parent '%s' is not a filesysem"), parent); 19142082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 1915789Sahrens 1916789Sahrens case EDOM: 19172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1918789Sahrens "must be power of 2 from %u to %uk"), 1919789Sahrens (uint_t)SPA_MINBLOCKSIZE, 1920789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 19212082Seschrock 19222082Seschrock return (zfs_error(hdl, EZFS_BADPROP, 19232082Seschrock dgettext(TEXT_DOMAIN, "bad block size '%s'"), 19242082Seschrock blocksizestr ? blocksizestr : "<unknown>")); 19252082Seschrock 1926789Sahrens #ifdef _ILP32 1927789Sahrens case EOVERFLOW: 1928789Sahrens /* 1929789Sahrens * This platform can't address a volume this big. 1930789Sahrens */ 19312082Seschrock if (type == ZFS_TYPE_VOLUME) 19322082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 19332082Seschrock errbuf)); 1934789Sahrens #endif 19352082Seschrock /* FALLTHROUGH */ 1936789Sahrens default: 19372082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1938789Sahrens } 1939789Sahrens } 1940789Sahrens 1941789Sahrens return (0); 1942789Sahrens } 1943789Sahrens 1944789Sahrens /* 1945789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 1946789Sahrens * isn't mounted, and that there are no active dependents. 1947789Sahrens */ 1948789Sahrens int 1949789Sahrens zfs_destroy(zfs_handle_t *zhp) 1950789Sahrens { 1951789Sahrens zfs_cmd_t zc = { 0 }; 1952789Sahrens int ret; 1953789Sahrens 1954789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1955789Sahrens 1956789Sahrens /* 1957789Sahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME 1958789Sahrens * so that we do the right thing for snapshots of volumes. 1959789Sahrens */ 1960789Sahrens if (zhp->zfs_volblocksize != 0) { 19612082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 1962789Sahrens return (-1); 1963789Sahrens 1964789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1965789Sahrens } else { 1966789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1967789Sahrens } 1968789Sahrens 19692082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 19702199Sahrens if (ret != 0) { 19712082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 19722082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 19732082Seschrock zhp->zfs_name)); 19742199Sahrens } 1975789Sahrens 1976789Sahrens remove_mountpoint(zhp); 1977789Sahrens 1978789Sahrens return (0); 1979789Sahrens } 1980789Sahrens 19812199Sahrens struct destroydata { 19822199Sahrens char *snapname; 19832199Sahrens boolean_t gotone; 19842199Sahrens }; 19852199Sahrens 19862199Sahrens static int 19872199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 19882199Sahrens { 19892199Sahrens struct destroydata *dd = arg; 19902199Sahrens zfs_handle_t *szhp; 19912199Sahrens char name[ZFS_MAXNAMELEN]; 19922199Sahrens 19932199Sahrens (void) strcpy(name, zhp->zfs_name); 19942199Sahrens (void) strcat(name, "@"); 19952199Sahrens (void) strcat(name, dd->snapname); 19962199Sahrens 19972199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 19982199Sahrens if (szhp) { 19992199Sahrens dd->gotone = B_TRUE; 20002199Sahrens zfs_close(szhp); 20012199Sahrens } 20022199Sahrens 20032199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 20042199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 20052199Sahrens /* 20062199Sahrens * NB: this is simply a best-effort. We don't want to 20072199Sahrens * return an error, because then we wouldn't visit all 20082199Sahrens * the volumes. 20092199Sahrens */ 20102199Sahrens } 20112199Sahrens 20122199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 20132199Sahrens } 20142199Sahrens 20152199Sahrens /* 20162199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 20172199Sahrens */ 20182199Sahrens int 20192199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 20202199Sahrens { 20212199Sahrens zfs_cmd_t zc = { 0 }; 20222199Sahrens int ret; 20232199Sahrens struct destroydata dd = { 0 }; 20242199Sahrens 20252199Sahrens dd.snapname = snapname; 20262199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 20272199Sahrens 20282199Sahrens if (!dd.gotone) { 20292199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 20302199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 20312199Sahrens zhp->zfs_name, snapname)); 20322199Sahrens } 20332199Sahrens 20342199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 20352199Sahrens (void) strlcpy(zc.zc_prop_value, snapname, sizeof (zc.zc_prop_value)); 20362199Sahrens 20372199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 20382199Sahrens if (ret != 0) { 20392199Sahrens char errbuf[1024]; 20402199Sahrens 20412199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20422199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 20432199Sahrens 20442199Sahrens switch (errno) { 20452199Sahrens case EEXIST: 20462199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 20472199Sahrens "snapshot is cloned")); 20482199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 20492199Sahrens 20502199Sahrens default: 20512199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 20522199Sahrens errbuf)); 20532199Sahrens } 20542199Sahrens } 20552199Sahrens 20562199Sahrens return (0); 20572199Sahrens } 20582199Sahrens 2059789Sahrens /* 2060789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2061789Sahrens */ 2062789Sahrens int 2063789Sahrens zfs_clone(zfs_handle_t *zhp, const char *target) 2064789Sahrens { 2065789Sahrens zfs_cmd_t zc = { 0 }; 2066789Sahrens char parent[ZFS_MAXNAMELEN]; 2067789Sahrens int ret; 20682082Seschrock char errbuf[1024]; 20692082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2070789Sahrens 2071789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2072789Sahrens 20732082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20742082Seschrock "cannot create '%s'"), target); 20752082Seschrock 2076789Sahrens /* validate the target name */ 20772082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 20782082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2079789Sahrens 2080789Sahrens /* validate parents exist */ 20812082Seschrock if (check_parents(zhp->zfs_hdl, target) != 0) 2082789Sahrens return (-1); 2083789Sahrens 2084789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2085789Sahrens 2086789Sahrens /* do the clone */ 2087789Sahrens if (zhp->zfs_volblocksize != 0) 2088789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2089789Sahrens else 2090789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2091789Sahrens 2092789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2093789Sahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename)); 20942082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2095789Sahrens 2096789Sahrens if (ret != 0) { 2097789Sahrens switch (errno) { 2098789Sahrens 2099789Sahrens case ENOENT: 2100789Sahrens /* 2101789Sahrens * The parent doesn't exist. We should have caught this 2102789Sahrens * above, but there may a race condition that has since 2103789Sahrens * destroyed the parent. 2104789Sahrens * 2105789Sahrens * At this point, we don't know whether it's the source 2106789Sahrens * that doesn't exist anymore, or whether the target 2107789Sahrens * dataset doesn't exist. 2108789Sahrens */ 21092082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21102082Seschrock "no such parent '%s'"), parent); 21112082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 21122082Seschrock 21132082Seschrock case EXDEV: 21142082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21152082Seschrock "source and target pools differ")); 21162082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 21172082Seschrock errbuf)); 21182082Seschrock 21192082Seschrock default: 21202082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 21212082Seschrock errbuf)); 21222082Seschrock } 21232082Seschrock } else if (zhp->zfs_volblocksize != 0) { 21242082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 21252082Seschrock } 21262082Seschrock 21272082Seschrock return (ret); 21282082Seschrock } 21292082Seschrock 21302082Seschrock typedef struct promote_data { 21312082Seschrock char cb_mountpoint[MAXPATHLEN]; 21322082Seschrock const char *cb_target; 21332082Seschrock const char *cb_errbuf; 21342082Seschrock uint64_t cb_pivot_txg; 21352082Seschrock } promote_data_t; 21362082Seschrock 21372082Seschrock static int 21382082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 21392082Seschrock { 21402082Seschrock promote_data_t *pd = data; 21412082Seschrock zfs_handle_t *szhp; 21422082Seschrock char snapname[MAXPATHLEN]; 21432082Seschrock 21442082Seschrock /* We don't care about snapshots after the pivot point */ 21452082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 21462082Seschrock return (0); 21472082Seschrock 21482417Sahrens /* Remove the device link if it's a zvol. */ 21492417Sahrens if (zhp->zfs_volblocksize != 0) 21502417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 21512082Seschrock 21522082Seschrock /* Check for conflicting names */ 21532082Seschrock (void) strcpy(snapname, pd->cb_target); 21542417Sahrens (void) strcat(snapname, strchr(zhp->zfs_name, '@')); 21552082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 21562082Seschrock if (szhp != NULL) { 21572082Seschrock zfs_close(szhp); 21582082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21592082Seschrock "snapshot name '%s' from origin \n" 21602082Seschrock "conflicts with '%s' from target"), 21612082Seschrock zhp->zfs_name, snapname); 21622082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 21632082Seschrock } 21642082Seschrock return (0); 21652082Seschrock } 21662082Seschrock 21672417Sahrens static int 21682417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 21692417Sahrens { 21702417Sahrens promote_data_t *pd = data; 21712417Sahrens 21722417Sahrens /* We don't care about snapshots after the pivot point */ 21732417Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 21742417Sahrens return (0); 21752417Sahrens 21762417Sahrens /* Create the device link if it's a zvol. */ 21772417Sahrens if (zhp->zfs_volblocksize != 0) 21782417Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 21792417Sahrens 21802417Sahrens return (0); 21812417Sahrens } 21822417Sahrens 21832082Seschrock /* 21842082Seschrock * Promotes the given clone fs to be the clone parent. 21852082Seschrock */ 21862082Seschrock int 21872082Seschrock zfs_promote(zfs_handle_t *zhp) 21882082Seschrock { 21892082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 21902082Seschrock zfs_cmd_t zc = { 0 }; 21912082Seschrock char parent[MAXPATHLEN]; 21922082Seschrock char *cp; 21932082Seschrock int ret; 21942082Seschrock zfs_handle_t *pzhp; 21952082Seschrock promote_data_t pd; 21962082Seschrock char errbuf[1024]; 21972082Seschrock 21982082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 21992082Seschrock "cannot promote '%s'"), zhp->zfs_name); 22002082Seschrock 22012082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 22022082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22032082Seschrock "snapshots can not be promoted")); 22042082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22052082Seschrock } 22062082Seschrock 22072082Seschrock (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of); 22082082Seschrock if (parent[0] == '\0') { 22092082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22102082Seschrock "not a cloned filesystem")); 22112082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22122082Seschrock } 22132082Seschrock cp = strchr(parent, '@'); 22142082Seschrock *cp = '\0'; 22152082Seschrock 22162082Seschrock /* Walk the snapshots we will be moving */ 22172082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 22182082Seschrock if (pzhp == NULL) 22192082Seschrock return (-1); 22202082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 22212082Seschrock zfs_close(pzhp); 22222082Seschrock pd.cb_target = zhp->zfs_name; 22232082Seschrock pd.cb_errbuf = errbuf; 22242082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 22252082Seschrock if (pzhp == NULL) 22262082Seschrock return (-1); 22272082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 22282082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 22292082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 22302417Sahrens if (ret != 0) { 22312417Sahrens zfs_close(pzhp); 22322082Seschrock return (-1); 22332417Sahrens } 22342082Seschrock 22352082Seschrock /* issue the ioctl */ 22362417Sahrens (void) strlcpy(zc.zc_prop_value, zhp->zfs_dmustats.dds_clone_of, 22372417Sahrens sizeof (zc.zc_prop_value)); 22382082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22392082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 22402082Seschrock 22412082Seschrock if (ret != 0) { 22422417Sahrens int save_errno = errno; 22432417Sahrens 22442417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 22452417Sahrens zfs_close(pzhp); 22462417Sahrens 22472417Sahrens switch (save_errno) { 2248789Sahrens case EEXIST: 2249789Sahrens /* 22502082Seschrock * There is a conflicting snapshot name. We 22512082Seschrock * should have caught this above, but they could 22522082Seschrock * have renamed something in the mean time. 2253789Sahrens */ 22542082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22552082Seschrock "conflicting snapshot name from parent '%s'"), 22562082Seschrock parent); 22572082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2258789Sahrens 2259789Sahrens default: 22602417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2261789Sahrens } 22622417Sahrens } else { 22632417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2264789Sahrens } 2265789Sahrens 22662417Sahrens zfs_close(pzhp); 2267789Sahrens return (ret); 2268789Sahrens } 2269789Sahrens 22702199Sahrens static int 22712199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 22722199Sahrens { 22732199Sahrens char *snapname = arg; 22742199Sahrens 22752199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 22762199Sahrens char name[MAXPATHLEN]; 22772199Sahrens 22782199Sahrens (void) strcpy(name, zhp->zfs_name); 22792199Sahrens (void) strcat(name, "@"); 22802199Sahrens (void) strcat(name, snapname); 22812199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 22822199Sahrens /* 22832199Sahrens * NB: this is simply a best-effort. We don't want to 22842199Sahrens * return an error, because then we wouldn't visit all 22852199Sahrens * the volumes. 22862199Sahrens */ 22872199Sahrens } 22882199Sahrens return (zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname)); 22892199Sahrens } 22902199Sahrens 2291789Sahrens /* 2292789Sahrens * Takes a snapshot of the given dataset 2293789Sahrens */ 2294789Sahrens int 22952199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2296789Sahrens { 2297789Sahrens const char *delim; 2298789Sahrens char *parent; 2299789Sahrens zfs_handle_t *zhp; 2300789Sahrens zfs_cmd_t zc = { 0 }; 2301789Sahrens int ret; 23022082Seschrock char errbuf[1024]; 23032082Seschrock 23042082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23052082Seschrock "cannot snapshot '%s'"), path); 23062082Seschrock 23072082Seschrock /* validate the target name */ 23082082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 23092082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2310789Sahrens 2311789Sahrens /* make sure the parent exists and is of the appropriate type */ 23122199Sahrens delim = strchr(path, '@'); 23132082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 23142082Seschrock return (-1); 2315789Sahrens (void) strncpy(parent, path, delim - path); 2316789Sahrens parent[delim - path] = '\0'; 2317789Sahrens 23182082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2319789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2320789Sahrens free(parent); 2321789Sahrens return (-1); 2322789Sahrens } 2323789Sahrens 23242199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 23252199Sahrens (void) strlcpy(zc.zc_prop_value, delim+1, sizeof (zc.zc_prop_value)); 23262199Sahrens zc.zc_cookie = recursive; 23272199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 23282199Sahrens 23292199Sahrens /* 23302199Sahrens * if it was recursive, the one that actually failed will be in 23312199Sahrens * zc.zc_name. 23322199Sahrens */ 23332199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23342199Sahrens "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_prop_value); 23352199Sahrens if (ret == 0 && recursive) { 23362199Sahrens (void) zfs_iter_filesystems(zhp, 23372199Sahrens zfs_create_link_cb, (char *)delim+1); 23382199Sahrens } 2339789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 23402082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 23412199Sahrens if (ret != 0) { 23422082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 23432082Seschrock &zc); 23442199Sahrens } 2345789Sahrens } 2346789Sahrens 23472082Seschrock if (ret != 0) 23482082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2349789Sahrens 2350789Sahrens free(parent); 2351789Sahrens zfs_close(zhp); 2352789Sahrens 2353789Sahrens return (ret); 2354789Sahrens } 2355789Sahrens 2356789Sahrens /* 2357789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2358789Sahrens */ 2359789Sahrens int 23601749Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2361789Sahrens { 2362789Sahrens zfs_cmd_t zc = { 0 }; 2363789Sahrens int ret; 23642082Seschrock char errbuf[1024]; 23652082Seschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 23662082Seschrock 23672082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23682082Seschrock "cannot send '%s'"), zhp_to->zfs_name); 2369789Sahrens 2370789Sahrens /* do the ioctl() */ 2371789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2372789Sahrens if (zhp_from) { 2373789Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2374789Sahrens sizeof (zc.zc_name)); 2375789Sahrens } else { 2376789Sahrens zc.zc_prop_value[0] = '\0'; 2377789Sahrens } 2378789Sahrens zc.zc_cookie = STDOUT_FILENO; 2379789Sahrens 23802082Seschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2381789Sahrens if (ret != 0) { 2382789Sahrens switch (errno) { 2383789Sahrens 2384789Sahrens case EXDEV: 23852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23862082Seschrock "not an ealier snapshot from the same fs")); 23872082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2388789Sahrens 2389789Sahrens case EDQUOT: 2390789Sahrens case EFBIG: 2391789Sahrens case EIO: 2392789Sahrens case ENOLINK: 2393789Sahrens case ENOSPC: 2394789Sahrens case ENOSTR: 2395789Sahrens case ENXIO: 2396789Sahrens case EPIPE: 2397789Sahrens case ERANGE: 2398789Sahrens case EFAULT: 2399789Sahrens case EROFS: 24002082Seschrock zfs_error_aux(hdl, strerror(errno)); 24012082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2402789Sahrens 2403789Sahrens default: 24042082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2405789Sahrens } 2406789Sahrens } 2407789Sahrens 2408789Sahrens return (ret); 2409789Sahrens } 2410789Sahrens 2411789Sahrens /* 2412789Sahrens * Restores a backup of tosnap from stdin. 2413789Sahrens */ 2414789Sahrens int 24152082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 24162082Seschrock int verbose, int dryrun) 2417789Sahrens { 2418789Sahrens zfs_cmd_t zc = { 0 }; 2419789Sahrens time_t begin_time; 2420868Sahrens int ioctl_err, err, bytes, size; 2421789Sahrens char *cp; 2422789Sahrens dmu_replay_record_t drr; 2423789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 24242082Seschrock char errbuf[1024]; 2425789Sahrens 2426789Sahrens begin_time = time(NULL); 2427789Sahrens 24282082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24292082Seschrock "cannot receive")); 24302082Seschrock 2431789Sahrens /* trim off snapname, if any */ 2432789Sahrens (void) strcpy(zc.zc_name, tosnap); 2433789Sahrens cp = strchr(zc.zc_name, '@'); 2434789Sahrens if (cp) 2435789Sahrens *cp = '\0'; 2436789Sahrens 2437789Sahrens /* read in the BEGIN record */ 2438789Sahrens cp = (char *)&drr; 2439789Sahrens bytes = 0; 2440789Sahrens do { 2441868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2442868Sahrens cp += size; 2443868Sahrens bytes += size; 2444868Sahrens } while (size > 0); 2445868Sahrens 2446868Sahrens if (size < 0 || bytes != sizeof (drr)) { 24472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24482082Seschrock "stream (failed to read first record)")); 24492082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2450789Sahrens } 2451789Sahrens 2452789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2453789Sahrens 2454789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2455789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 24562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24572082Seschrock "stream (bad magic number)")); 24582082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2459789Sahrens } 2460789Sahrens 2461789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2462789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 24632082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 24642082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2465789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 24662082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2467789Sahrens } 2468789Sahrens 2469789Sahrens /* 2470789Sahrens * Determine name of destination snapshot. 2471789Sahrens */ 24721544Seschrock (void) strcpy(zc.zc_filename, tosnap); 2473789Sahrens if (isprefix) { 2474789Sahrens if (strchr(tosnap, '@') != NULL) { 24752082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24762082Seschrock "destination must be a filesystem")); 24772082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2478789Sahrens } 2479789Sahrens 2480789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2481789Sahrens if (cp == NULL) 2482789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2483789Sahrens else 2484789Sahrens cp++; 2485789Sahrens 24861544Seschrock (void) strcat(zc.zc_filename, "/"); 24871544Seschrock (void) strcat(zc.zc_filename, cp); 2488789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2489789Sahrens /* 2490789Sahrens * they specified just a filesystem; tack on the 2491789Sahrens * snapname from the backup. 2492789Sahrens */ 2493789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 24942082Seschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 24952082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 24961544Seschrock (void) strcat(zc.zc_filename, cp); 2497789Sahrens } 2498789Sahrens 2499789Sahrens if (drrb->drr_fromguid) { 2500789Sahrens zfs_handle_t *h; 2501789Sahrens /* incremental backup stream */ 2502789Sahrens 2503789Sahrens /* do the ioctl to the containing fs */ 25041544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2505789Sahrens cp = strchr(zc.zc_name, '@'); 2506789Sahrens *cp = '\0'; 2507789Sahrens 2508789Sahrens /* make sure destination fs exists */ 25092082Seschrock h = zfs_open(hdl, zc.zc_name, 25102082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 25112082Seschrock if (h == NULL) 2512789Sahrens return (-1); 2513868Sahrens if (!dryrun) { 2514868Sahrens /* unmount destination fs or remove device link. */ 2515868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2516868Sahrens (void) zfs_unmount(h, NULL, 0); 2517868Sahrens } else { 25182082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2519868Sahrens } 2520868Sahrens } 2521789Sahrens zfs_close(h); 2522789Sahrens } else { 2523789Sahrens /* full backup stream */ 2524789Sahrens 25251544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2526868Sahrens 25271749Sahrens /* make sure they aren't trying to receive into the root */ 2528868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2529789Sahrens cp = strchr(zc.zc_name, '@'); 2530789Sahrens if (cp) 2531789Sahrens *cp = '\0'; 25322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25332082Seschrock "destination '%s' already exists"), zc.zc_name); 25342082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2535789Sahrens } 2536789Sahrens 2537789Sahrens if (isprefix) { 2538868Sahrens zfs_handle_t *h; 2539868Sahrens 2540789Sahrens /* make sure prefix exists */ 25412082Seschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 25422082Seschrock if (h == NULL) 2543789Sahrens return (-1); 25441544Seschrock zfs_close(h); 2545789Sahrens 2546789Sahrens /* create any necessary ancestors up to prefix */ 2547868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 25481544Seschrock 2549868Sahrens /* 2550868Sahrens * zc.zc_name is now the full name of the snap 25511544Seschrock * we're restoring into. Attempt to create, 25521544Seschrock * mount, and share any ancestor filesystems, up 25531544Seschrock * to the one that was named. 2554868Sahrens */ 25551544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 25561544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 25571544Seschrock const char *opname; 2558789Sahrens *cp = '\0'; 25591544Seschrock 25602082Seschrock opname = dgettext(TEXT_DOMAIN, "create"); 25612082Seschrock if (zfs_create(hdl, zc.zc_name, 25622082Seschrock ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) { 25631544Seschrock if (errno == EEXIST) 25641544Seschrock continue; 25651544Seschrock goto ancestorerr; 2566789Sahrens } 25671544Seschrock 25682082Seschrock opname = dgettext(TEXT_DOMAIN, "open"); 25692082Seschrock h = zfs_open(hdl, zc.zc_name, 25702082Seschrock ZFS_TYPE_FILESYSTEM); 25711544Seschrock if (h == NULL) 25721544Seschrock goto ancestorerr; 25731544Seschrock 25742082Seschrock opname = dgettext(TEXT_DOMAIN, "mount"); 25751544Seschrock if (zfs_mount(h, NULL, 0) != 0) 25761544Seschrock goto ancestorerr; 25771544Seschrock 25782082Seschrock opname = dgettext(TEXT_DOMAIN, "share"); 25791544Seschrock if (zfs_share(h) != 0) 25801544Seschrock goto ancestorerr; 25811544Seschrock 25821544Seschrock zfs_close(h); 25831544Seschrock 25841544Seschrock continue; 25851544Seschrock ancestorerr: 25862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25872082Seschrock "failed to %s ancestor '%s'"), opname, 25882082Seschrock zc.zc_name); 25892082Seschrock return (zfs_error(hdl, EZFS_BADRESTORE, 25902082Seschrock errbuf)); 2591789Sahrens } 2592789Sahrens } 2593868Sahrens 2594868Sahrens /* Make sure destination fs does not exist */ 2595868Sahrens cp = strchr(zc.zc_name, '@'); 2596868Sahrens *cp = '\0'; 25972082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 25982082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25992082Seschrock "destination '%s' exists"), zc.zc_name); 26002082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2601868Sahrens } 2602868Sahrens 2603868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2604868Sahrens cp = strrchr(zc.zc_name, '/'); 2605868Sahrens *cp = '\0'; 2606789Sahrens } 2607789Sahrens 2608789Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2609789Sahrens zc.zc_cookie = STDIN_FILENO; 2610789Sahrens zc.zc_intsz = isprefix; 2611789Sahrens if (verbose) { 26121749Sahrens (void) printf("%s %s stream of %s into %s\n", 26131749Sahrens dryrun ? "would receive" : "receiving", 2614789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2615789Sahrens drr.drr_u.drr_begin.drr_toname, 26161544Seschrock zc.zc_filename); 2617789Sahrens (void) fflush(stdout); 2618789Sahrens } 2619789Sahrens if (dryrun) 2620789Sahrens return (0); 26212082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2622868Sahrens if (ioctl_err != 0) { 2623789Sahrens switch (errno) { 2624789Sahrens case ENODEV: 26252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26262082Seschrock "most recent snapshot does not match incremental " 26272082Seschrock "source")); 26282082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2629789Sahrens break; 2630789Sahrens case ETXTBSY: 26312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26322082Seschrock "destination has been modified since most recent " 26332082Seschrock "snapshot")); 26342082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2635789Sahrens break; 2636789Sahrens case EEXIST: 2637789Sahrens if (drrb->drr_fromguid == 0) { 2638789Sahrens /* it's the containing fs that exists */ 26391544Seschrock cp = strchr(zc.zc_filename, '@'); 2640789Sahrens *cp = '\0'; 2641789Sahrens } 26422082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26432082Seschrock "destination already exists")); 26442082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 26452082Seschrock "cannot restore to %s"), zc.zc_filename); 2646789Sahrens break; 2647789Sahrens case EINVAL: 26482082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2649868Sahrens break; 26501544Seschrock case ECKSUM: 26512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26522082Seschrock "invalid stream (checksum mismatch)")); 26532082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2654789Sahrens break; 2655789Sahrens default: 26562082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2657789Sahrens } 2658789Sahrens } 2659789Sahrens 2660789Sahrens /* 2661868Sahrens * Mount or recreate the /dev links for the target filesystem 2662868Sahrens * (if created, or if we tore them down to do an incremental 2663868Sahrens * restore), and the /dev links for the new snapshot (if 2664868Sahrens * created). 2665789Sahrens */ 26661544Seschrock cp = strchr(zc.zc_filename, '@'); 2667868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2668789Sahrens zfs_handle_t *h; 2669789Sahrens 2670789Sahrens *cp = '\0'; 26712082Seschrock h = zfs_open(hdl, zc.zc_filename, 2672789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2673868Sahrens *cp = '@'; 2674789Sahrens if (h) { 2675868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2676789Sahrens err = zfs_mount(h, NULL, 0); 2677868Sahrens } else { 26782082Seschrock err = zvol_create_link(hdl, h->zfs_name); 26791544Seschrock if (err == 0 && ioctl_err == 0) 26802082Seschrock err = zvol_create_link(hdl, 26812082Seschrock zc.zc_filename); 2682868Sahrens } 2683789Sahrens zfs_close(h); 2684789Sahrens } 2685789Sahrens } 2686789Sahrens 2687868Sahrens if (err || ioctl_err) 2688868Sahrens return (-1); 2689789Sahrens 2690789Sahrens if (verbose) { 2691789Sahrens char buf1[64]; 2692789Sahrens char buf2[64]; 2693789Sahrens uint64_t bytes = zc.zc_cookie; 2694789Sahrens time_t delta = time(NULL) - begin_time; 2695789Sahrens if (delta == 0) 2696789Sahrens delta = 1; 2697789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2698789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2699789Sahrens 27001749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2701789Sahrens buf1, delta, buf2); 2702789Sahrens } 2703789Sahrens return (0); 2704789Sahrens } 2705789Sahrens 2706789Sahrens /* 27071294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 27081294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 27091294Slling * is a dependent and we should just destroy it without checking the transaction 27101294Slling * group. 2711789Sahrens */ 27121294Slling typedef struct rollback_data { 27131294Slling const char *cb_target; /* the snapshot */ 27141294Slling uint64_t cb_create; /* creation time reference */ 27151294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 27161294Slling int cb_error; 27172082Seschrock boolean_t cb_dependent; 27181294Slling } rollback_data_t; 27191294Slling 27201294Slling static int 27211294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 27221294Slling { 27231294Slling rollback_data_t *cbp = data; 27241294Slling 27251294Slling if (!cbp->cb_dependent) { 27261294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 27271294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 27281294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 27291294Slling cbp->cb_create) { 27301294Slling 27312082Seschrock cbp->cb_dependent = B_TRUE; 27321294Slling (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 27332082Seschrock cbp->cb_dependent = B_FALSE; 27341294Slling 27351294Slling if (zfs_destroy(zhp) != 0) 27361294Slling cbp->cb_error = 1; 27371294Slling else 27381294Slling changelist_remove(zhp, cbp->cb_clp); 27391294Slling } 27401294Slling } else { 27411294Slling if (zfs_destroy(zhp) != 0) 27421294Slling cbp->cb_error = 1; 27431294Slling else 27441294Slling changelist_remove(zhp, cbp->cb_clp); 27451294Slling } 27461294Slling 27471294Slling zfs_close(zhp); 27481294Slling return (0); 27491294Slling } 27501294Slling 27511294Slling /* 27521294Slling * Rollback the dataset to its latest snapshot. 27531294Slling */ 27541294Slling static int 27551294Slling do_rollback(zfs_handle_t *zhp) 2756789Sahrens { 2757789Sahrens int ret; 2758789Sahrens zfs_cmd_t zc = { 0 }; 2759789Sahrens 2760789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2761789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2762789Sahrens 2763789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 27642082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2765789Sahrens return (-1); 2766789Sahrens 2767789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2768789Sahrens 2769789Sahrens if (zhp->zfs_volblocksize != 0) 2770789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2771789Sahrens else 2772789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2773789Sahrens 2774789Sahrens /* 2775789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2776789Sahrens * for the given dataset. Given these constraints, we can simply pass 2777789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2778789Sahrens * condition where the user has taken a snapshot since we verified that 2779789Sahrens * this was the most recent. 2780789Sahrens */ 27812082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 27822082Seschrock &zc)) != 0) { 27832082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 27842082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 27852082Seschrock zhp->zfs_name); 2786789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 27872082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2788789Sahrens } 2789789Sahrens 2790789Sahrens return (ret); 2791789Sahrens } 2792789Sahrens 2793789Sahrens /* 27941294Slling * Given a dataset, rollback to a specific snapshot, discarding any 27951294Slling * data changes since then and making it the active dataset. 27961294Slling * 27971294Slling * Any snapshots more recent than the target are destroyed, along with 27981294Slling * their dependents. 27991294Slling */ 28001294Slling int 28011294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 28021294Slling { 28031294Slling int ret; 28041294Slling rollback_data_t cb = { 0 }; 28051294Slling prop_changelist_t *clp; 28061294Slling 28071294Slling /* 28081294Slling * Unmount all dependendents of the dataset and the dataset itself. 28091294Slling * The list we need to gather is the same as for doing rename 28101294Slling */ 28111294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 28121294Slling if (clp == NULL) 28131294Slling return (-1); 28141294Slling 28151294Slling if ((ret = changelist_prefix(clp)) != 0) 28161294Slling goto out; 28171294Slling 28181294Slling /* 28191294Slling * Destroy all recent snapshots and its dependends. 28201294Slling */ 28211294Slling cb.cb_target = snap->zfs_name; 28221294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 28231294Slling cb.cb_clp = clp; 28241294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 28251294Slling 28261294Slling if ((ret = cb.cb_error) != 0) { 28271294Slling (void) changelist_postfix(clp); 28281294Slling goto out; 28291294Slling } 28301294Slling 28311294Slling /* 28321294Slling * Now that we have verified that the snapshot is the latest, 28331294Slling * rollback to the given snapshot. 28341294Slling */ 28351294Slling ret = do_rollback(zhp); 28361294Slling 28371294Slling if (ret != 0) { 28381294Slling (void) changelist_postfix(clp); 28391294Slling goto out; 28401294Slling } 28411294Slling 28421294Slling /* 28431294Slling * We only want to re-mount the filesystem if it was mounted in the 28441294Slling * first place. 28451294Slling */ 28461294Slling ret = changelist_postfix(clp); 28471294Slling 28481294Slling out: 28491294Slling changelist_free(clp); 28501294Slling return (ret); 28511294Slling } 28521294Slling 28531294Slling /* 2854789Sahrens * Iterate over all dependents for a given dataset. This includes both 2855789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2856789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2857789Sahrens * libzfs_graph.c. 2858789Sahrens */ 2859789Sahrens int 2860789Sahrens zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2861789Sahrens { 2862789Sahrens char **dependents; 2863789Sahrens size_t count; 2864789Sahrens int i; 2865789Sahrens zfs_handle_t *child; 2866789Sahrens int ret = 0; 2867789Sahrens 28682082Seschrock dependents = get_dependents(zhp->zfs_hdl, zhp->zfs_name, &count); 2869789Sahrens for (i = 0; i < count; i++) { 28702082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 28712082Seschrock dependents[i])) == NULL) 2872789Sahrens continue; 2873789Sahrens 2874789Sahrens if ((ret = func(child, data)) != 0) 2875789Sahrens break; 2876789Sahrens } 2877789Sahrens 2878789Sahrens for (i = 0; i < count; i++) 2879789Sahrens free(dependents[i]); 2880789Sahrens free(dependents); 2881789Sahrens 2882789Sahrens return (ret); 2883789Sahrens } 2884789Sahrens 2885789Sahrens /* 2886789Sahrens * Renames the given dataset. 2887789Sahrens */ 2888789Sahrens int 2889789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2890789Sahrens { 2891789Sahrens int ret; 2892789Sahrens zfs_cmd_t zc = { 0 }; 2893789Sahrens char *delim; 2894789Sahrens prop_changelist_t *cl; 2895789Sahrens char parent[ZFS_MAXNAMELEN]; 28962082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 28972082Seschrock char errbuf[1024]; 2898789Sahrens 2899789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2900789Sahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 2901789Sahrens 2902789Sahrens /* if we have the same exact name, just return success */ 2903789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2904789Sahrens return (0); 2905789Sahrens 29062082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 29072082Seschrock "cannot rename to '%s'"), target); 29082082Seschrock 2909789Sahrens /* 2910789Sahrens * Make sure the target name is valid 2911789Sahrens */ 29122082Seschrock if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 29132082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2914789Sahrens 2915789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 29162082Seschrock 2917789Sahrens if ((delim = strchr(target, '@')) == NULL) { 29182082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29192082Seschrock "not a snapshot")); 29202082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2921789Sahrens } 2922789Sahrens 2923789Sahrens /* 2924789Sahrens * Make sure we're renaming within the same dataset. 2925789Sahrens */ 2926789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2927789Sahrens zhp->zfs_name[delim - target] != '@') { 29282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29292082Seschrock "snapshots must be part of same dataset")); 29302082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2931789Sahrens } 2932789Sahrens 2933789Sahrens (void) strncpy(parent, target, delim - target); 2934789Sahrens parent[delim - target] = '\0'; 2935789Sahrens } else { 2936789Sahrens /* validate parents */ 29372082Seschrock if (check_parents(hdl, target) != 0) 2938789Sahrens return (-1); 2939789Sahrens 2940789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2941789Sahrens 2942789Sahrens /* make sure we're in the same pool */ 2943789Sahrens verify((delim = strchr(target, '/')) != NULL); 2944789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2945789Sahrens zhp->zfs_name[delim - target] != '/') { 29462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29472082Seschrock "datasets must be within same pool")); 29482082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2949789Sahrens } 2950*2440Snd150628 2951*2440Snd150628 /* new name cannot be a child of the current dataset name */ 2952*2440Snd150628 if (strncmp(parent, zhp->zfs_name, 2953*2440Snd150628 strlen(zhp->zfs_name)) == 0) { 2954*2440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2955*2440Snd150628 "New dataset name cannot be a descendent of " 2956*2440Snd150628 "current dataset name")); 2957*2440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2958*2440Snd150628 } 2959789Sahrens } 2960789Sahrens 29612082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 29622082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 29632082Seschrock 2964789Sahrens if (getzoneid() == GLOBAL_ZONEID && 2965789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 29662082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29672082Seschrock "dataset is used in a non-global zone")); 29682082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 2969789Sahrens } 2970789Sahrens 2971789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 29722082Seschrock return (-1); 2973789Sahrens 2974789Sahrens if (changelist_haszonedchild(cl)) { 29752082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29762082Seschrock "child dataset with inherited mountpoint is used " 29772082Seschrock "in a non-global zone")); 29782082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 2979789Sahrens goto error; 2980789Sahrens } 2981789Sahrens 2982789Sahrens if ((ret = changelist_prefix(cl)) != 0) 2983789Sahrens goto error; 2984789Sahrens 2985789Sahrens if (zhp->zfs_volblocksize != 0) 2986789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2987789Sahrens else 2988789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2989789Sahrens 29902082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 29912082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 2992789Sahrens 2993789Sahrens /* 2994789Sahrens * On failure, we still want to remount any filesystems that 2995789Sahrens * were previously mounted, so we don't alter the system state. 2996789Sahrens */ 2997789Sahrens (void) changelist_postfix(cl); 2998789Sahrens } else { 2999789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3000789Sahrens 3001789Sahrens ret = changelist_postfix(cl); 3002789Sahrens } 3003789Sahrens 3004789Sahrens error: 3005789Sahrens changelist_free(cl); 3006789Sahrens return (ret); 3007789Sahrens } 3008789Sahrens 3009789Sahrens /* 3010789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3011789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3012789Sahrens */ 3013789Sahrens int 30142082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3015789Sahrens { 3016789Sahrens zfs_cmd_t zc = { 0 }; 30172082Seschrock di_devlink_handle_t dhdl; 3018789Sahrens 3019789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3020789Sahrens 3021789Sahrens /* 3022789Sahrens * Issue the appropriate ioctl. 3023789Sahrens */ 30242082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3025789Sahrens switch (errno) { 3026789Sahrens case EEXIST: 3027789Sahrens /* 3028789Sahrens * Silently ignore the case where the link already 3029789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3030789Sahrens * times without errors. 3031789Sahrens */ 3032789Sahrens return (0); 3033789Sahrens 3034789Sahrens default: 30352082Seschrock return (zfs_standard_error(hdl, errno, 30362082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30372082Seschrock "for '%s'"), dataset)); 3038789Sahrens } 3039789Sahrens } 3040789Sahrens 3041789Sahrens /* 3042789Sahrens * Call devfsadm and wait for the links to magically appear. 3043789Sahrens */ 30442082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 30452082Seschrock zfs_error_aux(hdl, strerror(errno)); 30462082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 30472082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30482082Seschrock "for '%s'"), dataset); 30492082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3050789Sahrens return (-1); 3051789Sahrens } else { 30522082Seschrock (void) di_devlink_fini(&dhdl); 3053789Sahrens } 3054789Sahrens 3055789Sahrens return (0); 3056789Sahrens } 3057789Sahrens 3058789Sahrens /* 3059789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3060789Sahrens */ 3061789Sahrens int 30622082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3063789Sahrens { 3064789Sahrens zfs_cmd_t zc = { 0 }; 3065789Sahrens 3066789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3067789Sahrens 30682082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3069789Sahrens switch (errno) { 3070789Sahrens case ENXIO: 3071789Sahrens /* 3072789Sahrens * Silently ignore the case where the link no longer 3073789Sahrens * exists, so that 'zfs volfini' can 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 remove device " 30812082Seschrock "links for '%s'"), dataset)); 3082789Sahrens } 3083789Sahrens } 3084789Sahrens 3085789Sahrens return (0); 3086789Sahrens } 3087