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