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> 39789Sahrens #include <sys/mntent.h> 40789Sahrens #include <sys/mnttab.h> 411294Slling #include <sys/mount.h> 42789Sahrens 43789Sahrens #include <sys/spa.h> 44789Sahrens #include <sys/zio.h> 45789Sahrens #include <libzfs.h> 46789Sahrens 47789Sahrens #include "zfs_namecheck.h" 48789Sahrens #include "zfs_prop.h" 49789Sahrens #include "libzfs_impl.h" 50789Sahrens 51789Sahrens /* 52789Sahrens * Given a single type (not a mask of types), return the type in a human 53789Sahrens * readable form. 54789Sahrens */ 55789Sahrens const char * 56789Sahrens zfs_type_to_name(zfs_type_t type) 57789Sahrens { 58789Sahrens switch (type) { 59789Sahrens case ZFS_TYPE_FILESYSTEM: 60789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 61789Sahrens case ZFS_TYPE_SNAPSHOT: 62789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 63789Sahrens case ZFS_TYPE_VOLUME: 64789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 65789Sahrens } 66789Sahrens 67789Sahrens zfs_baderror(type); 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 121789Sahrens zfs_validate_name(const char *path, int type, char *buf, size_t buflen) 122789Sahrens { 123789Sahrens namecheck_err_t why; 124789Sahrens char what; 125789Sahrens 126789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 127789Sahrens if (buf != NULL) { 128789Sahrens switch (why) { 1291003Slling case NAME_ERR_TOOLONG: 1301003Slling (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 1311003Slling "name is too long"), buflen); 1321003Slling break; 1331003Slling 134789Sahrens case NAME_ERR_LEADING_SLASH: 135789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 136789Sahrens "leading slash"), buflen); 137789Sahrens break; 138789Sahrens 139789Sahrens case NAME_ERR_EMPTY_COMPONENT: 140789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 141789Sahrens "empty component"), buflen); 142789Sahrens break; 143789Sahrens 144789Sahrens case NAME_ERR_TRAILING_SLASH: 145789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 146789Sahrens "trailing slash"), buflen); 147789Sahrens break; 148789Sahrens 149789Sahrens case NAME_ERR_INVALCHAR: 150789Sahrens (void) snprintf(buf, buflen, 151789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 152789Sahrens "'%c'"), what); 153789Sahrens break; 154789Sahrens 155789Sahrens case NAME_ERR_MULTIPLE_AT: 156789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 157789Sahrens "multiple '@' delimiters"), buflen); 158789Sahrens break; 159789Sahrens } 160789Sahrens } 161789Sahrens 162789Sahrens return (0); 163789Sahrens } 164789Sahrens 165789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 166789Sahrens if (buf != NULL) 167789Sahrens (void) strlcpy(buf, 168789Sahrens dgettext(TEXT_DOMAIN, 169789Sahrens "snapshot delimiter '@'"), buflen); 170789Sahrens return (0); 171789Sahrens } 172789Sahrens 173789Sahrens return (1); 174789Sahrens } 175789Sahrens 176789Sahrens int 177789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 178789Sahrens { 179789Sahrens return (zfs_validate_name(name, type, NULL, NULL)); 180789Sahrens } 181789Sahrens 182789Sahrens /* 183789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 184789Sahrens */ 185789Sahrens static int 186789Sahrens get_stats(zfs_handle_t *zhp) 187789Sahrens { 188789Sahrens zfs_cmd_t zc = { 0 }; 189789Sahrens 190789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 191789Sahrens 1921356Seschrock zc.zc_config_src = (uint64_t)(uintptr_t)zfs_malloc(1024); 1931356Seschrock zc.zc_config_src_size = 1024; 1941356Seschrock 1951544Seschrock while (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0) { 1961356Seschrock if (errno == ENOMEM) { 1971356Seschrock zc.zc_config_src = (uint64_t)(uintptr_t) 1981356Seschrock zfs_malloc(zc.zc_config_src_size); 1991356Seschrock } else { 2001356Seschrock free((void *)(uintptr_t)zc.zc_config_src); 2011356Seschrock return (-1); 2021356Seschrock } 2031356Seschrock } 204789Sahrens 205789Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 206789Sahrens sizeof (zc.zc_objset_stats)); 207789Sahrens 2081544Seschrock (void) strcpy(zhp->zfs_root, zc.zc_root); 2091544Seschrock 2101356Seschrock verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_src, 2111356Seschrock zc.zc_config_src_size, &zhp->zfs_props, 0) == 0); 212789Sahrens 213789Sahrens zhp->zfs_volsize = zc.zc_volsize; 214789Sahrens zhp->zfs_volblocksize = zc.zc_volblocksize; 215789Sahrens 216789Sahrens return (0); 217789Sahrens } 218789Sahrens 219789Sahrens /* 220789Sahrens * Refresh the properties currently stored in the handle. 221789Sahrens */ 222789Sahrens void 223789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 224789Sahrens { 225789Sahrens (void) get_stats(zhp); 226789Sahrens } 227789Sahrens 228789Sahrens /* 229789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 230789Sahrens * zfs_iter_* to create child handles on the fly. 231789Sahrens */ 232789Sahrens zfs_handle_t * 233789Sahrens make_dataset_handle(const char *path) 234789Sahrens { 235789Sahrens zfs_handle_t *zhp = zfs_malloc(sizeof (zfs_handle_t)); 236789Sahrens 237789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 238789Sahrens 239789Sahrens if (get_stats(zhp) != 0) { 240789Sahrens free(zhp); 241789Sahrens return (NULL); 242789Sahrens } 243789Sahrens 244789Sahrens /* 245789Sahrens * We've managed to open the dataset and gather statistics. Determine 246789Sahrens * the high-level type. 247789Sahrens */ 248789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 249789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 250789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 251789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 252789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 253789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 254789Sahrens else 255789Sahrens /* we should never see any other dataset types */ 256789Sahrens zfs_baderror(zhp->zfs_dmustats.dds_type); 257789Sahrens 258789Sahrens return (zhp); 259789Sahrens } 260789Sahrens 261789Sahrens /* 262789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 263789Sahrens * argument is a mask of acceptable types. The function will print an 264789Sahrens * appropriate error message and return NULL if it can't be opened. 265789Sahrens */ 266789Sahrens zfs_handle_t * 267789Sahrens zfs_open(const char *path, int types) 268789Sahrens { 269789Sahrens zfs_handle_t *zhp; 270789Sahrens 271789Sahrens /* 272789Sahrens * Validate the name before we even try to open it. We don't care about 273789Sahrens * the verbose invalid messages here; just report a generic error. 274789Sahrens */ 275789Sahrens if (!zfs_validate_name(path, types, NULL, 0)) { 276789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 277789Sahrens "cannot open '%s': invalid %s name"), path, 278789Sahrens path_to_str(path, types)); 279789Sahrens return (NULL); 280789Sahrens } 281789Sahrens 282789Sahrens /* 283789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 284789Sahrens */ 285789Sahrens errno = 0; 286789Sahrens if ((zhp = make_dataset_handle(path)) == NULL) { 287789Sahrens switch (errno) { 288789Sahrens case ENOENT: 289789Sahrens /* 290789Sahrens * The dataset doesn't exist. 291789Sahrens */ 292789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 293789Sahrens "cannot open '%s': no such %s"), path, 294789Sahrens path_to_str(path, types)); 295789Sahrens break; 296789Sahrens 297789Sahrens case EBUSY: 298789Sahrens /* 299789Sahrens * We were able to open the dataset but couldn't 300789Sahrens * get the stats. 301789Sahrens */ 302789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 303789Sahrens "cannot open '%s': %s is busy"), path, 304789Sahrens path_to_str(path, types)); 305789Sahrens break; 306789Sahrens 3071544Seschrock case ENXIO: 3081544Seschrock case EIO: 3091544Seschrock /* 3101544Seschrock * I/O error from the underlying pool. 3111544Seschrock */ 3121544Seschrock zfs_error(dgettext(TEXT_DOMAIN, 3131544Seschrock "cannot open '%s': I/O error"), path, 3141544Seschrock path_to_str(path, types)); 3151544Seschrock break; 3161544Seschrock 317789Sahrens default: 318789Sahrens zfs_baderror(errno); 319789Sahrens 320789Sahrens } 321789Sahrens return (NULL); 322789Sahrens } 323789Sahrens 324789Sahrens if (!(types & zhp->zfs_type)) { 325789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': operation " 326789Sahrens "not supported for %ss"), path, 327789Sahrens zfs_type_to_name(zhp->zfs_type)); 328789Sahrens free(zhp); 329789Sahrens return (NULL); 330789Sahrens } 331789Sahrens 332789Sahrens return (zhp); 333789Sahrens } 334789Sahrens 335789Sahrens /* 336789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 337789Sahrens */ 338789Sahrens void 339789Sahrens zfs_close(zfs_handle_t *zhp) 340789Sahrens { 341789Sahrens if (zhp->zfs_mntopts) 342789Sahrens free(zhp->zfs_mntopts); 343789Sahrens free(zhp); 344789Sahrens } 345789Sahrens 346789Sahrens struct { 347789Sahrens const char *name; 348789Sahrens uint64_t value; 349789Sahrens } checksum_table[] = { 350789Sahrens { "on", ZIO_CHECKSUM_ON }, 351789Sahrens { "off", ZIO_CHECKSUM_OFF }, 352789Sahrens { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 }, 353789Sahrens { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 }, 354789Sahrens { "sha256", ZIO_CHECKSUM_SHA256 }, 355789Sahrens { NULL } 356789Sahrens }; 357789Sahrens 358789Sahrens struct { 359789Sahrens const char *name; 360789Sahrens uint64_t value; 361789Sahrens } compress_table[] = { 362789Sahrens { "on", ZIO_COMPRESS_ON }, 363789Sahrens { "off", ZIO_COMPRESS_OFF }, 364789Sahrens { "lzjb", ZIO_COMPRESS_LZJB }, 365789Sahrens { NULL } 366789Sahrens }; 367789Sahrens 368789Sahrens struct { 369789Sahrens const char *name; 370789Sahrens uint64_t value; 371789Sahrens } snapdir_table[] = { 372849Sbonwick { "hidden", ZFS_SNAPDIR_HIDDEN }, 373849Sbonwick { "visible", ZFS_SNAPDIR_VISIBLE }, 374789Sahrens { NULL } 375789Sahrens }; 376789Sahrens 377789Sahrens struct { 378789Sahrens const char *name; 379789Sahrens uint64_t value; 380789Sahrens } acl_mode_table[] = { 381789Sahrens { "discard", DISCARD }, 382789Sahrens { "groupmask", GROUPMASK }, 383789Sahrens { "passthrough", PASSTHROUGH }, 384789Sahrens { NULL } 385789Sahrens }; 386789Sahrens 387789Sahrens struct { 388789Sahrens const char *name; 389789Sahrens uint64_t value; 390789Sahrens } acl_inherit_table[] = { 391789Sahrens { "discard", DISCARD }, 392789Sahrens { "noallow", NOALLOW }, 393789Sahrens { "secure", SECURE }, 394789Sahrens { "passthrough", PASSTHROUGH }, 395789Sahrens { NULL } 396789Sahrens }; 397789Sahrens 398789Sahrens 399789Sahrens /* 400789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 401789Sahrens * resulting value must be shifted. 402789Sahrens */ 403789Sahrens static int 404789Sahrens str2shift(const char *buf, char *reason, size_t len) 405789Sahrens { 406789Sahrens const char *ends = "BKMGTPEZ"; 407789Sahrens int i; 408789Sahrens 409789Sahrens if (buf[0] == '\0') 410789Sahrens return (0); 411789Sahrens for (i = 0; i < strlen(ends); i++) { 412789Sahrens if (toupper(buf[0]) == ends[i]) 413789Sahrens break; 414789Sahrens } 415789Sahrens if (i == strlen(ends)) { 416789Sahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid " 417789Sahrens "numeric suffix '%s'"), buf); 418789Sahrens return (-1); 419789Sahrens } 420789Sahrens 421789Sahrens /* 422789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 423789Sahrens * allow 'BB' - that's just weird. 424789Sahrens */ 425789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 426789Sahrens toupper(buf[0]) != 'B')) { 427789Sahrens return (10*i); 428789Sahrens } 429789Sahrens 430789Sahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid numeric " 431789Sahrens "suffix '%s'"), buf); 432789Sahrens return (-1); 433789Sahrens } 434789Sahrens 435789Sahrens /* 436789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 437789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 438789Sahrens * message for the caller to use. 439789Sahrens */ 440789Sahrens static int 441789Sahrens nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen) 442789Sahrens { 443789Sahrens char *end; 444789Sahrens int shift; 445789Sahrens 446789Sahrens *num = 0; 447789Sahrens 448789Sahrens /* Check to see if this looks like a number. */ 449789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 450789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 451789Sahrens "must be a numeric value"), buflen); 452789Sahrens return (-1); 453789Sahrens } 454789Sahrens 455789Sahrens /* Rely on stroll() to process the numeric portion. */ 456789Sahrens errno = 0; 457789Sahrens *num = strtoll(value, &end, 10); 458789Sahrens 459789Sahrens /* 460789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 461789Sahrens * in a 64-bit value. 462789Sahrens */ 463789Sahrens if (errno == ERANGE) { 464789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 465789Sahrens "value is too large"), buflen); 466789Sahrens return (-1); 467789Sahrens } 468789Sahrens 469789Sahrens /* 470789Sahrens * If we have a decimal value, then do the computation with floating 471789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 472789Sahrens */ 473789Sahrens if (*end == '.') { 474789Sahrens double fval = strtod(value, &end); 475789Sahrens 476789Sahrens if ((shift = str2shift(end, buf, buflen)) == -1) 477789Sahrens return (-1); 478789Sahrens 479789Sahrens fval *= pow(2, shift); 480789Sahrens 481789Sahrens if (fval > UINT64_MAX) { 482789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 483789Sahrens "value is too large"), buflen); 484789Sahrens return (-1); 485789Sahrens } 486789Sahrens 487789Sahrens *num = (uint64_t)fval; 488789Sahrens } else { 489789Sahrens if ((shift = str2shift(end, buf, buflen)) == -1) 490789Sahrens return (-1); 491789Sahrens 492789Sahrens /* Check for overflow */ 493789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 494789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 495789Sahrens "value is too large"), buflen); 496789Sahrens return (-1); 497789Sahrens } 498789Sahrens 499789Sahrens *num <<= shift; 500789Sahrens } 501789Sahrens 502789Sahrens return (0); 503789Sahrens } 504789Sahrens 505789Sahrens int 506789Sahrens zfs_nicestrtonum(const char *str, uint64_t *val) 507789Sahrens { 508789Sahrens char buf[1]; 509789Sahrens 510789Sahrens return (nicestrtonum(str, val, buf, sizeof (buf))); 511789Sahrens } 512789Sahrens 513789Sahrens /* 514789Sahrens * Given a property type and value, verify that the value is appropriate. Used 515789Sahrens * by zfs_prop_set() and some libzfs consumers. 516789Sahrens */ 517789Sahrens int 518789Sahrens zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval) 519789Sahrens { 520789Sahrens const char *propname = zfs_prop_to_name(prop); 521789Sahrens uint64_t number; 522789Sahrens char reason[64]; 523789Sahrens int i; 524789Sahrens 525789Sahrens /* 526789Sahrens * Check to see if this a read-only property. 527789Sahrens */ 528789Sahrens if (zfs_prop_readonly(prop)) { 529789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 530789Sahrens "cannot set %s property: read-only property"), propname); 531789Sahrens return (-1); 532789Sahrens } 533789Sahrens 534789Sahrens /* See if the property value is too long */ 535789Sahrens if (strlen(value) >= ZFS_MAXPROPLEN) { 536789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 537789Sahrens "bad %s value '%s': value is too long"), propname, 538789Sahrens value); 539789Sahrens return (-1); 540789Sahrens } 541789Sahrens 542789Sahrens /* Perform basic checking based on property type */ 543789Sahrens switch (zfs_prop_get_type(prop)) { 544789Sahrens case prop_type_boolean: 545789Sahrens if (strcmp(value, "on") == 0) { 546789Sahrens number = 1; 547789Sahrens } else if (strcmp(value, "off") == 0) { 548789Sahrens number = 0; 549789Sahrens } else { 550789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 551789Sahrens "bad %s value '%s': must be 'on' or 'off'"), 552789Sahrens propname, value); 553789Sahrens return (-1); 554789Sahrens } 555789Sahrens break; 556789Sahrens 557789Sahrens case prop_type_number: 558789Sahrens /* treat 'none' as 0 */ 559789Sahrens if (strcmp(value, "none") == 0) { 560789Sahrens number = 0; 561789Sahrens break; 562789Sahrens } 563789Sahrens 564789Sahrens if (nicestrtonum(value, &number, reason, 565789Sahrens sizeof (reason)) != 0) { 566789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 567789Sahrens "bad %s value '%s': %s"), propname, value, 568789Sahrens reason); 569789Sahrens return (-1); 570789Sahrens } 571789Sahrens 572789Sahrens /* don't allow 0 for quota, use 'none' instead */ 573789Sahrens if (prop == ZFS_PROP_QUOTA && number == 0 && 574789Sahrens strcmp(value, "none") != 0) { 575789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 576789Sahrens "bad %s value '%s': use '%s=none' to disable"), 577789Sahrens propname, value, propname); 578789Sahrens return (-1); 579789Sahrens } 580789Sahrens 581789Sahrens /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 582789Sahrens if (prop == ZFS_PROP_RECORDSIZE || 583789Sahrens prop == ZFS_PROP_VOLBLOCKSIZE) { 584789Sahrens if (number < SPA_MINBLOCKSIZE || 585789Sahrens number > SPA_MAXBLOCKSIZE || !ISP2(number)) { 586789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 587789Sahrens "bad %s value '%s': " 588789Sahrens "must be power of 2 from %u to %uk"), 589789Sahrens propname, value, 590789Sahrens (uint_t)SPA_MINBLOCKSIZE, 591789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 592789Sahrens return (-1); 593789Sahrens } 594789Sahrens } 595789Sahrens 596789Sahrens break; 597789Sahrens 598789Sahrens case prop_type_string: 599789Sahrens case prop_type_index: 600789Sahrens /* 601789Sahrens * The two writable string values, 'mountpoint' and 602789Sahrens * 'checksum' need special consideration. The 'index' types are 603789Sahrens * specified as strings by the user, but passed to the kernel as 604789Sahrens * integers. 605789Sahrens */ 606789Sahrens switch (prop) { 607789Sahrens case ZFS_PROP_MOUNTPOINT: 608789Sahrens if (strcmp(value, ZFS_MOUNTPOINT_NONE) == 0 || 609789Sahrens strcmp(value, ZFS_MOUNTPOINT_LEGACY) == 0) 610789Sahrens break; 611789Sahrens 612789Sahrens if (value[0] != '/') { 613789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 614789Sahrens "bad %s value '%s': must be an absolute " 615789Sahrens "path, 'none', or 'legacy'"), 616789Sahrens propname, value); 617789Sahrens return (-1); 618789Sahrens } 619789Sahrens break; 620789Sahrens 621789Sahrens case ZFS_PROP_CHECKSUM: 622789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 623789Sahrens if (strcmp(value, checksum_table[i].name) 624789Sahrens == 0) { 625789Sahrens number = checksum_table[i].value; 626789Sahrens break; 627789Sahrens } 628789Sahrens } 629789Sahrens 630789Sahrens if (checksum_table[i].name == NULL) { 631789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 632789Sahrens "bad %s value '%s': must be 'on', 'off', " 633789Sahrens "'fletcher2', 'fletcher4', or 'sha256'"), 634789Sahrens propname, value); 635789Sahrens return (-1); 636789Sahrens } 637789Sahrens break; 638789Sahrens 639789Sahrens case ZFS_PROP_COMPRESSION: 640789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 641789Sahrens if (strcmp(value, compress_table[i].name) 642789Sahrens == 0) { 643789Sahrens number = compress_table[i].value; 644789Sahrens break; 645789Sahrens } 646789Sahrens } 647789Sahrens 648789Sahrens if (compress_table[i].name == NULL) { 649789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 650789Sahrens "bad %s value '%s': must be 'on', 'off', " 651789Sahrens "or 'lzjb'"), 652789Sahrens propname, value); 653789Sahrens return (-1); 654789Sahrens } 655789Sahrens break; 656789Sahrens 657789Sahrens case ZFS_PROP_SNAPDIR: 658789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 659789Sahrens if (strcmp(value, snapdir_table[i].name) == 0) { 660789Sahrens number = snapdir_table[i].value; 661789Sahrens break; 662789Sahrens } 663789Sahrens } 664789Sahrens 665789Sahrens if (snapdir_table[i].name == NULL) { 666789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 667789Sahrens "bad %s value '%s': must be 'hidden' " 668789Sahrens "or 'visible'"), 669789Sahrens propname, value); 670789Sahrens return (-1); 671789Sahrens } 672789Sahrens break; 673789Sahrens 674789Sahrens case ZFS_PROP_ACLMODE: 675789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 676789Sahrens if (strcmp(value, acl_mode_table[i].name) 677789Sahrens == 0) { 678789Sahrens number = acl_mode_table[i].value; 679789Sahrens break; 680789Sahrens } 681789Sahrens } 682789Sahrens 683789Sahrens if (acl_mode_table[i].name == NULL) { 684789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 685789Sahrens "bad %s value '%s': must be 'discard', " 686789Sahrens "'groupmask' or 'passthrough'"), 687789Sahrens propname, value); 688789Sahrens return (-1); 689789Sahrens } 690789Sahrens break; 691789Sahrens 692789Sahrens case ZFS_PROP_ACLINHERIT: 693789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 694789Sahrens if (strcmp(value, acl_inherit_table[i].name) 695789Sahrens == 0) { 696789Sahrens number = acl_inherit_table[i].value; 697789Sahrens break; 698789Sahrens } 699789Sahrens } 700789Sahrens 701789Sahrens if (acl_inherit_table[i].name == NULL) { 702789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 703789Sahrens "bad %s value '%s': must be 'discard', " 704905Smarks "'noallow', 'secure' or 'passthrough'"), 705789Sahrens propname, value); 706789Sahrens return (-1); 707789Sahrens } 708789Sahrens break; 709789Sahrens 710789Sahrens case ZFS_PROP_SHARENFS: 711789Sahrens /* 712789Sahrens * Nothing to do for 'sharenfs', this gets passed on to 713789Sahrens * share(1M) verbatim. 714789Sahrens */ 715789Sahrens break; 716789Sahrens } 717789Sahrens } 718789Sahrens 719789Sahrens if (intval != NULL) 720789Sahrens *intval = number; 721789Sahrens 722789Sahrens return (0); 723789Sahrens } 724789Sahrens 725789Sahrens /* 726789Sahrens * Given a property name and value, set the property for the given dataset. 727789Sahrens */ 728789Sahrens int 729789Sahrens zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval) 730789Sahrens { 731789Sahrens const char *propname = zfs_prop_to_name(prop); 732789Sahrens uint64_t number; 733789Sahrens zfs_cmd_t zc = { 0 }; 734789Sahrens int ret; 735789Sahrens prop_changelist_t *cl; 736789Sahrens 737789Sahrens if (zfs_prop_validate(prop, propval, &number) != 0) 738789Sahrens return (-1); 739789Sahrens 740789Sahrens /* 741789Sahrens * Check to see if the value applies to this type 742789Sahrens */ 743789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 744789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 745789Sahrens "cannot set %s for '%s': property does not apply to %ss"), 746789Sahrens propname, zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 747789Sahrens return (-1); 748789Sahrens } 749789Sahrens 750789Sahrens /* 751789Sahrens * For the mountpoint and sharenfs properties, check if it can be set 752789Sahrens * in a global/non-global zone based on the zoned property value: 753789Sahrens * 754789Sahrens * global zone non-global zone 755789Sahrens * ----------------------------------------------------- 756789Sahrens * zoned=on mountpoint (no) mountpoint (yes) 757789Sahrens * sharenfs (no) sharenfs (no) 758789Sahrens * 759789Sahrens * zoned=off mountpoint (yes) N/A 760789Sahrens * sharenfs (yes) 761789Sahrens */ 762789Sahrens if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 763789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 764789Sahrens if (getzoneid() == GLOBAL_ZONEID) { 765789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7661133Seschrock "cannot set %s for '%s': " 767789Sahrens "dataset is used in a non-global zone"), 768789Sahrens propname, zhp->zfs_name); 769789Sahrens return (-1); 770789Sahrens } else if (prop == ZFS_PROP_SHARENFS) { 771789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7721133Seschrock "cannot set %s for '%s': filesystems " 773789Sahrens "cannot be shared in a non-global zone"), 774789Sahrens propname, zhp->zfs_name); 775789Sahrens return (-1); 776789Sahrens } 777789Sahrens } else if (getzoneid() != GLOBAL_ZONEID) { 778789Sahrens /* 779789Sahrens * If zoned property is 'off', this must be in 780789Sahrens * a globle zone. If not, something is wrong. 781789Sahrens */ 782789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7831133Seschrock "cannot set %s for '%s': dataset is " 784789Sahrens "used in a non-global zone, but 'zoned' " 785789Sahrens "property is not set"), 786789Sahrens propname, zhp->zfs_name); 787789Sahrens return (-1); 788789Sahrens } 789789Sahrens } 790789Sahrens 791789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 792789Sahrens return (-1); 793789Sahrens 794789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 795789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for '%s', " 796789Sahrens "child dataset with inherited mountpoint is used " 797789Sahrens "in a non-global zone"), 798789Sahrens propname, zhp->zfs_name); 799789Sahrens ret = -1; 800789Sahrens goto error; 801789Sahrens } 802789Sahrens 803789Sahrens if ((ret = changelist_prefix(cl)) != 0) 804789Sahrens goto error; 805789Sahrens 806789Sahrens /* 807789Sahrens * Execute the corresponding ioctl() to set this property. 808789Sahrens */ 809789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 810789Sahrens 811789Sahrens switch (prop) { 812789Sahrens case ZFS_PROP_QUOTA: 813789Sahrens zc.zc_cookie = number; 8141544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_QUOTA, &zc); 815789Sahrens break; 816789Sahrens case ZFS_PROP_RESERVATION: 817789Sahrens zc.zc_cookie = number; 8181544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_RESERVATION, &zc); 819789Sahrens break; 820789Sahrens case ZFS_PROP_MOUNTPOINT: 821789Sahrens case ZFS_PROP_SHARENFS: 822789Sahrens /* 823789Sahrens * These properties are passed down as real strings. 824789Sahrens */ 825789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 826789Sahrens sizeof (zc.zc_prop_name)); 827789Sahrens (void) strlcpy(zc.zc_prop_value, propval, 828789Sahrens sizeof (zc.zc_prop_value)); 829789Sahrens zc.zc_intsz = 1; 830789Sahrens zc.zc_numints = strlen(propval) + 1; 8311544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc); 832789Sahrens break; 833789Sahrens case ZFS_PROP_VOLSIZE: 834789Sahrens zc.zc_volsize = number; 8351544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_VOLSIZE, &zc); 836789Sahrens break; 837789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 838789Sahrens zc.zc_volblocksize = number; 8391544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_VOLBLOCKSIZE, &zc); 840789Sahrens break; 841789Sahrens default: 842789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 843789Sahrens sizeof (zc.zc_prop_name)); 844789Sahrens /* LINTED - alignment */ 845789Sahrens *(uint64_t *)zc.zc_prop_value = number; 846789Sahrens zc.zc_intsz = 8; 847789Sahrens zc.zc_numints = 1; 8481544Seschrock ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc); 849789Sahrens break; 850789Sahrens } 851789Sahrens 852789Sahrens if (ret != 0) { 853789Sahrens switch (errno) { 854789Sahrens 855789Sahrens case EPERM: 856789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 857789Sahrens "cannot set %s for '%s': permission " 858789Sahrens "denied"), propname, zhp->zfs_name); 859789Sahrens break; 860789Sahrens 861789Sahrens case ENOENT: 862789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 863789Sahrens "cannot open '%s': no such %s"), zhp->zfs_name, 864789Sahrens zfs_type_to_name(zhp->zfs_type)); 865789Sahrens break; 866789Sahrens 867789Sahrens case ENOSPC: 868789Sahrens /* 869789Sahrens * For quotas and reservations, ENOSPC indicates 870789Sahrens * something different; setting a quota or reservation 871789Sahrens * doesn't use any disk space. 872789Sahrens */ 873789Sahrens switch (prop) { 874789Sahrens case ZFS_PROP_QUOTA: 875789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s " 876789Sahrens "for '%s': size is less than current " 877789Sahrens "used or reserved space"), propname, 878789Sahrens zhp->zfs_name); 879789Sahrens break; 880789Sahrens 881789Sahrens case ZFS_PROP_RESERVATION: 882789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s " 883789Sahrens "for '%s': size is greater than available " 884789Sahrens "space"), propname, zhp->zfs_name); 885789Sahrens break; 886789Sahrens 887789Sahrens default: 888789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 889789Sahrens "cannot set %s for '%s': out of space"), 890789Sahrens propname, zhp->zfs_name); 891789Sahrens break; 892789Sahrens } 893789Sahrens break; 894789Sahrens 895789Sahrens case EBUSY: 896789Sahrens if (prop == ZFS_PROP_VOLBLOCKSIZE) { 897789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 898789Sahrens "cannot set %s for '%s': " 899789Sahrens "volume already contains data"), 900789Sahrens propname, zhp->zfs_name); 901789Sahrens } else { 902789Sahrens zfs_baderror(errno); 903789Sahrens } 904789Sahrens break; 905789Sahrens 9061175Slling case EROFS: 9071175Slling zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for " 9081175Slling "'%s': read only %s"), propname, zhp->zfs_name, 9091175Slling zfs_type_to_name(zhp->zfs_type)); 9101175Slling break; 9111175Slling 912789Sahrens case EOVERFLOW: 913789Sahrens /* 914789Sahrens * This platform can't address a volume this big. 915789Sahrens */ 916789Sahrens #ifdef _ILP32 917789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 918789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 919789Sahrens "cannot set %s for '%s': " 920789Sahrens "max volume size is 1TB on 32-bit systems"), 921789Sahrens propname, zhp->zfs_name); 922789Sahrens break; 923789Sahrens } 924789Sahrens #endif 925789Sahrens zfs_baderror(errno); 926789Sahrens default: 927789Sahrens zfs_baderror(errno); 928789Sahrens } 929789Sahrens } else { 930789Sahrens /* 931789Sahrens * Refresh the statistics so the new property value 932789Sahrens * is reflected. 933789Sahrens */ 934789Sahrens if ((ret = changelist_postfix(cl)) != 0) 935789Sahrens goto error; 936789Sahrens 937789Sahrens (void) get_stats(zhp); 938789Sahrens } 939789Sahrens 940789Sahrens error: 941789Sahrens changelist_free(cl); 942789Sahrens return (ret); 943789Sahrens } 944789Sahrens 945789Sahrens /* 946789Sahrens * Given a property, inherit the value from the parent dataset. 947789Sahrens */ 948789Sahrens int 949789Sahrens zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop) 950789Sahrens { 951789Sahrens const char *propname = zfs_prop_to_name(prop); 952789Sahrens zfs_cmd_t zc = { 0 }; 953789Sahrens int ret; 954789Sahrens prop_changelist_t *cl; 955789Sahrens 956789Sahrens /* 957789Sahrens * Verify that this property is inheritable. 958789Sahrens */ 959789Sahrens if (zfs_prop_readonly(prop)) { 960789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 961789Sahrens "cannot inherit %s for '%s': property is read-only"), 962789Sahrens propname, zhp->zfs_name); 963789Sahrens return (-1); 964789Sahrens } 965789Sahrens 966789Sahrens if (!zfs_prop_inheritable(prop)) { 967789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 968789Sahrens "cannot inherit %s for '%s': property is not inheritable"), 969789Sahrens propname, zhp->zfs_name); 970789Sahrens return (-1); 971789Sahrens } 972789Sahrens 973789Sahrens /* 974789Sahrens * Check to see if the value applies to this type 975789Sahrens */ 976789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 977789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 978789Sahrens "cannot inherit %s for '%s': property does " 979789Sahrens "not apply to %ss"), propname, zhp->zfs_name, 980789Sahrens zfs_type_to_name(zhp->zfs_type)); 981789Sahrens return (-1); 982789Sahrens } 983789Sahrens 984789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 985789Sahrens (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name)); 986789Sahrens 987789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 988789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 989789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', " 990789Sahrens "dataset is used in a non-global zone"), propname, 991789Sahrens zhp->zfs_name); 992789Sahrens return (-1); 993789Sahrens } 994789Sahrens 995789Sahrens /* 996789Sahrens * Determine datasets which will be affected by this change, if any. 997789Sahrens */ 998789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 999789Sahrens return (-1); 1000789Sahrens 1001789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1002789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', " 1003789Sahrens "child dataset with inherited mountpoint is " 1004789Sahrens "used in a non-global zone"), 1005789Sahrens propname, zhp->zfs_name); 1006789Sahrens ret = -1; 1007789Sahrens goto error; 1008789Sahrens } 1009789Sahrens 1010789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1011789Sahrens goto error; 1012789Sahrens 1013789Sahrens zc.zc_numints = 0; 1014789Sahrens 10151544Seschrock if ((ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc)) != 0) { 1016789Sahrens switch (errno) { 1017789Sahrens case EPERM: 1018789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1019789Sahrens "cannot inherit %s for '%s': permission " 1020789Sahrens "denied"), propname, zhp->zfs_name); 1021789Sahrens break; 1022789Sahrens case ENOENT: 1023789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1024789Sahrens "cannot open '%s': no such %s"), zhp->zfs_name, 1025789Sahrens zfs_type_to_name(zhp->zfs_type)); 1026789Sahrens break; 1027789Sahrens case ENOSPC: 1028789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1029789Sahrens "cannot inherit %s for '%s': " 1030789Sahrens "out of space"), propname, zhp->zfs_name); 1031789Sahrens break; 1032789Sahrens default: 1033789Sahrens zfs_baderror(errno); 1034789Sahrens } 1035789Sahrens 1036789Sahrens } else { 1037789Sahrens 1038789Sahrens if ((ret = changelist_postfix(cl)) != 0) 1039789Sahrens goto error; 1040789Sahrens 1041789Sahrens /* 1042789Sahrens * Refresh the statistics so the new property is reflected. 1043789Sahrens */ 1044789Sahrens (void) get_stats(zhp); 1045789Sahrens } 1046789Sahrens 1047789Sahrens 1048789Sahrens error: 1049789Sahrens changelist_free(cl); 1050789Sahrens return (ret); 1051789Sahrens } 1052789Sahrens 1053789Sahrens static void 1054789Sahrens nicebool(int value, char *buf, size_t buflen) 1055789Sahrens { 1056789Sahrens if (value) 1057789Sahrens (void) strlcpy(buf, "on", buflen); 1058789Sahrens else 1059789Sahrens (void) strlcpy(buf, "off", buflen); 1060789Sahrens } 1061789Sahrens 1062789Sahrens /* 10631356Seschrock * True DSL properties are stored in an nvlist. The following two functions 10641356Seschrock * extract them appropriately. 10651356Seschrock */ 10661356Seschrock static uint64_t 10671356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10681356Seschrock { 10691356Seschrock nvlist_t *nv; 10701356Seschrock uint64_t value; 10711356Seschrock 10721356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10731356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 10741356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 10751356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10761356Seschrock } else { 10771356Seschrock value = zfs_prop_default_numeric(prop); 10781356Seschrock *source = ""; 10791356Seschrock } 10801356Seschrock 10811356Seschrock return (value); 10821356Seschrock } 10831356Seschrock 10841356Seschrock static char * 10851356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10861356Seschrock { 10871356Seschrock nvlist_t *nv; 10881356Seschrock char *value; 10891356Seschrock 10901356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10911356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 10921356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 10931356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10941356Seschrock } else { 10951356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 10961356Seschrock value = ""; 10971356Seschrock *source = ""; 10981356Seschrock } 10991356Seschrock 11001356Seschrock return (value); 11011356Seschrock } 11021356Seschrock 11031356Seschrock /* 1104789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1105789Sahrens * zfs_prop_get_int() are built using this interface. 1106789Sahrens * 1107789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1108789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1109789Sahrens * If they differ from the on-disk values, report the current values and mark 1110789Sahrens * the source "temporary". 1111789Sahrens */ 1112789Sahrens static uint64_t 1113789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 1114789Sahrens char **source) 1115789Sahrens { 1116789Sahrens uint64_t val; 1117789Sahrens struct mnttab mnt; 1118789Sahrens 1119789Sahrens *source = NULL; 1120789Sahrens 1121789Sahrens if (zhp->zfs_mntopts == NULL) 1122789Sahrens mnt.mnt_mntopts = ""; 1123789Sahrens else 1124789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1125789Sahrens 1126789Sahrens switch (prop) { 1127789Sahrens case ZFS_PROP_ATIME: 11281356Seschrock val = getprop_uint64(zhp, prop, source); 1129789Sahrens 1130789Sahrens if (hasmntopt(&mnt, MNTOPT_ATIME) && !val) { 1131789Sahrens val = TRUE; 1132789Sahrens if (src) 1133789Sahrens *src = ZFS_SRC_TEMPORARY; 1134789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && val) { 1135789Sahrens val = FALSE; 1136789Sahrens if (src) 1137789Sahrens *src = ZFS_SRC_TEMPORARY; 1138789Sahrens } 11391356Seschrock return (val); 1140789Sahrens 1141789Sahrens case ZFS_PROP_AVAILABLE: 1142789Sahrens return (zhp->zfs_dmustats.dds_available); 1143789Sahrens 1144789Sahrens case ZFS_PROP_DEVICES: 11451356Seschrock val = getprop_uint64(zhp, prop, source); 1146789Sahrens 1147789Sahrens if (hasmntopt(&mnt, MNTOPT_DEVICES) && !val) { 1148789Sahrens val = TRUE; 1149789Sahrens if (src) 1150789Sahrens *src = ZFS_SRC_TEMPORARY; 1151789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && val) { 1152789Sahrens val = FALSE; 1153789Sahrens if (src) 1154789Sahrens *src = ZFS_SRC_TEMPORARY; 1155789Sahrens } 1156789Sahrens return (val); 1157789Sahrens 1158789Sahrens case ZFS_PROP_EXEC: 11591356Seschrock val = getprop_uint64(zhp, prop, source); 1160789Sahrens 1161789Sahrens if (hasmntopt(&mnt, MNTOPT_EXEC) && !val) { 1162789Sahrens val = TRUE; 1163789Sahrens if (src) 1164789Sahrens *src = ZFS_SRC_TEMPORARY; 1165789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && val) { 1166789Sahrens val = FALSE; 1167789Sahrens if (src) 1168789Sahrens *src = ZFS_SRC_TEMPORARY; 1169789Sahrens } 1170789Sahrens return (val); 1171789Sahrens 1172789Sahrens case ZFS_PROP_RECORDSIZE: 1173789Sahrens case ZFS_PROP_COMPRESSION: 11741356Seschrock case ZFS_PROP_ZONED: 11751356Seschrock val = getprop_uint64(zhp, prop, source); 11761356Seschrock return (val); 1177789Sahrens 1178789Sahrens case ZFS_PROP_READONLY: 11791356Seschrock val = getprop_uint64(zhp, prop, source); 1180789Sahrens 1181789Sahrens if (hasmntopt(&mnt, MNTOPT_RO) && !val) { 1182789Sahrens val = TRUE; 1183789Sahrens if (src) 1184789Sahrens *src = ZFS_SRC_TEMPORARY; 1185789Sahrens } else if (hasmntopt(&mnt, MNTOPT_RW) && val) { 1186789Sahrens val = FALSE; 1187789Sahrens if (src) 1188789Sahrens *src = ZFS_SRC_TEMPORARY; 1189789Sahrens } 1190789Sahrens return (val); 1191789Sahrens 11921544Seschrock case ZFS_PROP_CREATION: 11931544Seschrock return (zhp->zfs_dmustats.dds_creation_time); 11941544Seschrock 1195789Sahrens case ZFS_PROP_QUOTA: 1196789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1197789Sahrens *source = ""; /* default */ 1198789Sahrens else 1199789Sahrens *source = zhp->zfs_name; 1200789Sahrens return (zhp->zfs_dmustats.dds_quota); 1201789Sahrens 1202789Sahrens case ZFS_PROP_RESERVATION: 1203789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1204789Sahrens *source = ""; /* default */ 1205789Sahrens else 1206789Sahrens *source = zhp->zfs_name; 1207789Sahrens return (zhp->zfs_dmustats.dds_reserved); 1208789Sahrens 1209789Sahrens case ZFS_PROP_COMPRESSRATIO: 1210789Sahrens /* 1211789Sahrens * Using physical space and logical space, calculate the 1212789Sahrens * compression ratio. We return the number as a multiple of 1213789Sahrens * 100, so '2.5x' would be returned as 250. 1214789Sahrens */ 1215789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 1216789Sahrens return (100ULL); 1217789Sahrens else 1218789Sahrens return (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1219789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 1220789Sahrens 1221789Sahrens case ZFS_PROP_REFERENCED: 1222789Sahrens /* 1223789Sahrens * 'referenced' refers to the amount of physical space 1224789Sahrens * referenced (possibly shared) by this object. 1225789Sahrens */ 1226789Sahrens return (zhp->zfs_dmustats.dds_space_refd); 1227789Sahrens 1228789Sahrens case ZFS_PROP_SETUID: 12291356Seschrock val = getprop_uint64(zhp, prop, source); 1230789Sahrens 1231789Sahrens if (hasmntopt(&mnt, MNTOPT_SETUID) && !val) { 1232789Sahrens val = TRUE; 1233789Sahrens if (src) 1234789Sahrens *src = ZFS_SRC_TEMPORARY; 1235789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && val) { 1236789Sahrens val = FALSE; 1237789Sahrens if (src) 1238789Sahrens *src = ZFS_SRC_TEMPORARY; 1239789Sahrens } 1240789Sahrens return (val); 1241789Sahrens 1242789Sahrens case ZFS_PROP_VOLSIZE: 1243789Sahrens return (zhp->zfs_volsize); 1244789Sahrens 1245789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1246789Sahrens return (zhp->zfs_volblocksize); 1247789Sahrens 1248789Sahrens case ZFS_PROP_USED: 1249789Sahrens return (zhp->zfs_dmustats.dds_space_used); 1250789Sahrens 1251789Sahrens case ZFS_PROP_CREATETXG: 1252789Sahrens return (zhp->zfs_dmustats.dds_creation_txg); 1253789Sahrens 1254789Sahrens case ZFS_PROP_MOUNTED: 1255789Sahrens /* 1256789Sahrens * Unlike other properties, we defer calculation of 'MOUNTED' 1257789Sahrens * until actually requested. This is because the getmntany() 1258789Sahrens * call can be extremely expensive on systems with a large 1259789Sahrens * number of filesystems, and the property isn't needed in 1260789Sahrens * normal use cases. 1261789Sahrens */ 1262789Sahrens if (zhp->zfs_mntopts == NULL) { 1263789Sahrens struct mnttab search = { 0 }, entry; 1264789Sahrens 1265789Sahrens search.mnt_special = (char *)zhp->zfs_name; 12661407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 12671544Seschrock rewind(zfs_mnttab()); 12681544Seschrock 12691544Seschrock if (getmntany(zfs_mnttab(), &entry, &search) == 0) 1270789Sahrens zhp->zfs_mntopts = 1271789Sahrens zfs_strdup(entry.mnt_mntopts); 1272789Sahrens } 1273789Sahrens return (zhp->zfs_mntopts != NULL); 1274789Sahrens 1275789Sahrens default: 1276789Sahrens zfs_baderror(EINVAL); 1277789Sahrens } 1278789Sahrens 1279789Sahrens return (0); 1280789Sahrens } 1281789Sahrens 1282789Sahrens /* 1283789Sahrens * Calculate the source type, given the raw source string. 1284789Sahrens */ 1285789Sahrens static void 1286789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1287789Sahrens char *statbuf, size_t statlen) 1288789Sahrens { 1289789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1290789Sahrens return; 1291789Sahrens 1292789Sahrens if (source == NULL) { 1293789Sahrens *srctype = ZFS_SRC_NONE; 1294789Sahrens } else if (source[0] == '\0') { 1295789Sahrens *srctype = ZFS_SRC_DEFAULT; 1296789Sahrens } else { 1297789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1298789Sahrens *srctype = ZFS_SRC_LOCAL; 1299789Sahrens } else { 1300789Sahrens (void) strlcpy(statbuf, source, statlen); 1301789Sahrens *srctype = ZFS_SRC_INHERITED; 1302789Sahrens } 1303789Sahrens } 1304789Sahrens 1305789Sahrens } 1306789Sahrens 1307789Sahrens /* 1308789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1309789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1310789Sahrens * human-readable form. 1311789Sahrens * 1312789Sahrens * Returns 0 on success, or -1 on error. 1313789Sahrens */ 1314789Sahrens int 1315789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1316789Sahrens zfs_source_t *src, char *statbuf, size_t statlen, int literal) 1317789Sahrens { 1318789Sahrens char *source = NULL; 1319789Sahrens uint64_t val; 1320789Sahrens char *str; 1321789Sahrens int i; 1322789Sahrens const char *root; 1323789Sahrens 1324789Sahrens /* 1325789Sahrens * Check to see if this property applies to our object 1326789Sahrens */ 1327789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1328789Sahrens return (-1); 1329789Sahrens 1330789Sahrens if (src) 1331789Sahrens *src = ZFS_SRC_NONE; 1332789Sahrens 1333789Sahrens switch (prop) { 1334789Sahrens case ZFS_PROP_ATIME: 1335789Sahrens case ZFS_PROP_READONLY: 1336789Sahrens case ZFS_PROP_SETUID: 1337789Sahrens case ZFS_PROP_ZONED: 1338789Sahrens case ZFS_PROP_DEVICES: 1339789Sahrens case ZFS_PROP_EXEC: 1340789Sahrens /* 1341789Sahrens * Basic boolean values are built on top of 1342789Sahrens * get_numeric_property(). 1343789Sahrens */ 1344789Sahrens nicebool(get_numeric_property(zhp, prop, src, &source), 1345789Sahrens propbuf, proplen); 1346789Sahrens 1347789Sahrens break; 1348789Sahrens 1349789Sahrens case ZFS_PROP_AVAILABLE: 1350789Sahrens case ZFS_PROP_RECORDSIZE: 1351789Sahrens case ZFS_PROP_CREATETXG: 1352789Sahrens case ZFS_PROP_REFERENCED: 1353789Sahrens case ZFS_PROP_USED: 1354789Sahrens case ZFS_PROP_VOLSIZE: 1355789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1356789Sahrens /* 1357789Sahrens * Basic numeric values are built on top of 1358789Sahrens * get_numeric_property(). 1359789Sahrens */ 1360789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1361789Sahrens if (literal) 1362789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1363789Sahrens else 1364789Sahrens zfs_nicenum(val, propbuf, proplen); 1365789Sahrens break; 1366789Sahrens 1367789Sahrens case ZFS_PROP_COMPRESSION: 13681356Seschrock val = getprop_uint64(zhp, prop, &source); 1369789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 13701356Seschrock if (compress_table[i].value == val) 1371789Sahrens break; 1372789Sahrens } 1373789Sahrens assert(compress_table[i].name != NULL); 1374789Sahrens (void) strlcpy(propbuf, compress_table[i].name, proplen); 1375789Sahrens break; 1376789Sahrens 1377789Sahrens case ZFS_PROP_CHECKSUM: 13781356Seschrock val = getprop_uint64(zhp, prop, &source); 1379789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 13801356Seschrock if (checksum_table[i].value == val) 1381789Sahrens break; 1382789Sahrens } 1383789Sahrens assert(checksum_table[i].name != NULL); 1384789Sahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen); 1385789Sahrens break; 1386789Sahrens 1387789Sahrens case ZFS_PROP_SNAPDIR: 13881356Seschrock val = getprop_uint64(zhp, prop, &source); 1389789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 13901356Seschrock if (snapdir_table[i].value == val) 1391789Sahrens break; 1392789Sahrens } 1393789Sahrens assert(snapdir_table[i].name != NULL); 1394789Sahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen); 1395789Sahrens break; 1396789Sahrens 1397789Sahrens case ZFS_PROP_ACLMODE: 13981356Seschrock val = getprop_uint64(zhp, prop, &source); 1399789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 14001356Seschrock if (acl_mode_table[i].value == val) 1401789Sahrens break; 1402789Sahrens } 1403789Sahrens assert(acl_mode_table[i].name != NULL); 1404789Sahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen); 1405789Sahrens break; 1406789Sahrens 1407789Sahrens case ZFS_PROP_ACLINHERIT: 14081356Seschrock val = getprop_uint64(zhp, prop, &source); 1409789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 14101356Seschrock if (acl_inherit_table[i].value == val) 1411789Sahrens break; 1412789Sahrens } 1413789Sahrens assert(acl_inherit_table[i].name != NULL); 1414789Sahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen); 1415789Sahrens break; 1416789Sahrens 1417789Sahrens case ZFS_PROP_CREATION: 1418789Sahrens /* 1419789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1420789Sahrens * this into a string unless 'literal' is specified. 1421789Sahrens */ 1422789Sahrens { 1423789Sahrens time_t time = (time_t) 1424789Sahrens zhp->zfs_dmustats.dds_creation_time; 1425789Sahrens struct tm t; 1426789Sahrens 1427789Sahrens if (literal || 1428789Sahrens localtime_r(&time, &t) == NULL || 1429789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1430789Sahrens &t) == 0) 1431789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1432789Sahrens zhp->zfs_dmustats.dds_creation_time); 1433789Sahrens } 1434789Sahrens break; 1435789Sahrens 1436789Sahrens case ZFS_PROP_MOUNTPOINT: 1437789Sahrens /* 1438789Sahrens * Getting the precise mountpoint can be tricky. 1439789Sahrens * 1440789Sahrens * - for 'none' or 'legacy', return those values. 1441789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1442789Sahrens * - for inherited mountpoints, we want to take everything 1443789Sahrens * after our ancestor and append it to the inherited value. 1444789Sahrens * 1445789Sahrens * If the pool has an alternate root, we want to prepend that 1446789Sahrens * root to any values we return. 1447789Sahrens */ 14481544Seschrock root = zhp->zfs_root; 14491356Seschrock str = getprop_string(zhp, prop, &source); 14501356Seschrock 14511356Seschrock if (str[0] == '\0') { 1452789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1453789Sahrens root, zhp->zfs_name); 14541356Seschrock } else if (str[0] == '/') { 14551356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1456789Sahrens 1457789Sahrens if (relpath[0] == '/') 1458789Sahrens relpath++; 14591356Seschrock if (str[1] == '\0') 14601356Seschrock str++; 1461789Sahrens 1462789Sahrens if (relpath[0] == '\0') 1463789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 14641356Seschrock root, str); 1465789Sahrens else 1466789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 14671356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1468789Sahrens relpath); 1469789Sahrens } else { 1470789Sahrens /* 'legacy' or 'none' */ 14711356Seschrock (void) strlcpy(propbuf, str, proplen); 1472789Sahrens } 1473789Sahrens 1474789Sahrens break; 1475789Sahrens 1476789Sahrens case ZFS_PROP_SHARENFS: 14771356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 14781356Seschrock proplen); 1479789Sahrens break; 1480789Sahrens 1481789Sahrens case ZFS_PROP_ORIGIN: 14821544Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1483789Sahrens proplen); 1484789Sahrens /* 1485789Sahrens * If there is no parent at all, return failure to indicate that 1486789Sahrens * it doesn't apply to this dataset. 1487789Sahrens */ 1488789Sahrens if (propbuf[0] == '\0') 1489789Sahrens return (-1); 1490789Sahrens break; 1491789Sahrens 1492789Sahrens case ZFS_PROP_QUOTA: 1493789Sahrens case ZFS_PROP_RESERVATION: 1494789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1495789Sahrens 1496789Sahrens /* 1497789Sahrens * If quota or reservation is 0, we translate this into 'none' 1498789Sahrens * (unless literal is set), and indicate that it's the default 1499789Sahrens * value. Otherwise, we print the number nicely and indicate 1500789Sahrens * that its set locally. 1501789Sahrens */ 1502789Sahrens if (val == 0) { 1503789Sahrens if (literal) 1504789Sahrens (void) strlcpy(propbuf, "0", proplen); 1505789Sahrens else 1506789Sahrens (void) strlcpy(propbuf, "none", proplen); 1507789Sahrens } else { 1508789Sahrens if (literal) 1509789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1510789Sahrens else 1511789Sahrens zfs_nicenum(val, propbuf, proplen); 1512789Sahrens } 1513789Sahrens break; 1514789Sahrens 1515789Sahrens case ZFS_PROP_COMPRESSRATIO: 1516789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1517789Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1518789Sahrens val % 100); 1519789Sahrens break; 1520789Sahrens 1521789Sahrens case ZFS_PROP_TYPE: 1522789Sahrens switch (zhp->zfs_type) { 1523789Sahrens case ZFS_TYPE_FILESYSTEM: 1524789Sahrens str = "filesystem"; 1525789Sahrens break; 1526789Sahrens case ZFS_TYPE_VOLUME: 1527789Sahrens str = "volume"; 1528789Sahrens break; 1529789Sahrens case ZFS_TYPE_SNAPSHOT: 1530789Sahrens str = "snapshot"; 1531789Sahrens break; 1532789Sahrens default: 1533789Sahrens zfs_baderror(zhp->zfs_type); 1534789Sahrens } 1535789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1536789Sahrens break; 1537789Sahrens 1538789Sahrens case ZFS_PROP_MOUNTED: 1539789Sahrens /* 1540789Sahrens * The 'mounted' property is a pseudo-property that described 1541789Sahrens * whether the filesystem is currently mounted. Even though 1542789Sahrens * it's a boolean value, the typical values of "on" and "off" 1543789Sahrens * don't make sense, so we translate to "yes" and "no". 1544789Sahrens */ 1545789Sahrens if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source)) 1546789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1547789Sahrens else 1548789Sahrens (void) strlcpy(propbuf, "no", proplen); 1549789Sahrens break; 1550789Sahrens 1551789Sahrens case ZFS_PROP_NAME: 1552789Sahrens /* 1553789Sahrens * The 'name' property is a pseudo-property derived from the 1554789Sahrens * dataset name. It is presented as a real property to simplify 1555789Sahrens * consumers. 1556789Sahrens */ 1557789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1558789Sahrens break; 1559789Sahrens 1560789Sahrens default: 1561789Sahrens zfs_baderror(EINVAL); 1562789Sahrens } 1563789Sahrens 1564789Sahrens get_source(zhp, src, source, statbuf, statlen); 1565789Sahrens 1566789Sahrens return (0); 1567789Sahrens } 1568789Sahrens 1569789Sahrens /* 1570789Sahrens * Utility function to get the given numeric property. Does no validation that 1571789Sahrens * the given property is the appropriate type; should only be used with 1572789Sahrens * hard-coded property types. 1573789Sahrens */ 1574789Sahrens uint64_t 1575789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1576789Sahrens { 1577789Sahrens char *source; 1578789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 1579789Sahrens 1580789Sahrens return (get_numeric_property(zhp, prop, &sourcetype, &source)); 1581789Sahrens } 1582789Sahrens 1583789Sahrens /* 1584789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1585789Sahrens */ 1586789Sahrens int 1587789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1588789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1589789Sahrens { 1590789Sahrens char *source; 1591789Sahrens 1592789Sahrens /* 1593789Sahrens * Check to see if this property applies to our object 1594789Sahrens */ 1595789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1596789Sahrens return (-1); 1597789Sahrens 1598789Sahrens if (src) 1599789Sahrens *src = ZFS_SRC_NONE; 1600789Sahrens 1601789Sahrens *value = get_numeric_property(zhp, prop, src, &source); 1602789Sahrens 1603789Sahrens get_source(zhp, src, source, statbuf, statlen); 1604789Sahrens 1605789Sahrens return (0); 1606789Sahrens } 1607789Sahrens 1608789Sahrens /* 1609789Sahrens * Returns the name of the given zfs handle. 1610789Sahrens */ 1611789Sahrens const char * 1612789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1613789Sahrens { 1614789Sahrens return (zhp->zfs_name); 1615789Sahrens } 1616789Sahrens 1617789Sahrens /* 1618789Sahrens * Returns the type of the given zfs handle. 1619789Sahrens */ 1620789Sahrens zfs_type_t 1621789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1622789Sahrens { 1623789Sahrens return (zhp->zfs_type); 1624789Sahrens } 1625789Sahrens 1626789Sahrens /* 16271356Seschrock * Iterate over all child filesystems 1628789Sahrens */ 1629789Sahrens int 16301356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1631789Sahrens { 1632789Sahrens zfs_cmd_t zc = { 0 }; 1633789Sahrens zfs_handle_t *nzhp; 1634789Sahrens int ret; 1635789Sahrens 1636789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16371544Seschrock zfs_ioctl(ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1638789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1639789Sahrens /* 1640789Sahrens * Ignore private dataset names. 1641789Sahrens */ 1642789Sahrens if (dataset_name_hidden(zc.zc_name)) 1643789Sahrens continue; 1644789Sahrens 1645789Sahrens /* 1646789Sahrens * Silently ignore errors, as the only plausible explanation is 1647789Sahrens * that the pool has since been removed. 1648789Sahrens */ 1649789Sahrens if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL) 1650789Sahrens continue; 1651789Sahrens 1652789Sahrens if ((ret = func(nzhp, data)) != 0) 1653789Sahrens return (ret); 1654789Sahrens } 1655789Sahrens 1656789Sahrens /* 1657789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1658789Sahrens * returned, then the underlying dataset has been removed since we 1659789Sahrens * obtained the handle. 1660789Sahrens */ 1661789Sahrens if (errno != ESRCH && errno != ENOENT) 1662789Sahrens zfs_baderror(errno); 1663789Sahrens 16641356Seschrock return (0); 16651356Seschrock } 16661356Seschrock 16671356Seschrock /* 16681356Seschrock * Iterate over all snapshots 16691356Seschrock */ 16701356Seschrock int 16711356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 16721356Seschrock { 16731356Seschrock zfs_cmd_t zc = { 0 }; 16741356Seschrock zfs_handle_t *nzhp; 16751356Seschrock int ret; 1676789Sahrens 1677789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 16781544Seschrock zfs_ioctl(ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; 1679789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1680789Sahrens 1681789Sahrens if ((nzhp = make_dataset_handle(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) 1694789Sahrens zfs_baderror(errno); 1695789Sahrens 1696789Sahrens return (0); 1697789Sahrens } 1698789Sahrens 1699789Sahrens /* 17001356Seschrock * Iterate over all children, snapshots and filesystems 17011356Seschrock */ 17021356Seschrock int 17031356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 17041356Seschrock { 17051356Seschrock int ret; 17061356Seschrock 17071356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 17081356Seschrock return (ret); 17091356Seschrock 17101356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 17111356Seschrock } 17121356Seschrock 17131356Seschrock /* 1714789Sahrens * Given a complete name, return just the portion that refers to the parent. 1715789Sahrens * Can return NULL if this is a pool. 1716789Sahrens */ 1717789Sahrens static int 1718789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1719789Sahrens { 1720789Sahrens char *loc; 1721789Sahrens 1722789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1723789Sahrens return (-1); 1724789Sahrens 1725789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1726789Sahrens buf[loc - path] = '\0'; 1727789Sahrens 1728789Sahrens return (0); 1729789Sahrens } 1730789Sahrens 1731789Sahrens /* 1732789Sahrens * Checks to make sure that the given path has a parent, and that it exists. 1733789Sahrens */ 1734789Sahrens static int 1735789Sahrens check_parents(const char *path, zfs_type_t type) 1736789Sahrens { 1737789Sahrens zfs_cmd_t zc = { 0 }; 1738789Sahrens char parent[ZFS_MAXNAMELEN]; 1739789Sahrens char *slash; 17401356Seschrock zfs_handle_t *zhp; 1741789Sahrens 1742789Sahrens /* get parent, and check to see if this is just a pool */ 1743789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 1744789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1745789Sahrens "cannot create '%s': missing dataset name"), 1746789Sahrens path, zfs_type_to_name(type)); 1747789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1748789Sahrens "use 'zpool create' to create a storage pool")); 1749789Sahrens return (-1); 1750789Sahrens } 1751789Sahrens 1752789Sahrens /* check to see if the pool exists */ 1753789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1754789Sahrens slash = parent + strlen(parent); 1755789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1756789Sahrens zc.zc_name[slash - parent] = '\0'; 17571544Seschrock if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1758789Sahrens errno == ENOENT) { 1759789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1760789Sahrens "cannot create '%s': no such pool '%s'"), path, zc.zc_name); 1761789Sahrens return (-1); 1762789Sahrens } 1763789Sahrens 1764789Sahrens /* check to see if the parent dataset exists */ 17651356Seschrock if ((zhp = make_dataset_handle(parent)) == NULL) { 1766789Sahrens switch (errno) { 1767789Sahrens case ENOENT: 1768789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1769789Sahrens "cannot create '%s': parent does not exist"), path); 1770789Sahrens return (-1); 1771789Sahrens 1772789Sahrens default: 1773789Sahrens zfs_baderror(errno); 1774789Sahrens } 1775789Sahrens } 1776789Sahrens 1777789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 17781356Seschrock if (getzoneid() != GLOBAL_ZONEID && 17791393Slling !zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1780789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1781789Sahrens "cannot create '%s': permission denied"), path); 17821356Seschrock zfs_close(zhp); 1783789Sahrens return (-1); 1784789Sahrens } 1785789Sahrens 1786789Sahrens /* make sure parent is a filesystem */ 17871356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1788789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1789789Sahrens "cannot create '%s': parent is not a filesystem"), 1790789Sahrens path); 17911356Seschrock zfs_close(zhp); 1792789Sahrens return (-1); 1793789Sahrens } 1794789Sahrens 17951356Seschrock zfs_close(zhp); 1796789Sahrens return (0); 1797789Sahrens } 1798789Sahrens 1799789Sahrens /* 1800789Sahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used 1801789Sahrens * only for volumes, and indicate the size and blocksize of the volume. 1802789Sahrens */ 1803789Sahrens int 1804789Sahrens zfs_create(const char *path, zfs_type_t type, 1805789Sahrens const char *sizestr, const char *blocksizestr) 1806789Sahrens { 1807789Sahrens char reason[64]; 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); 1812789Sahrens 1813789Sahrens /* convert sizestr into integer size */ 1814789Sahrens if (sizestr != NULL && nicestrtonum(sizestr, &size, 1815789Sahrens reason, sizeof (reason)) != 0) { 1816789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1817789Sahrens "bad volume size '%s': %s"), sizestr, reason); 1818789Sahrens return (-1); 1819789Sahrens } 1820789Sahrens 1821789Sahrens /* convert blocksizestr into integer blocksize */ 1822789Sahrens if (blocksizestr != NULL && nicestrtonum(blocksizestr, &blocksize, 1823789Sahrens reason, sizeof (reason)) != 0) { 1824789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1825789Sahrens "bad volume blocksize '%s': %s"), blocksizestr, reason); 1826789Sahrens return (-1); 1827789Sahrens } 1828789Sahrens 1829789Sahrens /* validate the path, taking care to note the extended error message */ 1830789Sahrens if (!zfs_validate_name(path, type, reason, sizeof (reason))) { 1831789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1832789Sahrens "cannot create '%s': %s in %s name"), path, reason, 1833789Sahrens zfs_type_to_name(type)); 1834789Sahrens if (strstr(reason, "snapshot") != NULL) 1835789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1836789Sahrens "use 'zfs snapshot' to create a snapshot")); 1837789Sahrens return (-1); 1838789Sahrens } 1839789Sahrens 1840789Sahrens /* validate parents exist */ 1841789Sahrens if (check_parents(path, type) != 0) 1842789Sahrens return (-1); 1843789Sahrens 1844789Sahrens /* 1845789Sahrens * The failure modes when creating a dataset of a different type over 1846789Sahrens * one that already exists is a little strange. In particular, if you 1847789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1848789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1849789Sahrens * first try to see if the dataset exists. 1850789Sahrens */ 1851789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 18521544Seschrock if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) == 0) { 1853789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1854789Sahrens "cannot create '%s': dataset exists"), path); 1855789Sahrens return (-1); 1856789Sahrens } 1857789Sahrens 1858789Sahrens if (type == ZFS_TYPE_VOLUME) 1859789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1860789Sahrens else 1861789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1862789Sahrens 1863789Sahrens if (type == ZFS_TYPE_VOLUME) { 18641133Seschrock /* 18651133Seschrock * If we are creating a volume, the size and block size must 18661133Seschrock * satisfy a few restraints. First, the blocksize must be a 18671133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 18681133Seschrock * volsize must be a multiple of the block size, and cannot be 18691133Seschrock * zero. 18701133Seschrock */ 1871789Sahrens if (size == 0) { 1872789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1873789Sahrens "bad volume size '%s': cannot be zero"), sizestr); 1874789Sahrens return (-1); 1875789Sahrens } 1876789Sahrens 18771133Seschrock if (blocksize < SPA_MINBLOCKSIZE || 18781133Seschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) { 18791133Seschrock zfs_error(dgettext(TEXT_DOMAIN, 18801133Seschrock "bad volume block size '%s': " 18811133Seschrock "must be power of 2 from %u to %uk"), 18821133Seschrock blocksizestr, 18831133Seschrock (uint_t)SPA_MINBLOCKSIZE, 18841133Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 18851133Seschrock return (-1); 18861133Seschrock } 18871133Seschrock 18881133Seschrock if (size % blocksize != 0) { 18891133Seschrock char buf[64]; 18901133Seschrock zfs_nicenum(blocksize, buf, sizeof (buf)); 18911133Seschrock zfs_error(dgettext(TEXT_DOMAIN, 18921133Seschrock "bad volume size '%s': " 18931133Seschrock "must be multiple of volume block size (%s)"), 18941133Seschrock sizestr, buf); 18951133Seschrock return (-1); 18961133Seschrock } 18971133Seschrock 1898789Sahrens zc.zc_volsize = size; 1899789Sahrens zc.zc_volblocksize = blocksize; 1900789Sahrens } 1901789Sahrens 1902789Sahrens /* create the dataset */ 19031544Seschrock ret = zfs_ioctl(ZFS_IOC_CREATE, &zc); 1904789Sahrens 1905789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 1906789Sahrens ret = zvol_create_link(path); 1907789Sahrens 1908789Sahrens /* check for failure */ 1909789Sahrens if (ret != 0) { 1910789Sahrens char parent[ZFS_MAXNAMELEN]; 1911789Sahrens (void) parent_name(path, parent, sizeof (parent)); 1912789Sahrens 1913789Sahrens switch (errno) { 1914789Sahrens case ENOENT: 1915789Sahrens /* 1916789Sahrens * The parent dataset has been deleted since our 1917789Sahrens * previous check. 1918789Sahrens */ 1919789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1920789Sahrens "cannot create '%s': no such parent '%s'"), 1921789Sahrens path, parent); 1922789Sahrens break; 1923789Sahrens 1924789Sahrens case EPERM: 1925789Sahrens /* 1926789Sahrens * The user doesn't have permission to create a new 1927789Sahrens * dataset here. 1928789Sahrens */ 1929789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1930789Sahrens "cannot create '%s': permission denied"), path); 1931789Sahrens break; 1932789Sahrens 1933789Sahrens case EDQUOT: 1934789Sahrens case ENOSPC: 1935789Sahrens /* 1936789Sahrens * The parent dataset does not have enough free space 1937789Sahrens * to create a new dataset. 1938789Sahrens */ 1939789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1940789Sahrens "cannot create '%s': not enough space in '%s'"), 1941789Sahrens path, parent); 1942789Sahrens break; 1943789Sahrens 1944789Sahrens case EEXIST: 1945789Sahrens /* 1946789Sahrens * The target dataset already exists. We should have 1947789Sahrens * caught this above, but there may be some unexplained 1948789Sahrens * race condition. 1949789Sahrens */ 1950789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1951789Sahrens "cannot create '%s': dataset exists"), path); 1952789Sahrens break; 1953789Sahrens 1954789Sahrens case EINVAL: 1955789Sahrens /* 1956789Sahrens * The target dataset does not support children. 1957789Sahrens */ 1958789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1959789Sahrens "cannot create '%s': children unsupported in '%s'"), 1960789Sahrens path, parent); 1961789Sahrens break; 1962789Sahrens 1963789Sahrens case EDOM: 1964789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "bad %s value '%s': " 1965789Sahrens "must be power of 2 from %u to %uk"), 1966789Sahrens zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1967789Sahrens blocksizestr ? blocksizestr : "<unknown>", 1968789Sahrens (uint_t)SPA_MINBLOCKSIZE, 1969789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 1970789Sahrens break; 1971789Sahrens #ifdef _ILP32 1972789Sahrens case EOVERFLOW: 1973789Sahrens /* 1974789Sahrens * This platform can't address a volume this big. 1975789Sahrens */ 1976789Sahrens if (type == ZFS_TYPE_VOLUME) { 1977789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1978789Sahrens "cannot create '%s': " 1979789Sahrens "max volume size is 1TB on 32-bit systems"), 1980789Sahrens path); 1981789Sahrens break; 1982789Sahrens } 1983789Sahrens #endif 1984789Sahrens 1985789Sahrens default: 1986789Sahrens zfs_baderror(errno); 1987789Sahrens } 1988789Sahrens 1989789Sahrens return (-1); 1990789Sahrens } 1991789Sahrens 1992789Sahrens return (0); 1993789Sahrens } 1994789Sahrens 1995789Sahrens /* 1996789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 1997789Sahrens * isn't mounted, and that there are no active dependents. 1998789Sahrens */ 1999789Sahrens int 2000789Sahrens zfs_destroy(zfs_handle_t *zhp) 2001789Sahrens { 2002789Sahrens zfs_cmd_t zc = { 0 }; 2003789Sahrens int ret; 2004789Sahrens 2005789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2006789Sahrens 2007789Sahrens /* 2008789Sahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME 2009789Sahrens * so that we do the right thing for snapshots of volumes. 2010789Sahrens */ 2011789Sahrens if (zhp->zfs_volblocksize != 0) { 2012789Sahrens if (zvol_remove_link(zhp->zfs_name) != 0) 2013789Sahrens return (-1); 2014789Sahrens 2015789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2016789Sahrens } else { 2017789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2018789Sahrens } 2019789Sahrens 20201544Seschrock ret = zfs_ioctl(ZFS_IOC_DESTROY, &zc); 2021789Sahrens 2022789Sahrens if (ret != 0) { 2023789Sahrens switch (errno) { 2024789Sahrens 2025789Sahrens case EPERM: 2026789Sahrens /* 2027789Sahrens * We don't have permission to destroy this dataset. 2028789Sahrens */ 2029789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2030789Sahrens "cannot destroy '%s': permission denied"), 2031789Sahrens zhp->zfs_name); 2032789Sahrens break; 2033789Sahrens 2034789Sahrens case ENOENT: 2035789Sahrens /* 2036789Sahrens * We've hit a race condition where the dataset has been 2037789Sahrens * destroyed since we opened it. 2038789Sahrens */ 2039789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2040789Sahrens "cannot destroy '%s': no such %s"), 2041789Sahrens zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 2042789Sahrens break; 2043789Sahrens 2044789Sahrens case EBUSY: 2045789Sahrens /* 2046789Sahrens * Even if we destroy all children, there is a chance we 2047789Sahrens * can hit this case if: 2048789Sahrens * 2049789Sahrens * - A child dataset has since been created 2050789Sahrens * - A filesystem is mounted 2051789Sahrens * 2052789Sahrens * This error message is awful, but hopefully we've 2053789Sahrens * already caught the common cases (and aborted more 2054789Sahrens * appropriately) before calling this function. There's 2055789Sahrens * nothing else we can do at this point. 2056789Sahrens */ 2057789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2058789Sahrens "cannot destroy '%s': %s is busy"), 2059789Sahrens zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 2060789Sahrens break; 2061789Sahrens 2062789Sahrens default: 2063789Sahrens zfs_baderror(errno); 2064789Sahrens } 2065789Sahrens 2066789Sahrens return (-1); 2067789Sahrens } 2068789Sahrens 2069789Sahrens remove_mountpoint(zhp); 2070789Sahrens 2071789Sahrens return (0); 2072789Sahrens } 2073789Sahrens 2074789Sahrens /* 2075789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2076789Sahrens */ 2077789Sahrens int 2078789Sahrens zfs_clone(zfs_handle_t *zhp, const char *target) 2079789Sahrens { 2080789Sahrens char reason[64]; 2081789Sahrens zfs_cmd_t zc = { 0 }; 2082789Sahrens char parent[ZFS_MAXNAMELEN]; 2083789Sahrens int ret; 2084789Sahrens 2085789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2086789Sahrens 2087789Sahrens /* validate the target name */ 2088789Sahrens if (!zfs_validate_name(target, ZFS_TYPE_FILESYSTEM, reason, 2089789Sahrens sizeof (reason))) { 2090789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2091789Sahrens "cannot create '%s': %s in filesystem name"), target, 2092789Sahrens reason, zfs_type_to_name(ZFS_TYPE_FILESYSTEM)); 2093789Sahrens return (-1); 2094789Sahrens } 2095789Sahrens 2096789Sahrens /* validate parents exist */ 2097789Sahrens if (check_parents(target, zhp->zfs_type) != 0) 2098789Sahrens return (-1); 2099789Sahrens 2100789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2101789Sahrens 2102789Sahrens /* do the clone */ 2103789Sahrens if (zhp->zfs_volblocksize != 0) 2104789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2105789Sahrens else 2106789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2107789Sahrens 2108789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2109789Sahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename)); 21101544Seschrock ret = zfs_ioctl(ZFS_IOC_CREATE, &zc); 2111789Sahrens 2112789Sahrens if (ret != 0) { 2113789Sahrens switch (errno) { 2114789Sahrens case EPERM: 2115789Sahrens /* 2116789Sahrens * The user doesn't have permission to create the clone. 2117789Sahrens */ 2118789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2119789Sahrens "cannot create '%s': permission denied"), 2120789Sahrens target); 2121789Sahrens break; 2122789Sahrens 2123789Sahrens case ENOENT: 2124789Sahrens /* 2125789Sahrens * The parent doesn't exist. We should have caught this 2126789Sahrens * above, but there may a race condition that has since 2127789Sahrens * destroyed the parent. 2128789Sahrens * 2129789Sahrens * At this point, we don't know whether it's the source 2130789Sahrens * that doesn't exist anymore, or whether the target 2131789Sahrens * dataset doesn't exist. 2132789Sahrens */ 2133789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2134789Sahrens "cannot create '%s': no such parent '%s'"), 2135789Sahrens target, parent); 2136789Sahrens break; 2137789Sahrens 2138789Sahrens case EDQUOT: 2139789Sahrens case ENOSPC: 2140789Sahrens /* 2141789Sahrens * There is not enough space in the target dataset 2142789Sahrens */ 2143789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2144789Sahrens "cannot create '%s': not enough space in '%s'"), 2145789Sahrens target, parent); 2146789Sahrens break; 2147789Sahrens 2148789Sahrens case EEXIST: 2149789Sahrens /* 2150789Sahrens * The target already exists. 2151789Sahrens */ 2152789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2153789Sahrens "cannot create '%s': dataset exists"), target); 2154789Sahrens break; 2155789Sahrens 2156789Sahrens case EXDEV: 2157789Sahrens /* 2158789Sahrens * The source and target pools differ. 2159789Sahrens */ 2160789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2161789Sahrens "source and target pools differ"), target); 2162789Sahrens break; 2163789Sahrens 2164789Sahrens default: 2165789Sahrens zfs_baderror(errno); 2166789Sahrens } 2167789Sahrens } else if (zhp->zfs_volblocksize != 0) { 2168789Sahrens ret = zvol_create_link(target); 2169789Sahrens } 2170789Sahrens 2171789Sahrens return (ret); 2172789Sahrens } 2173789Sahrens 2174789Sahrens /* 2175789Sahrens * Takes a snapshot of the given dataset 2176789Sahrens */ 2177789Sahrens int 2178789Sahrens zfs_snapshot(const char *path) 2179789Sahrens { 2180789Sahrens char reason[64]; 2181789Sahrens const char *delim; 2182789Sahrens char *parent; 2183789Sahrens zfs_handle_t *zhp; 2184789Sahrens zfs_cmd_t zc = { 0 }; 2185789Sahrens int ret; 2186789Sahrens 2187789Sahrens /* validate the snapshot name */ 2188789Sahrens if (!zfs_validate_name(path, ZFS_TYPE_SNAPSHOT, reason, 2189789Sahrens sizeof (reason))) { 2190789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2191789Sahrens "cannot snapshot '%s': %s in snapshot name"), path, 2192789Sahrens reason); 2193789Sahrens return (-1); 2194789Sahrens } 2195789Sahrens 2196789Sahrens /* make sure we have a snapshot */ 2197789Sahrens if ((delim = strchr(path, '@')) == NULL) { 2198789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2199789Sahrens "cannot snapshot '%s': missing '@' delim in snapshot " 2200789Sahrens "name"), path); 2201789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2202789Sahrens "use 'zfs create' to create a filesystem")); 2203789Sahrens return (-1); 2204789Sahrens } 2205789Sahrens 2206789Sahrens /* make sure the parent exists and is of the appropriate type */ 2207789Sahrens parent = zfs_malloc(delim - path + 1); 2208789Sahrens (void) strncpy(parent, path, delim - path); 2209789Sahrens parent[delim - path] = '\0'; 2210789Sahrens 2211789Sahrens if ((zhp = zfs_open(parent, ZFS_TYPE_FILESYSTEM | 2212789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2213789Sahrens free(parent); 2214789Sahrens return (-1); 2215789Sahrens } 2216789Sahrens 2217789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2218789Sahrens 2219789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) 2220789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2221789Sahrens else 2222789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2223789Sahrens 22241544Seschrock ret = zfs_ioctl(ZFS_IOC_CREATE, &zc); 2225789Sahrens 2226789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 2227789Sahrens ret = zvol_create_link(path); 2228789Sahrens if (ret != 0) 22291544Seschrock (void) zfs_ioctl(ZFS_IOC_DESTROY, &zc); 2230789Sahrens } 2231789Sahrens 2232789Sahrens if (ret != 0) { 2233789Sahrens switch (errno) { 2234789Sahrens case EPERM: 2235789Sahrens /* 2236789Sahrens * User doesn't have permission to create a snapshot 2237789Sahrens */ 2238789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2239789Sahrens "permission denied"), path); 2240789Sahrens break; 2241789Sahrens 2242789Sahrens case EDQUOT: 2243789Sahrens case ENOSPC: 2244789Sahrens /* 2245789Sahrens * Out of space in parent. 2246789Sahrens */ 2247789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2248789Sahrens "not enough space in '%s'"), path, parent); 2249789Sahrens break; 2250789Sahrens 2251789Sahrens case EEXIST: 2252789Sahrens /* 2253789Sahrens * Snapshot already exists. 2254789Sahrens */ 2255789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2256789Sahrens "snapshot exists"), path); 2257789Sahrens break; 2258789Sahrens 2259789Sahrens case ENOENT: 2260789Sahrens /* 2261789Sahrens * Shouldn't happen because we verified the parent 2262789Sahrens * above. But there may be a race condition where it 2263789Sahrens * has since been removed. 2264789Sahrens */ 2265789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': " 2266789Sahrens "no such %s"), parent, 2267789Sahrens zfs_type_to_name(zhp->zfs_type)); 2268789Sahrens break; 2269789Sahrens 2270789Sahrens default: 2271789Sahrens zfs_baderror(errno); 2272789Sahrens } 2273789Sahrens } 2274789Sahrens 2275789Sahrens free(parent); 2276789Sahrens zfs_close(zhp); 2277789Sahrens 2278789Sahrens return (ret); 2279789Sahrens } 2280789Sahrens 2281789Sahrens /* 2282789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2283789Sahrens */ 2284789Sahrens int 2285789Sahrens zfs_backup(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2286789Sahrens { 2287789Sahrens zfs_cmd_t zc = { 0 }; 2288789Sahrens int ret; 2289789Sahrens 2290789Sahrens /* do the ioctl() */ 2291789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2292789Sahrens if (zhp_from) { 2293789Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2294789Sahrens sizeof (zc.zc_name)); 2295789Sahrens } else { 2296789Sahrens zc.zc_prop_value[0] = '\0'; 2297789Sahrens } 2298789Sahrens zc.zc_cookie = STDOUT_FILENO; 2299789Sahrens 23001544Seschrock ret = zfs_ioctl(ZFS_IOC_SENDBACKUP, &zc); 2301789Sahrens if (ret != 0) { 2302789Sahrens switch (errno) { 2303789Sahrens case EPERM: 2304789Sahrens /* 2305789Sahrens * User doesn't have permission to do a backup 2306789Sahrens */ 2307789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot backup '%s': " 2308789Sahrens "permission denied"), zhp_to->zfs_name); 2309789Sahrens break; 2310789Sahrens 2311789Sahrens case EXDEV: 2312789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2313789Sahrens "cannot do incremental backup from %s:\n" 2314789Sahrens "it is not an earlier snapshot from the " 2315789Sahrens "same fs as %s"), 2316789Sahrens zhp_from->zfs_name, zhp_to->zfs_name); 2317789Sahrens break; 2318789Sahrens 2319789Sahrens case ENOENT: 2320789Sahrens /* 2321789Sahrens * Shouldn't happen because we verified the parent 2322789Sahrens * above. But there may be a race condition where it 2323789Sahrens * has since been removed. 2324789Sahrens */ 2325789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open: " 2326789Sahrens "no such snapshot")); 2327789Sahrens break; 2328789Sahrens 2329789Sahrens case EDQUOT: 2330789Sahrens case EFBIG: 2331789Sahrens case EIO: 2332789Sahrens case ENOLINK: 2333789Sahrens case ENOSPC: 2334789Sahrens case ENOSTR: 2335789Sahrens case ENXIO: 2336789Sahrens case EPIPE: 2337789Sahrens case ERANGE: 2338789Sahrens case EFAULT: 2339789Sahrens case EROFS: 2340789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2341789Sahrens "cannot write backup stream: %s"), 2342789Sahrens strerror(errno)); 2343789Sahrens break; 2344789Sahrens 2345789Sahrens case EINTR: 2346789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2347789Sahrens "backup failed: signal recieved")); 2348789Sahrens break; 2349789Sahrens 2350789Sahrens default: 2351789Sahrens zfs_baderror(errno); 2352789Sahrens } 2353789Sahrens } 2354789Sahrens 2355789Sahrens return (ret); 2356789Sahrens } 2357789Sahrens 2358789Sahrens /* 2359789Sahrens * Restores a backup of tosnap from stdin. 2360789Sahrens */ 2361789Sahrens int 2362789Sahrens zfs_restore(const char *tosnap, int isprefix, int verbose, int dryrun) 2363789Sahrens { 2364789Sahrens zfs_cmd_t zc = { 0 }; 2365789Sahrens time_t begin_time; 2366868Sahrens int ioctl_err, err, bytes, size; 2367789Sahrens char *cp; 2368789Sahrens dmu_replay_record_t drr; 2369789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 2370789Sahrens 2371789Sahrens begin_time = time(NULL); 2372789Sahrens 2373789Sahrens /* trim off snapname, if any */ 2374789Sahrens (void) strcpy(zc.zc_name, tosnap); 2375789Sahrens cp = strchr(zc.zc_name, '@'); 2376789Sahrens if (cp) 2377789Sahrens *cp = '\0'; 2378789Sahrens 2379789Sahrens /* read in the BEGIN record */ 2380789Sahrens cp = (char *)&drr; 2381789Sahrens bytes = 0; 2382789Sahrens do { 2383868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2384868Sahrens cp += size; 2385868Sahrens bytes += size; 2386868Sahrens } while (size > 0); 2387868Sahrens 2388868Sahrens if (size < 0 || bytes != sizeof (drr)) { 2389789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2390868Sahrens "cannot restore: invalid backup stream " 2391789Sahrens "(couldn't read first record)")); 2392789Sahrens return (-1); 2393789Sahrens } 2394789Sahrens 2395789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2396789Sahrens 2397789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2398789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 2399789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2400868Sahrens "cannot restore: invalid backup stream " 2401789Sahrens "(invalid magic number)")); 2402789Sahrens return (-1); 2403789Sahrens } 2404789Sahrens 2405789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2406789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 2407789Sahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 2408789Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 2409789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2410868Sahrens "cannot restore: only backup version 0x%llx is supported, " 2411789Sahrens "stream is version %llx."), 2412789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 2413789Sahrens return (-1); 2414789Sahrens } 2415789Sahrens 2416789Sahrens /* 2417789Sahrens * Determine name of destination snapshot. 2418789Sahrens */ 24191544Seschrock (void) strcpy(zc.zc_filename, tosnap); 2420789Sahrens if (isprefix) { 2421789Sahrens if (strchr(tosnap, '@') != NULL) { 2422789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2423868Sahrens "cannot restore: " 2424789Sahrens "argument to -d must be a filesystem")); 2425789Sahrens return (-1); 2426789Sahrens } 2427789Sahrens 2428789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2429789Sahrens if (cp == NULL) 2430789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2431789Sahrens else 2432789Sahrens cp++; 2433789Sahrens 24341544Seschrock (void) strcat(zc.zc_filename, "/"); 24351544Seschrock (void) strcat(zc.zc_filename, cp); 2436789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2437789Sahrens /* 2438789Sahrens * they specified just a filesystem; tack on the 2439789Sahrens * snapname from the backup. 2440789Sahrens */ 2441789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 2442789Sahrens if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) { 2443789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 24441544Seschrock "cannot restore: invalid snapshot name")); 2445789Sahrens return (-1); 2446789Sahrens } 24471544Seschrock (void) strcat(zc.zc_filename, cp); 2448789Sahrens } 2449789Sahrens 2450789Sahrens if (drrb->drr_fromguid) { 2451789Sahrens zfs_handle_t *h; 2452789Sahrens /* incremental backup stream */ 2453789Sahrens 2454789Sahrens /* do the ioctl to the containing fs */ 24551544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2456789Sahrens cp = strchr(zc.zc_name, '@'); 2457789Sahrens *cp = '\0'; 2458789Sahrens 2459789Sahrens /* make sure destination fs exists */ 2460789Sahrens h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2461789Sahrens if (h == NULL) { 2462789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2463868Sahrens "cannot restore incrememtal backup: destination\n" 2464789Sahrens "filesystem %s does not exist"), 2465789Sahrens zc.zc_name); 2466789Sahrens return (-1); 2467789Sahrens } 2468868Sahrens if (!dryrun) { 2469868Sahrens /* unmount destination fs or remove device link. */ 2470868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2471868Sahrens (void) zfs_unmount(h, NULL, 0); 2472868Sahrens } else { 2473868Sahrens (void) zvol_remove_link(h->zfs_name); 2474868Sahrens } 2475868Sahrens } 2476789Sahrens zfs_close(h); 2477789Sahrens } else { 2478789Sahrens /* full backup stream */ 2479789Sahrens 24801544Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2481868Sahrens 2482868Sahrens /* make sure they aren't trying to restore into the root */ 2483868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2484789Sahrens cp = strchr(zc.zc_name, '@'); 2485789Sahrens if (cp) 2486789Sahrens *cp = '\0'; 2487789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2488868Sahrens "cannot restore: destination fs %s already exists"), 2489789Sahrens zc.zc_name); 2490789Sahrens return (-1); 2491789Sahrens } 2492789Sahrens 2493789Sahrens if (isprefix) { 2494868Sahrens zfs_handle_t *h; 2495868Sahrens 2496789Sahrens /* make sure prefix exists */ 2497*1566Smaybee h = zfs_open(tosnap, ZFS_TYPE_FILESYSTEM); 2498789Sahrens if (h == NULL) { 2499789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2500868Sahrens "cannot restore: " 2501*1566Smaybee "%s is an invalid destination"), 2502789Sahrens tosnap); 2503789Sahrens return (-1); 2504789Sahrens } 25051544Seschrock zfs_close(h); 2506789Sahrens 2507789Sahrens /* create any necessary ancestors up to prefix */ 2508868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 25091544Seschrock 2510868Sahrens /* 2511868Sahrens * zc.zc_name is now the full name of the snap 25121544Seschrock * we're restoring into. Attempt to create, 25131544Seschrock * mount, and share any ancestor filesystems, up 25141544Seschrock * to the one that was named. 2515868Sahrens */ 25161544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 25171544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 25181544Seschrock const char *opname; 2519789Sahrens *cp = '\0'; 25201544Seschrock 25211544Seschrock opname = "create"; 25221544Seschrock if (zfs_create(zc.zc_name, ZFS_TYPE_FILESYSTEM, 25231544Seschrock NULL, NULL) != 0) { 25241544Seschrock if (errno == EEXIST) 25251544Seschrock continue; 25261544Seschrock goto ancestorerr; 2527789Sahrens } 25281544Seschrock 25291544Seschrock opname = "open"; 25301544Seschrock h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM); 25311544Seschrock if (h == NULL) 25321544Seschrock goto ancestorerr; 25331544Seschrock 25341544Seschrock opname = "mount"; 25351544Seschrock if (zfs_mount(h, NULL, 0) != 0) 25361544Seschrock goto ancestorerr; 25371544Seschrock 25381544Seschrock opname = "share"; 25391544Seschrock if (zfs_share(h) != 0) 25401544Seschrock goto ancestorerr; 25411544Seschrock 25421544Seschrock zfs_close(h); 25431544Seschrock 25441544Seschrock continue; 25451544Seschrock ancestorerr: 25461544Seschrock zfs_error(dgettext(TEXT_DOMAIN, 25471544Seschrock "cannot restore: couldn't %s ancestor %s"), 25481544Seschrock opname, zc.zc_name); 25491544Seschrock return (-1); 2550789Sahrens } 2551789Sahrens } 2552868Sahrens 2553868Sahrens /* Make sure destination fs does not exist */ 2554868Sahrens cp = strchr(zc.zc_name, '@'); 2555868Sahrens *cp = '\0'; 25561544Seschrock if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2557868Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2558868Sahrens "cannot restore full backup: " 2559868Sahrens "destination filesystem %s already exists"), 2560868Sahrens zc.zc_name); 2561868Sahrens return (-1); 2562868Sahrens } 2563868Sahrens 2564868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2565868Sahrens cp = strrchr(zc.zc_name, '/'); 2566868Sahrens *cp = '\0'; 2567789Sahrens } 2568789Sahrens 2569789Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2570789Sahrens zc.zc_cookie = STDIN_FILENO; 2571789Sahrens zc.zc_intsz = isprefix; 2572789Sahrens if (verbose) { 2573789Sahrens (void) printf("%s %s backup of %s into %s\n", 2574789Sahrens dryrun ? "would restore" : "restoring", 2575789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2576789Sahrens drr.drr_u.drr_begin.drr_toname, 25771544Seschrock zc.zc_filename); 2578789Sahrens (void) fflush(stdout); 2579789Sahrens } 2580789Sahrens if (dryrun) 2581789Sahrens return (0); 25821544Seschrock err = ioctl_err = zfs_ioctl(ZFS_IOC_RECVBACKUP, &zc); 2583868Sahrens if (ioctl_err != 0) { 2584789Sahrens switch (errno) { 2585789Sahrens case ENODEV: 2586789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2587868Sahrens "cannot restore: " 2588868Sahrens "most recent snapshot does not " 2589789Sahrens "match incremental backup source")); 2590789Sahrens break; 2591789Sahrens case ETXTBSY: 2592789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2593868Sahrens "cannot restore: " 2594868Sahrens "destination has been modified since " 2595868Sahrens "most recent snapshot --\n" 2596868Sahrens "use 'zfs rollback' to discard changes")); 2597789Sahrens break; 2598789Sahrens case EEXIST: 2599789Sahrens if (drrb->drr_fromguid == 0) { 2600789Sahrens /* it's the containing fs that exists */ 26011544Seschrock cp = strchr(zc.zc_filename, '@'); 2602789Sahrens *cp = '\0'; 2603789Sahrens } 2604789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2605868Sahrens "cannot restore to %s: destination already exists"), 26061544Seschrock zc.zc_filename); 2607789Sahrens break; 2608789Sahrens case ENOENT: 2609789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2610868Sahrens "cannot restore: destination does not exist")); 2611789Sahrens break; 2612789Sahrens case EBUSY: 2613789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2614868Sahrens "cannot restore: destination is in use")); 2615789Sahrens break; 2616789Sahrens case ENOSPC: 2617789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2618868Sahrens "cannot restore: out of space")); 2619789Sahrens break; 2620789Sahrens case EDQUOT: 2621789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2622868Sahrens "cannot restore: quota exceeded")); 2623789Sahrens break; 2624789Sahrens case EINTR: 2625789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2626868Sahrens "restore failed: signal recieved")); 2627789Sahrens break; 2628789Sahrens case EINVAL: 2629789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2630868Sahrens "cannot restore: invalid backup stream")); 2631868Sahrens break; 26321544Seschrock case ECKSUM: 26331544Seschrock zfs_error(dgettext(TEXT_DOMAIN, 26341544Seschrock "cannot restore: invalid backup stream " 26351544Seschrock "(checksum mismatch)")); 26361544Seschrock break; 2637868Sahrens case EPERM: 2638868Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2639868Sahrens "cannot restore: permission denied")); 2640789Sahrens break; 2641789Sahrens default: 2642789Sahrens zfs_baderror(errno); 2643789Sahrens } 2644789Sahrens } 2645789Sahrens 2646789Sahrens /* 2647868Sahrens * Mount or recreate the /dev links for the target filesystem 2648868Sahrens * (if created, or if we tore them down to do an incremental 2649868Sahrens * restore), and the /dev links for the new snapshot (if 2650868Sahrens * created). 2651789Sahrens */ 26521544Seschrock cp = strchr(zc.zc_filename, '@'); 2653868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2654789Sahrens zfs_handle_t *h; 2655789Sahrens 2656789Sahrens *cp = '\0'; 26571544Seschrock h = zfs_open(zc.zc_filename, 2658789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2659868Sahrens *cp = '@'; 2660789Sahrens if (h) { 2661868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2662789Sahrens err = zfs_mount(h, NULL, 0); 2663868Sahrens } else { 2664789Sahrens err = zvol_create_link(h->zfs_name); 26651544Seschrock if (err == 0 && ioctl_err == 0) 26661544Seschrock err = zvol_create_link(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 2685789Sahrens (void) printf("restored %sb backup 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; 27021294Slling int 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 27161294Slling cbp->cb_dependent = TRUE; 27171294Slling (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 27181294Slling cbp->cb_dependent = 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 && 2749789Sahrens zvol_remove_link(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 */ 27661544Seschrock if ((ret = zfs_ioctl(ZFS_IOC_ROLLBACK, &zc)) != 0) { 2767789Sahrens switch (errno) { 2768789Sahrens case EPERM: 2769789Sahrens /* 2770789Sahrens * The user doesn't have permission to rollback the 2771789Sahrens * given dataset. 2772789Sahrens */ 2773789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2774789Sahrens "permission denied"), zhp->zfs_name); 2775789Sahrens break; 2776789Sahrens 2777789Sahrens case EDQUOT: 2778789Sahrens case ENOSPC: 2779789Sahrens /* 2780789Sahrens * The parent dataset doesn't have enough space to 2781789Sahrens * rollback to the last snapshot. 2782789Sahrens */ 2783789Sahrens { 2784789Sahrens char parent[ZFS_MAXNAMELEN]; 2785789Sahrens (void) parent_name(zhp->zfs_name, parent, 2786789Sahrens sizeof (parent)); 2787789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 2788789Sahrens "rollback '%s': out of space"), parent); 2789789Sahrens } 2790789Sahrens break; 2791789Sahrens 2792789Sahrens case ENOENT: 2793789Sahrens /* 2794789Sahrens * The dataset doesn't exist. This shouldn't happen 2795789Sahrens * except in race conditions. 2796789Sahrens */ 2797789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2798789Sahrens "no such %s"), zhp->zfs_name, 2799789Sahrens zfs_type_to_name(zhp->zfs_type)); 2800789Sahrens break; 2801789Sahrens 2802789Sahrens case EBUSY: 2803789Sahrens /* 2804789Sahrens * The filesystem is busy. This should have been caught 2805789Sahrens * by the caller before getting here, but there may be 2806789Sahrens * an unexpected problem. 2807789Sahrens */ 2808789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2809789Sahrens "%s is busy"), zhp->zfs_name, 2810789Sahrens zfs_type_to_name(zhp->zfs_type)); 2811789Sahrens break; 2812789Sahrens 2813789Sahrens default: 2814789Sahrens zfs_baderror(errno); 2815789Sahrens } 2816789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2817789Sahrens ret = zvol_create_link(zhp->zfs_name); 2818789Sahrens } 2819789Sahrens 2820789Sahrens return (ret); 2821789Sahrens } 2822789Sahrens 2823789Sahrens /* 28241294Slling * Given a dataset, rollback to a specific snapshot, discarding any 28251294Slling * data changes since then and making it the active dataset. 28261294Slling * 28271294Slling * Any snapshots more recent than the target are destroyed, along with 28281294Slling * their dependents. 28291294Slling */ 28301294Slling int 28311294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 28321294Slling { 28331294Slling int ret; 28341294Slling rollback_data_t cb = { 0 }; 28351294Slling prop_changelist_t *clp; 28361294Slling 28371294Slling /* 28381294Slling * Unmount all dependendents of the dataset and the dataset itself. 28391294Slling * The list we need to gather is the same as for doing rename 28401294Slling */ 28411294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 28421294Slling if (clp == NULL) 28431294Slling return (-1); 28441294Slling 28451294Slling if ((ret = changelist_prefix(clp)) != 0) 28461294Slling goto out; 28471294Slling 28481294Slling /* 28491294Slling * Destroy all recent snapshots and its dependends. 28501294Slling */ 28511294Slling cb.cb_target = snap->zfs_name; 28521294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 28531294Slling cb.cb_clp = clp; 28541294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 28551294Slling 28561294Slling if ((ret = cb.cb_error) != 0) { 28571294Slling (void) changelist_postfix(clp); 28581294Slling goto out; 28591294Slling } 28601294Slling 28611294Slling /* 28621294Slling * Now that we have verified that the snapshot is the latest, 28631294Slling * rollback to the given snapshot. 28641294Slling */ 28651294Slling ret = do_rollback(zhp); 28661294Slling 28671294Slling if (ret != 0) { 28681294Slling (void) changelist_postfix(clp); 28691294Slling goto out; 28701294Slling } 28711294Slling 28721294Slling /* 28731294Slling * We only want to re-mount the filesystem if it was mounted in the 28741294Slling * first place. 28751294Slling */ 28761294Slling ret = changelist_postfix(clp); 28771294Slling 28781294Slling out: 28791294Slling changelist_free(clp); 28801294Slling return (ret); 28811294Slling } 28821294Slling 28831294Slling /* 2884789Sahrens * Iterate over all dependents for a given dataset. This includes both 2885789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2886789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2887789Sahrens * libzfs_graph.c. 2888789Sahrens */ 2889789Sahrens int 2890789Sahrens zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2891789Sahrens { 2892789Sahrens char **dependents; 2893789Sahrens size_t count; 2894789Sahrens int i; 2895789Sahrens zfs_handle_t *child; 2896789Sahrens int ret = 0; 2897789Sahrens 2898789Sahrens dependents = get_dependents(zhp->zfs_name, &count); 2899789Sahrens for (i = 0; i < count; i++) { 2900789Sahrens if ((child = make_dataset_handle(dependents[i])) == NULL) 2901789Sahrens continue; 2902789Sahrens 2903789Sahrens if ((ret = func(child, data)) != 0) 2904789Sahrens break; 2905789Sahrens } 2906789Sahrens 2907789Sahrens for (i = 0; i < count; i++) 2908789Sahrens free(dependents[i]); 2909789Sahrens free(dependents); 2910789Sahrens 2911789Sahrens return (ret); 2912789Sahrens } 2913789Sahrens 2914789Sahrens /* 2915789Sahrens * Renames the given dataset. 2916789Sahrens */ 2917789Sahrens int 2918789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2919789Sahrens { 2920789Sahrens int ret; 2921789Sahrens zfs_cmd_t zc = { 0 }; 2922789Sahrens char reason[64]; 2923789Sahrens char *delim; 2924789Sahrens prop_changelist_t *cl; 2925789Sahrens char parent[ZFS_MAXNAMELEN]; 2926789Sahrens 2927789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2928789Sahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 2929789Sahrens 2930789Sahrens /* if we have the same exact name, just return success */ 2931789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2932789Sahrens return (0); 2933789Sahrens 2934789Sahrens /* 2935789Sahrens * Make sure the target name is valid 2936789Sahrens */ 2937789Sahrens if (!zfs_validate_name(target, zhp->zfs_type, reason, 2938789Sahrens sizeof (reason))) { 2939789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2940789Sahrens "cannot create '%s': %s in %s name"), target, reason, 2941789Sahrens zfs_type_to_name(zhp->zfs_type)); 2942789Sahrens return (-1); 2943789Sahrens } 2944789Sahrens 2945789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2946789Sahrens if ((delim = strchr(target, '@')) == NULL) { 2947789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2948789Sahrens "cannot rename to '%s': not a snapshot"), target); 2949789Sahrens return (-1); 2950789Sahrens } 2951789Sahrens 2952789Sahrens /* 2953789Sahrens * Make sure we're renaming within the same dataset. 2954789Sahrens */ 2955789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2956789Sahrens zhp->zfs_name[delim - target] != '@') { 2957789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2958789Sahrens "cannot rename to '%s': snapshots must be part " 2959789Sahrens "of same dataset"), target); 2960789Sahrens return (-1); 2961789Sahrens } 2962789Sahrens 2963789Sahrens (void) strncpy(parent, target, delim - target); 2964789Sahrens parent[delim - target] = '\0'; 2965789Sahrens } else { 2966789Sahrens /* validate parents */ 2967789Sahrens if (check_parents(target, zhp->zfs_type) != 0) 2968789Sahrens return (-1); 2969789Sahrens 2970789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2971789Sahrens 2972789Sahrens /* make sure we're in the same pool */ 2973789Sahrens verify((delim = strchr(target, '/')) != NULL); 2974789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2975789Sahrens zhp->zfs_name[delim - target] != '/') { 2976789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2977789Sahrens "cannot rename to '%s': " 2978789Sahrens "datasets must be within same pool"), target); 2979789Sahrens return (-1); 2980789Sahrens } 2981789Sahrens } 2982789Sahrens 2983789Sahrens if (getzoneid() == GLOBAL_ZONEID && 2984789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 2985789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename %s, " 2986789Sahrens "dataset is used in a non-global zone"), zhp->zfs_name); 2987789Sahrens return (-1); 2988789Sahrens } 2989789Sahrens 2990789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 2991789Sahrens return (1); 2992789Sahrens 2993789Sahrens if (changelist_haszonedchild(cl)) { 2994789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2995789Sahrens "cannot rename '%s': child dataset with inherited " 2996789Sahrens "mountpoint is used in a non-global zone"), zhp->zfs_name); 2997789Sahrens ret = -1; 2998789Sahrens goto error; 2999789Sahrens } 3000789Sahrens 3001789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3002789Sahrens goto error; 3003789Sahrens 3004789Sahrens if (zhp->zfs_volblocksize != 0) 3005789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3006789Sahrens else 3007789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3008789Sahrens 30091544Seschrock if ((ret = zfs_ioctl(ZFS_IOC_RENAME, &zc)) != 0) { 3010789Sahrens switch (errno) { 3011789Sahrens case EPERM: 3012789Sahrens /* 3013789Sahrens * The user doesn't have permission to rename the 3014789Sahrens * given dataset. 3015789Sahrens */ 3016789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': " 3017789Sahrens "permission denied"), zhp->zfs_name); 3018789Sahrens break; 3019789Sahrens 3020789Sahrens case EDQUOT: 3021789Sahrens case ENOSPC: 3022789Sahrens /* 3023789Sahrens * Not enough space in the parent dataset. 3024789Sahrens */ 3025789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 3026789Sahrens "rename '%s': not enough space in '%s'"), 3027789Sahrens zhp->zfs_name, parent); 3028789Sahrens break; 3029789Sahrens 3030789Sahrens case ENOENT: 3031789Sahrens /* 3032789Sahrens * The destination doesn't exist. 3033789Sahrens */ 3034789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' " 3035789Sahrens "to '%s': destination doesn't exist"), 3036789Sahrens zhp->zfs_name, target); 3037789Sahrens break; 3038789Sahrens 3039789Sahrens case EEXIST: 3040789Sahrens /* 3041789Sahrens * The destination already exists. 3042789Sahrens */ 3043789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' " 3044789Sahrens "to '%s': destination already exists"), 3045789Sahrens zhp->zfs_name, target); 3046789Sahrens break; 3047789Sahrens 3048789Sahrens case EBUSY: 3049789Sahrens /* 3050789Sahrens * The filesystem is busy. This should have been caught 3051789Sahrens * by the caller before getting here, but there may be 3052789Sahrens * an unexpected problem. 3053789Sahrens */ 3054789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': " 3055789Sahrens "%s is busy"), zhp->zfs_name, 3056789Sahrens zfs_type_to_name(zhp->zfs_type)); 3057789Sahrens break; 3058789Sahrens 3059789Sahrens default: 3060789Sahrens zfs_baderror(errno); 3061789Sahrens } 3062789Sahrens 3063789Sahrens /* 3064789Sahrens * On failure, we still want to remount any filesystems that 3065789Sahrens * were previously mounted, so we don't alter the system state. 3066789Sahrens */ 3067789Sahrens (void) changelist_postfix(cl); 3068789Sahrens } else { 3069789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3070789Sahrens 3071789Sahrens ret = changelist_postfix(cl); 3072789Sahrens } 3073789Sahrens 3074789Sahrens error: 3075789Sahrens changelist_free(cl); 3076789Sahrens return (ret); 3077789Sahrens } 3078789Sahrens 3079789Sahrens /* 3080789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3081789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3082789Sahrens */ 3083789Sahrens int 3084789Sahrens zvol_create_link(const char *dataset) 3085789Sahrens { 3086789Sahrens zfs_cmd_t zc = { 0 }; 3087789Sahrens di_devlink_handle_t hdl; 3088789Sahrens 3089789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3090789Sahrens 3091789Sahrens /* 3092789Sahrens * Issue the appropriate ioctl. 3093789Sahrens */ 30941544Seschrock if (zfs_ioctl(ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3095789Sahrens switch (errno) { 3096789Sahrens case EPERM: 3097789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create " 3098789Sahrens "device links for '%s': permission denied"), 3099789Sahrens dataset); 3100789Sahrens break; 3101789Sahrens 3102789Sahrens case EEXIST: 3103789Sahrens /* 3104789Sahrens * Silently ignore the case where the link already 3105789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3106789Sahrens * times without errors. 3107789Sahrens */ 3108789Sahrens return (0); 3109789Sahrens 3110789Sahrens default: 3111789Sahrens zfs_baderror(errno); 3112789Sahrens } 3113789Sahrens 3114789Sahrens return (-1); 3115789Sahrens } 3116789Sahrens 3117789Sahrens /* 3118789Sahrens * Call devfsadm and wait for the links to magically appear. 3119789Sahrens */ 3120789Sahrens if ((hdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 3121789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 3122789Sahrens "cannot create device links for '%s'"), dataset); 31231544Seschrock (void) zfs_ioctl(ZFS_IOC_REMOVE_MINOR, &zc); 3124789Sahrens return (-1); 3125789Sahrens } else { 3126789Sahrens (void) di_devlink_fini(&hdl); 3127789Sahrens } 3128789Sahrens 3129789Sahrens return (0); 3130789Sahrens } 3131789Sahrens 3132789Sahrens /* 3133789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3134789Sahrens */ 3135789Sahrens int 3136789Sahrens zvol_remove_link(const char *dataset) 3137789Sahrens { 3138789Sahrens zfs_cmd_t zc = { 0 }; 3139789Sahrens 3140789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3141789Sahrens 31421544Seschrock if (zfs_ioctl(ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3143789Sahrens switch (errno) { 3144789Sahrens case EPERM: 3145789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot remove " 3146789Sahrens "device links for '%s': permission denied"), 3147789Sahrens dataset); 3148789Sahrens break; 3149789Sahrens 3150789Sahrens case EBUSY: 3151789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot remove " 3152789Sahrens "device links for '%s': volume is in use"), 3153789Sahrens dataset); 3154789Sahrens break; 3155789Sahrens 3156789Sahrens case ENXIO: 3157789Sahrens /* 3158789Sahrens * Silently ignore the case where the link no longer 3159789Sahrens * exists, so that 'zfs volfini' can be run multiple 3160789Sahrens * times without errors. 3161789Sahrens */ 3162789Sahrens return (0); 3163789Sahrens 3164789Sahrens default: 3165789Sahrens zfs_baderror(errno); 3166789Sahrens } 3167789Sahrens 3168789Sahrens return (-1); 3169789Sahrens } 3170789Sahrens 3171789Sahrens return (0); 3172789Sahrens } 3173