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 172*2199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 173*2199Sahrens if (hdl != NULL) 174*2199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 175*2199Sahrens "missing '@' delimeter in snapshot name")); 176*2199Sahrens return (0); 177*2199Sahrens } 178*2199Sahrens 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); 1970*2199Sahrens if (ret != 0) { 19712082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 19722082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 19732082Seschrock zhp->zfs_name)); 1974*2199Sahrens } 1975789Sahrens 1976789Sahrens remove_mountpoint(zhp); 1977789Sahrens 1978789Sahrens return (0); 1979789Sahrens } 1980789Sahrens 1981*2199Sahrens struct destroydata { 1982*2199Sahrens char *snapname; 1983*2199Sahrens boolean_t gotone; 1984*2199Sahrens }; 1985*2199Sahrens 1986*2199Sahrens static int 1987*2199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 1988*2199Sahrens { 1989*2199Sahrens struct destroydata *dd = arg; 1990*2199Sahrens zfs_handle_t *szhp; 1991*2199Sahrens char name[ZFS_MAXNAMELEN]; 1992*2199Sahrens 1993*2199Sahrens (void) strcpy(name, zhp->zfs_name); 1994*2199Sahrens (void) strcat(name, "@"); 1995*2199Sahrens (void) strcat(name, dd->snapname); 1996*2199Sahrens 1997*2199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 1998*2199Sahrens if (szhp) { 1999*2199Sahrens dd->gotone = B_TRUE; 2000*2199Sahrens zfs_close(szhp); 2001*2199Sahrens } 2002*2199Sahrens 2003*2199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2004*2199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 2005*2199Sahrens /* 2006*2199Sahrens * NB: this is simply a best-effort. We don't want to 2007*2199Sahrens * return an error, because then we wouldn't visit all 2008*2199Sahrens * the volumes. 2009*2199Sahrens */ 2010*2199Sahrens } 2011*2199Sahrens 2012*2199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 2013*2199Sahrens } 2014*2199Sahrens 2015*2199Sahrens /* 2016*2199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 2017*2199Sahrens */ 2018*2199Sahrens int 2019*2199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 2020*2199Sahrens { 2021*2199Sahrens zfs_cmd_t zc = { 0 }; 2022*2199Sahrens int ret; 2023*2199Sahrens struct destroydata dd = { 0 }; 2024*2199Sahrens 2025*2199Sahrens dd.snapname = snapname; 2026*2199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 2027*2199Sahrens 2028*2199Sahrens if (!dd.gotone) { 2029*2199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 2030*2199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 2031*2199Sahrens zhp->zfs_name, snapname)); 2032*2199Sahrens } 2033*2199Sahrens 2034*2199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2035*2199Sahrens (void) strlcpy(zc.zc_prop_value, snapname, sizeof (zc.zc_prop_value)); 2036*2199Sahrens 2037*2199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 2038*2199Sahrens if (ret != 0) { 2039*2199Sahrens char errbuf[1024]; 2040*2199Sahrens 2041*2199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2042*2199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 2043*2199Sahrens 2044*2199Sahrens switch (errno) { 2045*2199Sahrens case EEXIST: 2046*2199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2047*2199Sahrens "snapshot is cloned")); 2048*2199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 2049*2199Sahrens 2050*2199Sahrens default: 2051*2199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 2052*2199Sahrens errbuf)); 2053*2199Sahrens } 2054*2199Sahrens } 2055*2199Sahrens 2056*2199Sahrens return (0); 2057*2199Sahrens } 2058*2199Sahrens 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 int err; 21432082Seschrock char snapname[MAXPATHLEN]; 21442082Seschrock char *cp; 21452082Seschrock 21462082Seschrock /* We don't care about snapshots after the pivot point */ 21472082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 21482082Seschrock return (0); 21492082Seschrock 21502082Seschrock /* 21512082Seschrock * Unmount it. We actually need to open it to provoke it to be 21522082Seschrock * mounted first, because if it is not mounted, umount2 will 21532082Seschrock * mount it! 21542082Seschrock */ 21552082Seschrock (void) strcpy(snapname, pd->cb_mountpoint); 21562082Seschrock (void) strcat(snapname, "/.zfs/snapshot/"); 21572082Seschrock cp = strchr(zhp->zfs_name, '@'); 21582082Seschrock (void) strcat(snapname, cp+1); 21592082Seschrock err = open(snapname, O_RDONLY); 21602082Seschrock if (err != -1) 21612082Seschrock (void) close(err); 21622082Seschrock (void) umount2(snapname, MS_FORCE); 21632082Seschrock 21642082Seschrock /* Check for conflicting names */ 21652082Seschrock (void) strcpy(snapname, pd->cb_target); 21662082Seschrock (void) strcat(snapname, cp); 21672082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 21682082Seschrock if (szhp != NULL) { 21692082Seschrock zfs_close(szhp); 21702082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21712082Seschrock "snapshot name '%s' from origin \n" 21722082Seschrock "conflicts with '%s' from target"), 21732082Seschrock zhp->zfs_name, snapname); 21742082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 21752082Seschrock } 21762082Seschrock return (0); 21772082Seschrock } 21782082Seschrock 21792082Seschrock /* 21802082Seschrock * Promotes the given clone fs to be the clone parent. 21812082Seschrock */ 21822082Seschrock int 21832082Seschrock zfs_promote(zfs_handle_t *zhp) 21842082Seschrock { 21852082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 21862082Seschrock zfs_cmd_t zc = { 0 }; 21872082Seschrock char parent[MAXPATHLEN]; 21882082Seschrock char *cp; 21892082Seschrock int ret; 21902082Seschrock zfs_handle_t *pzhp; 21912082Seschrock promote_data_t pd; 21922082Seschrock char errbuf[1024]; 21932082Seschrock 21942082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 21952082Seschrock "cannot promote '%s'"), zhp->zfs_name); 21962082Seschrock 21972082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 21982082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21992082Seschrock "snapshots can not be promoted")); 22002082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22012082Seschrock } 22022082Seschrock 22032082Seschrock (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of); 22042082Seschrock if (parent[0] == '\0') { 22052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22062082Seschrock "not a cloned filesystem")); 22072082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 22082082Seschrock } 22092082Seschrock cp = strchr(parent, '@'); 22102082Seschrock *cp = '\0'; 22112082Seschrock 22122082Seschrock /* Walk the snapshots we will be moving */ 22132082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 22142082Seschrock if (pzhp == NULL) 22152082Seschrock return (-1); 22162082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 22172082Seschrock zfs_close(pzhp); 22182082Seschrock pd.cb_target = zhp->zfs_name; 22192082Seschrock pd.cb_errbuf = errbuf; 22202082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 22212082Seschrock if (pzhp == NULL) 22222082Seschrock return (-1); 22232082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 22242082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 22252082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 22262082Seschrock if (ret != 0) 22272082Seschrock return (-1); 22282082Seschrock 22292082Seschrock /* issue the ioctl */ 22302082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22312082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 22322082Seschrock 22332082Seschrock if (ret != 0) { 22342082Seschrock switch (errno) { 2235789Sahrens 2236789Sahrens case EEXIST: 2237789Sahrens /* 22382082Seschrock * There is a conflicting snapshot name. We 22392082Seschrock * should have caught this above, but they could 22402082Seschrock * have renamed something in the mean time. 2241789Sahrens */ 22422082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22432082Seschrock "conflicting snapshot name from parent '%s'"), 22442082Seschrock parent); 22452082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2246789Sahrens 2247789Sahrens default: 22482082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2249789Sahrens } 2250789Sahrens } 2251789Sahrens 2252789Sahrens return (ret); 2253789Sahrens } 2254789Sahrens 2255*2199Sahrens static int 2256*2199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 2257*2199Sahrens { 2258*2199Sahrens char *snapname = arg; 2259*2199Sahrens 2260*2199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2261*2199Sahrens char name[MAXPATHLEN]; 2262*2199Sahrens 2263*2199Sahrens (void) strcpy(name, zhp->zfs_name); 2264*2199Sahrens (void) strcat(name, "@"); 2265*2199Sahrens (void) strcat(name, snapname); 2266*2199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 2267*2199Sahrens /* 2268*2199Sahrens * NB: this is simply a best-effort. We don't want to 2269*2199Sahrens * return an error, because then we wouldn't visit all 2270*2199Sahrens * the volumes. 2271*2199Sahrens */ 2272*2199Sahrens } 2273*2199Sahrens return (zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname)); 2274*2199Sahrens } 2275*2199Sahrens 2276789Sahrens /* 2277789Sahrens * Takes a snapshot of the given dataset 2278789Sahrens */ 2279789Sahrens int 2280*2199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2281789Sahrens { 2282789Sahrens const char *delim; 2283789Sahrens char *parent; 2284789Sahrens zfs_handle_t *zhp; 2285789Sahrens zfs_cmd_t zc = { 0 }; 2286789Sahrens int ret; 22872082Seschrock char errbuf[1024]; 22882082Seschrock 22892082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22902082Seschrock "cannot snapshot '%s'"), path); 22912082Seschrock 22922082Seschrock /* validate the target name */ 22932082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 22942082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2295789Sahrens 2296789Sahrens /* make sure the parent exists and is of the appropriate type */ 2297*2199Sahrens delim = strchr(path, '@'); 22982082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 22992082Seschrock return (-1); 2300789Sahrens (void) strncpy(parent, path, delim - path); 2301789Sahrens parent[delim - path] = '\0'; 2302789Sahrens 23032082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2304789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2305789Sahrens free(parent); 2306789Sahrens return (-1); 2307789Sahrens } 2308789Sahrens 2309*2199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2310*2199Sahrens (void) strlcpy(zc.zc_prop_value, delim+1, sizeof (zc.zc_prop_value)); 2311*2199Sahrens zc.zc_cookie = recursive; 2312*2199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 2313*2199Sahrens 2314*2199Sahrens /* 2315*2199Sahrens * if it was recursive, the one that actually failed will be in 2316*2199Sahrens * zc.zc_name. 2317*2199Sahrens */ 2318*2199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2319*2199Sahrens "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_prop_value); 2320*2199Sahrens if (ret == 0 && recursive) { 2321*2199Sahrens (void) zfs_iter_filesystems(zhp, 2322*2199Sahrens zfs_create_link_cb, (char *)delim+1); 2323*2199Sahrens } 2324789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 23252082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 2326*2199Sahrens if (ret != 0) { 23272082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 23282082Seschrock &zc); 2329*2199Sahrens } 2330789Sahrens } 2331789Sahrens 23322082Seschrock if (ret != 0) 23332082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2334789Sahrens 2335789Sahrens free(parent); 2336789Sahrens zfs_close(zhp); 2337789Sahrens 2338789Sahrens return (ret); 2339789Sahrens } 2340789Sahrens 2341789Sahrens /* 2342789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2343789Sahrens */ 2344789Sahrens int 23451749Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2346789Sahrens { 2347789Sahrens zfs_cmd_t zc = { 0 }; 2348789Sahrens int ret; 23492082Seschrock char errbuf[1024]; 23502082Seschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 23512082Seschrock 23522082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23532082Seschrock "cannot send '%s'"), zhp_to->zfs_name); 2354789Sahrens 2355789Sahrens /* do the ioctl() */ 2356789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2357789Sahrens if (zhp_from) { 2358789Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2359789Sahrens sizeof (zc.zc_name)); 2360789Sahrens } else { 2361789Sahrens zc.zc_prop_value[0] = '\0'; 2362789Sahrens } 2363789Sahrens zc.zc_cookie = STDOUT_FILENO; 2364789Sahrens 23652082Seschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2366789Sahrens if (ret != 0) { 2367789Sahrens switch (errno) { 2368789Sahrens 2369789Sahrens case EXDEV: 23702082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23712082Seschrock "not an ealier snapshot from the same fs")); 23722082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2373789Sahrens 2374789Sahrens case EDQUOT: 2375789Sahrens case EFBIG: 2376789Sahrens case EIO: 2377789Sahrens case ENOLINK: 2378789Sahrens case ENOSPC: 2379789Sahrens case ENOSTR: 2380789Sahrens case ENXIO: 2381789Sahrens case EPIPE: 2382789Sahrens case ERANGE: 2383789Sahrens case EFAULT: 2384789Sahrens case EROFS: 23852082Seschrock zfs_error_aux(hdl, strerror(errno)); 23862082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2387789Sahrens 2388789Sahrens default: 23892082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2390789Sahrens } 2391789Sahrens } 2392789Sahrens 2393789Sahrens return (ret); 2394789Sahrens } 2395789Sahrens 2396789Sahrens /* 2397789Sahrens * Restores a backup of tosnap from stdin. 2398789Sahrens */ 2399789Sahrens int 24002082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 24012082Seschrock int verbose, int dryrun) 2402789Sahrens { 2403789Sahrens zfs_cmd_t zc = { 0 }; 2404789Sahrens time_t begin_time; 2405868Sahrens int ioctl_err, err, bytes, size; 2406789Sahrens char *cp; 2407789Sahrens dmu_replay_record_t drr; 2408789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 24092082Seschrock char errbuf[1024]; 2410789Sahrens 2411789Sahrens begin_time = time(NULL); 2412789Sahrens 24132082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24142082Seschrock "cannot receive")); 24152082Seschrock 2416789Sahrens /* trim off snapname, if any */ 2417789Sahrens (void) strcpy(zc.zc_name, tosnap); 2418789Sahrens cp = strchr(zc.zc_name, '@'); 2419789Sahrens if (cp) 2420789Sahrens *cp = '\0'; 2421789Sahrens 2422789Sahrens /* read in the BEGIN record */ 2423789Sahrens cp = (char *)&drr; 2424789Sahrens bytes = 0; 2425789Sahrens do { 2426868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2427868Sahrens cp += size; 2428868Sahrens bytes += size; 2429868Sahrens } while (size > 0); 2430868Sahrens 2431868Sahrens if (size < 0 || bytes != sizeof (drr)) { 24322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24332082Seschrock "stream (failed to read first record)")); 24342082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2435789Sahrens } 2436789Sahrens 2437789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2438789Sahrens 2439789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2440789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 24412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 24422082Seschrock "stream (bad magic number)")); 24432082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2444789Sahrens } 2445789Sahrens 2446789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2447789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 24482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 24492082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2450789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 24512082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2452789Sahrens } 2453789Sahrens 2454789Sahrens /* 2455789Sahrens * Determine name of destination snapshot. 2456789Sahrens */ 24571544Seschrock (void) strcpy(zc.zc_filename, tosnap); 2458789Sahrens if (isprefix) { 2459789Sahrens if (strchr(tosnap, '@') != NULL) { 24602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24612082Seschrock "destination must be a filesystem")); 24622082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2463789Sahrens } 2464789Sahrens 2465789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2466789Sahrens if (cp == NULL) 2467789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2468789Sahrens else 2469789Sahrens cp++; 2470789Sahrens 24711544Seschrock (void) strcat(zc.zc_filename, "/"); 24721544Seschrock (void) strcat(zc.zc_filename, cp); 2473789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2474789Sahrens /* 2475789Sahrens * they specified just a filesystem; tack on the 2476789Sahrens * snapname from the backup. 2477789Sahrens */ 2478789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 24792082Seschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 24802082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 24811544Seschrock (void) strcat(zc.zc_filename, cp); 2482789Sahrens } 2483789Sahrens 2484789Sahrens if (drrb->drr_fromguid) { 2485789Sahrens zfs_handle_t *h; 2486789Sahrens /* incremental backup stream */ 2487789Sahrens 2488789Sahrens /* do the ioctl to the containing fs */ 24891544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2490789Sahrens cp = strchr(zc.zc_name, '@'); 2491789Sahrens *cp = '\0'; 2492789Sahrens 2493789Sahrens /* make sure destination fs exists */ 24942082Seschrock h = zfs_open(hdl, zc.zc_name, 24952082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 24962082Seschrock if (h == NULL) 2497789Sahrens return (-1); 2498868Sahrens if (!dryrun) { 2499868Sahrens /* unmount destination fs or remove device link. */ 2500868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2501868Sahrens (void) zfs_unmount(h, NULL, 0); 2502868Sahrens } else { 25032082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2504868Sahrens } 2505868Sahrens } 2506789Sahrens zfs_close(h); 2507789Sahrens } else { 2508789Sahrens /* full backup stream */ 2509789Sahrens 25101544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2511868Sahrens 25121749Sahrens /* make sure they aren't trying to receive into the root */ 2513868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2514789Sahrens cp = strchr(zc.zc_name, '@'); 2515789Sahrens if (cp) 2516789Sahrens *cp = '\0'; 25172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25182082Seschrock "destination '%s' already exists"), zc.zc_name); 25192082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2520789Sahrens } 2521789Sahrens 2522789Sahrens if (isprefix) { 2523868Sahrens zfs_handle_t *h; 2524868Sahrens 2525789Sahrens /* make sure prefix exists */ 25262082Seschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 25272082Seschrock if (h == NULL) 2528789Sahrens return (-1); 25291544Seschrock zfs_close(h); 2530789Sahrens 2531789Sahrens /* create any necessary ancestors up to prefix */ 2532868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 25331544Seschrock 2534868Sahrens /* 2535868Sahrens * zc.zc_name is now the full name of the snap 25361544Seschrock * we're restoring into. Attempt to create, 25371544Seschrock * mount, and share any ancestor filesystems, up 25381544Seschrock * to the one that was named. 2539868Sahrens */ 25401544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 25411544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 25421544Seschrock const char *opname; 2543789Sahrens *cp = '\0'; 25441544Seschrock 25452082Seschrock opname = dgettext(TEXT_DOMAIN, "create"); 25462082Seschrock if (zfs_create(hdl, zc.zc_name, 25472082Seschrock ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) { 25481544Seschrock if (errno == EEXIST) 25491544Seschrock continue; 25501544Seschrock goto ancestorerr; 2551789Sahrens } 25521544Seschrock 25532082Seschrock opname = dgettext(TEXT_DOMAIN, "open"); 25542082Seschrock h = zfs_open(hdl, zc.zc_name, 25552082Seschrock ZFS_TYPE_FILESYSTEM); 25561544Seschrock if (h == NULL) 25571544Seschrock goto ancestorerr; 25581544Seschrock 25592082Seschrock opname = dgettext(TEXT_DOMAIN, "mount"); 25601544Seschrock if (zfs_mount(h, NULL, 0) != 0) 25611544Seschrock goto ancestorerr; 25621544Seschrock 25632082Seschrock opname = dgettext(TEXT_DOMAIN, "share"); 25641544Seschrock if (zfs_share(h) != 0) 25651544Seschrock goto ancestorerr; 25661544Seschrock 25671544Seschrock zfs_close(h); 25681544Seschrock 25691544Seschrock continue; 25701544Seschrock ancestorerr: 25712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25722082Seschrock "failed to %s ancestor '%s'"), opname, 25732082Seschrock zc.zc_name); 25742082Seschrock return (zfs_error(hdl, EZFS_BADRESTORE, 25752082Seschrock errbuf)); 2576789Sahrens } 2577789Sahrens } 2578868Sahrens 2579868Sahrens /* Make sure destination fs does not exist */ 2580868Sahrens cp = strchr(zc.zc_name, '@'); 2581868Sahrens *cp = '\0'; 25822082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 25832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25842082Seschrock "destination '%s' exists"), zc.zc_name); 25852082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2586868Sahrens } 2587868Sahrens 2588868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2589868Sahrens cp = strrchr(zc.zc_name, '/'); 2590868Sahrens *cp = '\0'; 2591789Sahrens } 2592789Sahrens 2593789Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2594789Sahrens zc.zc_cookie = STDIN_FILENO; 2595789Sahrens zc.zc_intsz = isprefix; 2596789Sahrens if (verbose) { 25971749Sahrens (void) printf("%s %s stream of %s into %s\n", 25981749Sahrens dryrun ? "would receive" : "receiving", 2599789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2600789Sahrens drr.drr_u.drr_begin.drr_toname, 26011544Seschrock zc.zc_filename); 2602789Sahrens (void) fflush(stdout); 2603789Sahrens } 2604789Sahrens if (dryrun) 2605789Sahrens return (0); 26062082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2607868Sahrens if (ioctl_err != 0) { 2608789Sahrens switch (errno) { 2609789Sahrens case ENODEV: 26102082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26112082Seschrock "most recent snapshot does not match incremental " 26122082Seschrock "source")); 26132082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2614789Sahrens break; 2615789Sahrens case ETXTBSY: 26162082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26172082Seschrock "destination has been modified since most recent " 26182082Seschrock "snapshot")); 26192082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2620789Sahrens break; 2621789Sahrens case EEXIST: 2622789Sahrens if (drrb->drr_fromguid == 0) { 2623789Sahrens /* it's the containing fs that exists */ 26241544Seschrock cp = strchr(zc.zc_filename, '@'); 2625789Sahrens *cp = '\0'; 2626789Sahrens } 26272082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26282082Seschrock "destination already exists")); 26292082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 26302082Seschrock "cannot restore to %s"), zc.zc_filename); 2631789Sahrens break; 2632789Sahrens case EINVAL: 26332082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2634868Sahrens break; 26351544Seschrock case ECKSUM: 26362082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26372082Seschrock "invalid stream (checksum mismatch)")); 26382082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2639789Sahrens break; 2640789Sahrens default: 26412082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2642789Sahrens } 2643789Sahrens } 2644789Sahrens 2645789Sahrens /* 2646868Sahrens * Mount or recreate the /dev links for the target filesystem 2647868Sahrens * (if created, or if we tore them down to do an incremental 2648868Sahrens * restore), and the /dev links for the new snapshot (if 2649868Sahrens * created). 2650789Sahrens */ 26511544Seschrock cp = strchr(zc.zc_filename, '@'); 2652868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2653789Sahrens zfs_handle_t *h; 2654789Sahrens 2655789Sahrens *cp = '\0'; 26562082Seschrock h = zfs_open(hdl, zc.zc_filename, 2657789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2658868Sahrens *cp = '@'; 2659789Sahrens if (h) { 2660868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2661789Sahrens err = zfs_mount(h, NULL, 0); 2662868Sahrens } else { 26632082Seschrock err = zvol_create_link(hdl, h->zfs_name); 26641544Seschrock if (err == 0 && ioctl_err == 0) 26652082Seschrock err = zvol_create_link(hdl, 26662082Seschrock zc.zc_filename); 2667868Sahrens } 2668789Sahrens zfs_close(h); 2669789Sahrens } 2670789Sahrens } 2671789Sahrens 2672868Sahrens if (err || ioctl_err) 2673868Sahrens return (-1); 2674789Sahrens 2675789Sahrens if (verbose) { 2676789Sahrens char buf1[64]; 2677789Sahrens char buf2[64]; 2678789Sahrens uint64_t bytes = zc.zc_cookie; 2679789Sahrens time_t delta = time(NULL) - begin_time; 2680789Sahrens if (delta == 0) 2681789Sahrens delta = 1; 2682789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2683789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2684789Sahrens 26851749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2686789Sahrens buf1, delta, buf2); 2687789Sahrens } 2688789Sahrens return (0); 2689789Sahrens } 2690789Sahrens 2691789Sahrens /* 26921294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 26931294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 26941294Slling * is a dependent and we should just destroy it without checking the transaction 26951294Slling * group. 2696789Sahrens */ 26971294Slling typedef struct rollback_data { 26981294Slling const char *cb_target; /* the snapshot */ 26991294Slling uint64_t cb_create; /* creation time reference */ 27001294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 27011294Slling int cb_error; 27022082Seschrock boolean_t cb_dependent; 27031294Slling } rollback_data_t; 27041294Slling 27051294Slling static int 27061294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 27071294Slling { 27081294Slling rollback_data_t *cbp = data; 27091294Slling 27101294Slling if (!cbp->cb_dependent) { 27111294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 27121294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 27131294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 27141294Slling cbp->cb_create) { 27151294Slling 27162082Seschrock cbp->cb_dependent = B_TRUE; 27171294Slling (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 27182082Seschrock cbp->cb_dependent = B_FALSE; 27191294Slling 27201294Slling if (zfs_destroy(zhp) != 0) 27211294Slling cbp->cb_error = 1; 27221294Slling else 27231294Slling changelist_remove(zhp, cbp->cb_clp); 27241294Slling } 27251294Slling } else { 27261294Slling if (zfs_destroy(zhp) != 0) 27271294Slling cbp->cb_error = 1; 27281294Slling else 27291294Slling changelist_remove(zhp, cbp->cb_clp); 27301294Slling } 27311294Slling 27321294Slling zfs_close(zhp); 27331294Slling return (0); 27341294Slling } 27351294Slling 27361294Slling /* 27371294Slling * Rollback the dataset to its latest snapshot. 27381294Slling */ 27391294Slling static int 27401294Slling do_rollback(zfs_handle_t *zhp) 2741789Sahrens { 2742789Sahrens int ret; 2743789Sahrens zfs_cmd_t zc = { 0 }; 2744789Sahrens 2745789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2746789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2747789Sahrens 2748789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 27492082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2750789Sahrens return (-1); 2751789Sahrens 2752789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2753789Sahrens 2754789Sahrens if (zhp->zfs_volblocksize != 0) 2755789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2756789Sahrens else 2757789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2758789Sahrens 2759789Sahrens /* 2760789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2761789Sahrens * for the given dataset. Given these constraints, we can simply pass 2762789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2763789Sahrens * condition where the user has taken a snapshot since we verified that 2764789Sahrens * this was the most recent. 2765789Sahrens */ 27662082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 27672082Seschrock &zc)) != 0) { 27682082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 27692082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 27702082Seschrock zhp->zfs_name); 2771789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 27722082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2773789Sahrens } 2774789Sahrens 2775789Sahrens return (ret); 2776789Sahrens } 2777789Sahrens 2778789Sahrens /* 27791294Slling * Given a dataset, rollback to a specific snapshot, discarding any 27801294Slling * data changes since then and making it the active dataset. 27811294Slling * 27821294Slling * Any snapshots more recent than the target are destroyed, along with 27831294Slling * their dependents. 27841294Slling */ 27851294Slling int 27861294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 27871294Slling { 27881294Slling int ret; 27891294Slling rollback_data_t cb = { 0 }; 27901294Slling prop_changelist_t *clp; 27911294Slling 27921294Slling /* 27931294Slling * Unmount all dependendents of the dataset and the dataset itself. 27941294Slling * The list we need to gather is the same as for doing rename 27951294Slling */ 27961294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 27971294Slling if (clp == NULL) 27981294Slling return (-1); 27991294Slling 28001294Slling if ((ret = changelist_prefix(clp)) != 0) 28011294Slling goto out; 28021294Slling 28031294Slling /* 28041294Slling * Destroy all recent snapshots and its dependends. 28051294Slling */ 28061294Slling cb.cb_target = snap->zfs_name; 28071294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 28081294Slling cb.cb_clp = clp; 28091294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 28101294Slling 28111294Slling if ((ret = cb.cb_error) != 0) { 28121294Slling (void) changelist_postfix(clp); 28131294Slling goto out; 28141294Slling } 28151294Slling 28161294Slling /* 28171294Slling * Now that we have verified that the snapshot is the latest, 28181294Slling * rollback to the given snapshot. 28191294Slling */ 28201294Slling ret = do_rollback(zhp); 28211294Slling 28221294Slling if (ret != 0) { 28231294Slling (void) changelist_postfix(clp); 28241294Slling goto out; 28251294Slling } 28261294Slling 28271294Slling /* 28281294Slling * We only want to re-mount the filesystem if it was mounted in the 28291294Slling * first place. 28301294Slling */ 28311294Slling ret = changelist_postfix(clp); 28321294Slling 28331294Slling out: 28341294Slling changelist_free(clp); 28351294Slling return (ret); 28361294Slling } 28371294Slling 28381294Slling /* 2839789Sahrens * Iterate over all dependents for a given dataset. This includes both 2840789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2841789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2842789Sahrens * libzfs_graph.c. 2843789Sahrens */ 2844789Sahrens int 2845789Sahrens zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2846789Sahrens { 2847789Sahrens char **dependents; 2848789Sahrens size_t count; 2849789Sahrens int i; 2850789Sahrens zfs_handle_t *child; 2851789Sahrens int ret = 0; 2852789Sahrens 28532082Seschrock dependents = get_dependents(zhp->zfs_hdl, zhp->zfs_name, &count); 2854789Sahrens for (i = 0; i < count; i++) { 28552082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 28562082Seschrock dependents[i])) == NULL) 2857789Sahrens continue; 2858789Sahrens 2859789Sahrens if ((ret = func(child, data)) != 0) 2860789Sahrens break; 2861789Sahrens } 2862789Sahrens 2863789Sahrens for (i = 0; i < count; i++) 2864789Sahrens free(dependents[i]); 2865789Sahrens free(dependents); 2866789Sahrens 2867789Sahrens return (ret); 2868789Sahrens } 2869789Sahrens 2870789Sahrens /* 2871789Sahrens * Renames the given dataset. 2872789Sahrens */ 2873789Sahrens int 2874789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2875789Sahrens { 2876789Sahrens int ret; 2877789Sahrens zfs_cmd_t zc = { 0 }; 2878789Sahrens char *delim; 2879789Sahrens prop_changelist_t *cl; 2880789Sahrens char parent[ZFS_MAXNAMELEN]; 28812082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 28822082Seschrock char errbuf[1024]; 2883789Sahrens 2884789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2885789Sahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 2886789Sahrens 2887789Sahrens /* if we have the same exact name, just return success */ 2888789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2889789Sahrens return (0); 2890789Sahrens 28912082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 28922082Seschrock "cannot rename to '%s'"), target); 28932082Seschrock 2894789Sahrens /* 2895789Sahrens * Make sure the target name is valid 2896789Sahrens */ 28972082Seschrock if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 28982082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2899789Sahrens 2900789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 29012082Seschrock 2902789Sahrens if ((delim = strchr(target, '@')) == NULL) { 29032082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29042082Seschrock "not a snapshot")); 29052082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2906789Sahrens } 2907789Sahrens 2908789Sahrens /* 2909789Sahrens * Make sure we're renaming within the same dataset. 2910789Sahrens */ 2911789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2912789Sahrens zhp->zfs_name[delim - target] != '@') { 29132082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29142082Seschrock "snapshots must be part of same dataset")); 29152082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2916789Sahrens } 2917789Sahrens 2918789Sahrens (void) strncpy(parent, target, delim - target); 2919789Sahrens parent[delim - target] = '\0'; 2920789Sahrens } else { 2921789Sahrens /* validate parents */ 29222082Seschrock if (check_parents(hdl, target) != 0) 2923789Sahrens return (-1); 2924789Sahrens 2925789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2926789Sahrens 2927789Sahrens /* make sure we're in the same pool */ 2928789Sahrens verify((delim = strchr(target, '/')) != NULL); 2929789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2930789Sahrens zhp->zfs_name[delim - target] != '/') { 29312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29322082Seschrock "datasets must be within same pool")); 29332082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2934789Sahrens } 2935789Sahrens } 2936789Sahrens 29372082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 29382082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 29392082Seschrock 2940789Sahrens if (getzoneid() == GLOBAL_ZONEID && 2941789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 29422082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29432082Seschrock "dataset is used in a non-global zone")); 29442082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 2945789Sahrens } 2946789Sahrens 2947789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 29482082Seschrock return (-1); 2949789Sahrens 2950789Sahrens if (changelist_haszonedchild(cl)) { 29512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29522082Seschrock "child dataset with inherited mountpoint is used " 29532082Seschrock "in a non-global zone")); 29542082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 2955789Sahrens goto error; 2956789Sahrens } 2957789Sahrens 2958789Sahrens if ((ret = changelist_prefix(cl)) != 0) 2959789Sahrens goto error; 2960789Sahrens 2961789Sahrens if (zhp->zfs_volblocksize != 0) 2962789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2963789Sahrens else 2964789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2965789Sahrens 29662082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 29672082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 2968789Sahrens 2969789Sahrens /* 2970789Sahrens * On failure, we still want to remount any filesystems that 2971789Sahrens * were previously mounted, so we don't alter the system state. 2972789Sahrens */ 2973789Sahrens (void) changelist_postfix(cl); 2974789Sahrens } else { 2975789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 2976789Sahrens 2977789Sahrens ret = changelist_postfix(cl); 2978789Sahrens } 2979789Sahrens 2980789Sahrens error: 2981789Sahrens changelist_free(cl); 2982789Sahrens return (ret); 2983789Sahrens } 2984789Sahrens 2985789Sahrens /* 2986789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 2987789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 2988789Sahrens */ 2989789Sahrens int 29902082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 2991789Sahrens { 2992789Sahrens zfs_cmd_t zc = { 0 }; 29932082Seschrock di_devlink_handle_t dhdl; 2994789Sahrens 2995789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 2996789Sahrens 2997789Sahrens /* 2998789Sahrens * Issue the appropriate ioctl. 2999789Sahrens */ 30002082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3001789Sahrens switch (errno) { 3002789Sahrens case EEXIST: 3003789Sahrens /* 3004789Sahrens * Silently ignore the case where the link already 3005789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3006789Sahrens * times without errors. 3007789Sahrens */ 3008789Sahrens return (0); 3009789Sahrens 3010789Sahrens default: 30112082Seschrock return (zfs_standard_error(hdl, errno, 30122082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30132082Seschrock "for '%s'"), dataset)); 3014789Sahrens } 3015789Sahrens } 3016789Sahrens 3017789Sahrens /* 3018789Sahrens * Call devfsadm and wait for the links to magically appear. 3019789Sahrens */ 30202082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 30212082Seschrock zfs_error_aux(hdl, strerror(errno)); 30222082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 30232082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 30242082Seschrock "for '%s'"), dataset); 30252082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3026789Sahrens return (-1); 3027789Sahrens } else { 30282082Seschrock (void) di_devlink_fini(&dhdl); 3029789Sahrens } 3030789Sahrens 3031789Sahrens return (0); 3032789Sahrens } 3033789Sahrens 3034789Sahrens /* 3035789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3036789Sahrens */ 3037789Sahrens int 30382082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3039789Sahrens { 3040789Sahrens zfs_cmd_t zc = { 0 }; 3041789Sahrens 3042789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3043789Sahrens 30442082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3045789Sahrens switch (errno) { 3046789Sahrens case ENXIO: 3047789Sahrens /* 3048789Sahrens * Silently ignore the case where the link no longer 3049789Sahrens * exists, so that 'zfs volfini' can be run multiple 3050789Sahrens * times without errors. 3051789Sahrens */ 3052789Sahrens return (0); 3053789Sahrens 3054789Sahrens default: 30552082Seschrock return (zfs_standard_error(hdl, errno, 30562082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 30572082Seschrock "links for '%s'"), dataset)); 3058789Sahrens } 3059789Sahrens } 3060789Sahrens 3061789Sahrens return (0); 3062789Sahrens } 3063