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