1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5789Sahrens * Common Development and Distribution License, Version 1.0 only 6789Sahrens * (the "License"). You may not use this file except in compliance 7789Sahrens * with the License. 8789Sahrens * 9789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10789Sahrens * or http://www.opensolaris.org/os/licensing. 11789Sahrens * See the License for the specific language governing permissions 12789Sahrens * and limitations under the License. 13789Sahrens * 14789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19789Sahrens * 20789Sahrens * CDDL HEADER END 21789Sahrens */ 22789Sahrens /* 23*1294Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens #include <assert.h> 30789Sahrens #include <ctype.h> 31789Sahrens #include <errno.h> 32789Sahrens #include <libdevinfo.h> 33789Sahrens #include <libintl.h> 34789Sahrens #include <math.h> 35789Sahrens #include <stdio.h> 36789Sahrens #include <stdlib.h> 37789Sahrens #include <strings.h> 38789Sahrens #include <unistd.h> 39789Sahrens #include <zone.h> 40789Sahrens #include <sys/mntent.h> 41789Sahrens #include <sys/mnttab.h> 42*1294Slling #include <sys/mount.h> 43789Sahrens 44789Sahrens #include <sys/spa.h> 45789Sahrens #include <sys/zio.h> 46789Sahrens #include <libzfs.h> 47789Sahrens 48789Sahrens #include "zfs_namecheck.h" 49789Sahrens #include "zfs_prop.h" 50789Sahrens #include "libzfs_impl.h" 51789Sahrens 52789Sahrens /* 53789Sahrens * Given a single type (not a mask of types), return the type in a human 54789Sahrens * readable form. 55789Sahrens */ 56789Sahrens const char * 57789Sahrens zfs_type_to_name(zfs_type_t type) 58789Sahrens { 59789Sahrens switch (type) { 60789Sahrens case ZFS_TYPE_FILESYSTEM: 61789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 62789Sahrens case ZFS_TYPE_SNAPSHOT: 63789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 64789Sahrens case ZFS_TYPE_VOLUME: 65789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 66789Sahrens } 67789Sahrens 68789Sahrens zfs_baderror(type); 69789Sahrens return (NULL); 70789Sahrens } 71789Sahrens 72789Sahrens /* 73789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 74789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 75789Sahrens * We guess what the type would have been based on the path and the mask of 76789Sahrens * acceptable types. 77789Sahrens */ 78789Sahrens static const char * 79789Sahrens path_to_str(const char *path, int types) 80789Sahrens { 81789Sahrens /* 82789Sahrens * When given a single type, always report the exact type. 83789Sahrens */ 84789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 85789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 86789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 87789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 88789Sahrens if (types == ZFS_TYPE_VOLUME) 89789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 90789Sahrens 91789Sahrens /* 92789Sahrens * The user is requesting more than one type of dataset. If this is the 93789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 94789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 95789Sahrens * snapshot attribute and try again. 96789Sahrens */ 97789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 98789Sahrens if (strchr(path, '@') != NULL) 99789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 100789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 101789Sahrens } 102789Sahrens 103789Sahrens 104789Sahrens /* 105789Sahrens * The user has requested either filesystems or volumes. 106789Sahrens * We have no way of knowing a priori what type this would be, so always 107789Sahrens * report it as "filesystem" or "volume", our two primitive types. 108789Sahrens */ 109789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 110789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 111789Sahrens 112789Sahrens assert(types & ZFS_TYPE_VOLUME); 113789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 114789Sahrens } 115789Sahrens 116789Sahrens /* 117789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 118789Sahrens * provide a more meaningful error message. We place a more useful message in 119789Sahrens * 'buf' detailing exactly why the name was not valid. 120789Sahrens */ 121789Sahrens static int 122789Sahrens zfs_validate_name(const char *path, int type, char *buf, size_t buflen) 123789Sahrens { 124789Sahrens namecheck_err_t why; 125789Sahrens char what; 126789Sahrens 127789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 128789Sahrens if (buf != NULL) { 129789Sahrens switch (why) { 1301003Slling case NAME_ERR_TOOLONG: 1311003Slling (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 1321003Slling "name is too long"), buflen); 1331003Slling break; 1341003Slling 135789Sahrens case NAME_ERR_LEADING_SLASH: 136789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 137789Sahrens "leading slash"), buflen); 138789Sahrens break; 139789Sahrens 140789Sahrens case NAME_ERR_EMPTY_COMPONENT: 141789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 142789Sahrens "empty component"), buflen); 143789Sahrens break; 144789Sahrens 145789Sahrens case NAME_ERR_TRAILING_SLASH: 146789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 147789Sahrens "trailing slash"), buflen); 148789Sahrens break; 149789Sahrens 150789Sahrens case NAME_ERR_INVALCHAR: 151789Sahrens (void) snprintf(buf, buflen, 152789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 153789Sahrens "'%c'"), what); 154789Sahrens break; 155789Sahrens 156789Sahrens case NAME_ERR_MULTIPLE_AT: 157789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 158789Sahrens "multiple '@' delimiters"), buflen); 159789Sahrens break; 160789Sahrens } 161789Sahrens } 162789Sahrens 163789Sahrens return (0); 164789Sahrens } 165789Sahrens 166789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 167789Sahrens if (buf != NULL) 168789Sahrens (void) strlcpy(buf, 169789Sahrens dgettext(TEXT_DOMAIN, 170789Sahrens "snapshot delimiter '@'"), buflen); 171789Sahrens return (0); 172789Sahrens } 173789Sahrens 174789Sahrens return (1); 175789Sahrens } 176789Sahrens 177789Sahrens int 178789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 179789Sahrens { 180789Sahrens return (zfs_validate_name(name, type, NULL, NULL)); 181789Sahrens } 182789Sahrens 183789Sahrens /* 184789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 185789Sahrens */ 186789Sahrens static int 187789Sahrens get_stats(zfs_handle_t *zhp) 188789Sahrens { 189789Sahrens zfs_cmd_t zc = { 0 }; 190789Sahrens 191789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 192789Sahrens 193789Sahrens /* 194789Sahrens * get the generic DMU stats and per-type (zfs, zvol) stats 195789Sahrens */ 196789Sahrens if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) 197789Sahrens return (-1); 198789Sahrens 199789Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 200789Sahrens sizeof (zc.zc_objset_stats)); 201789Sahrens 202789Sahrens bcopy(&zc.zc_zfs_stats, &zhp->zfs_zplstats, sizeof (zc.zc_zfs_stats)); 203789Sahrens 204789Sahrens zhp->zfs_volsize = zc.zc_volsize; 205789Sahrens zhp->zfs_volblocksize = zc.zc_volblocksize; 206789Sahrens 207789Sahrens return (0); 208789Sahrens } 209789Sahrens 210789Sahrens /* 211789Sahrens * Refresh the properties currently stored in the handle. 212789Sahrens */ 213789Sahrens void 214789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 215789Sahrens { 216789Sahrens (void) get_stats(zhp); 217789Sahrens } 218789Sahrens 219789Sahrens /* 220789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 221789Sahrens * zfs_iter_* to create child handles on the fly. 222789Sahrens */ 223789Sahrens zfs_handle_t * 224789Sahrens make_dataset_handle(const char *path) 225789Sahrens { 226789Sahrens zfs_handle_t *zhp = zfs_malloc(sizeof (zfs_handle_t)); 227789Sahrens 228789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 229789Sahrens 230789Sahrens if (get_stats(zhp) != 0) { 231789Sahrens free(zhp); 232789Sahrens return (NULL); 233789Sahrens } 234789Sahrens 235789Sahrens /* 236789Sahrens * We've managed to open the dataset and gather statistics. Determine 237789Sahrens * the high-level type. 238789Sahrens */ 239789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 240789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 241789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 242789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 243789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 244789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 245789Sahrens else 246789Sahrens /* we should never see any other dataset types */ 247789Sahrens zfs_baderror(zhp->zfs_dmustats.dds_type); 248789Sahrens 249789Sahrens return (zhp); 250789Sahrens } 251789Sahrens 252789Sahrens /* 253789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 254789Sahrens * argument is a mask of acceptable types. The function will print an 255789Sahrens * appropriate error message and return NULL if it can't be opened. 256789Sahrens */ 257789Sahrens zfs_handle_t * 258789Sahrens zfs_open(const char *path, int types) 259789Sahrens { 260789Sahrens zfs_handle_t *zhp; 261789Sahrens 262789Sahrens /* 263789Sahrens * Validate the name before we even try to open it. We don't care about 264789Sahrens * the verbose invalid messages here; just report a generic error. 265789Sahrens */ 266789Sahrens if (!zfs_validate_name(path, types, NULL, 0)) { 267789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 268789Sahrens "cannot open '%s': invalid %s name"), path, 269789Sahrens path_to_str(path, types)); 270789Sahrens return (NULL); 271789Sahrens } 272789Sahrens 273789Sahrens /* 274789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 275789Sahrens */ 276789Sahrens errno = 0; 277789Sahrens if ((zhp = make_dataset_handle(path)) == NULL) { 278789Sahrens switch (errno) { 279789Sahrens case ENOENT: 280789Sahrens /* 281789Sahrens * The dataset doesn't exist. 282789Sahrens */ 283789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 284789Sahrens "cannot open '%s': no such %s"), path, 285789Sahrens path_to_str(path, types)); 286789Sahrens break; 287789Sahrens 288789Sahrens case EBUSY: 289789Sahrens /* 290789Sahrens * We were able to open the dataset but couldn't 291789Sahrens * get the stats. 292789Sahrens */ 293789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 294789Sahrens "cannot open '%s': %s is busy"), path, 295789Sahrens path_to_str(path, types)); 296789Sahrens break; 297789Sahrens 298789Sahrens default: 299789Sahrens zfs_baderror(errno); 300789Sahrens 301789Sahrens } 302789Sahrens return (NULL); 303789Sahrens } 304789Sahrens 305789Sahrens if (!(types & zhp->zfs_type)) { 306789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': operation " 307789Sahrens "not supported for %ss"), path, 308789Sahrens zfs_type_to_name(zhp->zfs_type)); 309789Sahrens free(zhp); 310789Sahrens return (NULL); 311789Sahrens } 312789Sahrens 313789Sahrens return (zhp); 314789Sahrens } 315789Sahrens 316789Sahrens /* 317789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 318789Sahrens */ 319789Sahrens void 320789Sahrens zfs_close(zfs_handle_t *zhp) 321789Sahrens { 322789Sahrens if (zhp->zfs_mntopts) 323789Sahrens free(zhp->zfs_mntopts); 324789Sahrens free(zhp); 325789Sahrens } 326789Sahrens 327789Sahrens struct { 328789Sahrens const char *name; 329789Sahrens uint64_t value; 330789Sahrens } checksum_table[] = { 331789Sahrens { "on", ZIO_CHECKSUM_ON }, 332789Sahrens { "off", ZIO_CHECKSUM_OFF }, 333789Sahrens { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 }, 334789Sahrens { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 }, 335789Sahrens { "sha256", ZIO_CHECKSUM_SHA256 }, 336789Sahrens { NULL } 337789Sahrens }; 338789Sahrens 339789Sahrens struct { 340789Sahrens const char *name; 341789Sahrens uint64_t value; 342789Sahrens } compress_table[] = { 343789Sahrens { "on", ZIO_COMPRESS_ON }, 344789Sahrens { "off", ZIO_COMPRESS_OFF }, 345789Sahrens { "lzjb", ZIO_COMPRESS_LZJB }, 346789Sahrens { NULL } 347789Sahrens }; 348789Sahrens 349789Sahrens struct { 350789Sahrens const char *name; 351789Sahrens uint64_t value; 352789Sahrens } snapdir_table[] = { 353849Sbonwick { "hidden", ZFS_SNAPDIR_HIDDEN }, 354849Sbonwick { "visible", ZFS_SNAPDIR_VISIBLE }, 355789Sahrens { NULL } 356789Sahrens }; 357789Sahrens 358789Sahrens struct { 359789Sahrens const char *name; 360789Sahrens uint64_t value; 361789Sahrens } acl_mode_table[] = { 362789Sahrens { "discard", DISCARD }, 363789Sahrens { "groupmask", GROUPMASK }, 364789Sahrens { "passthrough", PASSTHROUGH }, 365789Sahrens { NULL } 366789Sahrens }; 367789Sahrens 368789Sahrens struct { 369789Sahrens const char *name; 370789Sahrens uint64_t value; 371789Sahrens } acl_inherit_table[] = { 372789Sahrens { "discard", DISCARD }, 373789Sahrens { "noallow", NOALLOW }, 374789Sahrens { "secure", SECURE }, 375789Sahrens { "passthrough", PASSTHROUGH }, 376789Sahrens { NULL } 377789Sahrens }; 378789Sahrens 379789Sahrens 380789Sahrens /* 381789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 382789Sahrens * resulting value must be shifted. 383789Sahrens */ 384789Sahrens static int 385789Sahrens str2shift(const char *buf, char *reason, size_t len) 386789Sahrens { 387789Sahrens const char *ends = "BKMGTPEZ"; 388789Sahrens int i; 389789Sahrens 390789Sahrens if (buf[0] == '\0') 391789Sahrens return (0); 392789Sahrens for (i = 0; i < strlen(ends); i++) { 393789Sahrens if (toupper(buf[0]) == ends[i]) 394789Sahrens break; 395789Sahrens } 396789Sahrens if (i == strlen(ends)) { 397789Sahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid " 398789Sahrens "numeric suffix '%s'"), buf); 399789Sahrens return (-1); 400789Sahrens } 401789Sahrens 402789Sahrens /* 403789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 404789Sahrens * allow 'BB' - that's just weird. 405789Sahrens */ 406789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 407789Sahrens toupper(buf[0]) != 'B')) { 408789Sahrens return (10*i); 409789Sahrens } 410789Sahrens 411789Sahrens (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid numeric " 412789Sahrens "suffix '%s'"), buf); 413789Sahrens return (-1); 414789Sahrens } 415789Sahrens 416789Sahrens /* 417789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 418789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 419789Sahrens * message for the caller to use. 420789Sahrens */ 421789Sahrens static int 422789Sahrens nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen) 423789Sahrens { 424789Sahrens char *end; 425789Sahrens int shift; 426789Sahrens 427789Sahrens *num = 0; 428789Sahrens 429789Sahrens /* Check to see if this looks like a number. */ 430789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 431789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 432789Sahrens "must be a numeric value"), buflen); 433789Sahrens return (-1); 434789Sahrens } 435789Sahrens 436789Sahrens /* Rely on stroll() to process the numeric portion. */ 437789Sahrens errno = 0; 438789Sahrens *num = strtoll(value, &end, 10); 439789Sahrens 440789Sahrens /* 441789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 442789Sahrens * in a 64-bit value. 443789Sahrens */ 444789Sahrens if (errno == ERANGE) { 445789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 446789Sahrens "value is too large"), buflen); 447789Sahrens return (-1); 448789Sahrens } 449789Sahrens 450789Sahrens /* 451789Sahrens * If we have a decimal value, then do the computation with floating 452789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 453789Sahrens */ 454789Sahrens if (*end == '.') { 455789Sahrens double fval = strtod(value, &end); 456789Sahrens 457789Sahrens if ((shift = str2shift(end, buf, buflen)) == -1) 458789Sahrens return (-1); 459789Sahrens 460789Sahrens fval *= pow(2, shift); 461789Sahrens 462789Sahrens if (fval > UINT64_MAX) { 463789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 464789Sahrens "value is too large"), buflen); 465789Sahrens return (-1); 466789Sahrens } 467789Sahrens 468789Sahrens *num = (uint64_t)fval; 469789Sahrens } else { 470789Sahrens if ((shift = str2shift(end, buf, buflen)) == -1) 471789Sahrens return (-1); 472789Sahrens 473789Sahrens /* Check for overflow */ 474789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 475789Sahrens (void) strlcpy(buf, dgettext(TEXT_DOMAIN, 476789Sahrens "value is too large"), buflen); 477789Sahrens return (-1); 478789Sahrens } 479789Sahrens 480789Sahrens *num <<= shift; 481789Sahrens } 482789Sahrens 483789Sahrens return (0); 484789Sahrens } 485789Sahrens 486789Sahrens int 487789Sahrens zfs_nicestrtonum(const char *str, uint64_t *val) 488789Sahrens { 489789Sahrens char buf[1]; 490789Sahrens 491789Sahrens return (nicestrtonum(str, val, buf, sizeof (buf))); 492789Sahrens } 493789Sahrens 494789Sahrens /* 495789Sahrens * Given a property type and value, verify that the value is appropriate. Used 496789Sahrens * by zfs_prop_set() and some libzfs consumers. 497789Sahrens */ 498789Sahrens int 499789Sahrens zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval) 500789Sahrens { 501789Sahrens const char *propname = zfs_prop_to_name(prop); 502789Sahrens uint64_t number; 503789Sahrens char reason[64]; 504789Sahrens int i; 505789Sahrens 506789Sahrens /* 507789Sahrens * Check to see if this a read-only property. 508789Sahrens */ 509789Sahrens if (zfs_prop_readonly(prop)) { 510789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 511789Sahrens "cannot set %s property: read-only property"), propname); 512789Sahrens return (-1); 513789Sahrens } 514789Sahrens 515789Sahrens /* See if the property value is too long */ 516789Sahrens if (strlen(value) >= ZFS_MAXPROPLEN) { 517789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 518789Sahrens "bad %s value '%s': value is too long"), propname, 519789Sahrens value); 520789Sahrens return (-1); 521789Sahrens } 522789Sahrens 523789Sahrens /* Perform basic checking based on property type */ 524789Sahrens switch (zfs_prop_get_type(prop)) { 525789Sahrens case prop_type_boolean: 526789Sahrens if (strcmp(value, "on") == 0) { 527789Sahrens number = 1; 528789Sahrens } else if (strcmp(value, "off") == 0) { 529789Sahrens number = 0; 530789Sahrens } else { 531789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 532789Sahrens "bad %s value '%s': must be 'on' or 'off'"), 533789Sahrens propname, value); 534789Sahrens return (-1); 535789Sahrens } 536789Sahrens break; 537789Sahrens 538789Sahrens case prop_type_number: 539789Sahrens /* treat 'none' as 0 */ 540789Sahrens if (strcmp(value, "none") == 0) { 541789Sahrens number = 0; 542789Sahrens break; 543789Sahrens } 544789Sahrens 545789Sahrens if (nicestrtonum(value, &number, reason, 546789Sahrens sizeof (reason)) != 0) { 547789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 548789Sahrens "bad %s value '%s': %s"), propname, value, 549789Sahrens reason); 550789Sahrens return (-1); 551789Sahrens } 552789Sahrens 553789Sahrens /* don't allow 0 for quota, use 'none' instead */ 554789Sahrens if (prop == ZFS_PROP_QUOTA && number == 0 && 555789Sahrens strcmp(value, "none") != 0) { 556789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 557789Sahrens "bad %s value '%s': use '%s=none' to disable"), 558789Sahrens propname, value, propname); 559789Sahrens return (-1); 560789Sahrens } 561789Sahrens 562789Sahrens /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 563789Sahrens if (prop == ZFS_PROP_RECORDSIZE || 564789Sahrens prop == ZFS_PROP_VOLBLOCKSIZE) { 565789Sahrens if (number < SPA_MINBLOCKSIZE || 566789Sahrens number > SPA_MAXBLOCKSIZE || !ISP2(number)) { 567789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 568789Sahrens "bad %s value '%s': " 569789Sahrens "must be power of 2 from %u to %uk"), 570789Sahrens propname, value, 571789Sahrens (uint_t)SPA_MINBLOCKSIZE, 572789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 573789Sahrens return (-1); 574789Sahrens } 575789Sahrens } 576789Sahrens 577789Sahrens break; 578789Sahrens 579789Sahrens case prop_type_string: 580789Sahrens case prop_type_index: 581789Sahrens /* 582789Sahrens * The two writable string values, 'mountpoint' and 583789Sahrens * 'checksum' need special consideration. The 'index' types are 584789Sahrens * specified as strings by the user, but passed to the kernel as 585789Sahrens * integers. 586789Sahrens */ 587789Sahrens switch (prop) { 588789Sahrens case ZFS_PROP_MOUNTPOINT: 589789Sahrens if (strcmp(value, ZFS_MOUNTPOINT_NONE) == 0 || 590789Sahrens strcmp(value, ZFS_MOUNTPOINT_LEGACY) == 0) 591789Sahrens break; 592789Sahrens 593789Sahrens if (value[0] != '/') { 594789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 595789Sahrens "bad %s value '%s': must be an absolute " 596789Sahrens "path, 'none', or 'legacy'"), 597789Sahrens propname, value); 598789Sahrens return (-1); 599789Sahrens } 600789Sahrens break; 601789Sahrens 602789Sahrens case ZFS_PROP_CHECKSUM: 603789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 604789Sahrens if (strcmp(value, checksum_table[i].name) 605789Sahrens == 0) { 606789Sahrens number = checksum_table[i].value; 607789Sahrens break; 608789Sahrens } 609789Sahrens } 610789Sahrens 611789Sahrens if (checksum_table[i].name == NULL) { 612789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 613789Sahrens "bad %s value '%s': must be 'on', 'off', " 614789Sahrens "'fletcher2', 'fletcher4', or 'sha256'"), 615789Sahrens propname, value); 616789Sahrens return (-1); 617789Sahrens } 618789Sahrens break; 619789Sahrens 620789Sahrens case ZFS_PROP_COMPRESSION: 621789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 622789Sahrens if (strcmp(value, compress_table[i].name) 623789Sahrens == 0) { 624789Sahrens number = compress_table[i].value; 625789Sahrens break; 626789Sahrens } 627789Sahrens } 628789Sahrens 629789Sahrens if (compress_table[i].name == NULL) { 630789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 631789Sahrens "bad %s value '%s': must be 'on', 'off', " 632789Sahrens "or 'lzjb'"), 633789Sahrens propname, value); 634789Sahrens return (-1); 635789Sahrens } 636789Sahrens break; 637789Sahrens 638789Sahrens case ZFS_PROP_SNAPDIR: 639789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 640789Sahrens if (strcmp(value, snapdir_table[i].name) == 0) { 641789Sahrens number = snapdir_table[i].value; 642789Sahrens break; 643789Sahrens } 644789Sahrens } 645789Sahrens 646789Sahrens if (snapdir_table[i].name == NULL) { 647789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 648789Sahrens "bad %s value '%s': must be 'hidden' " 649789Sahrens "or 'visible'"), 650789Sahrens propname, value); 651789Sahrens return (-1); 652789Sahrens } 653789Sahrens break; 654789Sahrens 655789Sahrens case ZFS_PROP_ACLMODE: 656789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 657789Sahrens if (strcmp(value, acl_mode_table[i].name) 658789Sahrens == 0) { 659789Sahrens number = acl_mode_table[i].value; 660789Sahrens break; 661789Sahrens } 662789Sahrens } 663789Sahrens 664789Sahrens if (acl_mode_table[i].name == NULL) { 665789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 666789Sahrens "bad %s value '%s': must be 'discard', " 667789Sahrens "'groupmask' or 'passthrough'"), 668789Sahrens propname, value); 669789Sahrens return (-1); 670789Sahrens } 671789Sahrens break; 672789Sahrens 673789Sahrens case ZFS_PROP_ACLINHERIT: 674789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 675789Sahrens if (strcmp(value, acl_inherit_table[i].name) 676789Sahrens == 0) { 677789Sahrens number = acl_inherit_table[i].value; 678789Sahrens break; 679789Sahrens } 680789Sahrens } 681789Sahrens 682789Sahrens if (acl_inherit_table[i].name == NULL) { 683789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 684789Sahrens "bad %s value '%s': must be 'discard', " 685905Smarks "'noallow', 'secure' or 'passthrough'"), 686789Sahrens propname, value); 687789Sahrens return (-1); 688789Sahrens } 689789Sahrens break; 690789Sahrens 691789Sahrens case ZFS_PROP_SHARENFS: 692789Sahrens /* 693789Sahrens * Nothing to do for 'sharenfs', this gets passed on to 694789Sahrens * share(1M) verbatim. 695789Sahrens */ 696789Sahrens break; 697789Sahrens } 698789Sahrens } 699789Sahrens 700789Sahrens if (intval != NULL) 701789Sahrens *intval = number; 702789Sahrens 703789Sahrens return (0); 704789Sahrens } 705789Sahrens 706789Sahrens /* 707789Sahrens * Given a property name and value, set the property for the given dataset. 708789Sahrens */ 709789Sahrens int 710789Sahrens zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval) 711789Sahrens { 712789Sahrens const char *propname = zfs_prop_to_name(prop); 713789Sahrens uint64_t number; 714789Sahrens zfs_cmd_t zc = { 0 }; 715789Sahrens int ret; 716789Sahrens prop_changelist_t *cl; 717789Sahrens 718789Sahrens if (zfs_prop_validate(prop, propval, &number) != 0) 719789Sahrens return (-1); 720789Sahrens 721789Sahrens /* 722789Sahrens * Check to see if the value applies to this type 723789Sahrens */ 724789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 725789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 726789Sahrens "cannot set %s for '%s': property does not apply to %ss"), 727789Sahrens propname, zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 728789Sahrens return (-1); 729789Sahrens } 730789Sahrens 731789Sahrens /* 732789Sahrens * For the mountpoint and sharenfs properties, check if it can be set 733789Sahrens * in a global/non-global zone based on the zoned property value: 734789Sahrens * 735789Sahrens * global zone non-global zone 736789Sahrens * ----------------------------------------------------- 737789Sahrens * zoned=on mountpoint (no) mountpoint (yes) 738789Sahrens * sharenfs (no) sharenfs (no) 739789Sahrens * 740789Sahrens * zoned=off mountpoint (yes) N/A 741789Sahrens * sharenfs (yes) 742789Sahrens */ 743789Sahrens if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 744789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 745789Sahrens if (getzoneid() == GLOBAL_ZONEID) { 746789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7471133Seschrock "cannot set %s for '%s': " 748789Sahrens "dataset is used in a non-global zone"), 749789Sahrens propname, zhp->zfs_name); 750789Sahrens return (-1); 751789Sahrens } else if (prop == ZFS_PROP_SHARENFS) { 752789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7531133Seschrock "cannot set %s for '%s': filesystems " 754789Sahrens "cannot be shared in a non-global zone"), 755789Sahrens propname, zhp->zfs_name); 756789Sahrens return (-1); 757789Sahrens } 758789Sahrens } else if (getzoneid() != GLOBAL_ZONEID) { 759789Sahrens /* 760789Sahrens * If zoned property is 'off', this must be in 761789Sahrens * a globle zone. If not, something is wrong. 762789Sahrens */ 763789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 7641133Seschrock "cannot set %s for '%s': dataset is " 765789Sahrens "used in a non-global zone, but 'zoned' " 766789Sahrens "property is not set"), 767789Sahrens propname, zhp->zfs_name); 768789Sahrens return (-1); 769789Sahrens } 770789Sahrens } 771789Sahrens 772789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 773789Sahrens return (-1); 774789Sahrens 775789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 776789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for '%s', " 777789Sahrens "child dataset with inherited mountpoint is used " 778789Sahrens "in a non-global zone"), 779789Sahrens propname, zhp->zfs_name); 780789Sahrens ret = -1; 781789Sahrens goto error; 782789Sahrens } 783789Sahrens 784789Sahrens if ((ret = changelist_prefix(cl)) != 0) 785789Sahrens goto error; 786789Sahrens 787789Sahrens /* 788789Sahrens * Execute the corresponding ioctl() to set this property. 789789Sahrens */ 790789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 791789Sahrens 792789Sahrens switch (prop) { 793789Sahrens case ZFS_PROP_QUOTA: 794789Sahrens zc.zc_cookie = number; 795789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_QUOTA, &zc); 796789Sahrens break; 797789Sahrens case ZFS_PROP_RESERVATION: 798789Sahrens zc.zc_cookie = number; 799789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_RESERVATION, &zc); 800789Sahrens break; 801789Sahrens case ZFS_PROP_MOUNTPOINT: 802789Sahrens case ZFS_PROP_SHARENFS: 803789Sahrens /* 804789Sahrens * These properties are passed down as real strings. 805789Sahrens */ 806789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 807789Sahrens sizeof (zc.zc_prop_name)); 808789Sahrens (void) strlcpy(zc.zc_prop_value, propval, 809789Sahrens sizeof (zc.zc_prop_value)); 810789Sahrens zc.zc_intsz = 1; 811789Sahrens zc.zc_numints = strlen(propval) + 1; 812789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_PROP, &zc); 813789Sahrens break; 814789Sahrens case ZFS_PROP_VOLSIZE: 815789Sahrens zc.zc_volsize = number; 816789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_VOLSIZE, &zc); 817789Sahrens break; 818789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 819789Sahrens zc.zc_volblocksize = number; 820789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_VOLBLOCKSIZE, &zc); 821789Sahrens break; 822789Sahrens default: 823789Sahrens (void) strlcpy(zc.zc_prop_name, propname, 824789Sahrens sizeof (zc.zc_prop_name)); 825789Sahrens /* LINTED - alignment */ 826789Sahrens *(uint64_t *)zc.zc_prop_value = number; 827789Sahrens zc.zc_intsz = 8; 828789Sahrens zc.zc_numints = 1; 829789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SET_PROP, &zc); 830789Sahrens break; 831789Sahrens } 832789Sahrens 833789Sahrens if (ret != 0) { 834789Sahrens switch (errno) { 835789Sahrens 836789Sahrens case EPERM: 837789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 838789Sahrens "cannot set %s for '%s': permission " 839789Sahrens "denied"), propname, zhp->zfs_name); 840789Sahrens break; 841789Sahrens 842789Sahrens case ENOENT: 843789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 844789Sahrens "cannot open '%s': no such %s"), zhp->zfs_name, 845789Sahrens zfs_type_to_name(zhp->zfs_type)); 846789Sahrens break; 847789Sahrens 848789Sahrens case ENOSPC: 849789Sahrens /* 850789Sahrens * For quotas and reservations, ENOSPC indicates 851789Sahrens * something different; setting a quota or reservation 852789Sahrens * doesn't use any disk space. 853789Sahrens */ 854789Sahrens switch (prop) { 855789Sahrens case ZFS_PROP_QUOTA: 856789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s " 857789Sahrens "for '%s': size is less than current " 858789Sahrens "used or reserved space"), propname, 859789Sahrens zhp->zfs_name); 860789Sahrens break; 861789Sahrens 862789Sahrens case ZFS_PROP_RESERVATION: 863789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s " 864789Sahrens "for '%s': size is greater than available " 865789Sahrens "space"), propname, zhp->zfs_name); 866789Sahrens break; 867789Sahrens 868789Sahrens default: 869789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 870789Sahrens "cannot set %s for '%s': out of space"), 871789Sahrens propname, zhp->zfs_name); 872789Sahrens break; 873789Sahrens } 874789Sahrens break; 875789Sahrens 876789Sahrens case EBUSY: 877789Sahrens if (prop == ZFS_PROP_VOLBLOCKSIZE) { 878789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 879789Sahrens "cannot set %s for '%s': " 880789Sahrens "volume already contains data"), 881789Sahrens propname, zhp->zfs_name); 882789Sahrens } else { 883789Sahrens zfs_baderror(errno); 884789Sahrens } 885789Sahrens break; 886789Sahrens 8871175Slling case EROFS: 8881175Slling zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for " 8891175Slling "'%s': read only %s"), propname, zhp->zfs_name, 8901175Slling zfs_type_to_name(zhp->zfs_type)); 8911175Slling break; 8921175Slling 893789Sahrens case EOVERFLOW: 894789Sahrens /* 895789Sahrens * This platform can't address a volume this big. 896789Sahrens */ 897789Sahrens #ifdef _ILP32 898789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 899789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 900789Sahrens "cannot set %s for '%s': " 901789Sahrens "max volume size is 1TB on 32-bit systems"), 902789Sahrens propname, zhp->zfs_name); 903789Sahrens break; 904789Sahrens } 905789Sahrens #endif 906789Sahrens zfs_baderror(errno); 907789Sahrens default: 908789Sahrens zfs_baderror(errno); 909789Sahrens } 910789Sahrens } else { 911789Sahrens /* 912789Sahrens * Refresh the statistics so the new property value 913789Sahrens * is reflected. 914789Sahrens */ 915789Sahrens if ((ret = changelist_postfix(cl)) != 0) 916789Sahrens goto error; 917789Sahrens 918789Sahrens (void) get_stats(zhp); 919789Sahrens } 920789Sahrens 921789Sahrens error: 922789Sahrens changelist_free(cl); 923789Sahrens return (ret); 924789Sahrens } 925789Sahrens 926789Sahrens /* 927789Sahrens * Given a property, inherit the value from the parent dataset. 928789Sahrens */ 929789Sahrens int 930789Sahrens zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop) 931789Sahrens { 932789Sahrens const char *propname = zfs_prop_to_name(prop); 933789Sahrens zfs_cmd_t zc = { 0 }; 934789Sahrens int ret; 935789Sahrens prop_changelist_t *cl; 936789Sahrens 937789Sahrens /* 938789Sahrens * Verify that this property is inheritable. 939789Sahrens */ 940789Sahrens if (zfs_prop_readonly(prop)) { 941789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 942789Sahrens "cannot inherit %s for '%s': property is read-only"), 943789Sahrens propname, zhp->zfs_name); 944789Sahrens return (-1); 945789Sahrens } 946789Sahrens 947789Sahrens if (!zfs_prop_inheritable(prop)) { 948789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 949789Sahrens "cannot inherit %s for '%s': property is not inheritable"), 950789Sahrens propname, zhp->zfs_name); 951789Sahrens return (-1); 952789Sahrens } 953789Sahrens 954789Sahrens /* 955789Sahrens * Check to see if the value applies to this type 956789Sahrens */ 957789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { 958789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 959789Sahrens "cannot inherit %s for '%s': property does " 960789Sahrens "not apply to %ss"), propname, zhp->zfs_name, 961789Sahrens zfs_type_to_name(zhp->zfs_type)); 962789Sahrens return (-1); 963789Sahrens } 964789Sahrens 965789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 966789Sahrens (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name)); 967789Sahrens 968789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 969789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 970789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', " 971789Sahrens "dataset is used in a non-global zone"), propname, 972789Sahrens zhp->zfs_name); 973789Sahrens return (-1); 974789Sahrens } 975789Sahrens 976789Sahrens /* 977789Sahrens * Determine datasets which will be affected by this change, if any. 978789Sahrens */ 979789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 980789Sahrens return (-1); 981789Sahrens 982789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 983789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', " 984789Sahrens "child dataset with inherited mountpoint is " 985789Sahrens "used in a non-global zone"), 986789Sahrens propname, zhp->zfs_name); 987789Sahrens ret = -1; 988789Sahrens goto error; 989789Sahrens } 990789Sahrens 991789Sahrens if ((ret = changelist_prefix(cl)) != 0) 992789Sahrens goto error; 993789Sahrens 994789Sahrens zc.zc_numints = 0; 995789Sahrens 996789Sahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_SET_PROP, &zc)) != 0) { 997789Sahrens switch (errno) { 998789Sahrens case EPERM: 999789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1000789Sahrens "cannot inherit %s for '%s': permission " 1001789Sahrens "denied"), propname, zhp->zfs_name); 1002789Sahrens break; 1003789Sahrens case ENOENT: 1004789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1005789Sahrens "cannot open '%s': no such %s"), zhp->zfs_name, 1006789Sahrens zfs_type_to_name(zhp->zfs_type)); 1007789Sahrens break; 1008789Sahrens case ENOSPC: 1009789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1010789Sahrens "cannot inherit %s for '%s': " 1011789Sahrens "out of space"), propname, zhp->zfs_name); 1012789Sahrens break; 1013789Sahrens default: 1014789Sahrens zfs_baderror(errno); 1015789Sahrens } 1016789Sahrens 1017789Sahrens } else { 1018789Sahrens 1019789Sahrens if ((ret = changelist_postfix(cl)) != 0) 1020789Sahrens goto error; 1021789Sahrens 1022789Sahrens /* 1023789Sahrens * Refresh the statistics so the new property is reflected. 1024789Sahrens */ 1025789Sahrens (void) get_stats(zhp); 1026789Sahrens } 1027789Sahrens 1028789Sahrens 1029789Sahrens error: 1030789Sahrens changelist_free(cl); 1031789Sahrens return (ret); 1032789Sahrens } 1033789Sahrens 1034789Sahrens static void 1035789Sahrens nicebool(int value, char *buf, size_t buflen) 1036789Sahrens { 1037789Sahrens if (value) 1038789Sahrens (void) strlcpy(buf, "on", buflen); 1039789Sahrens else 1040789Sahrens (void) strlcpy(buf, "off", buflen); 1041789Sahrens } 1042789Sahrens 1043789Sahrens /* 1044789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1045789Sahrens * zfs_prop_get_int() are built using this interface. 1046789Sahrens * 1047789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1048789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1049789Sahrens * If they differ from the on-disk values, report the current values and mark 1050789Sahrens * the source "temporary". 1051789Sahrens */ 1052789Sahrens static uint64_t 1053789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 1054789Sahrens char **source) 1055789Sahrens { 1056789Sahrens uint64_t val; 1057789Sahrens struct mnttab mnt; 1058789Sahrens 1059789Sahrens *source = NULL; 1060789Sahrens 1061789Sahrens if (zhp->zfs_mntopts == NULL) 1062789Sahrens mnt.mnt_mntopts = ""; 1063789Sahrens else 1064789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1065789Sahrens 1066789Sahrens switch (prop) { 1067789Sahrens case ZFS_PROP_ATIME: 1068789Sahrens *source = zhp->zfs_zplstats.zs_atime_setpoint; 1069789Sahrens val = zhp->zfs_zplstats.zs_devices; 1070789Sahrens 1071789Sahrens if (hasmntopt(&mnt, MNTOPT_ATIME) && !val) { 1072789Sahrens val = TRUE; 1073789Sahrens if (src) 1074789Sahrens *src = ZFS_SRC_TEMPORARY; 1075789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && val) { 1076789Sahrens val = FALSE; 1077789Sahrens if (src) 1078789Sahrens *src = ZFS_SRC_TEMPORARY; 1079789Sahrens } 1080789Sahrens return (zhp->zfs_zplstats.zs_atime); 1081789Sahrens 1082789Sahrens case ZFS_PROP_AVAILABLE: 1083789Sahrens return (zhp->zfs_dmustats.dds_available); 1084789Sahrens 1085789Sahrens case ZFS_PROP_DEVICES: 1086789Sahrens *source = zhp->zfs_zplstats.zs_devices_setpoint; 1087789Sahrens val = zhp->zfs_zplstats.zs_devices; 1088789Sahrens 1089789Sahrens if (hasmntopt(&mnt, MNTOPT_DEVICES) && !val) { 1090789Sahrens val = TRUE; 1091789Sahrens if (src) 1092789Sahrens *src = ZFS_SRC_TEMPORARY; 1093789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && val) { 1094789Sahrens val = FALSE; 1095789Sahrens if (src) 1096789Sahrens *src = ZFS_SRC_TEMPORARY; 1097789Sahrens } 1098789Sahrens return (val); 1099789Sahrens 1100789Sahrens case ZFS_PROP_EXEC: 1101789Sahrens *source = zhp->zfs_zplstats.zs_exec_setpoint; 1102789Sahrens val = zhp->zfs_zplstats.zs_exec; 1103789Sahrens 1104789Sahrens if (hasmntopt(&mnt, MNTOPT_EXEC) && !val) { 1105789Sahrens val = TRUE; 1106789Sahrens if (src) 1107789Sahrens *src = ZFS_SRC_TEMPORARY; 1108789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && val) { 1109789Sahrens val = FALSE; 1110789Sahrens if (src) 1111789Sahrens *src = ZFS_SRC_TEMPORARY; 1112789Sahrens } 1113789Sahrens return (val); 1114789Sahrens 1115789Sahrens case ZFS_PROP_RECORDSIZE: 1116789Sahrens *source = zhp->zfs_zplstats.zs_recordsize_setpoint; 1117789Sahrens return (zhp->zfs_zplstats.zs_recordsize); 1118789Sahrens 1119789Sahrens case ZFS_PROP_COMPRESSION: 1120789Sahrens *source = zhp->zfs_dmustats.dds_compression_setpoint; 1121789Sahrens return (zhp->zfs_dmustats.dds_compression); 1122789Sahrens 1123789Sahrens case ZFS_PROP_READONLY: 1124789Sahrens *source = zhp->zfs_zplstats.zs_readonly_setpoint; 1125789Sahrens val = zhp->zfs_zplstats.zs_readonly; 1126789Sahrens 1127789Sahrens if (hasmntopt(&mnt, MNTOPT_RO) && !val) { 1128789Sahrens val = TRUE; 1129789Sahrens if (src) 1130789Sahrens *src = ZFS_SRC_TEMPORARY; 1131789Sahrens } else if (hasmntopt(&mnt, MNTOPT_RW) && val) { 1132789Sahrens val = FALSE; 1133789Sahrens if (src) 1134789Sahrens *src = ZFS_SRC_TEMPORARY; 1135789Sahrens } 1136789Sahrens return (val); 1137789Sahrens 1138789Sahrens case ZFS_PROP_QUOTA: 1139789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1140789Sahrens *source = ""; /* default */ 1141789Sahrens else 1142789Sahrens *source = zhp->zfs_name; 1143789Sahrens return (zhp->zfs_dmustats.dds_quota); 1144789Sahrens 1145789Sahrens case ZFS_PROP_RESERVATION: 1146789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1147789Sahrens *source = ""; /* default */ 1148789Sahrens else 1149789Sahrens *source = zhp->zfs_name; 1150789Sahrens return (zhp->zfs_dmustats.dds_reserved); 1151789Sahrens 1152789Sahrens case ZFS_PROP_COMPRESSRATIO: 1153789Sahrens /* 1154789Sahrens * Using physical space and logical space, calculate the 1155789Sahrens * compression ratio. We return the number as a multiple of 1156789Sahrens * 100, so '2.5x' would be returned as 250. 1157789Sahrens */ 1158789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 1159789Sahrens return (100ULL); 1160789Sahrens else 1161789Sahrens return (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1162789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 1163789Sahrens 1164789Sahrens case ZFS_PROP_REFERENCED: 1165789Sahrens /* 1166789Sahrens * 'referenced' refers to the amount of physical space 1167789Sahrens * referenced (possibly shared) by this object. 1168789Sahrens */ 1169789Sahrens return (zhp->zfs_dmustats.dds_space_refd); 1170789Sahrens 1171789Sahrens case ZFS_PROP_SETUID: 1172789Sahrens *source = zhp->zfs_zplstats.zs_setuid_setpoint; 1173789Sahrens val = zhp->zfs_zplstats.zs_setuid; 1174789Sahrens 1175789Sahrens if (hasmntopt(&mnt, MNTOPT_SETUID) && !val) { 1176789Sahrens val = TRUE; 1177789Sahrens if (src) 1178789Sahrens *src = ZFS_SRC_TEMPORARY; 1179789Sahrens } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && val) { 1180789Sahrens val = FALSE; 1181789Sahrens if (src) 1182789Sahrens *src = ZFS_SRC_TEMPORARY; 1183789Sahrens } 1184789Sahrens return (val); 1185789Sahrens 1186789Sahrens case ZFS_PROP_VOLSIZE: 1187789Sahrens return (zhp->zfs_volsize); 1188789Sahrens 1189789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1190789Sahrens return (zhp->zfs_volblocksize); 1191789Sahrens 1192789Sahrens case ZFS_PROP_ZONED: 1193789Sahrens *source = zhp->zfs_dmustats.dds_zoned_setpoint; 1194789Sahrens return (zhp->zfs_dmustats.dds_zoned); 1195789Sahrens 1196789Sahrens case ZFS_PROP_USED: 1197789Sahrens return (zhp->zfs_dmustats.dds_space_used); 1198789Sahrens 1199789Sahrens case ZFS_PROP_CREATETXG: 1200789Sahrens return (zhp->zfs_dmustats.dds_creation_txg); 1201789Sahrens 1202789Sahrens case ZFS_PROP_MOUNTED: 1203789Sahrens /* 1204789Sahrens * Unlike other properties, we defer calculation of 'MOUNTED' 1205789Sahrens * until actually requested. This is because the getmntany() 1206789Sahrens * call can be extremely expensive on systems with a large 1207789Sahrens * number of filesystems, and the property isn't needed in 1208789Sahrens * normal use cases. 1209789Sahrens */ 1210789Sahrens if (zhp->zfs_mntopts == NULL) { 1211789Sahrens struct mnttab search = { 0 }, entry; 1212789Sahrens 1213789Sahrens search.mnt_special = (char *)zhp->zfs_name; 1214789Sahrens rewind(mnttab_file); 1215789Sahrens 1216789Sahrens if (getmntany(mnttab_file, &entry, &search) == 0) 1217789Sahrens zhp->zfs_mntopts = 1218789Sahrens zfs_strdup(entry.mnt_mntopts); 1219789Sahrens } 1220789Sahrens return (zhp->zfs_mntopts != NULL); 1221789Sahrens 1222789Sahrens default: 1223789Sahrens zfs_baderror(EINVAL); 1224789Sahrens } 1225789Sahrens 1226789Sahrens return (0); 1227789Sahrens } 1228789Sahrens 1229789Sahrens /* 1230789Sahrens * Calculate the source type, given the raw source string. 1231789Sahrens */ 1232789Sahrens static void 1233789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1234789Sahrens char *statbuf, size_t statlen) 1235789Sahrens { 1236789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1237789Sahrens return; 1238789Sahrens 1239789Sahrens if (source == NULL) { 1240789Sahrens *srctype = ZFS_SRC_NONE; 1241789Sahrens } else if (source[0] == '\0') { 1242789Sahrens *srctype = ZFS_SRC_DEFAULT; 1243789Sahrens } else { 1244789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1245789Sahrens *srctype = ZFS_SRC_LOCAL; 1246789Sahrens } else { 1247789Sahrens (void) strlcpy(statbuf, source, statlen); 1248789Sahrens *srctype = ZFS_SRC_INHERITED; 1249789Sahrens } 1250789Sahrens } 1251789Sahrens 1252789Sahrens } 1253789Sahrens 1254789Sahrens /* 1255789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1256789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1257789Sahrens * human-readable form. 1258789Sahrens * 1259789Sahrens * Returns 0 on success, or -1 on error. 1260789Sahrens */ 1261789Sahrens int 1262789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1263789Sahrens zfs_source_t *src, char *statbuf, size_t statlen, int literal) 1264789Sahrens { 1265789Sahrens char *source = NULL; 1266789Sahrens uint64_t val; 1267789Sahrens char *str; 1268789Sahrens int i; 1269789Sahrens const char *root; 1270789Sahrens 1271789Sahrens /* 1272789Sahrens * Check to see if this property applies to our object 1273789Sahrens */ 1274789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1275789Sahrens return (-1); 1276789Sahrens 1277789Sahrens if (src) 1278789Sahrens *src = ZFS_SRC_NONE; 1279789Sahrens 1280789Sahrens switch (prop) { 1281789Sahrens case ZFS_PROP_ATIME: 1282789Sahrens case ZFS_PROP_READONLY: 1283789Sahrens case ZFS_PROP_SETUID: 1284789Sahrens case ZFS_PROP_ZONED: 1285789Sahrens case ZFS_PROP_DEVICES: 1286789Sahrens case ZFS_PROP_EXEC: 1287789Sahrens /* 1288789Sahrens * Basic boolean values are built on top of 1289789Sahrens * get_numeric_property(). 1290789Sahrens */ 1291789Sahrens nicebool(get_numeric_property(zhp, prop, src, &source), 1292789Sahrens propbuf, proplen); 1293789Sahrens 1294789Sahrens break; 1295789Sahrens 1296789Sahrens case ZFS_PROP_AVAILABLE: 1297789Sahrens case ZFS_PROP_RECORDSIZE: 1298789Sahrens case ZFS_PROP_CREATETXG: 1299789Sahrens case ZFS_PROP_REFERENCED: 1300789Sahrens case ZFS_PROP_USED: 1301789Sahrens case ZFS_PROP_VOLSIZE: 1302789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1303789Sahrens /* 1304789Sahrens * Basic numeric values are built on top of 1305789Sahrens * get_numeric_property(). 1306789Sahrens */ 1307789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1308789Sahrens if (literal) 1309789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1310789Sahrens else 1311789Sahrens zfs_nicenum(val, propbuf, proplen); 1312789Sahrens break; 1313789Sahrens 1314789Sahrens case ZFS_PROP_COMPRESSION: 1315789Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 1316789Sahrens if (compress_table[i].value == 1317789Sahrens zhp->zfs_dmustats.dds_compression) 1318789Sahrens break; 1319789Sahrens } 1320789Sahrens assert(compress_table[i].name != NULL); 1321789Sahrens (void) strlcpy(propbuf, compress_table[i].name, proplen); 1322789Sahrens source = zhp->zfs_dmustats.dds_compression_setpoint; 1323789Sahrens break; 1324789Sahrens 1325789Sahrens case ZFS_PROP_CHECKSUM: 1326789Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 1327789Sahrens if (checksum_table[i].value == 1328789Sahrens zhp->zfs_dmustats.dds_checksum) 1329789Sahrens break; 1330789Sahrens } 1331789Sahrens assert(checksum_table[i].name != NULL); 1332789Sahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen); 1333789Sahrens source = zhp->zfs_dmustats.dds_checksum_setpoint; 1334789Sahrens break; 1335789Sahrens 1336789Sahrens case ZFS_PROP_SNAPDIR: 1337789Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 1338789Sahrens if (snapdir_table[i].value == 1339789Sahrens zhp->zfs_zplstats.zs_snapdir) 1340789Sahrens break; 1341789Sahrens } 1342789Sahrens assert(snapdir_table[i].name != NULL); 1343789Sahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen); 1344789Sahrens source = zhp->zfs_zplstats.zs_snapdir_setpoint; 1345789Sahrens break; 1346789Sahrens 1347789Sahrens case ZFS_PROP_ACLMODE: 1348789Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 1349789Sahrens if (acl_mode_table[i].value == 1350789Sahrens zhp->zfs_zplstats.zs_acl_mode) 1351789Sahrens break; 1352789Sahrens } 1353789Sahrens assert(acl_mode_table[i].name != NULL); 1354789Sahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen); 1355789Sahrens source = zhp->zfs_zplstats.zs_acl_mode_setpoint; 1356789Sahrens break; 1357789Sahrens 1358789Sahrens case ZFS_PROP_ACLINHERIT: 1359789Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 1360789Sahrens if (acl_inherit_table[i].value == 1361789Sahrens zhp->zfs_zplstats.zs_acl_inherit) 1362789Sahrens break; 1363789Sahrens } 1364789Sahrens assert(acl_inherit_table[i].name != NULL); 1365789Sahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen); 1366789Sahrens source = zhp->zfs_zplstats.zs_acl_inherit_setpoint; 1367789Sahrens break; 1368789Sahrens 1369789Sahrens case ZFS_PROP_CREATION: 1370789Sahrens /* 1371789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1372789Sahrens * this into a string unless 'literal' is specified. 1373789Sahrens */ 1374789Sahrens { 1375789Sahrens time_t time = (time_t) 1376789Sahrens zhp->zfs_dmustats.dds_creation_time; 1377789Sahrens struct tm t; 1378789Sahrens 1379789Sahrens if (literal || 1380789Sahrens localtime_r(&time, &t) == NULL || 1381789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1382789Sahrens &t) == 0) 1383789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1384789Sahrens zhp->zfs_dmustats.dds_creation_time); 1385789Sahrens } 1386789Sahrens break; 1387789Sahrens 1388789Sahrens case ZFS_PROP_MOUNTPOINT: 1389789Sahrens /* 1390789Sahrens * Getting the precise mountpoint can be tricky. 1391789Sahrens * 1392789Sahrens * - for 'none' or 'legacy', return those values. 1393789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1394789Sahrens * - for inherited mountpoints, we want to take everything 1395789Sahrens * after our ancestor and append it to the inherited value. 1396789Sahrens * 1397789Sahrens * If the pool has an alternate root, we want to prepend that 1398789Sahrens * root to any values we return. 1399789Sahrens */ 1400789Sahrens root = zhp->zfs_dmustats.dds_altroot; 1401789Sahrens 1402789Sahrens if (zhp->zfs_zplstats.zs_mountpoint[0] == '\0') { 1403789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1404789Sahrens root, zhp->zfs_name); 1405789Sahrens } else if (zhp->zfs_zplstats.zs_mountpoint[0] == '/') { 1406789Sahrens const char *relpath = zhp->zfs_name + 1407789Sahrens strlen(zhp->zfs_zplstats.zs_mountpoint_setpoint); 1408789Sahrens const char *mntpoint = zhp->zfs_zplstats.zs_mountpoint; 1409789Sahrens 1410789Sahrens if (relpath[0] == '/') 1411789Sahrens relpath++; 1412789Sahrens if (mntpoint[1] == '\0') 1413789Sahrens mntpoint++; 1414789Sahrens 1415789Sahrens if (relpath[0] == '\0') 1416789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 1417789Sahrens root, mntpoint); 1418789Sahrens else 1419789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 1420789Sahrens root, mntpoint, 1421789Sahrens relpath[0] == '@' ? "" : "/", 1422789Sahrens relpath); 1423789Sahrens } else { 1424789Sahrens /* 'legacy' or 'none' */ 1425789Sahrens (void) strlcpy(propbuf, zhp->zfs_zplstats.zs_mountpoint, 1426789Sahrens proplen); 1427789Sahrens } 1428789Sahrens 1429789Sahrens source = zhp->zfs_zplstats.zs_mountpoint_setpoint; 1430789Sahrens break; 1431789Sahrens 1432789Sahrens case ZFS_PROP_SHARENFS: 1433789Sahrens (void) strlcpy(propbuf, zhp->zfs_zplstats.zs_sharenfs, proplen); 1434789Sahrens source = zhp->zfs_zplstats.zs_sharenfs_setpoint; 1435789Sahrens break; 1436789Sahrens 1437789Sahrens case ZFS_PROP_ORIGIN: 1438789Sahrens (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1439789Sahrens proplen); 1440789Sahrens /* 1441789Sahrens * If there is no parent at all, return failure to indicate that 1442789Sahrens * it doesn't apply to this dataset. 1443789Sahrens */ 1444789Sahrens if (propbuf[0] == '\0') 1445789Sahrens return (-1); 1446789Sahrens break; 1447789Sahrens 1448789Sahrens case ZFS_PROP_QUOTA: 1449789Sahrens case ZFS_PROP_RESERVATION: 1450789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1451789Sahrens 1452789Sahrens /* 1453789Sahrens * If quota or reservation is 0, we translate this into 'none' 1454789Sahrens * (unless literal is set), and indicate that it's the default 1455789Sahrens * value. Otherwise, we print the number nicely and indicate 1456789Sahrens * that its set locally. 1457789Sahrens */ 1458789Sahrens if (val == 0) { 1459789Sahrens if (literal) 1460789Sahrens (void) strlcpy(propbuf, "0", proplen); 1461789Sahrens else 1462789Sahrens (void) strlcpy(propbuf, "none", proplen); 1463789Sahrens } else { 1464789Sahrens if (literal) 1465789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1466789Sahrens else 1467789Sahrens zfs_nicenum(val, propbuf, proplen); 1468789Sahrens } 1469789Sahrens break; 1470789Sahrens 1471789Sahrens case ZFS_PROP_COMPRESSRATIO: 1472789Sahrens val = get_numeric_property(zhp, prop, src, &source); 1473789Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1474789Sahrens val % 100); 1475789Sahrens break; 1476789Sahrens 1477789Sahrens case ZFS_PROP_TYPE: 1478789Sahrens switch (zhp->zfs_type) { 1479789Sahrens case ZFS_TYPE_FILESYSTEM: 1480789Sahrens str = "filesystem"; 1481789Sahrens break; 1482789Sahrens case ZFS_TYPE_VOLUME: 1483789Sahrens str = "volume"; 1484789Sahrens break; 1485789Sahrens case ZFS_TYPE_SNAPSHOT: 1486789Sahrens str = "snapshot"; 1487789Sahrens break; 1488789Sahrens default: 1489789Sahrens zfs_baderror(zhp->zfs_type); 1490789Sahrens } 1491789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1492789Sahrens break; 1493789Sahrens 1494789Sahrens case ZFS_PROP_MOUNTED: 1495789Sahrens /* 1496789Sahrens * The 'mounted' property is a pseudo-property that described 1497789Sahrens * whether the filesystem is currently mounted. Even though 1498789Sahrens * it's a boolean value, the typical values of "on" and "off" 1499789Sahrens * don't make sense, so we translate to "yes" and "no". 1500789Sahrens */ 1501789Sahrens if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source)) 1502789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1503789Sahrens else 1504789Sahrens (void) strlcpy(propbuf, "no", proplen); 1505789Sahrens break; 1506789Sahrens 1507789Sahrens case ZFS_PROP_NAME: 1508789Sahrens /* 1509789Sahrens * The 'name' property is a pseudo-property derived from the 1510789Sahrens * dataset name. It is presented as a real property to simplify 1511789Sahrens * consumers. 1512789Sahrens */ 1513789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1514789Sahrens break; 1515789Sahrens 1516789Sahrens default: 1517789Sahrens zfs_baderror(EINVAL); 1518789Sahrens } 1519789Sahrens 1520789Sahrens get_source(zhp, src, source, statbuf, statlen); 1521789Sahrens 1522789Sahrens return (0); 1523789Sahrens } 1524789Sahrens 1525789Sahrens /* 1526789Sahrens * Utility function to get the given numeric property. Does no validation that 1527789Sahrens * the given property is the appropriate type; should only be used with 1528789Sahrens * hard-coded property types. 1529789Sahrens */ 1530789Sahrens uint64_t 1531789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1532789Sahrens { 1533789Sahrens char *source; 1534789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 1535789Sahrens 1536789Sahrens return (get_numeric_property(zhp, prop, &sourcetype, &source)); 1537789Sahrens } 1538789Sahrens 1539789Sahrens /* 1540789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1541789Sahrens */ 1542789Sahrens int 1543789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1544789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1545789Sahrens { 1546789Sahrens char *source; 1547789Sahrens 1548789Sahrens /* 1549789Sahrens * Check to see if this property applies to our object 1550789Sahrens */ 1551789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1552789Sahrens return (-1); 1553789Sahrens 1554789Sahrens if (src) 1555789Sahrens *src = ZFS_SRC_NONE; 1556789Sahrens 1557789Sahrens *value = get_numeric_property(zhp, prop, src, &source); 1558789Sahrens 1559789Sahrens get_source(zhp, src, source, statbuf, statlen); 1560789Sahrens 1561789Sahrens return (0); 1562789Sahrens } 1563789Sahrens 1564789Sahrens /* 1565789Sahrens * Returns the name of the given zfs handle. 1566789Sahrens */ 1567789Sahrens const char * 1568789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1569789Sahrens { 1570789Sahrens return (zhp->zfs_name); 1571789Sahrens } 1572789Sahrens 1573789Sahrens /* 1574789Sahrens * Returns the type of the given zfs handle. 1575789Sahrens */ 1576789Sahrens zfs_type_t 1577789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1578789Sahrens { 1579789Sahrens return (zhp->zfs_type); 1580789Sahrens } 1581789Sahrens 1582789Sahrens /* 1583789Sahrens * Iterate over all children, datasets and snapshots. 1584789Sahrens */ 1585789Sahrens int 1586789Sahrens zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1587789Sahrens { 1588789Sahrens zfs_cmd_t zc = { 0 }; 1589789Sahrens zfs_handle_t *nzhp; 1590789Sahrens int ret; 1591789Sahrens 1592789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1593789Sahrens ioctl(zfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1594789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1595789Sahrens /* 1596789Sahrens * Ignore private dataset names. 1597789Sahrens */ 1598789Sahrens if (dataset_name_hidden(zc.zc_name)) 1599789Sahrens continue; 1600789Sahrens 1601789Sahrens /* 1602789Sahrens * Silently ignore errors, as the only plausible explanation is 1603789Sahrens * that the pool has since been removed. 1604789Sahrens */ 1605789Sahrens if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL) 1606789Sahrens continue; 1607789Sahrens 1608789Sahrens if ((ret = func(nzhp, data)) != 0) 1609789Sahrens return (ret); 1610789Sahrens } 1611789Sahrens 1612789Sahrens /* 1613789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1614789Sahrens * returned, then the underlying dataset has been removed since we 1615789Sahrens * obtained the handle. 1616789Sahrens */ 1617789Sahrens if (errno != ESRCH && errno != ENOENT) 1618789Sahrens zfs_baderror(errno); 1619789Sahrens 1620789Sahrens bzero(&zc, sizeof (zc)); 1621789Sahrens 1622789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1623789Sahrens ioctl(zfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; 1624789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1625789Sahrens 1626789Sahrens if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL) 1627789Sahrens continue; 1628789Sahrens 1629789Sahrens if ((ret = func(nzhp, data)) != 0) 1630789Sahrens return (ret); 1631789Sahrens } 1632789Sahrens 1633789Sahrens /* 1634789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1635789Sahrens * returned, then the underlying dataset has been removed since we 1636789Sahrens * obtained the handle. Silently ignore this case, and return success. 1637789Sahrens */ 1638789Sahrens if (errno != ESRCH && errno != ENOENT) 1639789Sahrens zfs_baderror(errno); 1640789Sahrens 1641789Sahrens return (0); 1642789Sahrens } 1643789Sahrens 1644789Sahrens /* 1645789Sahrens * Given a complete name, return just the portion that refers to the parent. 1646789Sahrens * Can return NULL if this is a pool. 1647789Sahrens */ 1648789Sahrens static int 1649789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1650789Sahrens { 1651789Sahrens char *loc; 1652789Sahrens 1653789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1654789Sahrens return (-1); 1655789Sahrens 1656789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1657789Sahrens buf[loc - path] = '\0'; 1658789Sahrens 1659789Sahrens return (0); 1660789Sahrens } 1661789Sahrens 1662789Sahrens /* 1663789Sahrens * Checks to make sure that the given path has a parent, and that it exists. 1664789Sahrens */ 1665789Sahrens static int 1666789Sahrens check_parents(const char *path, zfs_type_t type) 1667789Sahrens { 1668789Sahrens zfs_cmd_t zc = { 0 }; 1669789Sahrens char parent[ZFS_MAXNAMELEN]; 1670789Sahrens char *slash; 1671789Sahrens 1672789Sahrens /* get parent, and check to see if this is just a pool */ 1673789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 1674789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1675789Sahrens "cannot create '%s': missing dataset name"), 1676789Sahrens path, zfs_type_to_name(type)); 1677789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1678789Sahrens "use 'zpool create' to create a storage pool")); 1679789Sahrens return (-1); 1680789Sahrens } 1681789Sahrens 1682789Sahrens /* check to see if the pool exists */ 1683789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1684789Sahrens slash = parent + strlen(parent); 1685789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1686789Sahrens zc.zc_name[slash - parent] = '\0'; 1687789Sahrens if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1688789Sahrens errno == ENOENT) { 1689789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1690789Sahrens "cannot create '%s': no such pool '%s'"), path, zc.zc_name); 1691789Sahrens return (-1); 1692789Sahrens } 1693789Sahrens 1694789Sahrens /* check to see if the parent dataset exists */ 1695789Sahrens (void) strlcpy(zc.zc_name, parent, sizeof (zc.zc_name)); 1696789Sahrens if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 1697789Sahrens switch (errno) { 1698789Sahrens case ENOENT: 1699789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1700789Sahrens "cannot create '%s': parent does not exist"), path); 1701789Sahrens return (-1); 1702789Sahrens 1703789Sahrens default: 1704789Sahrens zfs_baderror(errno); 1705789Sahrens } 1706789Sahrens } 1707789Sahrens 1708789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 1709789Sahrens if (getzoneid() != GLOBAL_ZONEID && !zc.zc_objset_stats.dds_zoned) { 1710789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1711789Sahrens "cannot create '%s': permission denied"), path); 1712789Sahrens return (-1); 1713789Sahrens } 1714789Sahrens 1715789Sahrens /* make sure parent is a filesystem */ 1716789Sahrens if (zc.zc_objset_stats.dds_type != DMU_OST_ZFS) { 1717789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1718789Sahrens "cannot create '%s': parent is not a filesystem"), 1719789Sahrens path); 1720789Sahrens return (-1); 1721789Sahrens } 1722789Sahrens 1723789Sahrens return (0); 1724789Sahrens } 1725789Sahrens 1726789Sahrens /* 1727789Sahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used 1728789Sahrens * only for volumes, and indicate the size and blocksize of the volume. 1729789Sahrens */ 1730789Sahrens int 1731789Sahrens zfs_create(const char *path, zfs_type_t type, 1732789Sahrens const char *sizestr, const char *blocksizestr) 1733789Sahrens { 1734789Sahrens char reason[64]; 1735789Sahrens zfs_cmd_t zc = { 0 }; 1736789Sahrens int ret; 1737789Sahrens uint64_t size = 0; 1738789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 1739789Sahrens 1740789Sahrens /* convert sizestr into integer size */ 1741789Sahrens if (sizestr != NULL && nicestrtonum(sizestr, &size, 1742789Sahrens reason, sizeof (reason)) != 0) { 1743789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1744789Sahrens "bad volume size '%s': %s"), sizestr, reason); 1745789Sahrens return (-1); 1746789Sahrens } 1747789Sahrens 1748789Sahrens /* convert blocksizestr into integer blocksize */ 1749789Sahrens if (blocksizestr != NULL && nicestrtonum(blocksizestr, &blocksize, 1750789Sahrens reason, sizeof (reason)) != 0) { 1751789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1752789Sahrens "bad volume blocksize '%s': %s"), blocksizestr, reason); 1753789Sahrens return (-1); 1754789Sahrens } 1755789Sahrens 1756789Sahrens /* validate the path, taking care to note the extended error message */ 1757789Sahrens if (!zfs_validate_name(path, type, reason, sizeof (reason))) { 1758789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1759789Sahrens "cannot create '%s': %s in %s name"), path, reason, 1760789Sahrens zfs_type_to_name(type)); 1761789Sahrens if (strstr(reason, "snapshot") != NULL) 1762789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1763789Sahrens "use 'zfs snapshot' to create a snapshot")); 1764789Sahrens return (-1); 1765789Sahrens } 1766789Sahrens 1767789Sahrens /* validate parents exist */ 1768789Sahrens if (check_parents(path, type) != 0) 1769789Sahrens return (-1); 1770789Sahrens 1771789Sahrens /* 1772789Sahrens * The failure modes when creating a dataset of a different type over 1773789Sahrens * one that already exists is a little strange. In particular, if you 1774789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1775789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1776789Sahrens * first try to see if the dataset exists. 1777789Sahrens */ 1778789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 1779789Sahrens if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 1780789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1781789Sahrens "cannot create '%s': dataset exists"), path); 1782789Sahrens return (-1); 1783789Sahrens } 1784789Sahrens 1785789Sahrens if (type == ZFS_TYPE_VOLUME) 1786789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1787789Sahrens else 1788789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1789789Sahrens 1790789Sahrens if (type == ZFS_TYPE_VOLUME) { 17911133Seschrock /* 17921133Seschrock * If we are creating a volume, the size and block size must 17931133Seschrock * satisfy a few restraints. First, the blocksize must be a 17941133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 17951133Seschrock * volsize must be a multiple of the block size, and cannot be 17961133Seschrock * zero. 17971133Seschrock */ 1798789Sahrens if (size == 0) { 1799789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1800789Sahrens "bad volume size '%s': cannot be zero"), sizestr); 1801789Sahrens return (-1); 1802789Sahrens } 1803789Sahrens 18041133Seschrock if (blocksize < SPA_MINBLOCKSIZE || 18051133Seschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) { 18061133Seschrock zfs_error(dgettext(TEXT_DOMAIN, 18071133Seschrock "bad volume block size '%s': " 18081133Seschrock "must be power of 2 from %u to %uk"), 18091133Seschrock blocksizestr, 18101133Seschrock (uint_t)SPA_MINBLOCKSIZE, 18111133Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 18121133Seschrock return (-1); 18131133Seschrock } 18141133Seschrock 18151133Seschrock if (size % blocksize != 0) { 18161133Seschrock char buf[64]; 18171133Seschrock zfs_nicenum(blocksize, buf, sizeof (buf)); 18181133Seschrock zfs_error(dgettext(TEXT_DOMAIN, 18191133Seschrock "bad volume size '%s': " 18201133Seschrock "must be multiple of volume block size (%s)"), 18211133Seschrock sizestr, buf); 18221133Seschrock return (-1); 18231133Seschrock } 18241133Seschrock 1825789Sahrens zc.zc_volsize = size; 1826789Sahrens zc.zc_volblocksize = blocksize; 1827789Sahrens } 1828789Sahrens 1829789Sahrens /* create the dataset */ 1830789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_CREATE, &zc); 1831789Sahrens 1832789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 1833789Sahrens ret = zvol_create_link(path); 1834789Sahrens 1835789Sahrens /* check for failure */ 1836789Sahrens if (ret != 0) { 1837789Sahrens char parent[ZFS_MAXNAMELEN]; 1838789Sahrens (void) parent_name(path, parent, sizeof (parent)); 1839789Sahrens 1840789Sahrens switch (errno) { 1841789Sahrens case ENOENT: 1842789Sahrens /* 1843789Sahrens * The parent dataset has been deleted since our 1844789Sahrens * previous check. 1845789Sahrens */ 1846789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1847789Sahrens "cannot create '%s': no such parent '%s'"), 1848789Sahrens path, parent); 1849789Sahrens break; 1850789Sahrens 1851789Sahrens case EPERM: 1852789Sahrens /* 1853789Sahrens * The user doesn't have permission to create a new 1854789Sahrens * dataset here. 1855789Sahrens */ 1856789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1857789Sahrens "cannot create '%s': permission denied"), path); 1858789Sahrens break; 1859789Sahrens 1860789Sahrens case EDQUOT: 1861789Sahrens case ENOSPC: 1862789Sahrens /* 1863789Sahrens * The parent dataset does not have enough free space 1864789Sahrens * to create a new dataset. 1865789Sahrens */ 1866789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1867789Sahrens "cannot create '%s': not enough space in '%s'"), 1868789Sahrens path, parent); 1869789Sahrens break; 1870789Sahrens 1871789Sahrens case EEXIST: 1872789Sahrens /* 1873789Sahrens * The target dataset already exists. We should have 1874789Sahrens * caught this above, but there may be some unexplained 1875789Sahrens * race condition. 1876789Sahrens */ 1877789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1878789Sahrens "cannot create '%s': dataset exists"), path); 1879789Sahrens break; 1880789Sahrens 1881789Sahrens case EINVAL: 1882789Sahrens /* 1883789Sahrens * The target dataset does not support children. 1884789Sahrens */ 1885789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1886789Sahrens "cannot create '%s': children unsupported in '%s'"), 1887789Sahrens path, parent); 1888789Sahrens break; 1889789Sahrens 1890789Sahrens case EDOM: 1891789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "bad %s value '%s': " 1892789Sahrens "must be power of 2 from %u to %uk"), 1893789Sahrens zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1894789Sahrens blocksizestr ? blocksizestr : "<unknown>", 1895789Sahrens (uint_t)SPA_MINBLOCKSIZE, 1896789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 1897789Sahrens break; 1898789Sahrens #ifdef _ILP32 1899789Sahrens case EOVERFLOW: 1900789Sahrens /* 1901789Sahrens * This platform can't address a volume this big. 1902789Sahrens */ 1903789Sahrens if (type == ZFS_TYPE_VOLUME) { 1904789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1905789Sahrens "cannot create '%s': " 1906789Sahrens "max volume size is 1TB on 32-bit systems"), 1907789Sahrens path); 1908789Sahrens break; 1909789Sahrens } 1910789Sahrens #endif 1911789Sahrens 1912789Sahrens default: 1913789Sahrens zfs_baderror(errno); 1914789Sahrens } 1915789Sahrens 1916789Sahrens return (-1); 1917789Sahrens } 1918789Sahrens 1919789Sahrens return (0); 1920789Sahrens } 1921789Sahrens 1922789Sahrens /* 1923789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 1924789Sahrens * isn't mounted, and that there are no active dependents. 1925789Sahrens */ 1926789Sahrens int 1927789Sahrens zfs_destroy(zfs_handle_t *zhp) 1928789Sahrens { 1929789Sahrens zfs_cmd_t zc = { 0 }; 1930789Sahrens int ret; 1931789Sahrens 1932789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1933789Sahrens 1934789Sahrens /* 1935789Sahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME 1936789Sahrens * so that we do the right thing for snapshots of volumes. 1937789Sahrens */ 1938789Sahrens if (zhp->zfs_volblocksize != 0) { 1939789Sahrens if (zvol_remove_link(zhp->zfs_name) != 0) 1940789Sahrens return (-1); 1941789Sahrens 1942789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1943789Sahrens } else { 1944789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1945789Sahrens } 1946789Sahrens 1947789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc); 1948789Sahrens 1949789Sahrens if (ret != 0) { 1950789Sahrens switch (errno) { 1951789Sahrens 1952789Sahrens case EPERM: 1953789Sahrens /* 1954789Sahrens * We don't have permission to destroy this dataset. 1955789Sahrens */ 1956789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1957789Sahrens "cannot destroy '%s': permission denied"), 1958789Sahrens zhp->zfs_name); 1959789Sahrens break; 1960789Sahrens 1961789Sahrens case ENOENT: 1962789Sahrens /* 1963789Sahrens * We've hit a race condition where the dataset has been 1964789Sahrens * destroyed since we opened it. 1965789Sahrens */ 1966789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1967789Sahrens "cannot destroy '%s': no such %s"), 1968789Sahrens zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 1969789Sahrens break; 1970789Sahrens 1971789Sahrens case EBUSY: 1972789Sahrens /* 1973789Sahrens * Even if we destroy all children, there is a chance we 1974789Sahrens * can hit this case if: 1975789Sahrens * 1976789Sahrens * - A child dataset has since been created 1977789Sahrens * - A filesystem is mounted 1978789Sahrens * 1979789Sahrens * This error message is awful, but hopefully we've 1980789Sahrens * already caught the common cases (and aborted more 1981789Sahrens * appropriately) before calling this function. There's 1982789Sahrens * nothing else we can do at this point. 1983789Sahrens */ 1984789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 1985789Sahrens "cannot destroy '%s': %s is busy"), 1986789Sahrens zhp->zfs_name, zfs_type_to_name(zhp->zfs_type)); 1987789Sahrens break; 1988789Sahrens 1989789Sahrens default: 1990789Sahrens zfs_baderror(errno); 1991789Sahrens } 1992789Sahrens 1993789Sahrens return (-1); 1994789Sahrens } 1995789Sahrens 1996789Sahrens remove_mountpoint(zhp); 1997789Sahrens 1998789Sahrens return (0); 1999789Sahrens } 2000789Sahrens 2001789Sahrens /* 2002789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2003789Sahrens */ 2004789Sahrens int 2005789Sahrens zfs_clone(zfs_handle_t *zhp, const char *target) 2006789Sahrens { 2007789Sahrens char reason[64]; 2008789Sahrens zfs_cmd_t zc = { 0 }; 2009789Sahrens char parent[ZFS_MAXNAMELEN]; 2010789Sahrens int ret; 2011789Sahrens 2012789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2013789Sahrens 2014789Sahrens /* validate the target name */ 2015789Sahrens if (!zfs_validate_name(target, ZFS_TYPE_FILESYSTEM, reason, 2016789Sahrens sizeof (reason))) { 2017789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2018789Sahrens "cannot create '%s': %s in filesystem name"), target, 2019789Sahrens reason, zfs_type_to_name(ZFS_TYPE_FILESYSTEM)); 2020789Sahrens return (-1); 2021789Sahrens } 2022789Sahrens 2023789Sahrens /* validate parents exist */ 2024789Sahrens if (check_parents(target, zhp->zfs_type) != 0) 2025789Sahrens return (-1); 2026789Sahrens 2027789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2028789Sahrens 2029789Sahrens /* do the clone */ 2030789Sahrens if (zhp->zfs_volblocksize != 0) 2031789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2032789Sahrens else 2033789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2034789Sahrens 2035789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2036789Sahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename)); 2037789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_CREATE, &zc); 2038789Sahrens 2039789Sahrens if (ret != 0) { 2040789Sahrens switch (errno) { 2041789Sahrens case EPERM: 2042789Sahrens /* 2043789Sahrens * The user doesn't have permission to create the clone. 2044789Sahrens */ 2045789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2046789Sahrens "cannot create '%s': permission denied"), 2047789Sahrens target); 2048789Sahrens break; 2049789Sahrens 2050789Sahrens case ENOENT: 2051789Sahrens /* 2052789Sahrens * The parent doesn't exist. We should have caught this 2053789Sahrens * above, but there may a race condition that has since 2054789Sahrens * destroyed the parent. 2055789Sahrens * 2056789Sahrens * At this point, we don't know whether it's the source 2057789Sahrens * that doesn't exist anymore, or whether the target 2058789Sahrens * dataset doesn't exist. 2059789Sahrens */ 2060789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2061789Sahrens "cannot create '%s': no such parent '%s'"), 2062789Sahrens target, parent); 2063789Sahrens break; 2064789Sahrens 2065789Sahrens case EDQUOT: 2066789Sahrens case ENOSPC: 2067789Sahrens /* 2068789Sahrens * There is not enough space in the target dataset 2069789Sahrens */ 2070789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2071789Sahrens "cannot create '%s': not enough space in '%s'"), 2072789Sahrens target, parent); 2073789Sahrens break; 2074789Sahrens 2075789Sahrens case EEXIST: 2076789Sahrens /* 2077789Sahrens * The target already exists. 2078789Sahrens */ 2079789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2080789Sahrens "cannot create '%s': dataset exists"), target); 2081789Sahrens break; 2082789Sahrens 2083789Sahrens case EXDEV: 2084789Sahrens /* 2085789Sahrens * The source and target pools differ. 2086789Sahrens */ 2087789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2088789Sahrens "source and target pools differ"), target); 2089789Sahrens break; 2090789Sahrens 2091789Sahrens default: 2092789Sahrens zfs_baderror(errno); 2093789Sahrens } 2094789Sahrens } else if (zhp->zfs_volblocksize != 0) { 2095789Sahrens ret = zvol_create_link(target); 2096789Sahrens } 2097789Sahrens 2098789Sahrens return (ret); 2099789Sahrens } 2100789Sahrens 2101789Sahrens /* 2102789Sahrens * Takes a snapshot of the given dataset 2103789Sahrens */ 2104789Sahrens int 2105789Sahrens zfs_snapshot(const char *path) 2106789Sahrens { 2107789Sahrens char reason[64]; 2108789Sahrens const char *delim; 2109789Sahrens char *parent; 2110789Sahrens zfs_handle_t *zhp; 2111789Sahrens zfs_cmd_t zc = { 0 }; 2112789Sahrens int ret; 2113789Sahrens 2114789Sahrens /* validate the snapshot name */ 2115789Sahrens if (!zfs_validate_name(path, ZFS_TYPE_SNAPSHOT, reason, 2116789Sahrens sizeof (reason))) { 2117789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2118789Sahrens "cannot snapshot '%s': %s in snapshot name"), path, 2119789Sahrens reason); 2120789Sahrens return (-1); 2121789Sahrens } 2122789Sahrens 2123789Sahrens /* make sure we have a snapshot */ 2124789Sahrens if ((delim = strchr(path, '@')) == NULL) { 2125789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2126789Sahrens "cannot snapshot '%s': missing '@' delim in snapshot " 2127789Sahrens "name"), path); 2128789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2129789Sahrens "use 'zfs create' to create a filesystem")); 2130789Sahrens return (-1); 2131789Sahrens } 2132789Sahrens 2133789Sahrens /* make sure the parent exists and is of the appropriate type */ 2134789Sahrens parent = zfs_malloc(delim - path + 1); 2135789Sahrens (void) strncpy(parent, path, delim - path); 2136789Sahrens parent[delim - path] = '\0'; 2137789Sahrens 2138789Sahrens if ((zhp = zfs_open(parent, ZFS_TYPE_FILESYSTEM | 2139789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2140789Sahrens free(parent); 2141789Sahrens return (-1); 2142789Sahrens } 2143789Sahrens 2144789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2145789Sahrens 2146789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) 2147789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2148789Sahrens else 2149789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2150789Sahrens 2151789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_CREATE, &zc); 2152789Sahrens 2153789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 2154789Sahrens ret = zvol_create_link(path); 2155789Sahrens if (ret != 0) 2156789Sahrens (void) ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc); 2157789Sahrens } 2158789Sahrens 2159789Sahrens if (ret != 0) { 2160789Sahrens switch (errno) { 2161789Sahrens case EPERM: 2162789Sahrens /* 2163789Sahrens * User doesn't have permission to create a snapshot 2164789Sahrens */ 2165789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2166789Sahrens "permission denied"), path); 2167789Sahrens break; 2168789Sahrens 2169789Sahrens case EDQUOT: 2170789Sahrens case ENOSPC: 2171789Sahrens /* 2172789Sahrens * Out of space in parent. 2173789Sahrens */ 2174789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2175789Sahrens "not enough space in '%s'"), path, parent); 2176789Sahrens break; 2177789Sahrens 2178789Sahrens case EEXIST: 2179789Sahrens /* 2180789Sahrens * Snapshot already exists. 2181789Sahrens */ 2182789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': " 2183789Sahrens "snapshot exists"), path); 2184789Sahrens break; 2185789Sahrens 2186789Sahrens case ENOENT: 2187789Sahrens /* 2188789Sahrens * Shouldn't happen because we verified the parent 2189789Sahrens * above. But there may be a race condition where it 2190789Sahrens * has since been removed. 2191789Sahrens */ 2192789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': " 2193789Sahrens "no such %s"), parent, 2194789Sahrens zfs_type_to_name(zhp->zfs_type)); 2195789Sahrens break; 2196789Sahrens 2197789Sahrens default: 2198789Sahrens zfs_baderror(errno); 2199789Sahrens } 2200789Sahrens } 2201789Sahrens 2202789Sahrens free(parent); 2203789Sahrens zfs_close(zhp); 2204789Sahrens 2205789Sahrens return (ret); 2206789Sahrens } 2207789Sahrens 2208789Sahrens /* 2209789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2210789Sahrens */ 2211789Sahrens int 2212789Sahrens zfs_backup(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2213789Sahrens { 2214789Sahrens zfs_cmd_t zc = { 0 }; 2215789Sahrens int ret; 2216789Sahrens 2217789Sahrens /* do the ioctl() */ 2218789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2219789Sahrens if (zhp_from) { 2220789Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2221789Sahrens sizeof (zc.zc_name)); 2222789Sahrens } else { 2223789Sahrens zc.zc_prop_value[0] = '\0'; 2224789Sahrens } 2225789Sahrens zc.zc_cookie = STDOUT_FILENO; 2226789Sahrens 2227789Sahrens ret = ioctl(zfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2228789Sahrens if (ret != 0) { 2229789Sahrens switch (errno) { 2230789Sahrens case EPERM: 2231789Sahrens /* 2232789Sahrens * User doesn't have permission to do a backup 2233789Sahrens */ 2234789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot backup '%s': " 2235789Sahrens "permission denied"), zhp_to->zfs_name); 2236789Sahrens break; 2237789Sahrens 2238789Sahrens case EXDEV: 2239789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2240789Sahrens "cannot do incremental backup from %s:\n" 2241789Sahrens "it is not an earlier snapshot from the " 2242789Sahrens "same fs as %s"), 2243789Sahrens zhp_from->zfs_name, zhp_to->zfs_name); 2244789Sahrens break; 2245789Sahrens 2246789Sahrens case ENOENT: 2247789Sahrens /* 2248789Sahrens * Shouldn't happen because we verified the parent 2249789Sahrens * above. But there may be a race condition where it 2250789Sahrens * has since been removed. 2251789Sahrens */ 2252789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot open: " 2253789Sahrens "no such snapshot")); 2254789Sahrens break; 2255789Sahrens 2256789Sahrens case EDQUOT: 2257789Sahrens case EFBIG: 2258789Sahrens case EIO: 2259789Sahrens case ENOLINK: 2260789Sahrens case ENOSPC: 2261789Sahrens case ENOSTR: 2262789Sahrens case ENXIO: 2263789Sahrens case EPIPE: 2264789Sahrens case ERANGE: 2265789Sahrens case EFAULT: 2266789Sahrens case EROFS: 2267789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2268789Sahrens "cannot write backup stream: %s"), 2269789Sahrens strerror(errno)); 2270789Sahrens break; 2271789Sahrens 2272789Sahrens case EINTR: 2273789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2274789Sahrens "backup failed: signal recieved")); 2275789Sahrens break; 2276789Sahrens 2277789Sahrens default: 2278789Sahrens zfs_baderror(errno); 2279789Sahrens } 2280789Sahrens } 2281789Sahrens 2282789Sahrens return (ret); 2283789Sahrens } 2284789Sahrens 2285789Sahrens /* 2286789Sahrens * Restores a backup of tosnap from stdin. 2287789Sahrens */ 2288789Sahrens int 2289789Sahrens zfs_restore(const char *tosnap, int isprefix, int verbose, int dryrun) 2290789Sahrens { 2291789Sahrens zfs_cmd_t zc = { 0 }; 2292789Sahrens time_t begin_time; 2293868Sahrens int ioctl_err, err, bytes, size; 2294789Sahrens char *cp; 2295789Sahrens dmu_replay_record_t drr; 2296789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 2297789Sahrens 2298789Sahrens begin_time = time(NULL); 2299789Sahrens 2300789Sahrens /* trim off snapname, if any */ 2301789Sahrens (void) strcpy(zc.zc_name, tosnap); 2302789Sahrens cp = strchr(zc.zc_name, '@'); 2303789Sahrens if (cp) 2304789Sahrens *cp = '\0'; 2305789Sahrens 2306789Sahrens /* read in the BEGIN record */ 2307789Sahrens cp = (char *)&drr; 2308789Sahrens bytes = 0; 2309789Sahrens do { 2310868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2311868Sahrens cp += size; 2312868Sahrens bytes += size; 2313868Sahrens } while (size > 0); 2314868Sahrens 2315868Sahrens if (size < 0 || bytes != sizeof (drr)) { 2316789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2317868Sahrens "cannot restore: invalid backup stream " 2318789Sahrens "(couldn't read first record)")); 2319789Sahrens return (-1); 2320789Sahrens } 2321789Sahrens 2322789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2323789Sahrens 2324789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2325789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 2326789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2327868Sahrens "cannot restore: invalid backup stream " 2328789Sahrens "(invalid magic number)")); 2329789Sahrens return (-1); 2330789Sahrens } 2331789Sahrens 2332789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2333789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 2334789Sahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 2335789Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 2336789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2337868Sahrens "cannot restore: only backup version 0x%llx is supported, " 2338789Sahrens "stream is version %llx."), 2339789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 2340789Sahrens return (-1); 2341789Sahrens } 2342789Sahrens 2343789Sahrens /* 2344789Sahrens * Determine name of destination snapshot. 2345789Sahrens */ 2346789Sahrens (void) strcpy(drrb->drr_toname, tosnap); 2347789Sahrens if (isprefix) { 2348789Sahrens if (strchr(tosnap, '@') != NULL) { 2349789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2350868Sahrens "cannot restore: " 2351789Sahrens "argument to -d must be a filesystem")); 2352789Sahrens return (-1); 2353789Sahrens } 2354789Sahrens 2355789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2356789Sahrens if (cp == NULL) 2357789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2358789Sahrens else 2359789Sahrens cp++; 2360789Sahrens 2361789Sahrens (void) strcat(drrb->drr_toname, "/"); 2362789Sahrens (void) strcat(drrb->drr_toname, cp); 2363789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2364789Sahrens /* 2365789Sahrens * they specified just a filesystem; tack on the 2366789Sahrens * snapname from the backup. 2367789Sahrens */ 2368789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 2369789Sahrens if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) { 2370789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2371868Sahrens "cannot restore: invalid backup stream " 2372789Sahrens "(invalid snapshot name)")); 2373789Sahrens return (-1); 2374789Sahrens } 2375789Sahrens (void) strcat(drrb->drr_toname, cp); 2376789Sahrens } 2377789Sahrens 2378789Sahrens if (drrb->drr_fromguid) { 2379789Sahrens zfs_handle_t *h; 2380789Sahrens /* incremental backup stream */ 2381789Sahrens 2382789Sahrens /* do the ioctl to the containing fs */ 2383789Sahrens (void) strcpy(zc.zc_name, drrb->drr_toname); 2384789Sahrens cp = strchr(zc.zc_name, '@'); 2385789Sahrens *cp = '\0'; 2386789Sahrens 2387789Sahrens /* make sure destination fs exists */ 2388789Sahrens h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2389789Sahrens if (h == NULL) { 2390789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2391868Sahrens "cannot restore incrememtal backup: destination\n" 2392789Sahrens "filesystem %s does not exist"), 2393789Sahrens zc.zc_name); 2394789Sahrens return (-1); 2395789Sahrens } 2396868Sahrens if (!dryrun) { 2397868Sahrens /* unmount destination fs or remove device link. */ 2398868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2399868Sahrens (void) zfs_unmount(h, NULL, 0); 2400868Sahrens } else { 2401868Sahrens (void) zvol_remove_link(h->zfs_name); 2402868Sahrens } 2403868Sahrens } 2404789Sahrens zfs_close(h); 2405789Sahrens } else { 2406789Sahrens /* full backup stream */ 2407789Sahrens 2408789Sahrens (void) strcpy(zc.zc_name, drrb->drr_toname); 2409868Sahrens 2410868Sahrens /* make sure they aren't trying to restore into the root */ 2411868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2412789Sahrens cp = strchr(zc.zc_name, '@'); 2413789Sahrens if (cp) 2414789Sahrens *cp = '\0'; 2415789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2416868Sahrens "cannot restore: destination fs %s already exists"), 2417789Sahrens zc.zc_name); 2418789Sahrens return (-1); 2419789Sahrens } 2420789Sahrens 2421789Sahrens if (isprefix) { 2422868Sahrens zfs_handle_t *h; 2423868Sahrens 2424789Sahrens /* make sure prefix exists */ 2425789Sahrens h = zfs_open(tosnap, ZFS_TYPE_FILESYSTEM | 2426789Sahrens ZFS_TYPE_VOLUME); 2427789Sahrens if (h == NULL) { 2428789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2429868Sahrens "cannot restore: " 2430789Sahrens "filesystem %s does not exist"), 2431789Sahrens tosnap); 2432789Sahrens return (-1); 2433789Sahrens } 2434789Sahrens 2435789Sahrens /* create any necessary ancestors up to prefix */ 2436868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2437868Sahrens /* 2438868Sahrens * zc.zc_name is now the full name of the snap 2439868Sahrens * we're restoring into 2440868Sahrens */ 2441789Sahrens cp = zc.zc_name + strlen(tosnap) + 1; 2442789Sahrens while (cp = strchr(cp, '/')) { 2443789Sahrens *cp = '\0'; 2444789Sahrens err = ioctl(zfs_fd, ZFS_IOC_CREATE, &zc); 2445868Sahrens if (err && errno != ENOENT && errno != EEXIST) { 2446789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2447868Sahrens "cannot restore: " 2448789Sahrens "couldn't create ancestor %s"), 2449789Sahrens zc.zc_name); 2450789Sahrens return (-1); 2451789Sahrens } 2452868Sahrens *cp = '/'; 2453868Sahrens cp++; 2454789Sahrens } 2455789Sahrens } 2456868Sahrens 2457868Sahrens /* Make sure destination fs does not exist */ 2458868Sahrens cp = strchr(zc.zc_name, '@'); 2459868Sahrens *cp = '\0'; 2460868Sahrens if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2461868Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2462868Sahrens "cannot restore full backup: " 2463868Sahrens "destination filesystem %s already exists"), 2464868Sahrens zc.zc_name); 2465868Sahrens return (-1); 2466868Sahrens } 2467868Sahrens 2468868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2469868Sahrens cp = strrchr(zc.zc_name, '/'); 2470868Sahrens *cp = '\0'; 2471789Sahrens } 2472789Sahrens 2473789Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2474789Sahrens zc.zc_cookie = STDIN_FILENO; 2475789Sahrens zc.zc_intsz = isprefix; 2476789Sahrens if (verbose) { 2477789Sahrens (void) printf("%s %s backup of %s into %s\n", 2478789Sahrens dryrun ? "would restore" : "restoring", 2479789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2480789Sahrens drr.drr_u.drr_begin.drr_toname, 2481789Sahrens zc.zc_begin_record.drr_toname); 2482789Sahrens (void) fflush(stdout); 2483789Sahrens } 2484789Sahrens if (dryrun) 2485789Sahrens return (0); 2486868Sahrens err = ioctl_err = ioctl(zfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2487868Sahrens if (ioctl_err != 0) { 2488789Sahrens switch (errno) { 2489789Sahrens case ENODEV: 2490789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2491868Sahrens "cannot restore: " 2492868Sahrens "most recent snapshot does not " 2493789Sahrens "match incremental backup source")); 2494789Sahrens break; 2495789Sahrens case ETXTBSY: 2496789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2497868Sahrens "cannot restore: " 2498868Sahrens "destination has been modified since " 2499868Sahrens "most recent snapshot --\n" 2500868Sahrens "use 'zfs rollback' to discard changes")); 2501789Sahrens break; 2502789Sahrens case EEXIST: 2503789Sahrens if (drrb->drr_fromguid == 0) { 2504789Sahrens /* it's the containing fs that exists */ 2505789Sahrens cp = strchr(drrb->drr_toname, '@'); 2506789Sahrens *cp = '\0'; 2507789Sahrens } 2508789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2509868Sahrens "cannot restore to %s: destination already exists"), 2510789Sahrens drrb->drr_toname); 2511789Sahrens break; 2512789Sahrens case ENOENT: 2513789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2514868Sahrens "cannot restore: destination does not exist")); 2515789Sahrens break; 2516789Sahrens case EBUSY: 2517789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2518868Sahrens "cannot restore: destination is in use")); 2519789Sahrens break; 2520789Sahrens case ENOSPC: 2521789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2522868Sahrens "cannot restore: out of space")); 2523789Sahrens break; 2524789Sahrens case EDQUOT: 2525789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2526868Sahrens "cannot restore: quota exceeded")); 2527789Sahrens break; 2528789Sahrens case EINTR: 2529789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2530868Sahrens "restore failed: signal recieved")); 2531789Sahrens break; 2532789Sahrens case EINVAL: 2533789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2534868Sahrens "cannot restore: invalid backup stream")); 2535868Sahrens break; 2536868Sahrens case EPERM: 2537868Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2538868Sahrens "cannot restore: permission denied")); 2539789Sahrens break; 2540789Sahrens default: 2541789Sahrens zfs_baderror(errno); 2542789Sahrens } 2543789Sahrens } 2544789Sahrens 2545789Sahrens /* 2546868Sahrens * Mount or recreate the /dev links for the target filesystem 2547868Sahrens * (if created, or if we tore them down to do an incremental 2548868Sahrens * restore), and the /dev links for the new snapshot (if 2549868Sahrens * created). 2550789Sahrens */ 2551789Sahrens cp = strchr(drrb->drr_toname, '@'); 2552868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2553789Sahrens zfs_handle_t *h; 2554789Sahrens 2555789Sahrens *cp = '\0'; 2556789Sahrens h = zfs_open(drrb->drr_toname, 2557789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2558868Sahrens *cp = '@'; 2559789Sahrens if (h) { 2560868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2561789Sahrens err = zfs_mount(h, NULL, 0); 2562868Sahrens } else { 2563789Sahrens err = zvol_create_link(h->zfs_name); 2564868Sahrens if (err == 0 && ioctl_err == 0) { 2565868Sahrens err = 2566868Sahrens zvol_create_link(drrb->drr_toname); 2567868Sahrens } 2568868Sahrens } 2569789Sahrens zfs_close(h); 2570789Sahrens } 2571789Sahrens } 2572789Sahrens 2573868Sahrens if (err || ioctl_err) 2574868Sahrens return (-1); 2575789Sahrens 2576789Sahrens if (verbose) { 2577789Sahrens char buf1[64]; 2578789Sahrens char buf2[64]; 2579789Sahrens uint64_t bytes = zc.zc_cookie; 2580789Sahrens time_t delta = time(NULL) - begin_time; 2581789Sahrens if (delta == 0) 2582789Sahrens delta = 1; 2583789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2584789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2585789Sahrens 2586789Sahrens (void) printf("restored %sb backup in %lu seconds (%sb/sec)\n", 2587789Sahrens buf1, delta, buf2); 2588789Sahrens } 2589789Sahrens return (0); 2590789Sahrens } 2591789Sahrens 2592789Sahrens /* 2593*1294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 2594*1294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 2595*1294Slling * is a dependent and we should just destroy it without checking the transaction 2596*1294Slling * group. 2597789Sahrens */ 2598*1294Slling typedef struct rollback_data { 2599*1294Slling const char *cb_target; /* the snapshot */ 2600*1294Slling uint64_t cb_create; /* creation time reference */ 2601*1294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 2602*1294Slling int cb_error; 2603*1294Slling int cb_dependent; 2604*1294Slling } rollback_data_t; 2605*1294Slling 2606*1294Slling static int 2607*1294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 2608*1294Slling { 2609*1294Slling rollback_data_t *cbp = data; 2610*1294Slling 2611*1294Slling if (!cbp->cb_dependent) { 2612*1294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 2613*1294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 2614*1294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 2615*1294Slling cbp->cb_create) { 2616*1294Slling 2617*1294Slling cbp->cb_dependent = TRUE; 2618*1294Slling (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 2619*1294Slling cbp->cb_dependent = FALSE; 2620*1294Slling 2621*1294Slling if (zfs_destroy(zhp) != 0) 2622*1294Slling cbp->cb_error = 1; 2623*1294Slling else 2624*1294Slling changelist_remove(zhp, cbp->cb_clp); 2625*1294Slling } 2626*1294Slling } else { 2627*1294Slling if (zfs_destroy(zhp) != 0) 2628*1294Slling cbp->cb_error = 1; 2629*1294Slling else 2630*1294Slling changelist_remove(zhp, cbp->cb_clp); 2631*1294Slling } 2632*1294Slling 2633*1294Slling zfs_close(zhp); 2634*1294Slling return (0); 2635*1294Slling } 2636*1294Slling 2637*1294Slling /* 2638*1294Slling * Rollback the dataset to its latest snapshot. 2639*1294Slling */ 2640*1294Slling static int 2641*1294Slling do_rollback(zfs_handle_t *zhp) 2642789Sahrens { 2643789Sahrens int ret; 2644789Sahrens zfs_cmd_t zc = { 0 }; 2645789Sahrens 2646789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2647789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2648789Sahrens 2649789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 2650789Sahrens zvol_remove_link(zhp->zfs_name) != 0) 2651789Sahrens return (-1); 2652789Sahrens 2653789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2654789Sahrens 2655789Sahrens if (zhp->zfs_volblocksize != 0) 2656789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2657789Sahrens else 2658789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2659789Sahrens 2660789Sahrens /* 2661789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2662789Sahrens * for the given dataset. Given these constraints, we can simply pass 2663789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2664789Sahrens * condition where the user has taken a snapshot since we verified that 2665789Sahrens * this was the most recent. 2666789Sahrens */ 2667789Sahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_ROLLBACK, &zc)) != 0) { 2668789Sahrens switch (errno) { 2669789Sahrens case EPERM: 2670789Sahrens /* 2671789Sahrens * The user doesn't have permission to rollback the 2672789Sahrens * given dataset. 2673789Sahrens */ 2674789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2675789Sahrens "permission denied"), zhp->zfs_name); 2676789Sahrens break; 2677789Sahrens 2678789Sahrens case EDQUOT: 2679789Sahrens case ENOSPC: 2680789Sahrens /* 2681789Sahrens * The parent dataset doesn't have enough space to 2682789Sahrens * rollback to the last snapshot. 2683789Sahrens */ 2684789Sahrens { 2685789Sahrens char parent[ZFS_MAXNAMELEN]; 2686789Sahrens (void) parent_name(zhp->zfs_name, parent, 2687789Sahrens sizeof (parent)); 2688789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 2689789Sahrens "rollback '%s': out of space"), parent); 2690789Sahrens } 2691789Sahrens break; 2692789Sahrens 2693789Sahrens case ENOENT: 2694789Sahrens /* 2695789Sahrens * The dataset doesn't exist. This shouldn't happen 2696789Sahrens * except in race conditions. 2697789Sahrens */ 2698789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2699789Sahrens "no such %s"), zhp->zfs_name, 2700789Sahrens zfs_type_to_name(zhp->zfs_type)); 2701789Sahrens break; 2702789Sahrens 2703789Sahrens case EBUSY: 2704789Sahrens /* 2705789Sahrens * The filesystem is busy. This should have been caught 2706789Sahrens * by the caller before getting here, but there may be 2707789Sahrens * an unexpected problem. 2708789Sahrens */ 2709789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': " 2710789Sahrens "%s is busy"), zhp->zfs_name, 2711789Sahrens zfs_type_to_name(zhp->zfs_type)); 2712789Sahrens break; 2713789Sahrens 2714789Sahrens default: 2715789Sahrens zfs_baderror(errno); 2716789Sahrens } 2717789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2718789Sahrens ret = zvol_create_link(zhp->zfs_name); 2719789Sahrens } 2720789Sahrens 2721789Sahrens return (ret); 2722789Sahrens } 2723789Sahrens 2724789Sahrens /* 2725*1294Slling * Given a dataset, rollback to a specific snapshot, discarding any 2726*1294Slling * data changes since then and making it the active dataset. 2727*1294Slling * 2728*1294Slling * Any snapshots more recent than the target are destroyed, along with 2729*1294Slling * their dependents. 2730*1294Slling */ 2731*1294Slling int 2732*1294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 2733*1294Slling { 2734*1294Slling int ret; 2735*1294Slling rollback_data_t cb = { 0 }; 2736*1294Slling prop_changelist_t *clp; 2737*1294Slling 2738*1294Slling /* 2739*1294Slling * Unmount all dependendents of the dataset and the dataset itself. 2740*1294Slling * The list we need to gather is the same as for doing rename 2741*1294Slling */ 2742*1294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 2743*1294Slling if (clp == NULL) 2744*1294Slling return (-1); 2745*1294Slling 2746*1294Slling if ((ret = changelist_prefix(clp)) != 0) 2747*1294Slling goto out; 2748*1294Slling 2749*1294Slling /* 2750*1294Slling * Destroy all recent snapshots and its dependends. 2751*1294Slling */ 2752*1294Slling cb.cb_target = snap->zfs_name; 2753*1294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 2754*1294Slling cb.cb_clp = clp; 2755*1294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 2756*1294Slling 2757*1294Slling if ((ret = cb.cb_error) != 0) { 2758*1294Slling (void) changelist_postfix(clp); 2759*1294Slling goto out; 2760*1294Slling } 2761*1294Slling 2762*1294Slling /* 2763*1294Slling * Now that we have verified that the snapshot is the latest, 2764*1294Slling * rollback to the given snapshot. 2765*1294Slling */ 2766*1294Slling ret = do_rollback(zhp); 2767*1294Slling 2768*1294Slling if (ret != 0) { 2769*1294Slling (void) changelist_postfix(clp); 2770*1294Slling goto out; 2771*1294Slling } 2772*1294Slling 2773*1294Slling /* 2774*1294Slling * We only want to re-mount the filesystem if it was mounted in the 2775*1294Slling * first place. 2776*1294Slling */ 2777*1294Slling ret = changelist_postfix(clp); 2778*1294Slling 2779*1294Slling out: 2780*1294Slling changelist_free(clp); 2781*1294Slling return (ret); 2782*1294Slling } 2783*1294Slling 2784*1294Slling /* 2785789Sahrens * Iterate over all dependents for a given dataset. This includes both 2786789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2787789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2788789Sahrens * libzfs_graph.c. 2789789Sahrens */ 2790789Sahrens int 2791789Sahrens zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2792789Sahrens { 2793789Sahrens char **dependents; 2794789Sahrens size_t count; 2795789Sahrens int i; 2796789Sahrens zfs_handle_t *child; 2797789Sahrens int ret = 0; 2798789Sahrens 2799789Sahrens dependents = get_dependents(zhp->zfs_name, &count); 2800789Sahrens for (i = 0; i < count; i++) { 2801789Sahrens if ((child = make_dataset_handle(dependents[i])) == NULL) 2802789Sahrens continue; 2803789Sahrens 2804789Sahrens if ((ret = func(child, data)) != 0) 2805789Sahrens break; 2806789Sahrens } 2807789Sahrens 2808789Sahrens for (i = 0; i < count; i++) 2809789Sahrens free(dependents[i]); 2810789Sahrens free(dependents); 2811789Sahrens 2812789Sahrens return (ret); 2813789Sahrens } 2814789Sahrens 2815789Sahrens /* 2816789Sahrens * Renames the given dataset. 2817789Sahrens */ 2818789Sahrens int 2819789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2820789Sahrens { 2821789Sahrens int ret; 2822789Sahrens zfs_cmd_t zc = { 0 }; 2823789Sahrens char reason[64]; 2824789Sahrens char *delim; 2825789Sahrens prop_changelist_t *cl; 2826789Sahrens char parent[ZFS_MAXNAMELEN]; 2827789Sahrens 2828789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2829789Sahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 2830789Sahrens 2831789Sahrens /* if we have the same exact name, just return success */ 2832789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2833789Sahrens return (0); 2834789Sahrens 2835789Sahrens /* 2836789Sahrens * Make sure the target name is valid 2837789Sahrens */ 2838789Sahrens if (!zfs_validate_name(target, zhp->zfs_type, reason, 2839789Sahrens sizeof (reason))) { 2840789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2841789Sahrens "cannot create '%s': %s in %s name"), target, reason, 2842789Sahrens zfs_type_to_name(zhp->zfs_type)); 2843789Sahrens return (-1); 2844789Sahrens } 2845789Sahrens 2846789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2847789Sahrens if ((delim = strchr(target, '@')) == NULL) { 2848789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2849789Sahrens "cannot rename to '%s': not a snapshot"), target); 2850789Sahrens return (-1); 2851789Sahrens } 2852789Sahrens 2853789Sahrens /* 2854789Sahrens * Make sure we're renaming within the same dataset. 2855789Sahrens */ 2856789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2857789Sahrens zhp->zfs_name[delim - target] != '@') { 2858789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2859789Sahrens "cannot rename to '%s': snapshots must be part " 2860789Sahrens "of same dataset"), target); 2861789Sahrens return (-1); 2862789Sahrens } 2863789Sahrens 2864789Sahrens (void) strncpy(parent, target, delim - target); 2865789Sahrens parent[delim - target] = '\0'; 2866789Sahrens } else { 2867789Sahrens /* validate parents */ 2868789Sahrens if (check_parents(target, zhp->zfs_type) != 0) 2869789Sahrens return (-1); 2870789Sahrens 2871789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2872789Sahrens 2873789Sahrens /* make sure we're in the same pool */ 2874789Sahrens verify((delim = strchr(target, '/')) != NULL); 2875789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2876789Sahrens zhp->zfs_name[delim - target] != '/') { 2877789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2878789Sahrens "cannot rename to '%s': " 2879789Sahrens "datasets must be within same pool"), target); 2880789Sahrens return (-1); 2881789Sahrens } 2882789Sahrens } 2883789Sahrens 2884789Sahrens if (getzoneid() == GLOBAL_ZONEID && 2885789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 2886789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename %s, " 2887789Sahrens "dataset is used in a non-global zone"), zhp->zfs_name); 2888789Sahrens return (-1); 2889789Sahrens } 2890789Sahrens 2891789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 2892789Sahrens return (1); 2893789Sahrens 2894789Sahrens if (changelist_haszonedchild(cl)) { 2895789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 2896789Sahrens "cannot rename '%s': child dataset with inherited " 2897789Sahrens "mountpoint is used in a non-global zone"), zhp->zfs_name); 2898789Sahrens ret = -1; 2899789Sahrens goto error; 2900789Sahrens } 2901789Sahrens 2902789Sahrens if ((ret = changelist_prefix(cl)) != 0) 2903789Sahrens goto error; 2904789Sahrens 2905789Sahrens if (zhp->zfs_volblocksize != 0) 2906789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2907789Sahrens else 2908789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2909789Sahrens 2910789Sahrens if ((ret = ioctl(zfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 2911789Sahrens switch (errno) { 2912789Sahrens case EPERM: 2913789Sahrens /* 2914789Sahrens * The user doesn't have permission to rename the 2915789Sahrens * given dataset. 2916789Sahrens */ 2917789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': " 2918789Sahrens "permission denied"), zhp->zfs_name); 2919789Sahrens break; 2920789Sahrens 2921789Sahrens case EDQUOT: 2922789Sahrens case ENOSPC: 2923789Sahrens /* 2924789Sahrens * Not enough space in the parent dataset. 2925789Sahrens */ 2926789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 2927789Sahrens "rename '%s': not enough space in '%s'"), 2928789Sahrens zhp->zfs_name, parent); 2929789Sahrens break; 2930789Sahrens 2931789Sahrens case ENOENT: 2932789Sahrens /* 2933789Sahrens * The destination doesn't exist. 2934789Sahrens */ 2935789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' " 2936789Sahrens "to '%s': destination doesn't exist"), 2937789Sahrens zhp->zfs_name, target); 2938789Sahrens break; 2939789Sahrens 2940789Sahrens case EEXIST: 2941789Sahrens /* 2942789Sahrens * The destination already exists. 2943789Sahrens */ 2944789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' " 2945789Sahrens "to '%s': destination already exists"), 2946789Sahrens zhp->zfs_name, target); 2947789Sahrens break; 2948789Sahrens 2949789Sahrens case EBUSY: 2950789Sahrens /* 2951789Sahrens * The filesystem is busy. This should have been caught 2952789Sahrens * by the caller before getting here, but there may be 2953789Sahrens * an unexpected problem. 2954789Sahrens */ 2955789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': " 2956789Sahrens "%s is busy"), zhp->zfs_name, 2957789Sahrens zfs_type_to_name(zhp->zfs_type)); 2958789Sahrens break; 2959789Sahrens 2960789Sahrens default: 2961789Sahrens zfs_baderror(errno); 2962789Sahrens } 2963789Sahrens 2964789Sahrens /* 2965789Sahrens * On failure, we still want to remount any filesystems that 2966789Sahrens * were previously mounted, so we don't alter the system state. 2967789Sahrens */ 2968789Sahrens (void) changelist_postfix(cl); 2969789Sahrens } else { 2970789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 2971789Sahrens 2972789Sahrens ret = changelist_postfix(cl); 2973789Sahrens } 2974789Sahrens 2975789Sahrens error: 2976789Sahrens changelist_free(cl); 2977789Sahrens return (ret); 2978789Sahrens } 2979789Sahrens 2980789Sahrens /* 2981789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 2982789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 2983789Sahrens */ 2984789Sahrens int 2985789Sahrens zvol_create_link(const char *dataset) 2986789Sahrens { 2987789Sahrens zfs_cmd_t zc = { 0 }; 2988789Sahrens di_devlink_handle_t hdl; 2989789Sahrens 2990789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 2991789Sahrens 2992789Sahrens /* 2993789Sahrens * Issue the appropriate ioctl. 2994789Sahrens */ 2995789Sahrens if (ioctl(zfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 2996789Sahrens switch (errno) { 2997789Sahrens case EPERM: 2998789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot create " 2999789Sahrens "device links for '%s': permission denied"), 3000789Sahrens dataset); 3001789Sahrens break; 3002789Sahrens 3003789Sahrens case EEXIST: 3004789Sahrens /* 3005789Sahrens * Silently ignore the case where the link already 3006789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3007789Sahrens * times without errors. 3008789Sahrens */ 3009789Sahrens return (0); 3010789Sahrens 3011789Sahrens default: 3012789Sahrens zfs_baderror(errno); 3013789Sahrens } 3014789Sahrens 3015789Sahrens return (-1); 3016789Sahrens } 3017789Sahrens 3018789Sahrens /* 3019789Sahrens * Call devfsadm and wait for the links to magically appear. 3020789Sahrens */ 3021789Sahrens if ((hdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 3022789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 3023789Sahrens "cannot create device links for '%s'"), dataset); 3024789Sahrens (void) ioctl(zfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3025789Sahrens return (-1); 3026789Sahrens } else { 3027789Sahrens (void) di_devlink_fini(&hdl); 3028789Sahrens } 3029789Sahrens 3030789Sahrens return (0); 3031789Sahrens } 3032789Sahrens 3033789Sahrens /* 3034789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3035789Sahrens */ 3036789Sahrens int 3037789Sahrens zvol_remove_link(const char *dataset) 3038789Sahrens { 3039789Sahrens zfs_cmd_t zc = { 0 }; 3040789Sahrens 3041789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3042789Sahrens 3043789Sahrens if (ioctl(zfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3044789Sahrens switch (errno) { 3045789Sahrens case EPERM: 3046789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot remove " 3047789Sahrens "device links for '%s': permission denied"), 3048789Sahrens dataset); 3049789Sahrens break; 3050789Sahrens 3051789Sahrens case EBUSY: 3052789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot remove " 3053789Sahrens "device links for '%s': volume is in use"), 3054789Sahrens dataset); 3055789Sahrens break; 3056789Sahrens 3057789Sahrens case ENXIO: 3058789Sahrens /* 3059789Sahrens * Silently ignore the case where the link no longer 3060789Sahrens * exists, so that 'zfs volfini' can be run multiple 3061789Sahrens * times without errors. 3062789Sahrens */ 3063789Sahrens return (0); 3064789Sahrens 3065789Sahrens default: 3066789Sahrens zfs_baderror(errno); 3067789Sahrens } 3068789Sahrens 3069789Sahrens return (-1); 3070789Sahrens } 3071789Sahrens 3072789Sahrens return (0); 3073789Sahrens } 3074