1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221294Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <assert.h> 29789Sahrens #include <ctype.h> 30789Sahrens #include <errno.h> 31789Sahrens #include <libdevinfo.h> 32789Sahrens #include <libintl.h> 33789Sahrens #include <math.h> 34789Sahrens #include <stdio.h> 35789Sahrens #include <stdlib.h> 36789Sahrens #include <strings.h> 37789Sahrens #include <unistd.h> 38789Sahrens #include <zone.h> 392082Seschrock #include <fcntl.h> 40789Sahrens #include <sys/mntent.h> 41789Sahrens #include <sys/mnttab.h> 421294Slling #include <sys/mount.h> 43789Sahrens 44789Sahrens #include <sys/spa.h> 45789Sahrens #include <sys/zio.h> 462676Seschrock #include <sys/zap.h> 47789Sahrens #include <libzfs.h> 48789Sahrens 49789Sahrens #include "zfs_namecheck.h" 50789Sahrens #include "zfs_prop.h" 51789Sahrens #include "libzfs_impl.h" 52789Sahrens 53789Sahrens /* 54789Sahrens * Given a single type (not a mask of types), return the type in a human 55789Sahrens * readable form. 56789Sahrens */ 57789Sahrens const char * 58789Sahrens zfs_type_to_name(zfs_type_t type) 59789Sahrens { 60789Sahrens switch (type) { 61789Sahrens case ZFS_TYPE_FILESYSTEM: 62789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 63789Sahrens case ZFS_TYPE_SNAPSHOT: 64789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 65789Sahrens case ZFS_TYPE_VOLUME: 66789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 67789Sahrens } 68789Sahrens 69789Sahrens return (NULL); 70789Sahrens } 71789Sahrens 72789Sahrens /* 73789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 74789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 75789Sahrens * We guess what the type would have been based on the path and the mask of 76789Sahrens * acceptable types. 77789Sahrens */ 78789Sahrens static const char * 79789Sahrens path_to_str(const char *path, int types) 80789Sahrens { 81789Sahrens /* 82789Sahrens * When given a single type, always report the exact type. 83789Sahrens */ 84789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 85789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 86789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 87789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 88789Sahrens if (types == ZFS_TYPE_VOLUME) 89789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 90789Sahrens 91789Sahrens /* 92789Sahrens * The user is requesting more than one type of dataset. If this is the 93789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 94789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 95789Sahrens * snapshot attribute and try again. 96789Sahrens */ 97789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 98789Sahrens if (strchr(path, '@') != NULL) 99789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 100789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 101789Sahrens } 102789Sahrens 103789Sahrens 104789Sahrens /* 105789Sahrens * The user has requested either filesystems or volumes. 106789Sahrens * We have no way of knowing a priori what type this would be, so always 107789Sahrens * report it as "filesystem" or "volume", our two primitive types. 108789Sahrens */ 109789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 110789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 111789Sahrens 112789Sahrens assert(types & ZFS_TYPE_VOLUME); 113789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 114789Sahrens } 115789Sahrens 116789Sahrens /* 117789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 118789Sahrens * provide a more meaningful error message. We place a more useful message in 119789Sahrens * 'buf' detailing exactly why the name was not valid. 120789Sahrens */ 121789Sahrens static int 1222082Seschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 123789Sahrens { 124789Sahrens namecheck_err_t why; 125789Sahrens char what; 126789Sahrens 127789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 1282082Seschrock if (hdl != NULL) { 129789Sahrens switch (why) { 1301003Slling case NAME_ERR_TOOLONG: 1312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1322082Seschrock "name is too long")); 1331003Slling break; 1341003Slling 135789Sahrens case NAME_ERR_LEADING_SLASH: 1362082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1372082Seschrock "leading slash in name")); 138789Sahrens break; 139789Sahrens 140789Sahrens case NAME_ERR_EMPTY_COMPONENT: 1412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1422082Seschrock "empty component in name")); 143789Sahrens break; 144789Sahrens 145789Sahrens case NAME_ERR_TRAILING_SLASH: 1462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1472082Seschrock "trailing slash in name")); 148789Sahrens break; 149789Sahrens 150789Sahrens case NAME_ERR_INVALCHAR: 1512082Seschrock zfs_error_aux(hdl, 152789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 1532082Seschrock "'%c' in name"), what); 154789Sahrens break; 155789Sahrens 156789Sahrens case NAME_ERR_MULTIPLE_AT: 1572082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1582082Seschrock "multiple '@' delimiters in name")); 159789Sahrens break; 1602856Snd150628 1612856Snd150628 case NAME_ERR_NOLETTER: 1622856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1632856Snd150628 "pool doesn't begin with a letter")); 1642856Snd150628 break; 1652856Snd150628 1662856Snd150628 case NAME_ERR_RESERVED: 1672856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1682856Snd150628 "name is reserved")); 1692856Snd150628 break; 1702856Snd150628 1712856Snd150628 case NAME_ERR_DISKLIKE: 1722856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1732856Snd150628 "reserved disk name")); 1742856Snd150628 break; 175789Sahrens } 176789Sahrens } 177789Sahrens 178789Sahrens return (0); 179789Sahrens } 180789Sahrens 181789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 1822082Seschrock if (hdl != NULL) 1832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1842082Seschrock "snapshot delimiter '@' in filesystem name")); 185789Sahrens return (0); 186789Sahrens } 187789Sahrens 1882199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1892199Sahrens if (hdl != NULL) 1902199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1912199Sahrens "missing '@' delimeter in snapshot name")); 1922199Sahrens return (0); 1932199Sahrens } 1942199Sahrens 1952082Seschrock return (-1); 196789Sahrens } 197789Sahrens 198789Sahrens int 199789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 200789Sahrens { 2012082Seschrock return (zfs_validate_name(NULL, name, type)); 202789Sahrens } 203789Sahrens 204789Sahrens /* 2052676Seschrock * This function takes the raw DSL properties, and filters out the user-defined 2062676Seschrock * properties into a separate nvlist. 2072676Seschrock */ 2082676Seschrock static int 2092676Seschrock process_user_props(zfs_handle_t *zhp) 2102676Seschrock { 2112676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2122676Seschrock nvpair_t *elem; 2132676Seschrock nvlist_t *propval; 2142676Seschrock 2152676Seschrock nvlist_free(zhp->zfs_user_props); 2162676Seschrock 2172676Seschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 2182676Seschrock return (no_memory(hdl)); 2192676Seschrock 2202676Seschrock elem = NULL; 2212676Seschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 2222676Seschrock if (!zfs_prop_user(nvpair_name(elem))) 2232676Seschrock continue; 2242676Seschrock 2252676Seschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 2262676Seschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 2272676Seschrock nvpair_name(elem), propval) != 0) 2282676Seschrock return (no_memory(hdl)); 2292676Seschrock } 2302676Seschrock 2312676Seschrock return (0); 2322676Seschrock } 2332676Seschrock 2342676Seschrock /* 235789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 236789Sahrens */ 237789Sahrens static int 238789Sahrens get_stats(zfs_handle_t *zhp) 239789Sahrens { 240789Sahrens zfs_cmd_t zc = { 0 }; 2412676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 242789Sahrens 243789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 244789Sahrens 2452676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 2462082Seschrock return (-1); 2471356Seschrock 2482082Seschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2491356Seschrock if (errno == ENOMEM) { 2502676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2512676Seschrock zcmd_free_nvlists(&zc); 2522082Seschrock return (-1); 2532676Seschrock } 2541356Seschrock } else { 2552676Seschrock zcmd_free_nvlists(&zc); 2561356Seschrock return (-1); 2571356Seschrock } 2581356Seschrock } 259789Sahrens 260*2885Sahrens zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 261789Sahrens 2622676Seschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 2631544Seschrock 2642082Seschrock if (zhp->zfs_props) { 2652082Seschrock nvlist_free(zhp->zfs_props); 2662082Seschrock zhp->zfs_props = NULL; 2672082Seschrock } 2682082Seschrock 2692676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 2702676Seschrock zcmd_free_nvlists(&zc); 2712082Seschrock return (-1); 2722082Seschrock } 273789Sahrens 2742676Seschrock zcmd_free_nvlists(&zc); 2752676Seschrock 2762676Seschrock if (process_user_props(zhp) != 0) 2772676Seschrock return (-1); 2782082Seschrock 279789Sahrens return (0); 280789Sahrens } 281789Sahrens 282789Sahrens /* 283789Sahrens * Refresh the properties currently stored in the handle. 284789Sahrens */ 285789Sahrens void 286789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 287789Sahrens { 288789Sahrens (void) get_stats(zhp); 289789Sahrens } 290789Sahrens 291789Sahrens /* 292789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 293789Sahrens * zfs_iter_* to create child handles on the fly. 294789Sahrens */ 295789Sahrens zfs_handle_t * 2962082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 297789Sahrens { 2982082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 2992082Seschrock 3002082Seschrock if (zhp == NULL) 3012082Seschrock return (NULL); 3022082Seschrock 3032082Seschrock zhp->zfs_hdl = hdl; 304789Sahrens 3051758Sahrens top: 306789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 307789Sahrens 308789Sahrens if (get_stats(zhp) != 0) { 309789Sahrens free(zhp); 310789Sahrens return (NULL); 311789Sahrens } 312789Sahrens 3131758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 3141758Sahrens zfs_cmd_t zc = { 0 }; 3151758Sahrens 3161758Sahrens /* 3171758Sahrens * If it is dds_inconsistent, then we've caught it in 3181758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 3191758Sahrens * it is inconsistent from the ZPL's point of view, so 3201758Sahrens * can't be mounted. However, it could also be that we 3211758Sahrens * have crashed in the middle of one of those 3221758Sahrens * operations, in which case we need to get rid of the 3231758Sahrens * inconsistent state. We do that by either rolling 3241758Sahrens * back to the previous snapshot (which will fail if 3251758Sahrens * there is none), or destroying the filesystem. Note 3261758Sahrens * that if we are still in the middle of an active 3271758Sahrens * 'receive' or 'destroy', then the rollback and destroy 3281758Sahrens * will fail with EBUSY and we will drive on as usual. 3291758Sahrens */ 3301758Sahrens 3311758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3321758Sahrens 333*2885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 3342082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 3351758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3361758Sahrens } else { 3371758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3381758Sahrens } 3391758Sahrens 3401758Sahrens /* If we can successfully roll it back, reget the stats */ 3412082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 3421758Sahrens goto top; 3431758Sahrens /* 3441758Sahrens * If we can sucessfully destroy it, pretend that it 3451758Sahrens * never existed. 3461758Sahrens */ 3472082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3481758Sahrens free(zhp); 3491758Sahrens errno = ENOENT; 3501758Sahrens return (NULL); 3511758Sahrens } 3521758Sahrens } 3531758Sahrens 354789Sahrens /* 355789Sahrens * We've managed to open the dataset and gather statistics. Determine 356789Sahrens * the high-level type. 357789Sahrens */ 358*2885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 359*2885Sahrens zhp->zfs_head_type = ZFS_TYPE_VOLUME; 360*2885Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 361*2885Sahrens zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 362*2885Sahrens else 363*2885Sahrens abort(); 364*2885Sahrens 365789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 366789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 367789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 368789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 369789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 370789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 371789Sahrens else 3722082Seschrock abort(); /* we should never see any other types */ 373789Sahrens 374789Sahrens return (zhp); 375789Sahrens } 376789Sahrens 377789Sahrens /* 378789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 379789Sahrens * argument is a mask of acceptable types. The function will print an 380789Sahrens * appropriate error message and return NULL if it can't be opened. 381789Sahrens */ 382789Sahrens zfs_handle_t * 3832082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 384789Sahrens { 385789Sahrens zfs_handle_t *zhp; 3862082Seschrock char errbuf[1024]; 3872082Seschrock 3882082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3892082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 390789Sahrens 391789Sahrens /* 3922082Seschrock * Validate the name before we even try to open it. 393789Sahrens */ 3942082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3962082Seschrock "invalid dataset name")); 3972082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 398789Sahrens return (NULL); 399789Sahrens } 400789Sahrens 401789Sahrens /* 402789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 403789Sahrens */ 404789Sahrens errno = 0; 4052082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 4062082Seschrock (void) zfs_standard_error(hdl, errno, errbuf, path); 407789Sahrens return (NULL); 408789Sahrens } 409789Sahrens 410789Sahrens if (!(types & zhp->zfs_type)) { 4112082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4122142Seschrock zfs_close(zhp); 413789Sahrens return (NULL); 414789Sahrens } 415789Sahrens 416789Sahrens return (zhp); 417789Sahrens } 418789Sahrens 419789Sahrens /* 420789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 421789Sahrens */ 422789Sahrens void 423789Sahrens zfs_close(zfs_handle_t *zhp) 424789Sahrens { 425789Sahrens if (zhp->zfs_mntopts) 426789Sahrens free(zhp->zfs_mntopts); 4272676Seschrock nvlist_free(zhp->zfs_props); 4282676Seschrock nvlist_free(zhp->zfs_user_props); 429789Sahrens free(zhp); 430789Sahrens } 431789Sahrens 432789Sahrens /* 433789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 434789Sahrens * resulting value must be shifted. 435789Sahrens */ 436789Sahrens static int 4372082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 438789Sahrens { 439789Sahrens const char *ends = "BKMGTPEZ"; 440789Sahrens int i; 441789Sahrens 442789Sahrens if (buf[0] == '\0') 443789Sahrens return (0); 444789Sahrens for (i = 0; i < strlen(ends); i++) { 445789Sahrens if (toupper(buf[0]) == ends[i]) 446789Sahrens break; 447789Sahrens } 448789Sahrens if (i == strlen(ends)) { 4492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4502082Seschrock "invalid numeric suffix '%s'"), buf); 451789Sahrens return (-1); 452789Sahrens } 453789Sahrens 454789Sahrens /* 455789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 456789Sahrens * allow 'BB' - that's just weird. 457789Sahrens */ 458789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4592082Seschrock toupper(buf[0]) != 'B')) 460789Sahrens return (10*i); 4612082Seschrock 4622082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4632082Seschrock "invalid numeric suffix '%s'"), buf); 464789Sahrens return (-1); 465789Sahrens } 466789Sahrens 467789Sahrens /* 468789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 469789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 470789Sahrens * message for the caller to use. 471789Sahrens */ 472789Sahrens static int 4732082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 474789Sahrens { 475789Sahrens char *end; 476789Sahrens int shift; 477789Sahrens 478789Sahrens *num = 0; 479789Sahrens 480789Sahrens /* Check to see if this looks like a number. */ 481789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4822082Seschrock if (hdl) 4832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4842082Seschrock "bad numeric value '%s'"), value); 485789Sahrens return (-1); 486789Sahrens } 487789Sahrens 488789Sahrens /* Rely on stroll() to process the numeric portion. */ 489789Sahrens errno = 0; 490789Sahrens *num = strtoll(value, &end, 10); 491789Sahrens 492789Sahrens /* 493789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 494789Sahrens * in a 64-bit value. 495789Sahrens */ 496789Sahrens if (errno == ERANGE) { 4972082Seschrock if (hdl) 4982082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4992082Seschrock "numeric value is too large")); 500789Sahrens return (-1); 501789Sahrens } 502789Sahrens 503789Sahrens /* 504789Sahrens * If we have a decimal value, then do the computation with floating 505789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 506789Sahrens */ 507789Sahrens if (*end == '.') { 508789Sahrens double fval = strtod(value, &end); 509789Sahrens 5102082Seschrock if ((shift = str2shift(hdl, end)) == -1) 511789Sahrens return (-1); 512789Sahrens 513789Sahrens fval *= pow(2, shift); 514789Sahrens 515789Sahrens if (fval > UINT64_MAX) { 5162082Seschrock if (hdl) 5172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5182082Seschrock "numeric value is too large")); 519789Sahrens return (-1); 520789Sahrens } 521789Sahrens 522789Sahrens *num = (uint64_t)fval; 523789Sahrens } else { 5242082Seschrock if ((shift = str2shift(hdl, end)) == -1) 525789Sahrens return (-1); 526789Sahrens 527789Sahrens /* Check for overflow */ 528789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5292082Seschrock if (hdl) 5302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5312082Seschrock "numeric value is too large")); 532789Sahrens return (-1); 533789Sahrens } 534789Sahrens 535789Sahrens *num <<= shift; 536789Sahrens } 537789Sahrens 538789Sahrens return (0); 539789Sahrens } 540789Sahrens 541789Sahrens int 5422676Seschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 5432676Seschrock { 5442676Seschrock return (nicestrtonum(hdl, str, val)); 5452676Seschrock } 5462676Seschrock 5472676Seschrock /* 5482676Seschrock * The prop_parse_*() functions are designed to allow flexibility in callers 5492676Seschrock * when setting properties. At the DSL layer, all properties are either 64-bit 5502676Seschrock * numbers or strings. We want the user to be able to ignore this fact and 5512676Seschrock * specify properties as native values (boolean, for example) or as strings (to 5522676Seschrock * simplify command line utilities). This also handles converting index types 5532676Seschrock * (compression, checksum, etc) from strings to their on-disk index. 5542676Seschrock */ 5552676Seschrock 5562676Seschrock static int 5572676Seschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 558789Sahrens { 5592676Seschrock uint64_t ret; 5602676Seschrock 5612676Seschrock switch (nvpair_type(elem)) { 5622676Seschrock case DATA_TYPE_STRING: 5632676Seschrock { 5642676Seschrock char *value; 5652676Seschrock VERIFY(nvpair_value_string(elem, &value) == 0); 5662676Seschrock 5672676Seschrock if (strcmp(value, "on") == 0) { 5682676Seschrock ret = 1; 5692676Seschrock } else if (strcmp(value, "off") == 0) { 5702676Seschrock ret = 0; 5712676Seschrock } else { 5722676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5732676Seschrock "property '%s' must be 'on' or 'off'"), 5742676Seschrock nvpair_name(elem)); 5752676Seschrock return (-1); 5762676Seschrock } 5772676Seschrock break; 5782676Seschrock } 5792676Seschrock 5802676Seschrock case DATA_TYPE_UINT64: 5812676Seschrock { 5822676Seschrock VERIFY(nvpair_value_uint64(elem, &ret) == 0); 5832676Seschrock if (ret > 1) { 5842676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5852676Seschrock "'%s' must be a boolean value"), 5862676Seschrock nvpair_name(elem)); 5872676Seschrock return (-1); 5882676Seschrock } 5892676Seschrock break; 5902676Seschrock } 5912676Seschrock 5922676Seschrock case DATA_TYPE_BOOLEAN_VALUE: 5932676Seschrock { 5942676Seschrock boolean_t value; 5952676Seschrock VERIFY(nvpair_value_boolean_value(elem, &value) == 0); 5962676Seschrock ret = value; 5972676Seschrock break; 5982676Seschrock } 5992676Seschrock 6002676Seschrock default: 6012676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6022676Seschrock "'%s' must be a boolean value"), 6032676Seschrock nvpair_name(elem)); 6042676Seschrock return (-1); 6052676Seschrock } 6062676Seschrock 6072676Seschrock *val = ret; 6082676Seschrock return (0); 6092676Seschrock } 6102676Seschrock 6112676Seschrock static int 6122676Seschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6132676Seschrock uint64_t *val) 6142676Seschrock { 6152676Seschrock uint64_t ret; 6162676Seschrock boolean_t isnone = B_FALSE; 6172676Seschrock 6182676Seschrock switch (nvpair_type(elem)) { 6192676Seschrock case DATA_TYPE_STRING: 6202676Seschrock { 6212676Seschrock char *value; 6222676Seschrock (void) nvpair_value_string(elem, &value); 6232676Seschrock if (strcmp(value, "none") == 0) { 6242676Seschrock isnone = B_TRUE; 6252676Seschrock ret = 0; 6262676Seschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 6272676Seschrock return (-1); 6282676Seschrock } 6292676Seschrock break; 6302676Seschrock } 6312676Seschrock 6322676Seschrock case DATA_TYPE_UINT64: 6332676Seschrock (void) nvpair_value_uint64(elem, &ret); 6342676Seschrock break; 6352676Seschrock 6362676Seschrock default: 6372676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6382676Seschrock "'%s' must be a number"), 6392676Seschrock nvpair_name(elem)); 6402676Seschrock return (-1); 6412676Seschrock } 6422676Seschrock 6432676Seschrock /* 6442676Seschrock * Quota special: force 'none' and don't allow 0. 6452676Seschrock */ 6462676Seschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 6472676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6482676Seschrock "use 'none' to disable quota")); 6492676Seschrock return (-1); 6502676Seschrock } 6512676Seschrock 6522676Seschrock *val = ret; 6532676Seschrock return (0); 6542676Seschrock } 6552676Seschrock 6562676Seschrock static int 6572676Seschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6582676Seschrock uint64_t *val) 6592676Seschrock { 6602676Seschrock char *propname = nvpair_name(elem); 6612676Seschrock char *value; 6622676Seschrock 6632676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 6642676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6652676Seschrock "'%s' must be a string"), propname); 6662676Seschrock return (-1); 6672676Seschrock } 6682676Seschrock 6692676Seschrock (void) nvpair_value_string(elem, &value); 6702676Seschrock 6712676Seschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 6722676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6732676Seschrock "'%s' must be one of '%s'"), propname, 6742676Seschrock zfs_prop_values(prop)); 6752676Seschrock return (-1); 6762676Seschrock } 6772676Seschrock 6782676Seschrock return (0); 679789Sahrens } 680789Sahrens 681789Sahrens /* 6822676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 6832676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 6842676Seschrock * strings. 685789Sahrens */ 6862676Seschrock static nvlist_t * 6872676Seschrock zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 6882676Seschrock uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 689789Sahrens { 6902676Seschrock nvpair_t *elem; 6912676Seschrock const char *propname; 6922676Seschrock zfs_prop_t prop; 6932676Seschrock uint64_t intval; 6942676Seschrock char *strval; 6952676Seschrock nvlist_t *ret; 6962676Seschrock 6972676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 6982676Seschrock (void) no_memory(hdl); 6992676Seschrock return (NULL); 7002676Seschrock } 7012676Seschrock 7022676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 7032676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7042676Seschrock "snaphot properties cannot be modified")); 7052676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7062676Seschrock goto error; 707789Sahrens } 708789Sahrens 7092676Seschrock elem = NULL; 7102676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 7112676Seschrock propname = nvpair_name(elem); 7122676Seschrock 7132676Seschrock /* 7142676Seschrock * Make sure this property is valid and applies to this type. 7152676Seschrock */ 7162676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 7172676Seschrock if (!zfs_prop_user(propname)) { 7182676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7192676Seschrock "invalid property '%s'"), 7202676Seschrock propname); 7212676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7222676Seschrock goto error; 7232676Seschrock } else { 7242676Seschrock /* 7252676Seschrock * If this is a user property, make sure it's a 7262676Seschrock * string, and that it's less than 7272676Seschrock * ZAP_MAXNAMELEN. 7282676Seschrock */ 7292676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7302676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7312676Seschrock "'%s' must be a string"), 7322676Seschrock propname); 7332676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7342676Seschrock errbuf); 7352676Seschrock goto error; 7362676Seschrock } 7372676Seschrock 7382676Seschrock if (strlen(nvpair_name(elem)) >= 7392676Seschrock ZAP_MAXNAMELEN) { 7402676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7412676Seschrock "property name '%s' is too long"), 7422676Seschrock propname); 7432676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7442676Seschrock errbuf); 7452676Seschrock goto error; 7462676Seschrock } 7472676Seschrock } 7482676Seschrock 7492676Seschrock (void) nvpair_value_string(elem, &strval); 7502676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7512676Seschrock (void) no_memory(hdl); 7522676Seschrock goto error; 7532676Seschrock } 7542676Seschrock continue; 755789Sahrens } 7562676Seschrock 7572676Seschrock /* 7582676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7592676Seschrock */ 7602676Seschrock propname = zfs_prop_to_name(prop); 7612676Seschrock 7622676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7632676Seschrock zfs_error_aux(hdl, 7642676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7652676Seschrock "apply to datasets of this type"), propname); 7662676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7672676Seschrock goto error; 7682676Seschrock } 7692676Seschrock 7702676Seschrock if (zfs_prop_readonly(prop) && 7712676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 7722676Seschrock zfs_error_aux(hdl, 7732676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 7742676Seschrock propname); 7752676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 7762676Seschrock goto error; 7772676Seschrock } 7782676Seschrock 7792676Seschrock /* 7802676Seschrock * Convert any properties to the internal DSL value types. 7812676Seschrock */ 7822676Seschrock strval = NULL; 7832676Seschrock switch (zfs_prop_get_type(prop)) { 7842676Seschrock case prop_type_boolean: 7852676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 7862676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7872676Seschrock goto error; 7882676Seschrock } 789789Sahrens break; 7902676Seschrock 7912676Seschrock case prop_type_string: 7922676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7932082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7942676Seschrock "'%s' must be a string"), 7952676Seschrock propname); 7962676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7972676Seschrock goto error; 798789Sahrens } 7992676Seschrock (void) nvpair_value_string(elem, &strval); 8002676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 8012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8022676Seschrock "'%s' is too long"), propname); 8032676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8042676Seschrock goto error; 8052676Seschrock } 8062676Seschrock break; 8072676Seschrock 8082676Seschrock case prop_type_number: 8092676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 8102676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8112676Seschrock goto error; 8122676Seschrock } 8132676Seschrock break; 8142676Seschrock 8152676Seschrock case prop_type_index: 8162676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 8172676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8182676Seschrock goto error; 819789Sahrens } 820789Sahrens break; 821789Sahrens 8222676Seschrock default: 8232676Seschrock abort(); 8242676Seschrock } 8252676Seschrock 8262676Seschrock /* 8272676Seschrock * Add the result to our return set of properties. 8282676Seschrock */ 8292676Seschrock if (strval) { 8302676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8312676Seschrock (void) no_memory(hdl); 8322676Seschrock goto error; 833789Sahrens } 8342676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8352676Seschrock (void) no_memory(hdl); 8362676Seschrock goto error; 8372676Seschrock } 8382676Seschrock 8392676Seschrock /* 8402676Seschrock * Perform some additional checks for specific properties. 8412676Seschrock */ 8422676Seschrock switch (prop) { 8432676Seschrock case ZFS_PROP_RECORDSIZE: 8442676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8452676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8462676Seschrock if (intval < SPA_MINBLOCKSIZE || 8472676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8492676Seschrock "'%s' must be power of 2 from %u " 8502676Seschrock "to %uk"), propname, 8512676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8522676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8532676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8542676Seschrock goto error; 855789Sahrens } 856789Sahrens break; 857789Sahrens 8582676Seschrock case ZFS_PROP_MOUNTPOINT: 8592676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 8602676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 8612676Seschrock break; 8622676Seschrock 8632676Seschrock if (strval[0] != '/') { 8642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8652676Seschrock "'%s' must be an absolute path, " 8662676Seschrock "'none', or 'legacy'"), propname); 8672676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8682676Seschrock goto error; 869789Sahrens } 870789Sahrens break; 8712676Seschrock } 8722676Seschrock 8732676Seschrock /* 8742676Seschrock * For the mountpoint and sharenfs properties, check if it can 8752676Seschrock * be set in a global/non-global zone based on the zoned 8762676Seschrock * property value: 8772676Seschrock * 8782676Seschrock * global zone non-global zone 8792676Seschrock * ----------------------------------------------------- 8802676Seschrock * zoned=on mountpoint (no) mountpoint (yes) 8812676Seschrock * sharenfs (no) sharenfs (no) 8822676Seschrock * 8832676Seschrock * zoned=off mountpoint (yes) N/A 8842676Seschrock * sharenfs (yes) 8852676Seschrock */ 8862676Seschrock if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 8872676Seschrock if (zoned) { 8882676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 8892676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8902676Seschrock "'%s' cannot be set on " 8912676Seschrock "dataset in a non-global zone"), 8922676Seschrock propname); 8932676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 8942676Seschrock errbuf); 8952676Seschrock goto error; 8962676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 8972676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8982676Seschrock "'%s' cannot be set in " 8992676Seschrock "a non-global zone"), propname); 9002676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9012676Seschrock errbuf); 9022676Seschrock goto error; 9032676Seschrock } 9042676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 9052676Seschrock /* 9062676Seschrock * If zoned property is 'off', this must be in 9072676Seschrock * a globle zone. If not, something is wrong. 9082676Seschrock */ 9092676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9102676Seschrock "'%s' cannot be set while dataset " 9112676Seschrock "'zoned' property is set"), propname); 9122676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 9132676Seschrock goto error; 9142676Seschrock } 9152676Seschrock } 9162676Seschrock 9172676Seschrock /* 9182676Seschrock * For changes to existing volumes, we have some additional 9192676Seschrock * checks to enforce. 9202676Seschrock */ 9212676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9222676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9232676Seschrock ZFS_PROP_VOLSIZE); 9242676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9252676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9262676Seschrock char buf[64]; 9272676Seschrock 9282676Seschrock switch (prop) { 9292676Seschrock case ZFS_PROP_RESERVATION: 9302676Seschrock if (intval > volsize) { 9312676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9322676Seschrock "'%s' is greater than current " 9332676Seschrock "volume size"), propname); 9342676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9352676Seschrock errbuf); 9362676Seschrock goto error; 9372676Seschrock } 9382676Seschrock break; 9392676Seschrock 9402676Seschrock case ZFS_PROP_VOLSIZE: 9412676Seschrock if (intval % blocksize != 0) { 9422676Seschrock zfs_nicenum(blocksize, buf, 9432676Seschrock sizeof (buf)); 9442676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9452676Seschrock "'%s' must be a multiple of " 9462676Seschrock "volume block size (%s)"), 9472676Seschrock propname, buf); 9482676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9492676Seschrock errbuf); 9502676Seschrock goto error; 9512676Seschrock } 9522676Seschrock 9532676Seschrock if (intval == 0) { 9542676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9552676Seschrock "'%s' cannot be zero"), 9562676Seschrock propname); 9572676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9582676Seschrock errbuf); 9592676Seschrock goto error; 960789Sahrens } 961789Sahrens } 962789Sahrens } 963789Sahrens } 964789Sahrens 9652676Seschrock /* 9662676Seschrock * If this is an existing volume, and someone is setting the volsize, 9672676Seschrock * make sure that it matches the reservation, or add it if necessary. 9682676Seschrock */ 9692676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 9702676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 9712676Seschrock &intval) == 0) { 9722676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 9732676Seschrock ZFS_PROP_VOLSIZE); 9742676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 9752676Seschrock ZFS_PROP_RESERVATION); 9762676Seschrock uint64_t new_reservation; 9772676Seschrock 9782676Seschrock if (old_volsize == old_reservation && 9792676Seschrock nvlist_lookup_uint64(ret, 9802676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9812676Seschrock &new_reservation) != 0) { 9822676Seschrock if (nvlist_add_uint64(ret, 9832676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9842676Seschrock intval) != 0) { 9852676Seschrock (void) no_memory(hdl); 9862676Seschrock goto error; 9872676Seschrock } 9882676Seschrock } 9892676Seschrock } 9902676Seschrock 9912676Seschrock return (ret); 9922676Seschrock 9932676Seschrock error: 9942676Seschrock nvlist_free(ret); 9952676Seschrock return (NULL); 996789Sahrens } 997789Sahrens 998789Sahrens /* 999789Sahrens * Given a property name and value, set the property for the given dataset. 1000789Sahrens */ 1001789Sahrens int 10022676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1003789Sahrens { 1004789Sahrens zfs_cmd_t zc = { 0 }; 10052676Seschrock int ret = -1; 10062676Seschrock prop_changelist_t *cl = NULL; 10072082Seschrock char errbuf[1024]; 10082082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 10092676Seschrock nvlist_t *nvl = NULL, *realprops; 10102676Seschrock zfs_prop_t prop; 10112082Seschrock 10122082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 10132676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 10142082Seschrock zhp->zfs_name); 10152082Seschrock 10162676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 10172676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 10182676Seschrock (void) no_memory(hdl); 10192676Seschrock goto error; 1020789Sahrens } 1021789Sahrens 10222676Seschrock if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl, 10232676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10242676Seschrock goto error; 10252676Seschrock nvlist_free(nvl); 10262676Seschrock nvl = realprops; 10272676Seschrock 10282676Seschrock prop = zfs_name_to_prop(propname); 10292676Seschrock 1030789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10312676Seschrock goto error; 1032789Sahrens 1033789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10352082Seschrock "child dataset with inherited mountpoint is used " 10362082Seschrock "in a non-global zone")); 10372082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1038789Sahrens goto error; 1039789Sahrens } 1040789Sahrens 1041789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1042789Sahrens goto error; 1043789Sahrens 1044789Sahrens /* 1045789Sahrens * Execute the corresponding ioctl() to set this property. 1046789Sahrens */ 1047789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1048789Sahrens 10492676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 10502676Seschrock goto error; 10512676Seschrock 10522676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1053789Sahrens 1054789Sahrens if (ret != 0) { 1055789Sahrens switch (errno) { 1056789Sahrens 1057789Sahrens case ENOSPC: 1058789Sahrens /* 1059789Sahrens * For quotas and reservations, ENOSPC indicates 1060789Sahrens * something different; setting a quota or reservation 1061789Sahrens * doesn't use any disk space. 1062789Sahrens */ 1063789Sahrens switch (prop) { 1064789Sahrens case ZFS_PROP_QUOTA: 10652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10662082Seschrock "size is less than current used or " 10672082Seschrock "reserved space")); 10682082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1069789Sahrens break; 1070789Sahrens 1071789Sahrens case ZFS_PROP_RESERVATION: 10722082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10732082Seschrock "size is greater than available space")); 10742082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1075789Sahrens break; 1076789Sahrens 1077789Sahrens default: 10782082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1079789Sahrens break; 1080789Sahrens } 1081789Sahrens break; 1082789Sahrens 1083789Sahrens case EBUSY: 10842082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 10852082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 10862082Seschrock else 10872676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1088789Sahrens break; 1089789Sahrens 10901175Slling case EROFS: 10912082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 10921175Slling break; 10931175Slling 1094789Sahrens case EOVERFLOW: 1095789Sahrens /* 1096789Sahrens * This platform can't address a volume this big. 1097789Sahrens */ 1098789Sahrens #ifdef _ILP32 1099789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 11002082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1101789Sahrens break; 1102789Sahrens } 1103789Sahrens #endif 11042082Seschrock /* FALLTHROUGH */ 1105789Sahrens default: 11062082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1107789Sahrens } 1108789Sahrens } else { 1109789Sahrens /* 1110789Sahrens * Refresh the statistics so the new property value 1111789Sahrens * is reflected. 1112789Sahrens */ 11132676Seschrock if ((ret = changelist_postfix(cl)) == 0) 11142676Seschrock (void) get_stats(zhp); 1115789Sahrens } 1116789Sahrens 1117789Sahrens error: 11182676Seschrock nvlist_free(nvl); 11192676Seschrock zcmd_free_nvlists(&zc); 11202676Seschrock if (cl) 11212676Seschrock changelist_free(cl); 1122789Sahrens return (ret); 1123789Sahrens } 1124789Sahrens 1125789Sahrens /* 1126789Sahrens * Given a property, inherit the value from the parent dataset. 1127789Sahrens */ 1128789Sahrens int 11292676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1130789Sahrens { 1131789Sahrens zfs_cmd_t zc = { 0 }; 1132789Sahrens int ret; 1133789Sahrens prop_changelist_t *cl; 11342082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 11352082Seschrock char errbuf[1024]; 11362676Seschrock zfs_prop_t prop; 11372082Seschrock 11382082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 11392082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1140789Sahrens 11412676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 11422676Seschrock /* 11432676Seschrock * For user properties, the amount of work we have to do is very 11442676Seschrock * small, so just do it here. 11452676Seschrock */ 11462676Seschrock if (!zfs_prop_user(propname)) { 11472676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11482676Seschrock "invalid property")); 11492676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 11502676Seschrock } 11512676Seschrock 11522676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11532676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 11542676Seschrock 11552676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 11562676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 11572676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 11582676Seschrock 11592676Seschrock return (0); 11602676Seschrock } 11612676Seschrock 1162789Sahrens /* 1163789Sahrens * Verify that this property is inheritable. 1164789Sahrens */ 11652082Seschrock if (zfs_prop_readonly(prop)) 11662082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 11672082Seschrock 11682082Seschrock if (!zfs_prop_inheritable(prop)) 11692082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1170789Sahrens 1171789Sahrens /* 1172789Sahrens * Check to see if the value applies to this type 1173789Sahrens */ 11742082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 11752082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1176789Sahrens 1177789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11782676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1179789Sahrens 1180789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1181789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 11822082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11832082Seschrock "dataset is used in a non-global zone")); 11842082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1185789Sahrens } 1186789Sahrens 1187789Sahrens /* 1188789Sahrens * Determine datasets which will be affected by this change, if any. 1189789Sahrens */ 1190789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1191789Sahrens return (-1); 1192789Sahrens 1193789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 11942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11952082Seschrock "child dataset with inherited mountpoint is used " 11962082Seschrock "in a non-global zone")); 11972082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1198789Sahrens goto error; 1199789Sahrens } 1200789Sahrens 1201789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1202789Sahrens goto error; 1203789Sahrens 12042082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 12052082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 12062082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1207789Sahrens } else { 1208789Sahrens 12092169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1210789Sahrens goto error; 1211789Sahrens 1212789Sahrens /* 1213789Sahrens * Refresh the statistics so the new property is reflected. 1214789Sahrens */ 1215789Sahrens (void) get_stats(zhp); 1216789Sahrens } 1217789Sahrens 1218789Sahrens error: 1219789Sahrens changelist_free(cl); 1220789Sahrens return (ret); 1221789Sahrens } 1222789Sahrens 1223789Sahrens static void 1224789Sahrens nicebool(int value, char *buf, size_t buflen) 1225789Sahrens { 1226789Sahrens if (value) 1227789Sahrens (void) strlcpy(buf, "on", buflen); 1228789Sahrens else 1229789Sahrens (void) strlcpy(buf, "off", buflen); 1230789Sahrens } 1231789Sahrens 1232789Sahrens /* 12331356Seschrock * True DSL properties are stored in an nvlist. The following two functions 12341356Seschrock * extract them appropriately. 12351356Seschrock */ 12361356Seschrock static uint64_t 12371356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12381356Seschrock { 12391356Seschrock nvlist_t *nv; 12401356Seschrock uint64_t value; 12411356Seschrock 1242*2885Sahrens *source = NULL; 12431356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12441356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12451356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 1246*2885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12471356Seschrock } else { 12481356Seschrock value = zfs_prop_default_numeric(prop); 12491356Seschrock *source = ""; 12501356Seschrock } 12511356Seschrock 12521356Seschrock return (value); 12531356Seschrock } 12541356Seschrock 12551356Seschrock static char * 12561356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12571356Seschrock { 12581356Seschrock nvlist_t *nv; 12591356Seschrock char *value; 12601356Seschrock 1261*2885Sahrens *source = NULL; 12621356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12631356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12641356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 1265*2885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12661356Seschrock } else { 12671356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 12681356Seschrock value = ""; 12691356Seschrock *source = ""; 12701356Seschrock } 12711356Seschrock 12721356Seschrock return (value); 12731356Seschrock } 12741356Seschrock 12751356Seschrock /* 1276789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1277789Sahrens * zfs_prop_get_int() are built using this interface. 1278789Sahrens * 1279789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1280789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1281789Sahrens * If they differ from the on-disk values, report the current values and mark 1282789Sahrens * the source "temporary". 1283789Sahrens */ 12842082Seschrock static int 1285789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 12862082Seschrock char **source, uint64_t *val) 1287789Sahrens { 1288789Sahrens struct mnttab mnt; 1289789Sahrens 1290789Sahrens *source = NULL; 1291789Sahrens 12922474Seschrock /* 12932474Seschrock * Because looking up the mount options is potentially expensive 12942474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 12952474Seschrock * we're looking up a property which requires its presence. 12962474Seschrock */ 12972474Seschrock if (!zhp->zfs_mntcheck && 12982474Seschrock (prop == ZFS_PROP_ATIME || 12992474Seschrock prop == ZFS_PROP_DEVICES || 13002474Seschrock prop == ZFS_PROP_EXEC || 13012474Seschrock prop == ZFS_PROP_READONLY || 13022474Seschrock prop == ZFS_PROP_SETUID || 13032474Seschrock prop == ZFS_PROP_MOUNTED)) { 13042474Seschrock struct mnttab search = { 0 }, entry; 13052474Seschrock 13062474Seschrock search.mnt_special = (char *)zhp->zfs_name; 13072474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 13082474Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 13092474Seschrock 13102474Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 13112474Seschrock &search) == 0 && (zhp->zfs_mntopts = 13122474Seschrock zfs_strdup(zhp->zfs_hdl, 13132474Seschrock entry.mnt_mntopts)) == NULL) 13142474Seschrock return (-1); 13152474Seschrock 13162474Seschrock zhp->zfs_mntcheck = B_TRUE; 13172474Seschrock } 13182474Seschrock 1319789Sahrens if (zhp->zfs_mntopts == NULL) 1320789Sahrens mnt.mnt_mntopts = ""; 1321789Sahrens else 1322789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1323789Sahrens 1324789Sahrens switch (prop) { 1325789Sahrens case ZFS_PROP_ATIME: 13262082Seschrock *val = getprop_uint64(zhp, prop, source); 13272082Seschrock 13282082Seschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 13292082Seschrock *val = B_TRUE; 1330789Sahrens if (src) 1331789Sahrens *src = ZFS_SRC_TEMPORARY; 13322082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 13332082Seschrock *val = B_FALSE; 1334789Sahrens if (src) 1335789Sahrens *src = ZFS_SRC_TEMPORARY; 1336789Sahrens } 13372082Seschrock break; 1338789Sahrens 1339789Sahrens case ZFS_PROP_DEVICES: 13402082Seschrock *val = getprop_uint64(zhp, prop, source); 13412082Seschrock 13422082Seschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 13432082Seschrock *val = B_TRUE; 1344789Sahrens if (src) 1345789Sahrens *src = ZFS_SRC_TEMPORARY; 13462082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 13472082Seschrock *val = B_FALSE; 1348789Sahrens if (src) 1349789Sahrens *src = ZFS_SRC_TEMPORARY; 1350789Sahrens } 13512082Seschrock break; 1352789Sahrens 1353789Sahrens case ZFS_PROP_EXEC: 13542082Seschrock *val = getprop_uint64(zhp, prop, source); 13552082Seschrock 13562082Seschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 13572082Seschrock *val = B_TRUE; 1358789Sahrens if (src) 1359789Sahrens *src = ZFS_SRC_TEMPORARY; 13602082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 13612082Seschrock *val = B_FALSE; 1362789Sahrens if (src) 1363789Sahrens *src = ZFS_SRC_TEMPORARY; 1364789Sahrens } 13652082Seschrock break; 1366789Sahrens 1367789Sahrens case ZFS_PROP_RECORDSIZE: 1368789Sahrens case ZFS_PROP_COMPRESSION: 13691356Seschrock case ZFS_PROP_ZONED: 1370*2885Sahrens case ZFS_PROP_CREATION: 1371*2885Sahrens case ZFS_PROP_COMPRESSRATIO: 1372*2885Sahrens case ZFS_PROP_REFERENCED: 1373*2885Sahrens case ZFS_PROP_USED: 1374*2885Sahrens case ZFS_PROP_CREATETXG: 1375*2885Sahrens case ZFS_PROP_AVAILABLE: 1376*2885Sahrens case ZFS_PROP_VOLSIZE: 1377*2885Sahrens case ZFS_PROP_VOLBLOCKSIZE: 13782082Seschrock *val = getprop_uint64(zhp, prop, source); 13792082Seschrock break; 1380789Sahrens 1381789Sahrens case ZFS_PROP_READONLY: 13822082Seschrock *val = getprop_uint64(zhp, prop, source); 13832082Seschrock 13842082Seschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 13852082Seschrock *val = B_TRUE; 1386789Sahrens if (src) 1387789Sahrens *src = ZFS_SRC_TEMPORARY; 13882082Seschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 13892082Seschrock *val = B_FALSE; 1390789Sahrens if (src) 1391789Sahrens *src = ZFS_SRC_TEMPORARY; 1392789Sahrens } 13932082Seschrock break; 1394789Sahrens 1395789Sahrens case ZFS_PROP_QUOTA: 1396789Sahrens case ZFS_PROP_RESERVATION: 1397*2885Sahrens *val = getprop_uint64(zhp, prop, source); 1398*2885Sahrens if (*val == 0) 1399789Sahrens *source = ""; /* default */ 1400789Sahrens else 1401789Sahrens *source = zhp->zfs_name; 14022082Seschrock break; 1403789Sahrens 1404789Sahrens case ZFS_PROP_SETUID: 14052082Seschrock *val = getprop_uint64(zhp, prop, source); 14062082Seschrock 14072082Seschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 14082082Seschrock *val = B_TRUE; 1409789Sahrens if (src) 1410789Sahrens *src = ZFS_SRC_TEMPORARY; 14112082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 14122082Seschrock *val = B_FALSE; 1413789Sahrens if (src) 1414789Sahrens *src = ZFS_SRC_TEMPORARY; 1415789Sahrens } 14162082Seschrock break; 1417789Sahrens 1418789Sahrens case ZFS_PROP_MOUNTED: 14192082Seschrock *val = (zhp->zfs_mntopts != NULL); 14202082Seschrock break; 1421789Sahrens 14222676Seschrock case ZFS_PROP_CANMOUNT: 14232676Seschrock *val = getprop_uint64(zhp, prop, source); 14242676Seschrock break; 14252676Seschrock 1426789Sahrens default: 14272082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14282082Seschrock "cannot get non-numeric property")); 14292082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14302082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1431789Sahrens } 1432789Sahrens 1433789Sahrens return (0); 1434789Sahrens } 1435789Sahrens 1436789Sahrens /* 1437789Sahrens * Calculate the source type, given the raw source string. 1438789Sahrens */ 1439789Sahrens static void 1440789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1441789Sahrens char *statbuf, size_t statlen) 1442789Sahrens { 1443789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1444789Sahrens return; 1445789Sahrens 1446789Sahrens if (source == NULL) { 1447789Sahrens *srctype = ZFS_SRC_NONE; 1448789Sahrens } else if (source[0] == '\0') { 1449789Sahrens *srctype = ZFS_SRC_DEFAULT; 1450789Sahrens } else { 1451789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1452789Sahrens *srctype = ZFS_SRC_LOCAL; 1453789Sahrens } else { 1454789Sahrens (void) strlcpy(statbuf, source, statlen); 1455789Sahrens *srctype = ZFS_SRC_INHERITED; 1456789Sahrens } 1457789Sahrens } 1458789Sahrens 1459789Sahrens } 1460789Sahrens 1461789Sahrens /* 1462789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1463789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1464789Sahrens * human-readable form. 1465789Sahrens * 1466789Sahrens * Returns 0 on success, or -1 on error. 1467789Sahrens */ 1468789Sahrens int 1469789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 14702082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1471789Sahrens { 1472789Sahrens char *source = NULL; 1473789Sahrens uint64_t val; 1474789Sahrens char *str; 1475789Sahrens const char *root; 14762676Seschrock const char *strval; 1477789Sahrens 1478789Sahrens /* 1479789Sahrens * Check to see if this property applies to our object 1480789Sahrens */ 1481789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1482789Sahrens return (-1); 1483789Sahrens 1484789Sahrens if (src) 1485789Sahrens *src = ZFS_SRC_NONE; 1486789Sahrens 1487789Sahrens switch (prop) { 1488789Sahrens case ZFS_PROP_ATIME: 1489789Sahrens case ZFS_PROP_READONLY: 1490789Sahrens case ZFS_PROP_SETUID: 1491789Sahrens case ZFS_PROP_ZONED: 1492789Sahrens case ZFS_PROP_DEVICES: 1493789Sahrens case ZFS_PROP_EXEC: 14942676Seschrock case ZFS_PROP_CANMOUNT: 1495789Sahrens /* 1496789Sahrens * Basic boolean values are built on top of 1497789Sahrens * get_numeric_property(). 1498789Sahrens */ 14992082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15002082Seschrock return (-1); 15012082Seschrock nicebool(val, propbuf, proplen); 1502789Sahrens 1503789Sahrens break; 1504789Sahrens 1505789Sahrens case ZFS_PROP_AVAILABLE: 1506789Sahrens case ZFS_PROP_RECORDSIZE: 1507789Sahrens case ZFS_PROP_CREATETXG: 1508789Sahrens case ZFS_PROP_REFERENCED: 1509789Sahrens case ZFS_PROP_USED: 1510789Sahrens case ZFS_PROP_VOLSIZE: 1511789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1512789Sahrens /* 1513789Sahrens * Basic numeric values are built on top of 1514789Sahrens * get_numeric_property(). 1515789Sahrens */ 15162082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15172082Seschrock return (-1); 1518789Sahrens if (literal) 15192856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 15202856Snd150628 (u_longlong_t)val); 1521789Sahrens else 1522789Sahrens zfs_nicenum(val, propbuf, proplen); 1523789Sahrens break; 1524789Sahrens 1525789Sahrens case ZFS_PROP_COMPRESSION: 1526789Sahrens case ZFS_PROP_CHECKSUM: 1527789Sahrens case ZFS_PROP_SNAPDIR: 1528789Sahrens case ZFS_PROP_ACLMODE: 1529789Sahrens case ZFS_PROP_ACLINHERIT: 15301356Seschrock val = getprop_uint64(zhp, prop, &source); 15312676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15322676Seschrock (void) strlcpy(propbuf, strval, proplen); 1533789Sahrens break; 1534789Sahrens 1535789Sahrens case ZFS_PROP_CREATION: 1536789Sahrens /* 1537789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1538789Sahrens * this into a string unless 'literal' is specified. 1539789Sahrens */ 1540789Sahrens { 1541*2885Sahrens val = getprop_uint64(zhp, prop, &source); 1542*2885Sahrens time_t time = (time_t)val; 1543789Sahrens struct tm t; 1544789Sahrens 1545789Sahrens if (literal || 1546789Sahrens localtime_r(&time, &t) == NULL || 1547789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1548789Sahrens &t) == 0) 1549*2885Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1550789Sahrens } 1551789Sahrens break; 1552789Sahrens 1553789Sahrens case ZFS_PROP_MOUNTPOINT: 1554789Sahrens /* 1555789Sahrens * Getting the precise mountpoint can be tricky. 1556789Sahrens * 1557789Sahrens * - for 'none' or 'legacy', return those values. 1558789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1559789Sahrens * - for inherited mountpoints, we want to take everything 1560789Sahrens * after our ancestor and append it to the inherited value. 1561789Sahrens * 1562789Sahrens * If the pool has an alternate root, we want to prepend that 1563789Sahrens * root to any values we return. 1564789Sahrens */ 15651544Seschrock root = zhp->zfs_root; 15661356Seschrock str = getprop_string(zhp, prop, &source); 15671356Seschrock 15681356Seschrock if (str[0] == '\0') { 1569789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1570789Sahrens root, zhp->zfs_name); 15711356Seschrock } else if (str[0] == '/') { 15721356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1573789Sahrens 1574789Sahrens if (relpath[0] == '/') 1575789Sahrens relpath++; 15761356Seschrock if (str[1] == '\0') 15771356Seschrock str++; 1578789Sahrens 1579789Sahrens if (relpath[0] == '\0') 1580789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 15811356Seschrock root, str); 1582789Sahrens else 1583789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 15841356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1585789Sahrens relpath); 1586789Sahrens } else { 1587789Sahrens /* 'legacy' or 'none' */ 15881356Seschrock (void) strlcpy(propbuf, str, proplen); 1589789Sahrens } 1590789Sahrens 1591789Sahrens break; 1592789Sahrens 1593789Sahrens case ZFS_PROP_SHARENFS: 15941356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 15951356Seschrock proplen); 1596789Sahrens break; 1597789Sahrens 1598789Sahrens case ZFS_PROP_ORIGIN: 1599*2885Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1600789Sahrens proplen); 1601789Sahrens /* 1602789Sahrens * If there is no parent at all, return failure to indicate that 1603789Sahrens * it doesn't apply to this dataset. 1604789Sahrens */ 1605789Sahrens if (propbuf[0] == '\0') 1606789Sahrens return (-1); 1607789Sahrens break; 1608789Sahrens 1609789Sahrens case ZFS_PROP_QUOTA: 1610789Sahrens case ZFS_PROP_RESERVATION: 16112082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16122082Seschrock return (-1); 1613789Sahrens 1614789Sahrens /* 1615789Sahrens * If quota or reservation is 0, we translate this into 'none' 1616789Sahrens * (unless literal is set), and indicate that it's the default 1617789Sahrens * value. Otherwise, we print the number nicely and indicate 1618789Sahrens * that its set locally. 1619789Sahrens */ 1620789Sahrens if (val == 0) { 1621789Sahrens if (literal) 1622789Sahrens (void) strlcpy(propbuf, "0", proplen); 1623789Sahrens else 1624789Sahrens (void) strlcpy(propbuf, "none", proplen); 1625789Sahrens } else { 1626789Sahrens if (literal) 16272856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 16282856Snd150628 (u_longlong_t)val); 1629789Sahrens else 1630789Sahrens zfs_nicenum(val, propbuf, proplen); 1631789Sahrens } 1632789Sahrens break; 1633789Sahrens 1634789Sahrens case ZFS_PROP_COMPRESSRATIO: 16352082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16362082Seschrock return (-1); 16372856Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 16382856Snd150628 val / 100, (longlong_t)val % 100); 1639789Sahrens break; 1640789Sahrens 1641789Sahrens case ZFS_PROP_TYPE: 1642789Sahrens switch (zhp->zfs_type) { 1643789Sahrens case ZFS_TYPE_FILESYSTEM: 1644789Sahrens str = "filesystem"; 1645789Sahrens break; 1646789Sahrens case ZFS_TYPE_VOLUME: 1647789Sahrens str = "volume"; 1648789Sahrens break; 1649789Sahrens case ZFS_TYPE_SNAPSHOT: 1650789Sahrens str = "snapshot"; 1651789Sahrens break; 1652789Sahrens default: 16532082Seschrock abort(); 1654789Sahrens } 1655789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1656789Sahrens break; 1657789Sahrens 1658789Sahrens case ZFS_PROP_MOUNTED: 1659789Sahrens /* 1660789Sahrens * The 'mounted' property is a pseudo-property that described 1661789Sahrens * whether the filesystem is currently mounted. Even though 1662789Sahrens * it's a boolean value, the typical values of "on" and "off" 1663789Sahrens * don't make sense, so we translate to "yes" and "no". 1664789Sahrens */ 16652082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 16662082Seschrock src, &source, &val) != 0) 16672082Seschrock return (-1); 16682082Seschrock if (val) 1669789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1670789Sahrens else 1671789Sahrens (void) strlcpy(propbuf, "no", proplen); 1672789Sahrens break; 1673789Sahrens 1674789Sahrens case ZFS_PROP_NAME: 1675789Sahrens /* 1676789Sahrens * The 'name' property is a pseudo-property derived from the 1677789Sahrens * dataset name. It is presented as a real property to simplify 1678789Sahrens * consumers. 1679789Sahrens */ 1680789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1681789Sahrens break; 1682789Sahrens 1683789Sahrens default: 16842082Seschrock abort(); 1685789Sahrens } 1686789Sahrens 1687789Sahrens get_source(zhp, src, source, statbuf, statlen); 1688789Sahrens 1689789Sahrens return (0); 1690789Sahrens } 1691789Sahrens 1692789Sahrens /* 1693789Sahrens * Utility function to get the given numeric property. Does no validation that 1694789Sahrens * the given property is the appropriate type; should only be used with 1695789Sahrens * hard-coded property types. 1696789Sahrens */ 1697789Sahrens uint64_t 1698789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1699789Sahrens { 1700789Sahrens char *source; 1701789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17022082Seschrock uint64_t val; 17032082Seschrock 17042082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17052082Seschrock 17062082Seschrock return (val); 1707789Sahrens } 1708789Sahrens 1709789Sahrens /* 1710789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1711789Sahrens */ 1712789Sahrens int 1713789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1714789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1715789Sahrens { 1716789Sahrens char *source; 1717789Sahrens 1718789Sahrens /* 1719789Sahrens * Check to see if this property applies to our object 1720789Sahrens */ 1721789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17222082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 17232082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17242082Seschrock zfs_prop_to_name(prop))); 1725789Sahrens 1726789Sahrens if (src) 1727789Sahrens *src = ZFS_SRC_NONE; 1728789Sahrens 17292082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17302082Seschrock return (-1); 1731789Sahrens 1732789Sahrens get_source(zhp, src, source, statbuf, statlen); 1733789Sahrens 1734789Sahrens return (0); 1735789Sahrens } 1736789Sahrens 1737789Sahrens /* 1738789Sahrens * Returns the name of the given zfs handle. 1739789Sahrens */ 1740789Sahrens const char * 1741789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1742789Sahrens { 1743789Sahrens return (zhp->zfs_name); 1744789Sahrens } 1745789Sahrens 1746789Sahrens /* 1747789Sahrens * Returns the type of the given zfs handle. 1748789Sahrens */ 1749789Sahrens zfs_type_t 1750789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1751789Sahrens { 1752789Sahrens return (zhp->zfs_type); 1753789Sahrens } 1754789Sahrens 1755789Sahrens /* 17561356Seschrock * Iterate over all child filesystems 1757789Sahrens */ 1758789Sahrens int 17591356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1760789Sahrens { 1761789Sahrens zfs_cmd_t zc = { 0 }; 1762789Sahrens zfs_handle_t *nzhp; 1763789Sahrens int ret; 1764789Sahrens 1765789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 17662082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1767789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1768789Sahrens /* 1769789Sahrens * Ignore private dataset names. 1770789Sahrens */ 1771789Sahrens if (dataset_name_hidden(zc.zc_name)) 1772789Sahrens continue; 1773789Sahrens 1774789Sahrens /* 1775789Sahrens * Silently ignore errors, as the only plausible explanation is 1776789Sahrens * that the pool has since been removed. 1777789Sahrens */ 17782082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 17792082Seschrock zc.zc_name)) == NULL) 1780789Sahrens continue; 1781789Sahrens 1782789Sahrens if ((ret = func(nzhp, data)) != 0) 1783789Sahrens return (ret); 1784789Sahrens } 1785789Sahrens 1786789Sahrens /* 1787789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1788789Sahrens * returned, then the underlying dataset has been removed since we 1789789Sahrens * obtained the handle. 1790789Sahrens */ 1791789Sahrens if (errno != ESRCH && errno != ENOENT) 17922082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 17932082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1794789Sahrens 17951356Seschrock return (0); 17961356Seschrock } 17971356Seschrock 17981356Seschrock /* 17991356Seschrock * Iterate over all snapshots 18001356Seschrock */ 18011356Seschrock int 18021356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18031356Seschrock { 18041356Seschrock zfs_cmd_t zc = { 0 }; 18051356Seschrock zfs_handle_t *nzhp; 18061356Seschrock int ret; 1807789Sahrens 1808789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18092082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18102082Seschrock &zc) == 0; 1811789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1812789Sahrens 18132082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18142082Seschrock zc.zc_name)) == NULL) 1815789Sahrens continue; 1816789Sahrens 1817789Sahrens if ((ret = func(nzhp, data)) != 0) 1818789Sahrens return (ret); 1819789Sahrens } 1820789Sahrens 1821789Sahrens /* 1822789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1823789Sahrens * returned, then the underlying dataset has been removed since we 1824789Sahrens * obtained the handle. Silently ignore this case, and return success. 1825789Sahrens */ 1826789Sahrens if (errno != ESRCH && errno != ENOENT) 18272082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18282082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1829789Sahrens 1830789Sahrens return (0); 1831789Sahrens } 1832789Sahrens 1833789Sahrens /* 18341356Seschrock * Iterate over all children, snapshots and filesystems 18351356Seschrock */ 18361356Seschrock int 18371356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18381356Seschrock { 18391356Seschrock int ret; 18401356Seschrock 18411356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 18421356Seschrock return (ret); 18431356Seschrock 18441356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 18451356Seschrock } 18461356Seschrock 18471356Seschrock /* 1848789Sahrens * Given a complete name, return just the portion that refers to the parent. 1849789Sahrens * Can return NULL if this is a pool. 1850789Sahrens */ 1851789Sahrens static int 1852789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1853789Sahrens { 1854789Sahrens char *loc; 1855789Sahrens 1856789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1857789Sahrens return (-1); 1858789Sahrens 1859789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1860789Sahrens buf[loc - path] = '\0'; 1861789Sahrens 1862789Sahrens return (0); 1863789Sahrens } 1864789Sahrens 1865789Sahrens /* 18662676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 18672676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 18682676Seschrock * when creating new datasets. 1869789Sahrens */ 1870789Sahrens static int 18712676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1872789Sahrens { 1873789Sahrens zfs_cmd_t zc = { 0 }; 1874789Sahrens char parent[ZFS_MAXNAMELEN]; 1875789Sahrens char *slash; 18761356Seschrock zfs_handle_t *zhp; 18772082Seschrock char errbuf[1024]; 18782082Seschrock 18792082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 18802082Seschrock path); 1881789Sahrens 1882789Sahrens /* get parent, and check to see if this is just a pool */ 1883789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 18842082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18852082Seschrock "missing dataset name")); 18862082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1887789Sahrens } 1888789Sahrens 1889789Sahrens /* check to see if the pool exists */ 1890789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1891789Sahrens slash = parent + strlen(parent); 1892789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1893789Sahrens zc.zc_name[slash - parent] = '\0'; 18942082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1895789Sahrens errno == ENOENT) { 18962082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18972082Seschrock "no such pool '%s'"), zc.zc_name); 18982082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1899789Sahrens } 1900789Sahrens 1901789Sahrens /* check to see if the parent dataset exists */ 19022082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1903789Sahrens switch (errno) { 1904789Sahrens case ENOENT: 19052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19062082Seschrock "parent does not exist")); 19072082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1908789Sahrens 1909789Sahrens default: 19102082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1911789Sahrens } 1912789Sahrens } 1913789Sahrens 19142676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1915789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19162676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19172082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19181356Seschrock zfs_close(zhp); 1919789Sahrens return (-1); 1920789Sahrens } 1921789Sahrens 1922789Sahrens /* make sure parent is a filesystem */ 19231356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19252082Seschrock "parent is not a filesystem")); 19262082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19271356Seschrock zfs_close(zhp); 1928789Sahrens return (-1); 1929789Sahrens } 1930789Sahrens 19311356Seschrock zfs_close(zhp); 1932789Sahrens return (0); 1933789Sahrens } 1934789Sahrens 1935789Sahrens /* 19362676Seschrock * Create a new filesystem or volume. 1937789Sahrens */ 1938789Sahrens int 19392082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 19402676Seschrock nvlist_t *props) 1941789Sahrens { 1942789Sahrens zfs_cmd_t zc = { 0 }; 1943789Sahrens int ret; 1944789Sahrens uint64_t size = 0; 1945789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 19462082Seschrock char errbuf[1024]; 19472676Seschrock uint64_t zoned; 19482082Seschrock 19492082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 19502082Seschrock "cannot create '%s'"), path); 1951789Sahrens 1952789Sahrens /* validate the path, taking care to note the extended error message */ 19532082Seschrock if (!zfs_validate_name(hdl, path, type)) 19542082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1955789Sahrens 1956789Sahrens /* validate parents exist */ 19572676Seschrock if (check_parents(hdl, path, &zoned) != 0) 1958789Sahrens return (-1); 1959789Sahrens 1960789Sahrens /* 1961789Sahrens * The failure modes when creating a dataset of a different type over 1962789Sahrens * one that already exists is a little strange. In particular, if you 1963789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1964789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1965789Sahrens * first try to see if the dataset exists. 1966789Sahrens */ 1967789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 19682082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 19692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19702082Seschrock "dataset already exists")); 19712082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1972789Sahrens } 1973789Sahrens 1974789Sahrens if (type == ZFS_TYPE_VOLUME) 1975789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1976789Sahrens else 1977789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1978789Sahrens 19792676Seschrock if (props && (props = zfs_validate_properties(hdl, type, props, zoned, 19802676Seschrock NULL, errbuf)) == 0) 19812676Seschrock return (-1); 19822676Seschrock 1983789Sahrens if (type == ZFS_TYPE_VOLUME) { 19841133Seschrock /* 19851133Seschrock * If we are creating a volume, the size and block size must 19861133Seschrock * satisfy a few restraints. First, the blocksize must be a 19871133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 19881133Seschrock * volsize must be a multiple of the block size, and cannot be 19891133Seschrock * zero. 19901133Seschrock */ 19912676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 19922676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 19932676Seschrock nvlist_free(props); 19942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19952676Seschrock "missing volume size")); 19962676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1997789Sahrens } 1998789Sahrens 19992676Seschrock if ((ret = nvlist_lookup_uint64(props, 20002676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20012676Seschrock &blocksize)) != 0) { 20022676Seschrock if (ret == ENOENT) { 20032676Seschrock blocksize = zfs_prop_default_numeric( 20042676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20052676Seschrock } else { 20062676Seschrock nvlist_free(props); 20072676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20082676Seschrock "missing volume block size")); 20092676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20102676Seschrock } 20112676Seschrock } 20122676Seschrock 20132676Seschrock if (size == 0) { 20142676Seschrock nvlist_free(props); 20152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20162676Seschrock "volume size cannot be zero")); 20172676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20181133Seschrock } 20191133Seschrock 20201133Seschrock if (size % blocksize != 0) { 20212676Seschrock nvlist_free(props); 20222082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20232676Seschrock "volume size must be a multiple of volume block " 20242676Seschrock "size")); 20252676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20261133Seschrock } 2027789Sahrens } 2028789Sahrens 20292676Seschrock if (props && 20302676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20312676Seschrock return (-1); 20322676Seschrock nvlist_free(props); 20332676Seschrock 2034789Sahrens /* create the dataset */ 20352082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2036789Sahrens 2037789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 20382082Seschrock ret = zvol_create_link(hdl, path); 2039789Sahrens 20402676Seschrock zcmd_free_nvlists(&zc); 20412676Seschrock 2042789Sahrens /* check for failure */ 2043789Sahrens if (ret != 0) { 2044789Sahrens char parent[ZFS_MAXNAMELEN]; 2045789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2046789Sahrens 2047789Sahrens switch (errno) { 2048789Sahrens case ENOENT: 20492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20502082Seschrock "no such parent '%s'"), parent); 20512082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2052789Sahrens 2053789Sahrens case EINVAL: 20542082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20552082Seschrock "parent '%s' is not a filesysem"), parent); 20562082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2057789Sahrens 2058789Sahrens case EDOM: 20592082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20602676Seschrock "volume block size must be power of 2 from " 20612676Seschrock "%u to %uk"), 2062789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2063789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 20642082Seschrock 20652676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20662082Seschrock 2067789Sahrens #ifdef _ILP32 2068789Sahrens case EOVERFLOW: 2069789Sahrens /* 2070789Sahrens * This platform can't address a volume this big. 2071789Sahrens */ 20722082Seschrock if (type == ZFS_TYPE_VOLUME) 20732082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 20742082Seschrock errbuf)); 2075789Sahrens #endif 20762082Seschrock /* FALLTHROUGH */ 2077789Sahrens default: 20782082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2079789Sahrens } 2080789Sahrens } 2081789Sahrens 2082789Sahrens return (0); 2083789Sahrens } 2084789Sahrens 2085789Sahrens /* 2086789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2087789Sahrens * isn't mounted, and that there are no active dependents. 2088789Sahrens */ 2089789Sahrens int 2090789Sahrens zfs_destroy(zfs_handle_t *zhp) 2091789Sahrens { 2092789Sahrens zfs_cmd_t zc = { 0 }; 2093789Sahrens int ret; 2094789Sahrens 2095789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2096789Sahrens 20972676Seschrock if (ZFS_IS_VOLUME(zhp)) { 20982082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2099789Sahrens return (-1); 2100789Sahrens 2101789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2102789Sahrens } else { 2103789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2104789Sahrens } 2105789Sahrens 21062082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 21072199Sahrens if (ret != 0) { 21082082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 21092082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21102082Seschrock zhp->zfs_name)); 21112199Sahrens } 2112789Sahrens 2113789Sahrens remove_mountpoint(zhp); 2114789Sahrens 2115789Sahrens return (0); 2116789Sahrens } 2117789Sahrens 21182199Sahrens struct destroydata { 21192199Sahrens char *snapname; 21202199Sahrens boolean_t gotone; 21212199Sahrens }; 21222199Sahrens 21232199Sahrens static int 21242199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 21252199Sahrens { 21262199Sahrens struct destroydata *dd = arg; 21272199Sahrens zfs_handle_t *szhp; 21282199Sahrens char name[ZFS_MAXNAMELEN]; 21292199Sahrens 21302676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 21312676Seschrock (void) strlcat(name, "@", sizeof (name)); 21322676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 21332199Sahrens 21342199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 21352199Sahrens if (szhp) { 21362199Sahrens dd->gotone = B_TRUE; 21372199Sahrens zfs_close(szhp); 21382199Sahrens } 21392199Sahrens 21402199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 21412199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 21422199Sahrens /* 21432199Sahrens * NB: this is simply a best-effort. We don't want to 21442199Sahrens * return an error, because then we wouldn't visit all 21452199Sahrens * the volumes. 21462199Sahrens */ 21472199Sahrens } 21482199Sahrens 21492199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 21502199Sahrens } 21512199Sahrens 21522199Sahrens /* 21532199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 21542199Sahrens */ 21552199Sahrens int 21562199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 21572199Sahrens { 21582199Sahrens zfs_cmd_t zc = { 0 }; 21592199Sahrens int ret; 21602199Sahrens struct destroydata dd = { 0 }; 21612199Sahrens 21622199Sahrens dd.snapname = snapname; 21632199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 21642199Sahrens 21652199Sahrens if (!dd.gotone) { 21662199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 21672199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 21682199Sahrens zhp->zfs_name, snapname)); 21692199Sahrens } 21702199Sahrens 21712199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 21722676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 21732199Sahrens 21742199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 21752199Sahrens if (ret != 0) { 21762199Sahrens char errbuf[1024]; 21772199Sahrens 21782199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 21792199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 21802199Sahrens 21812199Sahrens switch (errno) { 21822199Sahrens case EEXIST: 21832199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 21842199Sahrens "snapshot is cloned")); 21852199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 21862199Sahrens 21872199Sahrens default: 21882199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 21892199Sahrens errbuf)); 21902199Sahrens } 21912199Sahrens } 21922199Sahrens 21932199Sahrens return (0); 21942199Sahrens } 21952199Sahrens 2196789Sahrens /* 2197789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2198789Sahrens */ 2199789Sahrens int 22002676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2201789Sahrens { 2202789Sahrens zfs_cmd_t zc = { 0 }; 2203789Sahrens char parent[ZFS_MAXNAMELEN]; 2204789Sahrens int ret; 22052082Seschrock char errbuf[1024]; 22062082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22072676Seschrock zfs_type_t type; 22082676Seschrock uint64_t zoned; 2209789Sahrens 2210789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2211789Sahrens 22122082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22132082Seschrock "cannot create '%s'"), target); 22142082Seschrock 2215789Sahrens /* validate the target name */ 22162082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 22172082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2218789Sahrens 2219789Sahrens /* validate parents exist */ 22202676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2221789Sahrens return (-1); 2222789Sahrens 2223789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2224789Sahrens 2225789Sahrens /* do the clone */ 22262676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2227789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 22282744Snn35248 type = ZFS_TYPE_VOLUME; 22292676Seschrock } else { 2230789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 22312744Snn35248 type = ZFS_TYPE_FILESYSTEM; 22322676Seschrock } 22332676Seschrock 22342676Seschrock if (props) { 22352676Seschrock if ((props = zfs_validate_properties(hdl, type, props, zoned, 22362676Seschrock zhp, errbuf)) == NULL) 22372676Seschrock return (-1); 22382676Seschrock 22392676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 22402676Seschrock nvlist_free(props); 22412676Seschrock return (-1); 22422676Seschrock } 22432676Seschrock 22442676Seschrock nvlist_free(props); 22452676Seschrock } 2246789Sahrens 2247789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 22482676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 22492082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2250789Sahrens 22512676Seschrock zcmd_free_nvlists(&zc); 22522676Seschrock 2253789Sahrens if (ret != 0) { 2254789Sahrens switch (errno) { 2255789Sahrens 2256789Sahrens case ENOENT: 2257789Sahrens /* 2258789Sahrens * The parent doesn't exist. We should have caught this 2259789Sahrens * above, but there may a race condition that has since 2260789Sahrens * destroyed the parent. 2261789Sahrens * 2262789Sahrens * At this point, we don't know whether it's the source 2263789Sahrens * that doesn't exist anymore, or whether the target 2264789Sahrens * dataset doesn't exist. 2265789Sahrens */ 22662082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22672082Seschrock "no such parent '%s'"), parent); 22682082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 22692082Seschrock 22702082Seschrock case EXDEV: 22712082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22722082Seschrock "source and target pools differ")); 22732082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 22742082Seschrock errbuf)); 22752082Seschrock 22762082Seschrock default: 22772082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 22782082Seschrock errbuf)); 22792082Seschrock } 22802676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 22812082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 22822082Seschrock } 22832082Seschrock 22842082Seschrock return (ret); 22852082Seschrock } 22862082Seschrock 22872082Seschrock typedef struct promote_data { 22882082Seschrock char cb_mountpoint[MAXPATHLEN]; 22892082Seschrock const char *cb_target; 22902082Seschrock const char *cb_errbuf; 22912082Seschrock uint64_t cb_pivot_txg; 22922082Seschrock } promote_data_t; 22932082Seschrock 22942082Seschrock static int 22952082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 22962082Seschrock { 22972082Seschrock promote_data_t *pd = data; 22982082Seschrock zfs_handle_t *szhp; 22992082Seschrock char snapname[MAXPATHLEN]; 23002082Seschrock 23012082Seschrock /* We don't care about snapshots after the pivot point */ 23022082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23032082Seschrock return (0); 23042082Seschrock 23052417Sahrens /* Remove the device link if it's a zvol. */ 23062676Seschrock if (ZFS_IS_VOLUME(zhp)) 23072417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23082082Seschrock 23092082Seschrock /* Check for conflicting names */ 23102676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 23112676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 23122082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 23132082Seschrock if (szhp != NULL) { 23142082Seschrock zfs_close(szhp); 23152082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23162082Seschrock "snapshot name '%s' from origin \n" 23172082Seschrock "conflicts with '%s' from target"), 23182082Seschrock zhp->zfs_name, snapname); 23192082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 23202082Seschrock } 23212082Seschrock return (0); 23222082Seschrock } 23232082Seschrock 23242417Sahrens static int 23252417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 23262417Sahrens { 23272417Sahrens promote_data_t *pd = data; 23282417Sahrens 23292417Sahrens /* We don't care about snapshots after the pivot point */ 23302417Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23312417Sahrens return (0); 23322417Sahrens 23332417Sahrens /* Create the device link if it's a zvol. */ 23342676Seschrock if (ZFS_IS_VOLUME(zhp)) 23352417Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 23362417Sahrens 23372417Sahrens return (0); 23382417Sahrens } 23392417Sahrens 23402082Seschrock /* 23412082Seschrock * Promotes the given clone fs to be the clone parent. 23422082Seschrock */ 23432082Seschrock int 23442082Seschrock zfs_promote(zfs_handle_t *zhp) 23452082Seschrock { 23462082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 23472082Seschrock zfs_cmd_t zc = { 0 }; 23482082Seschrock char parent[MAXPATHLEN]; 23492082Seschrock char *cp; 23502082Seschrock int ret; 23512082Seschrock zfs_handle_t *pzhp; 23522082Seschrock promote_data_t pd; 23532082Seschrock char errbuf[1024]; 23542082Seschrock 23552082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23562082Seschrock "cannot promote '%s'"), zhp->zfs_name); 23572082Seschrock 23582082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 23592082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23602082Seschrock "snapshots can not be promoted")); 23612082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 23622082Seschrock } 23632082Seschrock 23642676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 23652082Seschrock if (parent[0] == '\0') { 23662082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23672082Seschrock "not a cloned filesystem")); 23682082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 23692082Seschrock } 23702082Seschrock cp = strchr(parent, '@'); 23712082Seschrock *cp = '\0'; 23722082Seschrock 23732082Seschrock /* Walk the snapshots we will be moving */ 23742082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 23752082Seschrock if (pzhp == NULL) 23762082Seschrock return (-1); 23772082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 23782082Seschrock zfs_close(pzhp); 23792082Seschrock pd.cb_target = zhp->zfs_name; 23802082Seschrock pd.cb_errbuf = errbuf; 23812082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 23822082Seschrock if (pzhp == NULL) 23832082Seschrock return (-1); 23842082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 23852082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 23862082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 23872417Sahrens if (ret != 0) { 23882417Sahrens zfs_close(pzhp); 23892082Seschrock return (-1); 23902417Sahrens } 23912082Seschrock 23922082Seschrock /* issue the ioctl */ 23932676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 23942676Seschrock sizeof (zc.zc_value)); 23952082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 23962082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 23972082Seschrock 23982082Seschrock if (ret != 0) { 23992417Sahrens int save_errno = errno; 24002417Sahrens 24012417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24022417Sahrens zfs_close(pzhp); 24032417Sahrens 24042417Sahrens switch (save_errno) { 2405789Sahrens case EEXIST: 2406789Sahrens /* 24072082Seschrock * There is a conflicting snapshot name. We 24082082Seschrock * should have caught this above, but they could 24092082Seschrock * have renamed something in the mean time. 2410789Sahrens */ 24112082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24122082Seschrock "conflicting snapshot name from parent '%s'"), 24132082Seschrock parent); 24142082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2415789Sahrens 2416789Sahrens default: 24172417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2418789Sahrens } 24192417Sahrens } else { 24202417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2421789Sahrens } 2422789Sahrens 24232417Sahrens zfs_close(pzhp); 2424789Sahrens return (ret); 2425789Sahrens } 2426789Sahrens 24272199Sahrens static int 24282199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 24292199Sahrens { 24302199Sahrens char *snapname = arg; 24312676Seschrock int ret; 24322199Sahrens 24332199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 24342199Sahrens char name[MAXPATHLEN]; 24352199Sahrens 24362676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 24372676Seschrock (void) strlcat(name, "@", sizeof (name)); 24382676Seschrock (void) strlcat(name, snapname, sizeof (name)); 24392199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 24402199Sahrens /* 24412199Sahrens * NB: this is simply a best-effort. We don't want to 24422199Sahrens * return an error, because then we wouldn't visit all 24432199Sahrens * the volumes. 24442199Sahrens */ 24452199Sahrens } 24462676Seschrock 24472676Seschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 24482676Seschrock 24492676Seschrock zfs_close(zhp); 24502676Seschrock 24512676Seschrock return (ret); 24522199Sahrens } 24532199Sahrens 2454789Sahrens /* 2455789Sahrens * Takes a snapshot of the given dataset 2456789Sahrens */ 2457789Sahrens int 24582199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2459789Sahrens { 2460789Sahrens const char *delim; 2461789Sahrens char *parent; 2462789Sahrens zfs_handle_t *zhp; 2463789Sahrens zfs_cmd_t zc = { 0 }; 2464789Sahrens int ret; 24652082Seschrock char errbuf[1024]; 24662082Seschrock 24672082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24682082Seschrock "cannot snapshot '%s'"), path); 24692082Seschrock 24702082Seschrock /* validate the target name */ 24712082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 24722082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2473789Sahrens 2474789Sahrens /* make sure the parent exists and is of the appropriate type */ 24752199Sahrens delim = strchr(path, '@'); 24762082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 24772082Seschrock return (-1); 2478789Sahrens (void) strncpy(parent, path, delim - path); 2479789Sahrens parent[delim - path] = '\0'; 2480789Sahrens 24812082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2482789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2483789Sahrens free(parent); 2484789Sahrens return (-1); 2485789Sahrens } 2486789Sahrens 24872199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24882676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 24892199Sahrens zc.zc_cookie = recursive; 24902199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 24912199Sahrens 24922199Sahrens /* 24932199Sahrens * if it was recursive, the one that actually failed will be in 24942199Sahrens * zc.zc_name. 24952199Sahrens */ 24962199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24972676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 24982199Sahrens if (ret == 0 && recursive) { 24992199Sahrens (void) zfs_iter_filesystems(zhp, 25002199Sahrens zfs_create_link_cb, (char *)delim+1); 25012199Sahrens } 2502789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 25032082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25042199Sahrens if (ret != 0) { 25052082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 25062082Seschrock &zc); 25072199Sahrens } 2508789Sahrens } 2509789Sahrens 25102082Seschrock if (ret != 0) 25112082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2512789Sahrens 2513789Sahrens free(parent); 2514789Sahrens zfs_close(zhp); 2515789Sahrens 2516789Sahrens return (ret); 2517789Sahrens } 2518789Sahrens 2519789Sahrens /* 2520789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2521789Sahrens */ 2522789Sahrens int 2523*2885Sahrens zfs_send(zfs_handle_t *zhp, const char *fromsnap) 2524789Sahrens { 2525789Sahrens zfs_cmd_t zc = { 0 }; 2526789Sahrens int ret; 25272082Seschrock char errbuf[1024]; 2528*2885Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 25292082Seschrock 25302082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2531*2885Sahrens "cannot send '%s'"), zhp->zfs_name); 2532789Sahrens 2533789Sahrens /* do the ioctl() */ 2534*2885Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2535*2885Sahrens if (fromsnap) 2536*2885Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 2537789Sahrens zc.zc_cookie = STDOUT_FILENO; 2538789Sahrens 2539*2885Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2540789Sahrens if (ret != 0) { 2541789Sahrens switch (errno) { 2542789Sahrens 2543789Sahrens case EXDEV: 25442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25452082Seschrock "not an ealier snapshot from the same fs")); 25462082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2547789Sahrens 2548789Sahrens case EDQUOT: 2549789Sahrens case EFBIG: 2550789Sahrens case EIO: 2551789Sahrens case ENOLINK: 2552789Sahrens case ENOSPC: 2553789Sahrens case ENOSTR: 2554789Sahrens case ENXIO: 2555789Sahrens case EPIPE: 2556789Sahrens case ERANGE: 2557789Sahrens case EFAULT: 2558789Sahrens case EROFS: 25592082Seschrock zfs_error_aux(hdl, strerror(errno)); 25602082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2561789Sahrens 2562789Sahrens default: 25632082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2564789Sahrens } 2565789Sahrens } 2566789Sahrens 2567789Sahrens return (ret); 2568789Sahrens } 2569789Sahrens 2570789Sahrens /* 2571*2885Sahrens * Create ancestors of 'target', but not target itself, and not 2572*2885Sahrens * ancestors whose names are shorter than prefixlen. Die if 2573*2885Sahrens * prefixlen-ancestor does not exist. 2574*2885Sahrens */ 2575*2885Sahrens static int 2576*2885Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2577*2885Sahrens { 2578*2885Sahrens zfs_handle_t *h; 2579*2885Sahrens char *cp; 2580*2885Sahrens 2581*2885Sahrens /* make sure prefix exists */ 2582*2885Sahrens cp = strchr(target + prefixlen, '/'); 2583*2885Sahrens *cp = '\0'; 2584*2885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2585*2885Sahrens *cp = '/'; 2586*2885Sahrens if (h == NULL) 2587*2885Sahrens return (-1); 2588*2885Sahrens zfs_close(h); 2589*2885Sahrens 2590*2885Sahrens /* 2591*2885Sahrens * Attempt to create, mount, and share any ancestor filesystems, 2592*2885Sahrens * up to the prefixlen-long one. 2593*2885Sahrens */ 2594*2885Sahrens for (cp = target + prefixlen + 1; 2595*2885Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 2596*2885Sahrens const char *opname; 2597*2885Sahrens 2598*2885Sahrens *cp = '\0'; 2599*2885Sahrens 2600*2885Sahrens h = make_dataset_handle(hdl, target); 2601*2885Sahrens if (h) { 2602*2885Sahrens /* it already exists, nothing to do here */ 2603*2885Sahrens zfs_close(h); 2604*2885Sahrens continue; 2605*2885Sahrens } 2606*2885Sahrens 2607*2885Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 2608*2885Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2609*2885Sahrens NULL) != 0) 2610*2885Sahrens goto ancestorerr; 2611*2885Sahrens 2612*2885Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 2613*2885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2614*2885Sahrens if (h == NULL) 2615*2885Sahrens goto ancestorerr; 2616*2885Sahrens 2617*2885Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 2618*2885Sahrens if (zfs_mount(h, NULL, 0) != 0) 2619*2885Sahrens goto ancestorerr; 2620*2885Sahrens 2621*2885Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 2622*2885Sahrens if (zfs_share(h) != 0) 2623*2885Sahrens goto ancestorerr; 2624*2885Sahrens 2625*2885Sahrens zfs_close(h); 2626*2885Sahrens 2627*2885Sahrens continue; 2628*2885Sahrens ancestorerr: 2629*2885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2630*2885Sahrens "failed to %s ancestor '%s'"), opname, target); 2631*2885Sahrens return (-1); 2632*2885Sahrens } 2633*2885Sahrens 2634*2885Sahrens return (0); 2635*2885Sahrens } 2636*2885Sahrens 2637*2885Sahrens /* 2638789Sahrens * Restores a backup of tosnap from stdin. 2639789Sahrens */ 2640789Sahrens int 26412082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 26422665Snd150628 int verbose, int dryrun, boolean_t force) 2643789Sahrens { 2644789Sahrens zfs_cmd_t zc = { 0 }; 2645789Sahrens time_t begin_time; 2646*2885Sahrens int ioctl_err, err, bytes, size, choplen; 2647789Sahrens char *cp; 2648789Sahrens dmu_replay_record_t drr; 2649789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 26502082Seschrock char errbuf[1024]; 26512665Snd150628 prop_changelist_t *clp; 2652*2885Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2653789Sahrens 2654789Sahrens begin_time = time(NULL); 2655789Sahrens 26562082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26572082Seschrock "cannot receive")); 26582082Seschrock 2659789Sahrens /* read in the BEGIN record */ 2660789Sahrens cp = (char *)&drr; 2661789Sahrens bytes = 0; 2662789Sahrens do { 2663868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2664868Sahrens cp += size; 2665868Sahrens bytes += size; 2666868Sahrens } while (size > 0); 2667868Sahrens 2668868Sahrens if (size < 0 || bytes != sizeof (drr)) { 26692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26702082Seschrock "stream (failed to read first record)")); 26712082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2672789Sahrens } 2673789Sahrens 2674789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2675789Sahrens 2676789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2677789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 26782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26792082Seschrock "stream (bad magic number)")); 26802082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2681789Sahrens } 2682789Sahrens 2683789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2684789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 26852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 26862082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2687789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 26882082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2689789Sahrens } 2690789Sahrens 2691*2885Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 2692*2885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2693*2885Sahrens "stream (bad snapshot name)")); 2694*2885Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2695*2885Sahrens } 2696789Sahrens /* 2697*2885Sahrens * Determine how much of the snapshot name stored in the stream 2698*2885Sahrens * we are going to tack on to the name they specified on the 2699*2885Sahrens * command line, and how much we are going to chop off. 2700*2885Sahrens * 2701*2885Sahrens * If they specified a snapshot, chop the entire name stored in 2702*2885Sahrens * the stream. 2703789Sahrens */ 2704*2885Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2705789Sahrens if (isprefix) { 2706*2885Sahrens /* 2707*2885Sahrens * They specified a fs with -d, we want to tack on 2708*2885Sahrens * everything but the pool name stored in the stream 2709*2885Sahrens */ 2710*2885Sahrens if (strchr(tosnap, '@')) { 2711*2885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2712*2885Sahrens "argument - snapshot not allowed with -d")); 2713*2885Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2714789Sahrens } 2715*2885Sahrens cp = strchr(chopprefix, '/'); 2716789Sahrens if (cp == NULL) 2717*2885Sahrens cp = strchr(chopprefix, '@'); 2718*2885Sahrens *cp = '\0'; 2719789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2720789Sahrens /* 2721*2885Sahrens * If they specified a filesystem without -d, we want to 2722*2885Sahrens * tack on everything after the fs specified in the 2723*2885Sahrens * first name from the stream. 2724789Sahrens */ 2725*2885Sahrens cp = strchr(chopprefix, '@'); 2726*2885Sahrens *cp = '\0'; 2727789Sahrens } 2728*2885Sahrens choplen = strlen(chopprefix); 2729*2885Sahrens 2730*2885Sahrens /* 2731*2885Sahrens * Determine name of destination snapshot, store in zc_value. 2732*2885Sahrens */ 2733*2885Sahrens (void) strcpy(zc.zc_value, tosnap); 2734*2885Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 2735*2885Sahrens sizeof (zc.zc_value)); 2736*2885Sahrens 2737*2885Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2738789Sahrens if (drrb->drr_fromguid) { 2739789Sahrens /* incremental backup stream */ 2740*2885Sahrens zfs_handle_t *h; 2741*2885Sahrens 2742*2885Sahrens /* do the recvbackup ioctl to the containing fs */ 2743*2885Sahrens *strchr(zc.zc_name, '@') = '\0'; 2744789Sahrens 2745789Sahrens /* make sure destination fs exists */ 27462082Seschrock h = zfs_open(hdl, zc.zc_name, 27472082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 27482082Seschrock if (h == NULL) 2749789Sahrens return (-1); 2750868Sahrens if (!dryrun) { 27512665Snd150628 /* 27522665Snd150628 * We need to unmount all the dependents of the dataset 27532665Snd150628 * and the dataset itself. If it's a volume 27542665Snd150628 * then remove device link. 27552665Snd150628 */ 2756868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 27572665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 27582665Snd150628 if (clp == NULL) 27592665Snd150628 return (-1); 27602665Snd150628 if (changelist_prefix(clp) != 0) { 27612665Snd150628 changelist_free(clp); 27622665Snd150628 return (-1); 27632665Snd150628 } 2764868Sahrens } else { 27652082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2766868Sahrens } 2767868Sahrens } 2768789Sahrens zfs_close(h); 2769789Sahrens } else { 2770789Sahrens /* full backup stream */ 2771789Sahrens 2772868Sahrens /* Make sure destination fs does not exist */ 2773*2885Sahrens *strchr(zc.zc_name, '@') = '\0'; 27742082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 27752082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27762082Seschrock "destination '%s' exists"), zc.zc_name); 27772082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2778868Sahrens } 2779868Sahrens 2780*2885Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2781*2885Sahrens /* 2782*2885Sahrens * they're trying to do a recv into a 2783*2885Sahrens * nonexistant topmost filesystem. 2784*2885Sahrens */ 2785*2885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2786*2885Sahrens "destination does not exist"), zc.zc_name); 2787*2885Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2788*2885Sahrens } 2789*2885Sahrens 2790868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2791*2885Sahrens *strrchr(zc.zc_name, '/') = '\0'; 2792*2885Sahrens 2793*2885Sahrens if (isprefix && (err = create_parents(hdl, 2794*2885Sahrens zc.zc_value, strlen(tosnap))) != 0) { 2795*2885Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 2796*2885Sahrens } 2797*2885Sahrens 2798789Sahrens } 2799789Sahrens 2800789Sahrens zc.zc_cookie = STDIN_FILENO; 28012676Seschrock zc.zc_guid = force; 2802789Sahrens if (verbose) { 28031749Sahrens (void) printf("%s %s stream of %s into %s\n", 28041749Sahrens dryrun ? "would receive" : "receiving", 2805789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2806789Sahrens drr.drr_u.drr_begin.drr_toname, 28072676Seschrock zc.zc_value); 2808789Sahrens (void) fflush(stdout); 2809789Sahrens } 2810789Sahrens if (dryrun) 2811789Sahrens return (0); 28122082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2813868Sahrens if (ioctl_err != 0) { 2814789Sahrens switch (errno) { 2815789Sahrens case ENODEV: 28162082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28172082Seschrock "most recent snapshot does not match incremental " 28182082Seschrock "source")); 28192082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2820789Sahrens break; 2821789Sahrens case ETXTBSY: 28222082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28232082Seschrock "destination has been modified since most recent " 28242082Seschrock "snapshot")); 28252082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2826789Sahrens break; 2827789Sahrens case EEXIST: 2828789Sahrens if (drrb->drr_fromguid == 0) { 2829789Sahrens /* it's the containing fs that exists */ 28302676Seschrock cp = strchr(zc.zc_value, '@'); 2831789Sahrens *cp = '\0'; 2832789Sahrens } 28332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28342082Seschrock "destination already exists")); 28352082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 28362676Seschrock "cannot restore to %s"), zc.zc_value); 2837789Sahrens break; 2838789Sahrens case EINVAL: 28392082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2840868Sahrens break; 28411544Seschrock case ECKSUM: 28422082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28432082Seschrock "invalid stream (checksum mismatch)")); 28442082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2845789Sahrens break; 2846789Sahrens default: 28472082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2848789Sahrens } 2849789Sahrens } 2850789Sahrens 2851789Sahrens /* 2852868Sahrens * Mount or recreate the /dev links for the target filesystem 2853868Sahrens * (if created, or if we tore them down to do an incremental 2854868Sahrens * restore), and the /dev links for the new snapshot (if 28552665Snd150628 * created). Also mount any children of the target filesystem 28562665Snd150628 * if we did an incremental receive. 2857789Sahrens */ 28582676Seschrock cp = strchr(zc.zc_value, '@'); 2859868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2860789Sahrens zfs_handle_t *h; 2861789Sahrens 2862789Sahrens *cp = '\0'; 28632676Seschrock h = zfs_open(hdl, zc.zc_value, 2864789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2865868Sahrens *cp = '@'; 2866789Sahrens if (h) { 28672665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 28682082Seschrock err = zvol_create_link(hdl, h->zfs_name); 28691544Seschrock if (err == 0 && ioctl_err == 0) 28702082Seschrock err = zvol_create_link(hdl, 28712676Seschrock zc.zc_value); 28722665Snd150628 } else { 28732665Snd150628 if (drrb->drr_fromguid) { 28742665Snd150628 err = changelist_postfix(clp); 28752665Snd150628 changelist_free(clp); 28762665Snd150628 } else { 28772665Snd150628 err = zfs_mount(h, NULL, 0); 28782665Snd150628 } 2879868Sahrens } 28802665Snd150628 zfs_close(h); 2881789Sahrens } 2882789Sahrens } 2883789Sahrens 2884868Sahrens if (err || ioctl_err) 2885868Sahrens return (-1); 2886789Sahrens 2887789Sahrens if (verbose) { 2888789Sahrens char buf1[64]; 2889789Sahrens char buf2[64]; 2890789Sahrens uint64_t bytes = zc.zc_cookie; 2891789Sahrens time_t delta = time(NULL) - begin_time; 2892789Sahrens if (delta == 0) 2893789Sahrens delta = 1; 2894789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2895789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2896789Sahrens 28971749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2898789Sahrens buf1, delta, buf2); 2899789Sahrens } 29002665Snd150628 2901789Sahrens return (0); 2902789Sahrens } 2903789Sahrens 2904789Sahrens /* 29051294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 29061294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 29071294Slling * is a dependent and we should just destroy it without checking the transaction 29081294Slling * group. 2909789Sahrens */ 29101294Slling typedef struct rollback_data { 29111294Slling const char *cb_target; /* the snapshot */ 29121294Slling uint64_t cb_create; /* creation time reference */ 29131294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 29141294Slling int cb_error; 29152082Seschrock boolean_t cb_dependent; 29161294Slling } rollback_data_t; 29171294Slling 29181294Slling static int 29191294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 29201294Slling { 29211294Slling rollback_data_t *cbp = data; 29221294Slling 29231294Slling if (!cbp->cb_dependent) { 29241294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 29251294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 29261294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 29271294Slling cbp->cb_create) { 29281294Slling 29292082Seschrock cbp->cb_dependent = B_TRUE; 29302474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 29312474Seschrock cbp) != 0) 29322474Seschrock cbp->cb_error = 1; 29332082Seschrock cbp->cb_dependent = B_FALSE; 29341294Slling 29351294Slling if (zfs_destroy(zhp) != 0) 29361294Slling cbp->cb_error = 1; 29371294Slling else 29381294Slling changelist_remove(zhp, cbp->cb_clp); 29391294Slling } 29401294Slling } else { 29411294Slling if (zfs_destroy(zhp) != 0) 29421294Slling cbp->cb_error = 1; 29431294Slling else 29441294Slling changelist_remove(zhp, cbp->cb_clp); 29451294Slling } 29461294Slling 29471294Slling zfs_close(zhp); 29481294Slling return (0); 29491294Slling } 29501294Slling 29511294Slling /* 29521294Slling * Rollback the dataset to its latest snapshot. 29531294Slling */ 29541294Slling static int 29551294Slling do_rollback(zfs_handle_t *zhp) 2956789Sahrens { 2957789Sahrens int ret; 2958789Sahrens zfs_cmd_t zc = { 0 }; 2959789Sahrens 2960789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2961789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2962789Sahrens 2963789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 29642082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2965789Sahrens return (-1); 2966789Sahrens 2967789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2968789Sahrens 29692676Seschrock if (ZFS_IS_VOLUME(zhp)) 2970789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2971789Sahrens else 2972789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2973789Sahrens 2974789Sahrens /* 2975789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2976789Sahrens * for the given dataset. Given these constraints, we can simply pass 2977789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2978789Sahrens * condition where the user has taken a snapshot since we verified that 2979789Sahrens * this was the most recent. 2980789Sahrens */ 29812082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 29822082Seschrock &zc)) != 0) { 29832082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 29842082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 29852082Seschrock zhp->zfs_name); 2986789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 29872082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2988789Sahrens } 2989789Sahrens 2990789Sahrens return (ret); 2991789Sahrens } 2992789Sahrens 2993789Sahrens /* 29941294Slling * Given a dataset, rollback to a specific snapshot, discarding any 29951294Slling * data changes since then and making it the active dataset. 29961294Slling * 29971294Slling * Any snapshots more recent than the target are destroyed, along with 29981294Slling * their dependents. 29991294Slling */ 30001294Slling int 30011294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 30021294Slling { 30031294Slling int ret; 30041294Slling rollback_data_t cb = { 0 }; 30051294Slling prop_changelist_t *clp; 30061294Slling 30071294Slling /* 30081294Slling * Unmount all dependendents of the dataset and the dataset itself. 30091294Slling * The list we need to gather is the same as for doing rename 30101294Slling */ 30111294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 30121294Slling if (clp == NULL) 30131294Slling return (-1); 30141294Slling 30151294Slling if ((ret = changelist_prefix(clp)) != 0) 30161294Slling goto out; 30171294Slling 30181294Slling /* 30191294Slling * Destroy all recent snapshots and its dependends. 30201294Slling */ 30211294Slling cb.cb_target = snap->zfs_name; 30221294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 30231294Slling cb.cb_clp = clp; 30241294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 30251294Slling 30261294Slling if ((ret = cb.cb_error) != 0) { 30271294Slling (void) changelist_postfix(clp); 30281294Slling goto out; 30291294Slling } 30301294Slling 30311294Slling /* 30321294Slling * Now that we have verified that the snapshot is the latest, 30331294Slling * rollback to the given snapshot. 30341294Slling */ 30351294Slling ret = do_rollback(zhp); 30361294Slling 30371294Slling if (ret != 0) { 30381294Slling (void) changelist_postfix(clp); 30391294Slling goto out; 30401294Slling } 30411294Slling 30421294Slling /* 30431294Slling * We only want to re-mount the filesystem if it was mounted in the 30441294Slling * first place. 30451294Slling */ 30461294Slling ret = changelist_postfix(clp); 30471294Slling 30481294Slling out: 30491294Slling changelist_free(clp); 30501294Slling return (ret); 30511294Slling } 30521294Slling 30531294Slling /* 3054789Sahrens * Iterate over all dependents for a given dataset. This includes both 3055789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3056789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3057789Sahrens * libzfs_graph.c. 3058789Sahrens */ 3059789Sahrens int 30602474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 30612474Seschrock zfs_iter_f func, void *data) 3062789Sahrens { 3063789Sahrens char **dependents; 3064789Sahrens size_t count; 3065789Sahrens int i; 3066789Sahrens zfs_handle_t *child; 3067789Sahrens int ret = 0; 3068789Sahrens 30692474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 30702474Seschrock &dependents, &count) != 0) 30712474Seschrock return (-1); 30722474Seschrock 3073789Sahrens for (i = 0; i < count; i++) { 30742082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 30752082Seschrock dependents[i])) == NULL) 3076789Sahrens continue; 3077789Sahrens 3078789Sahrens if ((ret = func(child, data)) != 0) 3079789Sahrens break; 3080789Sahrens } 3081789Sahrens 3082789Sahrens for (i = 0; i < count; i++) 3083789Sahrens free(dependents[i]); 3084789Sahrens free(dependents); 3085789Sahrens 3086789Sahrens return (ret); 3087789Sahrens } 3088789Sahrens 3089789Sahrens /* 3090789Sahrens * Renames the given dataset. 3091789Sahrens */ 3092789Sahrens int 3093789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3094789Sahrens { 3095789Sahrens int ret; 3096789Sahrens zfs_cmd_t zc = { 0 }; 3097789Sahrens char *delim; 3098789Sahrens prop_changelist_t *cl; 3099789Sahrens char parent[ZFS_MAXNAMELEN]; 31002082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 31012082Seschrock char errbuf[1024]; 3102789Sahrens 3103789Sahrens /* if we have the same exact name, just return success */ 3104789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3105789Sahrens return (0); 3106789Sahrens 31072082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31082082Seschrock "cannot rename to '%s'"), target); 31092082Seschrock 3110789Sahrens /* 3111789Sahrens * Make sure the target name is valid 3112789Sahrens */ 3113789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 31142665Snd150628 if ((strchr(target, '@') == NULL) || 31152665Snd150628 *target == '@') { 31162665Snd150628 /* 31172665Snd150628 * Snapshot target name is abbreviated, 31182665Snd150628 * reconstruct full dataset name 31192665Snd150628 */ 31202665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 31212665Snd150628 sizeof (parent)); 31222665Snd150628 delim = strchr(parent, '@'); 31232665Snd150628 if (strchr(target, '@') == NULL) 31242665Snd150628 *(++delim) = '\0'; 31252665Snd150628 else 31262665Snd150628 *delim = '\0'; 31272665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 31282665Snd150628 target = parent; 31292665Snd150628 } else { 31302665Snd150628 /* 31312665Snd150628 * Make sure we're renaming within the same dataset. 31322665Snd150628 */ 31332665Snd150628 delim = strchr(target, '@'); 31342665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 31352665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 31362665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31372665Snd150628 "snapshots must be part of same " 31382665Snd150628 "dataset")); 31392665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 31402665Snd150628 errbuf)); 31412665Snd150628 } 3142789Sahrens } 31432665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31442665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3145789Sahrens } else { 31462665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31472665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31482676Seschrock uint64_t unused; 31492676Seschrock 3150789Sahrens /* validate parents */ 31512676Seschrock if (check_parents(hdl, target, &unused) != 0) 3152789Sahrens return (-1); 3153789Sahrens 3154789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3155789Sahrens 3156789Sahrens /* make sure we're in the same pool */ 3157789Sahrens verify((delim = strchr(target, '/')) != NULL); 3158789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3159789Sahrens zhp->zfs_name[delim - target] != '/') { 31602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31612082Seschrock "datasets must be within same pool")); 31622082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3163789Sahrens } 31642440Snd150628 31652440Snd150628 /* new name cannot be a child of the current dataset name */ 31662440Snd150628 if (strncmp(parent, zhp->zfs_name, 31672440Snd150628 strlen(zhp->zfs_name)) == 0) { 31682440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31692440Snd150628 "New dataset name cannot be a descendent of " 31702440Snd150628 "current dataset name")); 31712440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31722440Snd150628 } 3173789Sahrens } 3174789Sahrens 31752082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 31762082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 31772082Seschrock 3178789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3179789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 31802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31812082Seschrock "dataset is used in a non-global zone")); 31822082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3183789Sahrens } 3184789Sahrens 3185789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 31862082Seschrock return (-1); 3187789Sahrens 3188789Sahrens if (changelist_haszonedchild(cl)) { 31892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31902082Seschrock "child dataset with inherited mountpoint is used " 31912082Seschrock "in a non-global zone")); 31922676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3193789Sahrens goto error; 3194789Sahrens } 3195789Sahrens 3196789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3197789Sahrens goto error; 3198789Sahrens 31992676Seschrock if (ZFS_IS_VOLUME(zhp)) 3200789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3201789Sahrens else 3202789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3203789Sahrens 32042665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 32052676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 32062665Snd150628 32072082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 32082082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3209789Sahrens 3210789Sahrens /* 3211789Sahrens * On failure, we still want to remount any filesystems that 3212789Sahrens * were previously mounted, so we don't alter the system state. 3213789Sahrens */ 3214789Sahrens (void) changelist_postfix(cl); 3215789Sahrens } else { 3216789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3217789Sahrens 3218789Sahrens ret = changelist_postfix(cl); 3219789Sahrens } 3220789Sahrens 3221789Sahrens error: 3222789Sahrens changelist_free(cl); 3223789Sahrens return (ret); 3224789Sahrens } 3225789Sahrens 3226789Sahrens /* 3227789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3228789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3229789Sahrens */ 3230789Sahrens int 32312082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3232789Sahrens { 3233789Sahrens zfs_cmd_t zc = { 0 }; 32342082Seschrock di_devlink_handle_t dhdl; 3235789Sahrens 3236789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3237789Sahrens 3238789Sahrens /* 3239789Sahrens * Issue the appropriate ioctl. 3240789Sahrens */ 32412082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3242789Sahrens switch (errno) { 3243789Sahrens case EEXIST: 3244789Sahrens /* 3245789Sahrens * Silently ignore the case where the link already 3246789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3247789Sahrens * times without errors. 3248789Sahrens */ 3249789Sahrens return (0); 3250789Sahrens 3251789Sahrens default: 32522082Seschrock return (zfs_standard_error(hdl, errno, 32532082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32542082Seschrock "for '%s'"), dataset)); 3255789Sahrens } 3256789Sahrens } 3257789Sahrens 3258789Sahrens /* 3259789Sahrens * Call devfsadm and wait for the links to magically appear. 3260789Sahrens */ 32612082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 32622082Seschrock zfs_error_aux(hdl, strerror(errno)); 32632082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 32642082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32652082Seschrock "for '%s'"), dataset); 32662082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3267789Sahrens return (-1); 3268789Sahrens } else { 32692082Seschrock (void) di_devlink_fini(&dhdl); 3270789Sahrens } 3271789Sahrens 3272789Sahrens return (0); 3273789Sahrens } 3274789Sahrens 3275789Sahrens /* 3276789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3277789Sahrens */ 3278789Sahrens int 32792082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3280789Sahrens { 3281789Sahrens zfs_cmd_t zc = { 0 }; 3282789Sahrens 3283789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3284789Sahrens 32852082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3286789Sahrens switch (errno) { 3287789Sahrens case ENXIO: 3288789Sahrens /* 3289789Sahrens * Silently ignore the case where the link no longer 3290789Sahrens * exists, so that 'zfs volfini' can be run multiple 3291789Sahrens * times without errors. 3292789Sahrens */ 3293789Sahrens return (0); 3294789Sahrens 3295789Sahrens default: 32962082Seschrock return (zfs_standard_error(hdl, errno, 32972082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 32982082Seschrock "links for '%s'"), dataset)); 3299789Sahrens } 3300789Sahrens } 3301789Sahrens 3302789Sahrens return (0); 3303789Sahrens } 33042676Seschrock 33052676Seschrock nvlist_t * 33062676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 33072676Seschrock { 33082676Seschrock return (zhp->zfs_user_props); 33092676Seschrock } 33102676Seschrock 33112676Seschrock /* 33122676Seschrock * Given a comma-separated list of properties, contruct a property list 33132676Seschrock * containing both user-defined and native properties. This function will 33142676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 33152676Seschrock * per-dataset basis by zfs_expand_proplist(). 33162676Seschrock */ 33172676Seschrock int 33182676Seschrock zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 33192676Seschrock { 33202676Seschrock int i; 33212676Seschrock size_t len; 33222676Seschrock char *s, *p; 33232676Seschrock char c; 33242676Seschrock zfs_prop_t prop; 33252676Seschrock zfs_proplist_t *entry; 33262676Seschrock zfs_proplist_t **last; 33272676Seschrock 33282676Seschrock *listp = NULL; 33292676Seschrock last = listp; 33302676Seschrock 33312676Seschrock /* 33322676Seschrock * If 'all' is specified, return a NULL list. 33332676Seschrock */ 33342676Seschrock if (strcmp(fields, "all") == 0) 33352676Seschrock return (0); 33362676Seschrock 33372676Seschrock /* 33382676Seschrock * If no fields were specified, return an error. 33392676Seschrock */ 33402676Seschrock if (fields[0] == '\0') { 33412676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33422676Seschrock "no properties specified")); 33432676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 33442676Seschrock "bad property list"))); 33452676Seschrock } 33462676Seschrock 33472676Seschrock /* 33482676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 33492676Seschrock * aliases makes this more effort than it's worth. 33502676Seschrock */ 33512676Seschrock s = fields; 33522676Seschrock while (*s != '\0') { 33532676Seschrock if ((p = strchr(s, ',')) == NULL) { 33542676Seschrock len = strlen(s); 33552676Seschrock p = s + len; 33562676Seschrock } else { 33572676Seschrock len = p - s; 33582676Seschrock } 33592676Seschrock 33602676Seschrock /* 33612676Seschrock * Check for empty options. 33622676Seschrock */ 33632676Seschrock if (len == 0) { 33642676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33652676Seschrock "empty property name")); 33662676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 33672676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 33682676Seschrock } 33692676Seschrock 33702676Seschrock /* 33712676Seschrock * Check all regular property names. 33722676Seschrock */ 33732676Seschrock c = s[len]; 33742676Seschrock s[len] = '\0'; 33752676Seschrock for (i = 0; i < ZFS_NPROP_ALL; i++) { 33762676Seschrock if ((prop = zfs_name_to_prop(s)) != ZFS_PROP_INVAL) 33772676Seschrock break; 33782676Seschrock } 33792676Seschrock 33802676Seschrock /* 33812676Seschrock * If no column is specified, and this isn't a user property, 33822676Seschrock * return failure. 33832676Seschrock */ 33842676Seschrock if (i == ZFS_NPROP_ALL && !zfs_prop_user(s)) { 33852676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33862676Seschrock "invalid property '%s'"), s); 33872676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 33882676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 33892676Seschrock } 33902676Seschrock 33912676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 33922676Seschrock return (-1); 33932676Seschrock 33942676Seschrock entry->pl_prop = prop; 33952676Seschrock if (prop == ZFS_PROP_INVAL) { 33962676Seschrock if ((entry->pl_user_prop = 33972676Seschrock zfs_strdup(hdl, s)) == NULL) { 33982676Seschrock free(entry); 33992676Seschrock return (-1); 34002676Seschrock } 34012676Seschrock entry->pl_width = strlen(s); 34022676Seschrock } else { 34032676Seschrock entry->pl_width = zfs_prop_width(prop, 34042676Seschrock &entry->pl_fixed); 34052676Seschrock } 34062676Seschrock 34072676Seschrock *last = entry; 34082676Seschrock last = &entry->pl_next; 34092676Seschrock 34102676Seschrock s = p; 34112676Seschrock if (c == ',') 34122676Seschrock s++; 34132676Seschrock } 34142676Seschrock 34152676Seschrock return (0); 34162676Seschrock } 34172676Seschrock 34182676Seschrock void 34192676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 34202676Seschrock { 34212676Seschrock zfs_proplist_t *next; 34222676Seschrock 34232676Seschrock while (pl != NULL) { 34242676Seschrock next = pl->pl_next; 34252676Seschrock free(pl->pl_user_prop); 34262676Seschrock free(pl); 34272676Seschrock pl = next; 34282676Seschrock } 34292676Seschrock } 34302676Seschrock 34312676Seschrock /* 34322676Seschrock * This function is used by 'zfs list' to determine the exact set of columns to 34332676Seschrock * display, and their maximum widths. This does two main things: 34342676Seschrock * 34352676Seschrock * - If this is a list of all properties, then expand the list to include 34362676Seschrock * all native properties, and set a flag so that for each dataset we look 34372676Seschrock * for new unique user properties and add them to the list. 34382676Seschrock * 34392676Seschrock * - For non fixed-width properties, keep track of the maximum width seen 34402676Seschrock * so that we can size the column appropriately. 34412676Seschrock */ 34422676Seschrock int 34432676Seschrock zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 34442676Seschrock { 34452676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 34462676Seschrock zfs_prop_t prop; 34472676Seschrock zfs_proplist_t *entry; 34482676Seschrock zfs_proplist_t **last, **start; 34492676Seschrock nvlist_t *userprops, *propval; 34502676Seschrock nvpair_t *elem; 34512676Seschrock char *strval; 34522676Seschrock char buf[ZFS_MAXPROPLEN]; 34532676Seschrock 34542676Seschrock if (*plp == NULL) { 34552676Seschrock /* 34562676Seschrock * If this is the very first time we've been called for an 'all' 34572676Seschrock * specification, expand the list to include all native 34582676Seschrock * properties. 34592676Seschrock */ 34602676Seschrock last = plp; 34612676Seschrock for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) { 34622676Seschrock if ((entry = zfs_alloc(hdl, 34632676Seschrock sizeof (zfs_proplist_t))) == NULL) 34642676Seschrock return (-1); 34652676Seschrock 34662676Seschrock entry->pl_prop = prop; 34672676Seschrock entry->pl_width = zfs_prop_width(prop, 34682676Seschrock &entry->pl_fixed); 34692676Seschrock entry->pl_all = B_TRUE; 34702676Seschrock 34712676Seschrock *last = entry; 34722676Seschrock last = &entry->pl_next; 34732676Seschrock } 34742676Seschrock 34752676Seschrock /* 34762676Seschrock * Add 'name' to the beginning of the list, which is handled 34772676Seschrock * specially. 34782676Seschrock */ 34792676Seschrock if ((entry = zfs_alloc(hdl, 34802676Seschrock sizeof (zfs_proplist_t))) == NULL) 34812676Seschrock return (-1); 34822676Seschrock 34832676Seschrock entry->pl_prop = ZFS_PROP_NAME; 34842676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 34852676Seschrock &entry->pl_fixed); 34862676Seschrock entry->pl_all = B_TRUE; 34872676Seschrock entry->pl_next = *plp; 34882676Seschrock *plp = entry; 34892676Seschrock } 34902676Seschrock 34912676Seschrock userprops = zfs_get_user_props(zhp); 34922676Seschrock 34932676Seschrock entry = *plp; 34942676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 34952676Seschrock /* 34962676Seschrock * Go through and add any user properties as necessary. We 34972676Seschrock * start by incrementing our list pointer to the first 34982676Seschrock * non-native property. 34992676Seschrock */ 35002676Seschrock start = plp; 35012676Seschrock while (*start != NULL) { 35022676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 35032676Seschrock break; 35042676Seschrock start = &(*start)->pl_next; 35052676Seschrock } 35062676Seschrock 35072676Seschrock elem = NULL; 35082676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 35092676Seschrock /* 35102676Seschrock * See if we've already found this property in our list. 35112676Seschrock */ 35122676Seschrock for (last = start; *last != NULL; 35132676Seschrock last = &(*last)->pl_next) { 35142676Seschrock if (strcmp((*last)->pl_user_prop, 35152676Seschrock nvpair_name(elem)) == 0) 35162676Seschrock break; 35172676Seschrock } 35182676Seschrock 35192676Seschrock if (*last == NULL) { 35202676Seschrock if ((entry = zfs_alloc(hdl, 35212676Seschrock sizeof (zfs_proplist_t))) == NULL || 35222676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 35232676Seschrock nvpair_name(elem)))) == NULL) { 35242676Seschrock free(entry); 35252676Seschrock return (-1); 35262676Seschrock } 35272676Seschrock 35282676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 35292676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 35302676Seschrock entry->pl_all = B_TRUE; 35312676Seschrock *last = entry; 35322676Seschrock } 35332676Seschrock } 35342676Seschrock } 35352676Seschrock 35362676Seschrock /* 35372676Seschrock * Now go through and check the width of any non-fixed columns 35382676Seschrock */ 35392676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 35402676Seschrock if (entry->pl_fixed) 35412676Seschrock continue; 35422676Seschrock 35432676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 35442676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 35452676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 35462676Seschrock if (strlen(buf) > entry->pl_width) 35472676Seschrock entry->pl_width = strlen(buf); 35482676Seschrock } 35492676Seschrock } else if (nvlist_lookup_nvlist(userprops, 35502676Seschrock entry->pl_user_prop, &propval) == 0) { 35512676Seschrock verify(nvlist_lookup_string(propval, 35522676Seschrock ZFS_PROP_VALUE, &strval) == 0); 35532676Seschrock if (strlen(strval) > entry->pl_width) 35542676Seschrock entry->pl_width = strlen(strval); 35552676Seschrock } 35562676Seschrock } 35572676Seschrock 35582676Seschrock return (0); 35592676Seschrock } 3560