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; 160*2856Snd150628 161*2856Snd150628 case NAME_ERR_NOLETTER: 162*2856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 163*2856Snd150628 "pool doesn't begin with a letter")); 164*2856Snd150628 break; 165*2856Snd150628 166*2856Snd150628 case NAME_ERR_RESERVED: 167*2856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 168*2856Snd150628 "name is reserved")); 169*2856Snd150628 break; 170*2856Snd150628 171*2856Snd150628 case NAME_ERR_DISKLIKE: 172*2856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 173*2856Snd150628 "reserved disk name")); 174*2856Snd150628 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 260789Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 261789Sahrens sizeof (zc.zc_objset_stats)); 262789Sahrens 2632676Seschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 2641544Seschrock 2652082Seschrock if (zhp->zfs_props) { 2662082Seschrock nvlist_free(zhp->zfs_props); 2672082Seschrock zhp->zfs_props = NULL; 2682082Seschrock } 2692082Seschrock 2702676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 2712676Seschrock zcmd_free_nvlists(&zc); 2722082Seschrock return (-1); 2732082Seschrock } 274789Sahrens 2752676Seschrock zcmd_free_nvlists(&zc); 2762676Seschrock 2772676Seschrock zhp->zfs_volstats = zc.zc_vol_stats; 2782676Seschrock 2792676Seschrock if (process_user_props(zhp) != 0) 2802676Seschrock return (-1); 2812082Seschrock 282789Sahrens return (0); 283789Sahrens } 284789Sahrens 285789Sahrens /* 286789Sahrens * Refresh the properties currently stored in the handle. 287789Sahrens */ 288789Sahrens void 289789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 290789Sahrens { 291789Sahrens (void) get_stats(zhp); 292789Sahrens } 293789Sahrens 294789Sahrens /* 295789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 296789Sahrens * zfs_iter_* to create child handles on the fly. 297789Sahrens */ 298789Sahrens zfs_handle_t * 2992082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 300789Sahrens { 3012082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 3022082Seschrock 3032082Seschrock if (zhp == NULL) 3042082Seschrock return (NULL); 3052082Seschrock 3062082Seschrock zhp->zfs_hdl = hdl; 307789Sahrens 3081758Sahrens top: 309789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 310789Sahrens 311789Sahrens if (get_stats(zhp) != 0) { 312789Sahrens free(zhp); 313789Sahrens return (NULL); 314789Sahrens } 315789Sahrens 3161758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 3171758Sahrens zfs_cmd_t zc = { 0 }; 3181758Sahrens 3191758Sahrens /* 3201758Sahrens * If it is dds_inconsistent, then we've caught it in 3211758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 3221758Sahrens * it is inconsistent from the ZPL's point of view, so 3231758Sahrens * can't be mounted. However, it could also be that we 3241758Sahrens * have crashed in the middle of one of those 3251758Sahrens * operations, in which case we need to get rid of the 3261758Sahrens * inconsistent state. We do that by either rolling 3271758Sahrens * back to the previous snapshot (which will fail if 3281758Sahrens * there is none), or destroying the filesystem. Note 3291758Sahrens * that if we are still in the middle of an active 3301758Sahrens * 'receive' or 'destroy', then the rollback and destroy 3311758Sahrens * will fail with EBUSY and we will drive on as usual. 3321758Sahrens */ 3331758Sahrens 3341758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3351758Sahrens 3361758Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3372082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 3381758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3391758Sahrens } else { 3401758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3411758Sahrens } 3421758Sahrens 3431758Sahrens /* If we can successfully roll it back, reget the stats */ 3442082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 3451758Sahrens goto top; 3461758Sahrens /* 3471758Sahrens * If we can sucessfully destroy it, pretend that it 3481758Sahrens * never existed. 3491758Sahrens */ 3502082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3511758Sahrens free(zhp); 3521758Sahrens errno = ENOENT; 3531758Sahrens return (NULL); 3541758Sahrens } 3551758Sahrens } 3561758Sahrens 357789Sahrens /* 358789Sahrens * We've managed to open the dataset and gather statistics. Determine 359789Sahrens * the high-level type. 360789Sahrens */ 361789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 362789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 363789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 364789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 365789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 366789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 367789Sahrens else 3682082Seschrock abort(); /* we should never see any other types */ 369789Sahrens 370789Sahrens return (zhp); 371789Sahrens } 372789Sahrens 373789Sahrens /* 374789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 375789Sahrens * argument is a mask of acceptable types. The function will print an 376789Sahrens * appropriate error message and return NULL if it can't be opened. 377789Sahrens */ 378789Sahrens zfs_handle_t * 3792082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 380789Sahrens { 381789Sahrens zfs_handle_t *zhp; 3822082Seschrock char errbuf[1024]; 3832082Seschrock 3842082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3852082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 386789Sahrens 387789Sahrens /* 3882082Seschrock * Validate the name before we even try to open it. 389789Sahrens */ 3902082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3922082Seschrock "invalid dataset name")); 3932082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 394789Sahrens return (NULL); 395789Sahrens } 396789Sahrens 397789Sahrens /* 398789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 399789Sahrens */ 400789Sahrens errno = 0; 4012082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 4022082Seschrock (void) zfs_standard_error(hdl, errno, errbuf, path); 403789Sahrens return (NULL); 404789Sahrens } 405789Sahrens 406789Sahrens if (!(types & zhp->zfs_type)) { 4072082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4082142Seschrock zfs_close(zhp); 409789Sahrens return (NULL); 410789Sahrens } 411789Sahrens 412789Sahrens return (zhp); 413789Sahrens } 414789Sahrens 415789Sahrens /* 416789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 417789Sahrens */ 418789Sahrens void 419789Sahrens zfs_close(zfs_handle_t *zhp) 420789Sahrens { 421789Sahrens if (zhp->zfs_mntopts) 422789Sahrens free(zhp->zfs_mntopts); 4232676Seschrock nvlist_free(zhp->zfs_props); 4242676Seschrock nvlist_free(zhp->zfs_user_props); 425789Sahrens free(zhp); 426789Sahrens } 427789Sahrens 428789Sahrens /* 429789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 430789Sahrens * resulting value must be shifted. 431789Sahrens */ 432789Sahrens static int 4332082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 434789Sahrens { 435789Sahrens const char *ends = "BKMGTPEZ"; 436789Sahrens int i; 437789Sahrens 438789Sahrens if (buf[0] == '\0') 439789Sahrens return (0); 440789Sahrens for (i = 0; i < strlen(ends); i++) { 441789Sahrens if (toupper(buf[0]) == ends[i]) 442789Sahrens break; 443789Sahrens } 444789Sahrens if (i == strlen(ends)) { 4452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4462082Seschrock "invalid numeric suffix '%s'"), buf); 447789Sahrens return (-1); 448789Sahrens } 449789Sahrens 450789Sahrens /* 451789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 452789Sahrens * allow 'BB' - that's just weird. 453789Sahrens */ 454789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4552082Seschrock toupper(buf[0]) != 'B')) 456789Sahrens return (10*i); 4572082Seschrock 4582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4592082Seschrock "invalid numeric suffix '%s'"), buf); 460789Sahrens return (-1); 461789Sahrens } 462789Sahrens 463789Sahrens /* 464789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 465789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 466789Sahrens * message for the caller to use. 467789Sahrens */ 468789Sahrens static int 4692082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 470789Sahrens { 471789Sahrens char *end; 472789Sahrens int shift; 473789Sahrens 474789Sahrens *num = 0; 475789Sahrens 476789Sahrens /* Check to see if this looks like a number. */ 477789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4782082Seschrock if (hdl) 4792082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4802082Seschrock "bad numeric value '%s'"), value); 481789Sahrens return (-1); 482789Sahrens } 483789Sahrens 484789Sahrens /* Rely on stroll() to process the numeric portion. */ 485789Sahrens errno = 0; 486789Sahrens *num = strtoll(value, &end, 10); 487789Sahrens 488789Sahrens /* 489789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 490789Sahrens * in a 64-bit value. 491789Sahrens */ 492789Sahrens if (errno == ERANGE) { 4932082Seschrock if (hdl) 4942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4952082Seschrock "numeric value is too large")); 496789Sahrens return (-1); 497789Sahrens } 498789Sahrens 499789Sahrens /* 500789Sahrens * If we have a decimal value, then do the computation with floating 501789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 502789Sahrens */ 503789Sahrens if (*end == '.') { 504789Sahrens double fval = strtod(value, &end); 505789Sahrens 5062082Seschrock if ((shift = str2shift(hdl, end)) == -1) 507789Sahrens return (-1); 508789Sahrens 509789Sahrens fval *= pow(2, shift); 510789Sahrens 511789Sahrens if (fval > UINT64_MAX) { 5122082Seschrock if (hdl) 5132082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5142082Seschrock "numeric value is too large")); 515789Sahrens return (-1); 516789Sahrens } 517789Sahrens 518789Sahrens *num = (uint64_t)fval; 519789Sahrens } else { 5202082Seschrock if ((shift = str2shift(hdl, end)) == -1) 521789Sahrens return (-1); 522789Sahrens 523789Sahrens /* Check for overflow */ 524789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5252082Seschrock if (hdl) 5262082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5272082Seschrock "numeric value is too large")); 528789Sahrens return (-1); 529789Sahrens } 530789Sahrens 531789Sahrens *num <<= shift; 532789Sahrens } 533789Sahrens 534789Sahrens return (0); 535789Sahrens } 536789Sahrens 537789Sahrens int 5382676Seschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 5392676Seschrock { 5402676Seschrock return (nicestrtonum(hdl, str, val)); 5412676Seschrock } 5422676Seschrock 5432676Seschrock /* 5442676Seschrock * The prop_parse_*() functions are designed to allow flexibility in callers 5452676Seschrock * when setting properties. At the DSL layer, all properties are either 64-bit 5462676Seschrock * numbers or strings. We want the user to be able to ignore this fact and 5472676Seschrock * specify properties as native values (boolean, for example) or as strings (to 5482676Seschrock * simplify command line utilities). This also handles converting index types 5492676Seschrock * (compression, checksum, etc) from strings to their on-disk index. 5502676Seschrock */ 5512676Seschrock 5522676Seschrock static int 5532676Seschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 554789Sahrens { 5552676Seschrock uint64_t ret; 5562676Seschrock 5572676Seschrock switch (nvpair_type(elem)) { 5582676Seschrock case DATA_TYPE_STRING: 5592676Seschrock { 5602676Seschrock char *value; 5612676Seschrock VERIFY(nvpair_value_string(elem, &value) == 0); 5622676Seschrock 5632676Seschrock if (strcmp(value, "on") == 0) { 5642676Seschrock ret = 1; 5652676Seschrock } else if (strcmp(value, "off") == 0) { 5662676Seschrock ret = 0; 5672676Seschrock } else { 5682676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5692676Seschrock "property '%s' must be 'on' or 'off'"), 5702676Seschrock nvpair_name(elem)); 5712676Seschrock return (-1); 5722676Seschrock } 5732676Seschrock break; 5742676Seschrock } 5752676Seschrock 5762676Seschrock case DATA_TYPE_UINT64: 5772676Seschrock { 5782676Seschrock VERIFY(nvpair_value_uint64(elem, &ret) == 0); 5792676Seschrock if (ret > 1) { 5802676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5812676Seschrock "'%s' must be a boolean value"), 5822676Seschrock nvpair_name(elem)); 5832676Seschrock return (-1); 5842676Seschrock } 5852676Seschrock break; 5862676Seschrock } 5872676Seschrock 5882676Seschrock case DATA_TYPE_BOOLEAN_VALUE: 5892676Seschrock { 5902676Seschrock boolean_t value; 5912676Seschrock VERIFY(nvpair_value_boolean_value(elem, &value) == 0); 5922676Seschrock ret = value; 5932676Seschrock break; 5942676Seschrock } 5952676Seschrock 5962676Seschrock default: 5972676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5982676Seschrock "'%s' must be a boolean value"), 5992676Seschrock nvpair_name(elem)); 6002676Seschrock return (-1); 6012676Seschrock } 6022676Seschrock 6032676Seschrock *val = ret; 6042676Seschrock return (0); 6052676Seschrock } 6062676Seschrock 6072676Seschrock static int 6082676Seschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6092676Seschrock uint64_t *val) 6102676Seschrock { 6112676Seschrock uint64_t ret; 6122676Seschrock boolean_t isnone = B_FALSE; 6132676Seschrock 6142676Seschrock switch (nvpair_type(elem)) { 6152676Seschrock case DATA_TYPE_STRING: 6162676Seschrock { 6172676Seschrock char *value; 6182676Seschrock (void) nvpair_value_string(elem, &value); 6192676Seschrock if (strcmp(value, "none") == 0) { 6202676Seschrock isnone = B_TRUE; 6212676Seschrock ret = 0; 6222676Seschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 6232676Seschrock return (-1); 6242676Seschrock } 6252676Seschrock break; 6262676Seschrock } 6272676Seschrock 6282676Seschrock case DATA_TYPE_UINT64: 6292676Seschrock (void) nvpair_value_uint64(elem, &ret); 6302676Seschrock break; 6312676Seschrock 6322676Seschrock default: 6332676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6342676Seschrock "'%s' must be a number"), 6352676Seschrock nvpair_name(elem)); 6362676Seschrock return (-1); 6372676Seschrock } 6382676Seschrock 6392676Seschrock /* 6402676Seschrock * Quota special: force 'none' and don't allow 0. 6412676Seschrock */ 6422676Seschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 6432676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6442676Seschrock "use 'none' to disable quota")); 6452676Seschrock return (-1); 6462676Seschrock } 6472676Seschrock 6482676Seschrock *val = ret; 6492676Seschrock return (0); 6502676Seschrock } 6512676Seschrock 6522676Seschrock static int 6532676Seschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6542676Seschrock uint64_t *val) 6552676Seschrock { 6562676Seschrock char *propname = nvpair_name(elem); 6572676Seschrock char *value; 6582676Seschrock 6592676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 6602676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6612676Seschrock "'%s' must be a string"), propname); 6622676Seschrock return (-1); 6632676Seschrock } 6642676Seschrock 6652676Seschrock (void) nvpair_value_string(elem, &value); 6662676Seschrock 6672676Seschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 6682676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6692676Seschrock "'%s' must be one of '%s'"), propname, 6702676Seschrock zfs_prop_values(prop)); 6712676Seschrock return (-1); 6722676Seschrock } 6732676Seschrock 6742676Seschrock return (0); 675789Sahrens } 676789Sahrens 677789Sahrens /* 6782676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 6792676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 6802676Seschrock * strings. 681789Sahrens */ 6822676Seschrock static nvlist_t * 6832676Seschrock zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 6842676Seschrock uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 685789Sahrens { 6862676Seschrock nvpair_t *elem; 6872676Seschrock const char *propname; 6882676Seschrock zfs_prop_t prop; 6892676Seschrock uint64_t intval; 6902676Seschrock char *strval; 6912676Seschrock nvlist_t *ret; 6922676Seschrock 6932676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 6942676Seschrock (void) no_memory(hdl); 6952676Seschrock return (NULL); 6962676Seschrock } 6972676Seschrock 6982676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 6992676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7002676Seschrock "snaphot properties cannot be modified")); 7012676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7022676Seschrock goto error; 703789Sahrens } 704789Sahrens 7052676Seschrock elem = NULL; 7062676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 7072676Seschrock propname = nvpair_name(elem); 7082676Seschrock 7092676Seschrock /* 7102676Seschrock * Make sure this property is valid and applies to this type. 7112676Seschrock */ 7122676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 7132676Seschrock if (!zfs_prop_user(propname)) { 7142676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7152676Seschrock "invalid property '%s'"), 7162676Seschrock propname); 7172676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7182676Seschrock goto error; 7192676Seschrock } else { 7202676Seschrock /* 7212676Seschrock * If this is a user property, make sure it's a 7222676Seschrock * string, and that it's less than 7232676Seschrock * ZAP_MAXNAMELEN. 7242676Seschrock */ 7252676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7262676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7272676Seschrock "'%s' must be a string"), 7282676Seschrock propname); 7292676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7302676Seschrock errbuf); 7312676Seschrock goto error; 7322676Seschrock } 7332676Seschrock 7342676Seschrock if (strlen(nvpair_name(elem)) >= 7352676Seschrock ZAP_MAXNAMELEN) { 7362676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7372676Seschrock "property name '%s' is too long"), 7382676Seschrock propname); 7392676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7402676Seschrock errbuf); 7412676Seschrock goto error; 7422676Seschrock } 7432676Seschrock } 7442676Seschrock 7452676Seschrock (void) nvpair_value_string(elem, &strval); 7462676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7472676Seschrock (void) no_memory(hdl); 7482676Seschrock goto error; 7492676Seschrock } 7502676Seschrock continue; 751789Sahrens } 7522676Seschrock 7532676Seschrock /* 7542676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7552676Seschrock */ 7562676Seschrock propname = zfs_prop_to_name(prop); 7572676Seschrock 7582676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7592676Seschrock zfs_error_aux(hdl, 7602676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7612676Seschrock "apply to datasets of this type"), propname); 7622676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7632676Seschrock goto error; 7642676Seschrock } 7652676Seschrock 7662676Seschrock if (zfs_prop_readonly(prop) && 7672676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 7682676Seschrock zfs_error_aux(hdl, 7692676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 7702676Seschrock propname); 7712676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 7722676Seschrock goto error; 7732676Seschrock } 7742676Seschrock 7752676Seschrock /* 7762676Seschrock * Convert any properties to the internal DSL value types. 7772676Seschrock */ 7782676Seschrock strval = NULL; 7792676Seschrock switch (zfs_prop_get_type(prop)) { 7802676Seschrock case prop_type_boolean: 7812676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 7822676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7832676Seschrock goto error; 7842676Seschrock } 785789Sahrens break; 7862676Seschrock 7872676Seschrock case prop_type_string: 7882676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7902676Seschrock "'%s' must be a string"), 7912676Seschrock propname); 7922676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7932676Seschrock goto error; 794789Sahrens } 7952676Seschrock (void) nvpair_value_string(elem, &strval); 7962676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 7972082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7982676Seschrock "'%s' is too long"), propname); 7992676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8002676Seschrock goto error; 8012676Seschrock } 8022676Seschrock break; 8032676Seschrock 8042676Seschrock case prop_type_number: 8052676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 8062676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8072676Seschrock goto error; 8082676Seschrock } 8092676Seschrock break; 8102676Seschrock 8112676Seschrock case prop_type_index: 8122676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 8132676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8142676Seschrock goto error; 815789Sahrens } 816789Sahrens break; 817789Sahrens 8182676Seschrock default: 8192676Seschrock abort(); 8202676Seschrock } 8212676Seschrock 8222676Seschrock /* 8232676Seschrock * Add the result to our return set of properties. 8242676Seschrock */ 8252676Seschrock if (strval) { 8262676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8272676Seschrock (void) no_memory(hdl); 8282676Seschrock goto error; 829789Sahrens } 8302676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8312676Seschrock (void) no_memory(hdl); 8322676Seschrock goto error; 8332676Seschrock } 8342676Seschrock 8352676Seschrock /* 8362676Seschrock * Perform some additional checks for specific properties. 8372676Seschrock */ 8382676Seschrock switch (prop) { 8392676Seschrock case ZFS_PROP_RECORDSIZE: 8402676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8412676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8422676Seschrock if (intval < SPA_MINBLOCKSIZE || 8432676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8452676Seschrock "'%s' must be power of 2 from %u " 8462676Seschrock "to %uk"), propname, 8472676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8482676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8492676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8502676Seschrock goto error; 851789Sahrens } 852789Sahrens break; 853789Sahrens 8542676Seschrock case ZFS_PROP_MOUNTPOINT: 8552676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 8562676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 8572676Seschrock break; 8582676Seschrock 8592676Seschrock if (strval[0] != '/') { 8602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8612676Seschrock "'%s' must be an absolute path, " 8622676Seschrock "'none', or 'legacy'"), propname); 8632676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8642676Seschrock goto error; 865789Sahrens } 866789Sahrens break; 8672676Seschrock } 8682676Seschrock 8692676Seschrock /* 8702676Seschrock * For the mountpoint and sharenfs properties, check if it can 8712676Seschrock * be set in a global/non-global zone based on the zoned 8722676Seschrock * property value: 8732676Seschrock * 8742676Seschrock * global zone non-global zone 8752676Seschrock * ----------------------------------------------------- 8762676Seschrock * zoned=on mountpoint (no) mountpoint (yes) 8772676Seschrock * sharenfs (no) sharenfs (no) 8782676Seschrock * 8792676Seschrock * zoned=off mountpoint (yes) N/A 8802676Seschrock * sharenfs (yes) 8812676Seschrock */ 8822676Seschrock if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 8832676Seschrock if (zoned) { 8842676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 8852676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8862676Seschrock "'%s' cannot be set on " 8872676Seschrock "dataset in a non-global zone"), 8882676Seschrock propname); 8892676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 8902676Seschrock errbuf); 8912676Seschrock goto error; 8922676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 8932676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8942676Seschrock "'%s' cannot be set in " 8952676Seschrock "a non-global zone"), propname); 8962676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 8972676Seschrock errbuf); 8982676Seschrock goto error; 8992676Seschrock } 9002676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 9012676Seschrock /* 9022676Seschrock * If zoned property is 'off', this must be in 9032676Seschrock * a globle zone. If not, something is wrong. 9042676Seschrock */ 9052676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9062676Seschrock "'%s' cannot be set while dataset " 9072676Seschrock "'zoned' property is set"), propname); 9082676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 9092676Seschrock goto error; 9102676Seschrock } 9112676Seschrock } 9122676Seschrock 9132676Seschrock /* 9142676Seschrock * For changes to existing volumes, we have some additional 9152676Seschrock * checks to enforce. 9162676Seschrock */ 9172676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9182676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9192676Seschrock ZFS_PROP_VOLSIZE); 9202676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9212676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9222676Seschrock char buf[64]; 9232676Seschrock 9242676Seschrock switch (prop) { 9252676Seschrock case ZFS_PROP_RESERVATION: 9262676Seschrock if (intval > volsize) { 9272676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9282676Seschrock "'%s' is greater than current " 9292676Seschrock "volume size"), propname); 9302676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9312676Seschrock errbuf); 9322676Seschrock goto error; 9332676Seschrock } 9342676Seschrock break; 9352676Seschrock 9362676Seschrock case ZFS_PROP_VOLSIZE: 9372676Seschrock if (intval % blocksize != 0) { 9382676Seschrock zfs_nicenum(blocksize, buf, 9392676Seschrock sizeof (buf)); 9402676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9412676Seschrock "'%s' must be a multiple of " 9422676Seschrock "volume block size (%s)"), 9432676Seschrock propname, buf); 9442676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9452676Seschrock errbuf); 9462676Seschrock goto error; 9472676Seschrock } 9482676Seschrock 9492676Seschrock if (intval == 0) { 9502676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9512676Seschrock "'%s' cannot be zero"), 9522676Seschrock propname); 9532676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9542676Seschrock errbuf); 9552676Seschrock goto error; 956789Sahrens } 957789Sahrens } 958789Sahrens } 959789Sahrens } 960789Sahrens 9612676Seschrock /* 9622676Seschrock * If this is an existing volume, and someone is setting the volsize, 9632676Seschrock * make sure that it matches the reservation, or add it if necessary. 9642676Seschrock */ 9652676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 9662676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 9672676Seschrock &intval) == 0) { 9682676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 9692676Seschrock ZFS_PROP_VOLSIZE); 9702676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 9712676Seschrock ZFS_PROP_RESERVATION); 9722676Seschrock uint64_t new_reservation; 9732676Seschrock 9742676Seschrock if (old_volsize == old_reservation && 9752676Seschrock nvlist_lookup_uint64(ret, 9762676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9772676Seschrock &new_reservation) != 0) { 9782676Seschrock if (nvlist_add_uint64(ret, 9792676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9802676Seschrock intval) != 0) { 9812676Seschrock (void) no_memory(hdl); 9822676Seschrock goto error; 9832676Seschrock } 9842676Seschrock } 9852676Seschrock } 9862676Seschrock 9872676Seschrock return (ret); 9882676Seschrock 9892676Seschrock error: 9902676Seschrock nvlist_free(ret); 9912676Seschrock return (NULL); 992789Sahrens } 993789Sahrens 994789Sahrens /* 995789Sahrens * Given a property name and value, set the property for the given dataset. 996789Sahrens */ 997789Sahrens int 9982676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 999789Sahrens { 1000789Sahrens zfs_cmd_t zc = { 0 }; 10012676Seschrock int ret = -1; 10022676Seschrock prop_changelist_t *cl = NULL; 10032082Seschrock char errbuf[1024]; 10042082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 10052676Seschrock nvlist_t *nvl = NULL, *realprops; 10062676Seschrock zfs_prop_t prop; 10072082Seschrock 10082082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 10092676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 10102082Seschrock zhp->zfs_name); 10112082Seschrock 10122676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 10132676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 10142676Seschrock (void) no_memory(hdl); 10152676Seschrock goto error; 1016789Sahrens } 1017789Sahrens 10182676Seschrock if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl, 10192676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10202676Seschrock goto error; 10212676Seschrock nvlist_free(nvl); 10222676Seschrock nvl = realprops; 10232676Seschrock 10242676Seschrock prop = zfs_name_to_prop(propname); 10252676Seschrock 1026789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10272676Seschrock goto error; 1028789Sahrens 1029789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10312082Seschrock "child dataset with inherited mountpoint is used " 10322082Seschrock "in a non-global zone")); 10332082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1034789Sahrens goto error; 1035789Sahrens } 1036789Sahrens 1037789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1038789Sahrens goto error; 1039789Sahrens 1040789Sahrens /* 1041789Sahrens * Execute the corresponding ioctl() to set this property. 1042789Sahrens */ 1043789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1044789Sahrens 10452676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 10462676Seschrock goto error; 10472676Seschrock 10482676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1049789Sahrens 1050789Sahrens if (ret != 0) { 1051789Sahrens switch (errno) { 1052789Sahrens 1053789Sahrens case ENOSPC: 1054789Sahrens /* 1055789Sahrens * For quotas and reservations, ENOSPC indicates 1056789Sahrens * something different; setting a quota or reservation 1057789Sahrens * doesn't use any disk space. 1058789Sahrens */ 1059789Sahrens switch (prop) { 1060789Sahrens case ZFS_PROP_QUOTA: 10612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10622082Seschrock "size is less than current used or " 10632082Seschrock "reserved space")); 10642082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1065789Sahrens break; 1066789Sahrens 1067789Sahrens case ZFS_PROP_RESERVATION: 10682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10692082Seschrock "size is greater than available space")); 10702082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1071789Sahrens break; 1072789Sahrens 1073789Sahrens default: 10742082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1075789Sahrens break; 1076789Sahrens } 1077789Sahrens break; 1078789Sahrens 1079789Sahrens case EBUSY: 10802082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 10812082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 10822082Seschrock else 10832676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1084789Sahrens break; 1085789Sahrens 10861175Slling case EROFS: 10872082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 10881175Slling break; 10891175Slling 1090789Sahrens case EOVERFLOW: 1091789Sahrens /* 1092789Sahrens * This platform can't address a volume this big. 1093789Sahrens */ 1094789Sahrens #ifdef _ILP32 1095789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 10962082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1097789Sahrens break; 1098789Sahrens } 1099789Sahrens #endif 11002082Seschrock /* FALLTHROUGH */ 1101789Sahrens default: 11022082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1103789Sahrens } 1104789Sahrens } else { 1105789Sahrens /* 1106789Sahrens * Refresh the statistics so the new property value 1107789Sahrens * is reflected. 1108789Sahrens */ 11092676Seschrock if ((ret = changelist_postfix(cl)) == 0) 11102676Seschrock (void) get_stats(zhp); 1111789Sahrens } 1112789Sahrens 1113789Sahrens error: 11142676Seschrock nvlist_free(nvl); 11152676Seschrock zcmd_free_nvlists(&zc); 11162676Seschrock if (cl) 11172676Seschrock changelist_free(cl); 1118789Sahrens return (ret); 1119789Sahrens } 1120789Sahrens 1121789Sahrens /* 1122789Sahrens * Given a property, inherit the value from the parent dataset. 1123789Sahrens */ 1124789Sahrens int 11252676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1126789Sahrens { 1127789Sahrens zfs_cmd_t zc = { 0 }; 1128789Sahrens int ret; 1129789Sahrens prop_changelist_t *cl; 11302082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 11312082Seschrock char errbuf[1024]; 11322676Seschrock zfs_prop_t prop; 11332082Seschrock 11342082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 11352082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1136789Sahrens 11372676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 11382676Seschrock /* 11392676Seschrock * For user properties, the amount of work we have to do is very 11402676Seschrock * small, so just do it here. 11412676Seschrock */ 11422676Seschrock if (!zfs_prop_user(propname)) { 11432676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11442676Seschrock "invalid property")); 11452676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 11462676Seschrock } 11472676Seschrock 11482676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11492676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 11502676Seschrock 11512676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 11522676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 11532676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 11542676Seschrock 11552676Seschrock return (0); 11562676Seschrock } 11572676Seschrock 1158789Sahrens /* 1159789Sahrens * Verify that this property is inheritable. 1160789Sahrens */ 11612082Seschrock if (zfs_prop_readonly(prop)) 11622082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 11632082Seschrock 11642082Seschrock if (!zfs_prop_inheritable(prop)) 11652082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1166789Sahrens 1167789Sahrens /* 1168789Sahrens * Check to see if the value applies to this type 1169789Sahrens */ 11702082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 11712082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1172789Sahrens 1173789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11742676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1175789Sahrens 1176789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1177789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 11782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11792082Seschrock "dataset is used in a non-global zone")); 11802082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1181789Sahrens } 1182789Sahrens 1183789Sahrens /* 1184789Sahrens * Determine datasets which will be affected by this change, if any. 1185789Sahrens */ 1186789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1187789Sahrens return (-1); 1188789Sahrens 1189789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 11902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11912082Seschrock "child dataset with inherited mountpoint is used " 11922082Seschrock "in a non-global zone")); 11932082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1194789Sahrens goto error; 1195789Sahrens } 1196789Sahrens 1197789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1198789Sahrens goto error; 1199789Sahrens 12002082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 12012082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 12022082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1203789Sahrens } else { 1204789Sahrens 12052169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1206789Sahrens goto error; 1207789Sahrens 1208789Sahrens /* 1209789Sahrens * Refresh the statistics so the new property is reflected. 1210789Sahrens */ 1211789Sahrens (void) get_stats(zhp); 1212789Sahrens } 1213789Sahrens 1214789Sahrens error: 1215789Sahrens changelist_free(cl); 1216789Sahrens return (ret); 1217789Sahrens } 1218789Sahrens 1219789Sahrens static void 1220789Sahrens nicebool(int value, char *buf, size_t buflen) 1221789Sahrens { 1222789Sahrens if (value) 1223789Sahrens (void) strlcpy(buf, "on", buflen); 1224789Sahrens else 1225789Sahrens (void) strlcpy(buf, "off", buflen); 1226789Sahrens } 1227789Sahrens 1228789Sahrens /* 12291356Seschrock * True DSL properties are stored in an nvlist. The following two functions 12301356Seschrock * extract them appropriately. 12311356Seschrock */ 12321356Seschrock static uint64_t 12331356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12341356Seschrock { 12351356Seschrock nvlist_t *nv; 12361356Seschrock uint64_t value; 12371356Seschrock 12381356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12391356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12401356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 12411356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 12421356Seschrock } else { 12431356Seschrock value = zfs_prop_default_numeric(prop); 12441356Seschrock *source = ""; 12451356Seschrock } 12461356Seschrock 12471356Seschrock return (value); 12481356Seschrock } 12491356Seschrock 12501356Seschrock static char * 12511356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12521356Seschrock { 12531356Seschrock nvlist_t *nv; 12541356Seschrock char *value; 12551356Seschrock 12561356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12571356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12581356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 12591356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 12601356Seschrock } else { 12611356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 12621356Seschrock value = ""; 12631356Seschrock *source = ""; 12641356Seschrock } 12651356Seschrock 12661356Seschrock return (value); 12671356Seschrock } 12681356Seschrock 12691356Seschrock /* 1270789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1271789Sahrens * zfs_prop_get_int() are built using this interface. 1272789Sahrens * 1273789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1274789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1275789Sahrens * If they differ from the on-disk values, report the current values and mark 1276789Sahrens * the source "temporary". 1277789Sahrens */ 12782082Seschrock static int 1279789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 12802082Seschrock char **source, uint64_t *val) 1281789Sahrens { 1282789Sahrens struct mnttab mnt; 1283789Sahrens 1284789Sahrens *source = NULL; 1285789Sahrens 12862474Seschrock /* 12872474Seschrock * Because looking up the mount options is potentially expensive 12882474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 12892474Seschrock * we're looking up a property which requires its presence. 12902474Seschrock */ 12912474Seschrock if (!zhp->zfs_mntcheck && 12922474Seschrock (prop == ZFS_PROP_ATIME || 12932474Seschrock prop == ZFS_PROP_DEVICES || 12942474Seschrock prop == ZFS_PROP_EXEC || 12952474Seschrock prop == ZFS_PROP_READONLY || 12962474Seschrock prop == ZFS_PROP_SETUID || 12972474Seschrock prop == ZFS_PROP_MOUNTED)) { 12982474Seschrock struct mnttab search = { 0 }, entry; 12992474Seschrock 13002474Seschrock search.mnt_special = (char *)zhp->zfs_name; 13012474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 13022474Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 13032474Seschrock 13042474Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 13052474Seschrock &search) == 0 && (zhp->zfs_mntopts = 13062474Seschrock zfs_strdup(zhp->zfs_hdl, 13072474Seschrock entry.mnt_mntopts)) == NULL) 13082474Seschrock return (-1); 13092474Seschrock 13102474Seschrock zhp->zfs_mntcheck = B_TRUE; 13112474Seschrock } 13122474Seschrock 1313789Sahrens if (zhp->zfs_mntopts == NULL) 1314789Sahrens mnt.mnt_mntopts = ""; 1315789Sahrens else 1316789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1317789Sahrens 1318789Sahrens switch (prop) { 1319789Sahrens case ZFS_PROP_ATIME: 13202082Seschrock *val = getprop_uint64(zhp, prop, source); 13212082Seschrock 13222082Seschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 13232082Seschrock *val = B_TRUE; 1324789Sahrens if (src) 1325789Sahrens *src = ZFS_SRC_TEMPORARY; 13262082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 13272082Seschrock *val = B_FALSE; 1328789Sahrens if (src) 1329789Sahrens *src = ZFS_SRC_TEMPORARY; 1330789Sahrens } 13312082Seschrock break; 1332789Sahrens 1333789Sahrens case ZFS_PROP_AVAILABLE: 13342082Seschrock *val = zhp->zfs_dmustats.dds_available; 13352082Seschrock break; 1336789Sahrens 1337789Sahrens case ZFS_PROP_DEVICES: 13382082Seschrock *val = getprop_uint64(zhp, prop, source); 13392082Seschrock 13402082Seschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 13412082Seschrock *val = B_TRUE; 1342789Sahrens if (src) 1343789Sahrens *src = ZFS_SRC_TEMPORARY; 13442082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 13452082Seschrock *val = B_FALSE; 1346789Sahrens if (src) 1347789Sahrens *src = ZFS_SRC_TEMPORARY; 1348789Sahrens } 13492082Seschrock break; 1350789Sahrens 1351789Sahrens case ZFS_PROP_EXEC: 13522082Seschrock *val = getprop_uint64(zhp, prop, source); 13532082Seschrock 13542082Seschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 13552082Seschrock *val = B_TRUE; 1356789Sahrens if (src) 1357789Sahrens *src = ZFS_SRC_TEMPORARY; 13582082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 13592082Seschrock *val = B_FALSE; 1360789Sahrens if (src) 1361789Sahrens *src = ZFS_SRC_TEMPORARY; 1362789Sahrens } 13632082Seschrock break; 1364789Sahrens 1365789Sahrens case ZFS_PROP_RECORDSIZE: 1366789Sahrens case ZFS_PROP_COMPRESSION: 13671356Seschrock case ZFS_PROP_ZONED: 13682082Seschrock *val = getprop_uint64(zhp, prop, source); 13692082Seschrock break; 1370789Sahrens 1371789Sahrens case ZFS_PROP_READONLY: 13722082Seschrock *val = getprop_uint64(zhp, prop, source); 13732082Seschrock 13742082Seschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 13752082Seschrock *val = B_TRUE; 1376789Sahrens if (src) 1377789Sahrens *src = ZFS_SRC_TEMPORARY; 13782082Seschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 13792082Seschrock *val = B_FALSE; 1380789Sahrens if (src) 1381789Sahrens *src = ZFS_SRC_TEMPORARY; 1382789Sahrens } 13832082Seschrock break; 1384789Sahrens 13851544Seschrock case ZFS_PROP_CREATION: 13862082Seschrock *val = zhp->zfs_dmustats.dds_creation_time; 13872082Seschrock break; 13881544Seschrock 1389789Sahrens case ZFS_PROP_QUOTA: 1390789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1391789Sahrens *source = ""; /* default */ 1392789Sahrens else 1393789Sahrens *source = zhp->zfs_name; 13942082Seschrock *val = zhp->zfs_dmustats.dds_quota; 13952082Seschrock break; 1396789Sahrens 1397789Sahrens case ZFS_PROP_RESERVATION: 1398789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1399789Sahrens *source = ""; /* default */ 1400789Sahrens else 1401789Sahrens *source = zhp->zfs_name; 14022082Seschrock *val = zhp->zfs_dmustats.dds_reserved; 14032082Seschrock break; 1404789Sahrens 1405789Sahrens case ZFS_PROP_COMPRESSRATIO: 1406789Sahrens /* 1407789Sahrens * Using physical space and logical space, calculate the 1408789Sahrens * compression ratio. We return the number as a multiple of 1409789Sahrens * 100, so '2.5x' would be returned as 250. 1410789Sahrens */ 1411789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 14122082Seschrock *val = 100ULL; 1413789Sahrens else 14142082Seschrock *val = 14152082Seschrock (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1416789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 14172082Seschrock break; 1418789Sahrens 1419789Sahrens case ZFS_PROP_REFERENCED: 1420789Sahrens /* 1421789Sahrens * 'referenced' refers to the amount of physical space 1422789Sahrens * referenced (possibly shared) by this object. 1423789Sahrens */ 14242082Seschrock *val = zhp->zfs_dmustats.dds_space_refd; 14252082Seschrock break; 1426789Sahrens 1427789Sahrens case ZFS_PROP_SETUID: 14282082Seschrock *val = getprop_uint64(zhp, prop, source); 14292082Seschrock 14302082Seschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 14312082Seschrock *val = B_TRUE; 1432789Sahrens if (src) 1433789Sahrens *src = ZFS_SRC_TEMPORARY; 14342082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 14352082Seschrock *val = B_FALSE; 1436789Sahrens if (src) 1437789Sahrens *src = ZFS_SRC_TEMPORARY; 1438789Sahrens } 14392082Seschrock break; 1440789Sahrens 1441789Sahrens case ZFS_PROP_VOLSIZE: 14422676Seschrock *val = zhp->zfs_volstats.zv_volsize; 14432082Seschrock break; 1444789Sahrens 1445789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 14462676Seschrock *val = zhp->zfs_volstats.zv_volblocksize; 14472082Seschrock break; 1448789Sahrens 1449789Sahrens case ZFS_PROP_USED: 14502082Seschrock *val = zhp->zfs_dmustats.dds_space_used; 14512082Seschrock break; 1452789Sahrens 1453789Sahrens case ZFS_PROP_CREATETXG: 14542082Seschrock *val = zhp->zfs_dmustats.dds_creation_txg; 14552082Seschrock break; 1456789Sahrens 1457789Sahrens case ZFS_PROP_MOUNTED: 14582082Seschrock *val = (zhp->zfs_mntopts != NULL); 14592082Seschrock break; 1460789Sahrens 14612676Seschrock case ZFS_PROP_CANMOUNT: 14622676Seschrock *val = getprop_uint64(zhp, prop, source); 14632676Seschrock break; 14642676Seschrock 1465789Sahrens default: 14662082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14672082Seschrock "cannot get non-numeric property")); 14682082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14692082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1470789Sahrens } 1471789Sahrens 1472789Sahrens return (0); 1473789Sahrens } 1474789Sahrens 1475789Sahrens /* 1476789Sahrens * Calculate the source type, given the raw source string. 1477789Sahrens */ 1478789Sahrens static void 1479789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1480789Sahrens char *statbuf, size_t statlen) 1481789Sahrens { 1482789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1483789Sahrens return; 1484789Sahrens 1485789Sahrens if (source == NULL) { 1486789Sahrens *srctype = ZFS_SRC_NONE; 1487789Sahrens } else if (source[0] == '\0') { 1488789Sahrens *srctype = ZFS_SRC_DEFAULT; 1489789Sahrens } else { 1490789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1491789Sahrens *srctype = ZFS_SRC_LOCAL; 1492789Sahrens } else { 1493789Sahrens (void) strlcpy(statbuf, source, statlen); 1494789Sahrens *srctype = ZFS_SRC_INHERITED; 1495789Sahrens } 1496789Sahrens } 1497789Sahrens 1498789Sahrens } 1499789Sahrens 1500789Sahrens /* 1501789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1502789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1503789Sahrens * human-readable form. 1504789Sahrens * 1505789Sahrens * Returns 0 on success, or -1 on error. 1506789Sahrens */ 1507789Sahrens int 1508789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 15092082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1510789Sahrens { 1511789Sahrens char *source = NULL; 1512789Sahrens uint64_t val; 1513789Sahrens char *str; 1514789Sahrens const char *root; 15152676Seschrock const char *strval; 1516789Sahrens 1517789Sahrens /* 1518789Sahrens * Check to see if this property applies to our object 1519789Sahrens */ 1520789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1521789Sahrens return (-1); 1522789Sahrens 1523789Sahrens if (src) 1524789Sahrens *src = ZFS_SRC_NONE; 1525789Sahrens 1526789Sahrens switch (prop) { 1527789Sahrens case ZFS_PROP_ATIME: 1528789Sahrens case ZFS_PROP_READONLY: 1529789Sahrens case ZFS_PROP_SETUID: 1530789Sahrens case ZFS_PROP_ZONED: 1531789Sahrens case ZFS_PROP_DEVICES: 1532789Sahrens case ZFS_PROP_EXEC: 15332676Seschrock case ZFS_PROP_CANMOUNT: 1534789Sahrens /* 1535789Sahrens * Basic boolean values are built on top of 1536789Sahrens * get_numeric_property(). 1537789Sahrens */ 15382082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15392082Seschrock return (-1); 15402082Seschrock nicebool(val, propbuf, proplen); 1541789Sahrens 1542789Sahrens break; 1543789Sahrens 1544789Sahrens case ZFS_PROP_AVAILABLE: 1545789Sahrens case ZFS_PROP_RECORDSIZE: 1546789Sahrens case ZFS_PROP_CREATETXG: 1547789Sahrens case ZFS_PROP_REFERENCED: 1548789Sahrens case ZFS_PROP_USED: 1549789Sahrens case ZFS_PROP_VOLSIZE: 1550789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1551789Sahrens /* 1552789Sahrens * Basic numeric values are built on top of 1553789Sahrens * get_numeric_property(). 1554789Sahrens */ 15552082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15562082Seschrock return (-1); 1557789Sahrens if (literal) 1558*2856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 1559*2856Snd150628 (u_longlong_t)val); 1560789Sahrens else 1561789Sahrens zfs_nicenum(val, propbuf, proplen); 1562789Sahrens break; 1563789Sahrens 1564789Sahrens case ZFS_PROP_COMPRESSION: 1565789Sahrens case ZFS_PROP_CHECKSUM: 1566789Sahrens case ZFS_PROP_SNAPDIR: 1567789Sahrens case ZFS_PROP_ACLMODE: 1568789Sahrens case ZFS_PROP_ACLINHERIT: 15691356Seschrock val = getprop_uint64(zhp, prop, &source); 15702676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15712676Seschrock (void) strlcpy(propbuf, strval, proplen); 1572789Sahrens break; 1573789Sahrens 1574789Sahrens case ZFS_PROP_CREATION: 1575789Sahrens /* 1576789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1577789Sahrens * this into a string unless 'literal' is specified. 1578789Sahrens */ 1579789Sahrens { 1580789Sahrens time_t time = (time_t) 1581789Sahrens zhp->zfs_dmustats.dds_creation_time; 1582789Sahrens struct tm t; 1583789Sahrens 1584789Sahrens if (literal || 1585789Sahrens localtime_r(&time, &t) == NULL || 1586789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1587789Sahrens &t) == 0) 1588789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1589*2856Snd150628 (u_longlong_t) 1590789Sahrens zhp->zfs_dmustats.dds_creation_time); 1591789Sahrens } 1592789Sahrens break; 1593789Sahrens 1594789Sahrens case ZFS_PROP_MOUNTPOINT: 1595789Sahrens /* 1596789Sahrens * Getting the precise mountpoint can be tricky. 1597789Sahrens * 1598789Sahrens * - for 'none' or 'legacy', return those values. 1599789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1600789Sahrens * - for inherited mountpoints, we want to take everything 1601789Sahrens * after our ancestor and append it to the inherited value. 1602789Sahrens * 1603789Sahrens * If the pool has an alternate root, we want to prepend that 1604789Sahrens * root to any values we return. 1605789Sahrens */ 16061544Seschrock root = zhp->zfs_root; 16071356Seschrock str = getprop_string(zhp, prop, &source); 16081356Seschrock 16091356Seschrock if (str[0] == '\0') { 1610789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1611789Sahrens root, zhp->zfs_name); 16121356Seschrock } else if (str[0] == '/') { 16131356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1614789Sahrens 1615789Sahrens if (relpath[0] == '/') 1616789Sahrens relpath++; 16171356Seschrock if (str[1] == '\0') 16181356Seschrock str++; 1619789Sahrens 1620789Sahrens if (relpath[0] == '\0') 1621789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 16221356Seschrock root, str); 1623789Sahrens else 1624789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16251356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1626789Sahrens relpath); 1627789Sahrens } else { 1628789Sahrens /* 'legacy' or 'none' */ 16291356Seschrock (void) strlcpy(propbuf, str, proplen); 1630789Sahrens } 1631789Sahrens 1632789Sahrens break; 1633789Sahrens 1634789Sahrens case ZFS_PROP_SHARENFS: 16351356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16361356Seschrock proplen); 1637789Sahrens break; 1638789Sahrens 1639789Sahrens case ZFS_PROP_ORIGIN: 16401544Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1641789Sahrens proplen); 1642789Sahrens /* 1643789Sahrens * If there is no parent at all, return failure to indicate that 1644789Sahrens * it doesn't apply to this dataset. 1645789Sahrens */ 1646789Sahrens if (propbuf[0] == '\0') 1647789Sahrens return (-1); 1648789Sahrens break; 1649789Sahrens 1650789Sahrens case ZFS_PROP_QUOTA: 1651789Sahrens case ZFS_PROP_RESERVATION: 16522082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16532082Seschrock return (-1); 1654789Sahrens 1655789Sahrens /* 1656789Sahrens * If quota or reservation is 0, we translate this into 'none' 1657789Sahrens * (unless literal is set), and indicate that it's the default 1658789Sahrens * value. Otherwise, we print the number nicely and indicate 1659789Sahrens * that its set locally. 1660789Sahrens */ 1661789Sahrens if (val == 0) { 1662789Sahrens if (literal) 1663789Sahrens (void) strlcpy(propbuf, "0", proplen); 1664789Sahrens else 1665789Sahrens (void) strlcpy(propbuf, "none", proplen); 1666789Sahrens } else { 1667789Sahrens if (literal) 1668*2856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 1669*2856Snd150628 (u_longlong_t)val); 1670789Sahrens else 1671789Sahrens zfs_nicenum(val, propbuf, proplen); 1672789Sahrens } 1673789Sahrens break; 1674789Sahrens 1675789Sahrens case ZFS_PROP_COMPRESSRATIO: 16762082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16772082Seschrock return (-1); 1678*2856Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 1679*2856Snd150628 val / 100, (longlong_t)val % 100); 1680789Sahrens break; 1681789Sahrens 1682789Sahrens case ZFS_PROP_TYPE: 1683789Sahrens switch (zhp->zfs_type) { 1684789Sahrens case ZFS_TYPE_FILESYSTEM: 1685789Sahrens str = "filesystem"; 1686789Sahrens break; 1687789Sahrens case ZFS_TYPE_VOLUME: 1688789Sahrens str = "volume"; 1689789Sahrens break; 1690789Sahrens case ZFS_TYPE_SNAPSHOT: 1691789Sahrens str = "snapshot"; 1692789Sahrens break; 1693789Sahrens default: 16942082Seschrock abort(); 1695789Sahrens } 1696789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1697789Sahrens break; 1698789Sahrens 1699789Sahrens case ZFS_PROP_MOUNTED: 1700789Sahrens /* 1701789Sahrens * The 'mounted' property is a pseudo-property that described 1702789Sahrens * whether the filesystem is currently mounted. Even though 1703789Sahrens * it's a boolean value, the typical values of "on" and "off" 1704789Sahrens * don't make sense, so we translate to "yes" and "no". 1705789Sahrens */ 17062082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 17072082Seschrock src, &source, &val) != 0) 17082082Seschrock return (-1); 17092082Seschrock if (val) 1710789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1711789Sahrens else 1712789Sahrens (void) strlcpy(propbuf, "no", proplen); 1713789Sahrens break; 1714789Sahrens 1715789Sahrens case ZFS_PROP_NAME: 1716789Sahrens /* 1717789Sahrens * The 'name' property is a pseudo-property derived from the 1718789Sahrens * dataset name. It is presented as a real property to simplify 1719789Sahrens * consumers. 1720789Sahrens */ 1721789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1722789Sahrens break; 1723789Sahrens 1724789Sahrens default: 17252082Seschrock abort(); 1726789Sahrens } 1727789Sahrens 1728789Sahrens get_source(zhp, src, source, statbuf, statlen); 1729789Sahrens 1730789Sahrens return (0); 1731789Sahrens } 1732789Sahrens 1733789Sahrens /* 1734789Sahrens * Utility function to get the given numeric property. Does no validation that 1735789Sahrens * the given property is the appropriate type; should only be used with 1736789Sahrens * hard-coded property types. 1737789Sahrens */ 1738789Sahrens uint64_t 1739789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1740789Sahrens { 1741789Sahrens char *source; 1742789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17432082Seschrock uint64_t val; 17442082Seschrock 17452082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17462082Seschrock 17472082Seschrock return (val); 1748789Sahrens } 1749789Sahrens 1750789Sahrens /* 1751789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1752789Sahrens */ 1753789Sahrens int 1754789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1755789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1756789Sahrens { 1757789Sahrens char *source; 1758789Sahrens 1759789Sahrens /* 1760789Sahrens * Check to see if this property applies to our object 1761789Sahrens */ 1762789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17632082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 17642082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17652082Seschrock zfs_prop_to_name(prop))); 1766789Sahrens 1767789Sahrens if (src) 1768789Sahrens *src = ZFS_SRC_NONE; 1769789Sahrens 17702082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17712082Seschrock return (-1); 1772789Sahrens 1773789Sahrens get_source(zhp, src, source, statbuf, statlen); 1774789Sahrens 1775789Sahrens return (0); 1776789Sahrens } 1777789Sahrens 1778789Sahrens /* 1779789Sahrens * Returns the name of the given zfs handle. 1780789Sahrens */ 1781789Sahrens const char * 1782789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1783789Sahrens { 1784789Sahrens return (zhp->zfs_name); 1785789Sahrens } 1786789Sahrens 1787789Sahrens /* 1788789Sahrens * Returns the type of the given zfs handle. 1789789Sahrens */ 1790789Sahrens zfs_type_t 1791789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1792789Sahrens { 1793789Sahrens return (zhp->zfs_type); 1794789Sahrens } 1795789Sahrens 1796789Sahrens /* 17971356Seschrock * Iterate over all child filesystems 1798789Sahrens */ 1799789Sahrens int 18001356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1801789Sahrens { 1802789Sahrens zfs_cmd_t zc = { 0 }; 1803789Sahrens zfs_handle_t *nzhp; 1804789Sahrens int ret; 1805789Sahrens 1806789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18072082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1808789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1809789Sahrens /* 1810789Sahrens * Ignore private dataset names. 1811789Sahrens */ 1812789Sahrens if (dataset_name_hidden(zc.zc_name)) 1813789Sahrens continue; 1814789Sahrens 1815789Sahrens /* 1816789Sahrens * Silently ignore errors, as the only plausible explanation is 1817789Sahrens * that the pool has since been removed. 1818789Sahrens */ 18192082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18202082Seschrock zc.zc_name)) == NULL) 1821789Sahrens continue; 1822789Sahrens 1823789Sahrens if ((ret = func(nzhp, data)) != 0) 1824789Sahrens return (ret); 1825789Sahrens } 1826789Sahrens 1827789Sahrens /* 1828789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1829789Sahrens * returned, then the underlying dataset has been removed since we 1830789Sahrens * obtained the handle. 1831789Sahrens */ 1832789Sahrens if (errno != ESRCH && errno != ENOENT) 18332082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18342082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1835789Sahrens 18361356Seschrock return (0); 18371356Seschrock } 18381356Seschrock 18391356Seschrock /* 18401356Seschrock * Iterate over all snapshots 18411356Seschrock */ 18421356Seschrock int 18431356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18441356Seschrock { 18451356Seschrock zfs_cmd_t zc = { 0 }; 18461356Seschrock zfs_handle_t *nzhp; 18471356Seschrock int ret; 1848789Sahrens 1849789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18502082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18512082Seschrock &zc) == 0; 1852789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1853789Sahrens 18542082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18552082Seschrock zc.zc_name)) == NULL) 1856789Sahrens continue; 1857789Sahrens 1858789Sahrens if ((ret = func(nzhp, data)) != 0) 1859789Sahrens return (ret); 1860789Sahrens } 1861789Sahrens 1862789Sahrens /* 1863789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1864789Sahrens * returned, then the underlying dataset has been removed since we 1865789Sahrens * obtained the handle. Silently ignore this case, and return success. 1866789Sahrens */ 1867789Sahrens if (errno != ESRCH && errno != ENOENT) 18682082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18692082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1870789Sahrens 1871789Sahrens return (0); 1872789Sahrens } 1873789Sahrens 1874789Sahrens /* 18751356Seschrock * Iterate over all children, snapshots and filesystems 18761356Seschrock */ 18771356Seschrock int 18781356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18791356Seschrock { 18801356Seschrock int ret; 18811356Seschrock 18821356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 18831356Seschrock return (ret); 18841356Seschrock 18851356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 18861356Seschrock } 18871356Seschrock 18881356Seschrock /* 1889789Sahrens * Given a complete name, return just the portion that refers to the parent. 1890789Sahrens * Can return NULL if this is a pool. 1891789Sahrens */ 1892789Sahrens static int 1893789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1894789Sahrens { 1895789Sahrens char *loc; 1896789Sahrens 1897789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1898789Sahrens return (-1); 1899789Sahrens 1900789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1901789Sahrens buf[loc - path] = '\0'; 1902789Sahrens 1903789Sahrens return (0); 1904789Sahrens } 1905789Sahrens 1906789Sahrens /* 19072676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 19082676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 19092676Seschrock * when creating new datasets. 1910789Sahrens */ 1911789Sahrens static int 19122676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1913789Sahrens { 1914789Sahrens zfs_cmd_t zc = { 0 }; 1915789Sahrens char parent[ZFS_MAXNAMELEN]; 1916789Sahrens char *slash; 19171356Seschrock zfs_handle_t *zhp; 19182082Seschrock char errbuf[1024]; 19192082Seschrock 19202082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 19212082Seschrock path); 1922789Sahrens 1923789Sahrens /* get parent, and check to see if this is just a pool */ 1924789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 19252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19262082Seschrock "missing dataset name")); 19272082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1928789Sahrens } 1929789Sahrens 1930789Sahrens /* check to see if the pool exists */ 1931789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1932789Sahrens slash = parent + strlen(parent); 1933789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1934789Sahrens zc.zc_name[slash - parent] = '\0'; 19352082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1936789Sahrens errno == ENOENT) { 19372082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19382082Seschrock "no such pool '%s'"), zc.zc_name); 19392082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1940789Sahrens } 1941789Sahrens 1942789Sahrens /* check to see if the parent dataset exists */ 19432082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1944789Sahrens switch (errno) { 1945789Sahrens case ENOENT: 19462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19472082Seschrock "parent does not exist")); 19482082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1949789Sahrens 1950789Sahrens default: 19512082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1952789Sahrens } 1953789Sahrens } 1954789Sahrens 19552676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1956789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19572676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19582082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19591356Seschrock zfs_close(zhp); 1960789Sahrens return (-1); 1961789Sahrens } 1962789Sahrens 1963789Sahrens /* make sure parent is a filesystem */ 19641356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19662082Seschrock "parent is not a filesystem")); 19672082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19681356Seschrock zfs_close(zhp); 1969789Sahrens return (-1); 1970789Sahrens } 1971789Sahrens 19721356Seschrock zfs_close(zhp); 1973789Sahrens return (0); 1974789Sahrens } 1975789Sahrens 1976789Sahrens /* 19772676Seschrock * Create a new filesystem or volume. 1978789Sahrens */ 1979789Sahrens int 19802082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 19812676Seschrock nvlist_t *props) 1982789Sahrens { 1983789Sahrens zfs_cmd_t zc = { 0 }; 1984789Sahrens int ret; 1985789Sahrens uint64_t size = 0; 1986789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 19872082Seschrock char errbuf[1024]; 19882676Seschrock uint64_t zoned; 19892082Seschrock 19902082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 19912082Seschrock "cannot create '%s'"), path); 1992789Sahrens 1993789Sahrens /* validate the path, taking care to note the extended error message */ 19942082Seschrock if (!zfs_validate_name(hdl, path, type)) 19952082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1996789Sahrens 1997789Sahrens /* validate parents exist */ 19982676Seschrock if (check_parents(hdl, path, &zoned) != 0) 1999789Sahrens return (-1); 2000789Sahrens 2001789Sahrens /* 2002789Sahrens * The failure modes when creating a dataset of a different type over 2003789Sahrens * one that already exists is a little strange. In particular, if you 2004789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 2005789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 2006789Sahrens * first try to see if the dataset exists. 2007789Sahrens */ 2008789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 20092082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 20102082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20112082Seschrock "dataset already exists")); 20122082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2013789Sahrens } 2014789Sahrens 2015789Sahrens if (type == ZFS_TYPE_VOLUME) 2016789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2017789Sahrens else 2018789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2019789Sahrens 20202676Seschrock if (props && (props = zfs_validate_properties(hdl, type, props, zoned, 20212676Seschrock NULL, errbuf)) == 0) 20222676Seschrock return (-1); 20232676Seschrock 2024789Sahrens if (type == ZFS_TYPE_VOLUME) { 20251133Seschrock /* 20261133Seschrock * If we are creating a volume, the size and block size must 20271133Seschrock * satisfy a few restraints. First, the blocksize must be a 20281133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20291133Seschrock * volsize must be a multiple of the block size, and cannot be 20301133Seschrock * zero. 20311133Seschrock */ 20322676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 20332676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 20342676Seschrock nvlist_free(props); 20352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20362676Seschrock "missing volume size")); 20372676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2038789Sahrens } 2039789Sahrens 20402676Seschrock if ((ret = nvlist_lookup_uint64(props, 20412676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20422676Seschrock &blocksize)) != 0) { 20432676Seschrock if (ret == ENOENT) { 20442676Seschrock blocksize = zfs_prop_default_numeric( 20452676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20462676Seschrock } else { 20472676Seschrock nvlist_free(props); 20482676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20492676Seschrock "missing volume block size")); 20502676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20512676Seschrock } 20522676Seschrock } 20532676Seschrock 20542676Seschrock if (size == 0) { 20552676Seschrock nvlist_free(props); 20562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20572676Seschrock "volume size cannot be zero")); 20582676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20591133Seschrock } 20601133Seschrock 20611133Seschrock if (size % blocksize != 0) { 20622676Seschrock nvlist_free(props); 20632082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20642676Seschrock "volume size must be a multiple of volume block " 20652676Seschrock "size")); 20662676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20671133Seschrock } 2068789Sahrens } 2069789Sahrens 20702676Seschrock if (props && 20712676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20722676Seschrock return (-1); 20732676Seschrock nvlist_free(props); 20742676Seschrock 2075789Sahrens /* create the dataset */ 20762082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2077789Sahrens 2078789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 20792082Seschrock ret = zvol_create_link(hdl, path); 2080789Sahrens 20812676Seschrock zcmd_free_nvlists(&zc); 20822676Seschrock 2083789Sahrens /* check for failure */ 2084789Sahrens if (ret != 0) { 2085789Sahrens char parent[ZFS_MAXNAMELEN]; 2086789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2087789Sahrens 2088789Sahrens switch (errno) { 2089789Sahrens case ENOENT: 20902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20912082Seschrock "no such parent '%s'"), parent); 20922082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2093789Sahrens 2094789Sahrens case EINVAL: 20952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20962082Seschrock "parent '%s' is not a filesysem"), parent); 20972082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2098789Sahrens 2099789Sahrens case EDOM: 21002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21012676Seschrock "volume block size must be power of 2 from " 21022676Seschrock "%u to %uk"), 2103789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2104789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 21052082Seschrock 21062676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 21072082Seschrock 2108789Sahrens #ifdef _ILP32 2109789Sahrens case EOVERFLOW: 2110789Sahrens /* 2111789Sahrens * This platform can't address a volume this big. 2112789Sahrens */ 21132082Seschrock if (type == ZFS_TYPE_VOLUME) 21142082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 21152082Seschrock errbuf)); 2116789Sahrens #endif 21172082Seschrock /* FALLTHROUGH */ 2118789Sahrens default: 21192082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2120789Sahrens } 2121789Sahrens } 2122789Sahrens 2123789Sahrens return (0); 2124789Sahrens } 2125789Sahrens 2126789Sahrens /* 2127789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2128789Sahrens * isn't mounted, and that there are no active dependents. 2129789Sahrens */ 2130789Sahrens int 2131789Sahrens zfs_destroy(zfs_handle_t *zhp) 2132789Sahrens { 2133789Sahrens zfs_cmd_t zc = { 0 }; 2134789Sahrens int ret; 2135789Sahrens 2136789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2137789Sahrens 21382676Seschrock if (ZFS_IS_VOLUME(zhp)) { 21392082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2140789Sahrens return (-1); 2141789Sahrens 2142789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2143789Sahrens } else { 2144789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2145789Sahrens } 2146789Sahrens 21472082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 21482199Sahrens if (ret != 0) { 21492082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 21502082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21512082Seschrock zhp->zfs_name)); 21522199Sahrens } 2153789Sahrens 2154789Sahrens remove_mountpoint(zhp); 2155789Sahrens 2156789Sahrens return (0); 2157789Sahrens } 2158789Sahrens 21592199Sahrens struct destroydata { 21602199Sahrens char *snapname; 21612199Sahrens boolean_t gotone; 21622199Sahrens }; 21632199Sahrens 21642199Sahrens static int 21652199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 21662199Sahrens { 21672199Sahrens struct destroydata *dd = arg; 21682199Sahrens zfs_handle_t *szhp; 21692199Sahrens char name[ZFS_MAXNAMELEN]; 21702199Sahrens 21712676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 21722676Seschrock (void) strlcat(name, "@", sizeof (name)); 21732676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 21742199Sahrens 21752199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 21762199Sahrens if (szhp) { 21772199Sahrens dd->gotone = B_TRUE; 21782199Sahrens zfs_close(szhp); 21792199Sahrens } 21802199Sahrens 21812199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 21822199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 21832199Sahrens /* 21842199Sahrens * NB: this is simply a best-effort. We don't want to 21852199Sahrens * return an error, because then we wouldn't visit all 21862199Sahrens * the volumes. 21872199Sahrens */ 21882199Sahrens } 21892199Sahrens 21902199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 21912199Sahrens } 21922199Sahrens 21932199Sahrens /* 21942199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 21952199Sahrens */ 21962199Sahrens int 21972199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 21982199Sahrens { 21992199Sahrens zfs_cmd_t zc = { 0 }; 22002199Sahrens int ret; 22012199Sahrens struct destroydata dd = { 0 }; 22022199Sahrens 22032199Sahrens dd.snapname = snapname; 22042199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 22052199Sahrens 22062199Sahrens if (!dd.gotone) { 22072199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 22082199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 22092199Sahrens zhp->zfs_name, snapname)); 22102199Sahrens } 22112199Sahrens 22122199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22132676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 22142199Sahrens 22152199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 22162199Sahrens if (ret != 0) { 22172199Sahrens char errbuf[1024]; 22182199Sahrens 22192199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22202199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22212199Sahrens 22222199Sahrens switch (errno) { 22232199Sahrens case EEXIST: 22242199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22252199Sahrens "snapshot is cloned")); 22262199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22272199Sahrens 22282199Sahrens default: 22292199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22302199Sahrens errbuf)); 22312199Sahrens } 22322199Sahrens } 22332199Sahrens 22342199Sahrens return (0); 22352199Sahrens } 22362199Sahrens 2237789Sahrens /* 2238789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2239789Sahrens */ 2240789Sahrens int 22412676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2242789Sahrens { 2243789Sahrens zfs_cmd_t zc = { 0 }; 2244789Sahrens char parent[ZFS_MAXNAMELEN]; 2245789Sahrens int ret; 22462082Seschrock char errbuf[1024]; 22472082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22482676Seschrock zfs_type_t type; 22492676Seschrock uint64_t zoned; 2250789Sahrens 2251789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2252789Sahrens 22532082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22542082Seschrock "cannot create '%s'"), target); 22552082Seschrock 2256789Sahrens /* validate the target name */ 22572082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 22582082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2259789Sahrens 2260789Sahrens /* validate parents exist */ 22612676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2262789Sahrens return (-1); 2263789Sahrens 2264789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2265789Sahrens 2266789Sahrens /* do the clone */ 22672676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2268789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 22692744Snn35248 type = ZFS_TYPE_VOLUME; 22702676Seschrock } else { 2271789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 22722744Snn35248 type = ZFS_TYPE_FILESYSTEM; 22732676Seschrock } 22742676Seschrock 22752676Seschrock if (props) { 22762676Seschrock if ((props = zfs_validate_properties(hdl, type, props, zoned, 22772676Seschrock zhp, errbuf)) == NULL) 22782676Seschrock return (-1); 22792676Seschrock 22802676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 22812676Seschrock nvlist_free(props); 22822676Seschrock return (-1); 22832676Seschrock } 22842676Seschrock 22852676Seschrock nvlist_free(props); 22862676Seschrock } 2287789Sahrens 2288789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 22892676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 22902082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2291789Sahrens 22922676Seschrock zcmd_free_nvlists(&zc); 22932676Seschrock 2294789Sahrens if (ret != 0) { 2295789Sahrens switch (errno) { 2296789Sahrens 2297789Sahrens case ENOENT: 2298789Sahrens /* 2299789Sahrens * The parent doesn't exist. We should have caught this 2300789Sahrens * above, but there may a race condition that has since 2301789Sahrens * destroyed the parent. 2302789Sahrens * 2303789Sahrens * At this point, we don't know whether it's the source 2304789Sahrens * that doesn't exist anymore, or whether the target 2305789Sahrens * dataset doesn't exist. 2306789Sahrens */ 23072082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23082082Seschrock "no such parent '%s'"), parent); 23092082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 23102082Seschrock 23112082Seschrock case EXDEV: 23122082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23132082Seschrock "source and target pools differ")); 23142082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 23152082Seschrock errbuf)); 23162082Seschrock 23172082Seschrock default: 23182082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 23192082Seschrock errbuf)); 23202082Seschrock } 23212676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 23222082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 23232082Seschrock } 23242082Seschrock 23252082Seschrock return (ret); 23262082Seschrock } 23272082Seschrock 23282082Seschrock typedef struct promote_data { 23292082Seschrock char cb_mountpoint[MAXPATHLEN]; 23302082Seschrock const char *cb_target; 23312082Seschrock const char *cb_errbuf; 23322082Seschrock uint64_t cb_pivot_txg; 23332082Seschrock } promote_data_t; 23342082Seschrock 23352082Seschrock static int 23362082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 23372082Seschrock { 23382082Seschrock promote_data_t *pd = data; 23392082Seschrock zfs_handle_t *szhp; 23402082Seschrock char snapname[MAXPATHLEN]; 23412082Seschrock 23422082Seschrock /* We don't care about snapshots after the pivot point */ 23432082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23442082Seschrock return (0); 23452082Seschrock 23462417Sahrens /* Remove the device link if it's a zvol. */ 23472676Seschrock if (ZFS_IS_VOLUME(zhp)) 23482417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23492082Seschrock 23502082Seschrock /* Check for conflicting names */ 23512676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 23522676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 23532082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 23542082Seschrock if (szhp != NULL) { 23552082Seschrock zfs_close(szhp); 23562082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23572082Seschrock "snapshot name '%s' from origin \n" 23582082Seschrock "conflicts with '%s' from target"), 23592082Seschrock zhp->zfs_name, snapname); 23602082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 23612082Seschrock } 23622082Seschrock return (0); 23632082Seschrock } 23642082Seschrock 23652417Sahrens static int 23662417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 23672417Sahrens { 23682417Sahrens promote_data_t *pd = data; 23692417Sahrens 23702417Sahrens /* We don't care about snapshots after the pivot point */ 23712417Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23722417Sahrens return (0); 23732417Sahrens 23742417Sahrens /* Create the device link if it's a zvol. */ 23752676Seschrock if (ZFS_IS_VOLUME(zhp)) 23762417Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 23772417Sahrens 23782417Sahrens return (0); 23792417Sahrens } 23802417Sahrens 23812082Seschrock /* 23822082Seschrock * Promotes the given clone fs to be the clone parent. 23832082Seschrock */ 23842082Seschrock int 23852082Seschrock zfs_promote(zfs_handle_t *zhp) 23862082Seschrock { 23872082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 23882082Seschrock zfs_cmd_t zc = { 0 }; 23892082Seschrock char parent[MAXPATHLEN]; 23902082Seschrock char *cp; 23912082Seschrock int ret; 23922082Seschrock zfs_handle_t *pzhp; 23932082Seschrock promote_data_t pd; 23942082Seschrock char errbuf[1024]; 23952082Seschrock 23962082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23972082Seschrock "cannot promote '%s'"), zhp->zfs_name); 23982082Seschrock 23992082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 24002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24012082Seschrock "snapshots can not be promoted")); 24022082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24032082Seschrock } 24042082Seschrock 24052676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 24062082Seschrock if (parent[0] == '\0') { 24072082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24082082Seschrock "not a cloned filesystem")); 24092082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24102082Seschrock } 24112082Seschrock cp = strchr(parent, '@'); 24122082Seschrock *cp = '\0'; 24132082Seschrock 24142082Seschrock /* Walk the snapshots we will be moving */ 24152082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 24162082Seschrock if (pzhp == NULL) 24172082Seschrock return (-1); 24182082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 24192082Seschrock zfs_close(pzhp); 24202082Seschrock pd.cb_target = zhp->zfs_name; 24212082Seschrock pd.cb_errbuf = errbuf; 24222082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 24232082Seschrock if (pzhp == NULL) 24242082Seschrock return (-1); 24252082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 24262082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 24272082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24282417Sahrens if (ret != 0) { 24292417Sahrens zfs_close(pzhp); 24302082Seschrock return (-1); 24312417Sahrens } 24322082Seschrock 24332082Seschrock /* issue the ioctl */ 24342676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 24352676Seschrock sizeof (zc.zc_value)); 24362082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24372082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 24382082Seschrock 24392082Seschrock if (ret != 0) { 24402417Sahrens int save_errno = errno; 24412417Sahrens 24422417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24432417Sahrens zfs_close(pzhp); 24442417Sahrens 24452417Sahrens switch (save_errno) { 2446789Sahrens case EEXIST: 2447789Sahrens /* 24482082Seschrock * There is a conflicting snapshot name. We 24492082Seschrock * should have caught this above, but they could 24502082Seschrock * have renamed something in the mean time. 2451789Sahrens */ 24522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24532082Seschrock "conflicting snapshot name from parent '%s'"), 24542082Seschrock parent); 24552082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2456789Sahrens 2457789Sahrens default: 24582417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2459789Sahrens } 24602417Sahrens } else { 24612417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2462789Sahrens } 2463789Sahrens 24642417Sahrens zfs_close(pzhp); 2465789Sahrens return (ret); 2466789Sahrens } 2467789Sahrens 24682199Sahrens static int 24692199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 24702199Sahrens { 24712199Sahrens char *snapname = arg; 24722676Seschrock int ret; 24732199Sahrens 24742199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 24752199Sahrens char name[MAXPATHLEN]; 24762199Sahrens 24772676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 24782676Seschrock (void) strlcat(name, "@", sizeof (name)); 24792676Seschrock (void) strlcat(name, snapname, sizeof (name)); 24802199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 24812199Sahrens /* 24822199Sahrens * NB: this is simply a best-effort. We don't want to 24832199Sahrens * return an error, because then we wouldn't visit all 24842199Sahrens * the volumes. 24852199Sahrens */ 24862199Sahrens } 24872676Seschrock 24882676Seschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 24892676Seschrock 24902676Seschrock zfs_close(zhp); 24912676Seschrock 24922676Seschrock return (ret); 24932199Sahrens } 24942199Sahrens 2495789Sahrens /* 2496789Sahrens * Takes a snapshot of the given dataset 2497789Sahrens */ 2498789Sahrens int 24992199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2500789Sahrens { 2501789Sahrens const char *delim; 2502789Sahrens char *parent; 2503789Sahrens zfs_handle_t *zhp; 2504789Sahrens zfs_cmd_t zc = { 0 }; 2505789Sahrens int ret; 25062082Seschrock char errbuf[1024]; 25072082Seschrock 25082082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25092082Seschrock "cannot snapshot '%s'"), path); 25102082Seschrock 25112082Seschrock /* validate the target name */ 25122082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 25132082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2514789Sahrens 2515789Sahrens /* make sure the parent exists and is of the appropriate type */ 25162199Sahrens delim = strchr(path, '@'); 25172082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 25182082Seschrock return (-1); 2519789Sahrens (void) strncpy(parent, path, delim - path); 2520789Sahrens parent[delim - path] = '\0'; 2521789Sahrens 25222082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2523789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2524789Sahrens free(parent); 2525789Sahrens return (-1); 2526789Sahrens } 2527789Sahrens 25282199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25292676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25302199Sahrens zc.zc_cookie = recursive; 25312199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 25322199Sahrens 25332199Sahrens /* 25342199Sahrens * if it was recursive, the one that actually failed will be in 25352199Sahrens * zc.zc_name. 25362199Sahrens */ 25372199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25382676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25392199Sahrens if (ret == 0 && recursive) { 25402199Sahrens (void) zfs_iter_filesystems(zhp, 25412199Sahrens zfs_create_link_cb, (char *)delim+1); 25422199Sahrens } 2543789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 25442082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25452199Sahrens if (ret != 0) { 25462082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 25472082Seschrock &zc); 25482199Sahrens } 2549789Sahrens } 2550789Sahrens 25512082Seschrock if (ret != 0) 25522082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2553789Sahrens 2554789Sahrens free(parent); 2555789Sahrens zfs_close(zhp); 2556789Sahrens 2557789Sahrens return (ret); 2558789Sahrens } 2559789Sahrens 2560789Sahrens /* 2561789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2562789Sahrens */ 2563789Sahrens int 25641749Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2565789Sahrens { 2566789Sahrens zfs_cmd_t zc = { 0 }; 2567789Sahrens int ret; 25682082Seschrock char errbuf[1024]; 25692082Seschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 25702082Seschrock 25712082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25722082Seschrock "cannot send '%s'"), zhp_to->zfs_name); 2573789Sahrens 2574789Sahrens /* do the ioctl() */ 2575789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2576789Sahrens if (zhp_from) { 25772676Seschrock (void) strlcpy(zc.zc_value, zhp_from->zfs_name, 2578789Sahrens sizeof (zc.zc_name)); 2579789Sahrens } else { 25802676Seschrock zc.zc_value[0] = '\0'; 2581789Sahrens } 2582789Sahrens zc.zc_cookie = STDOUT_FILENO; 2583789Sahrens 25842082Seschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2585789Sahrens if (ret != 0) { 2586789Sahrens switch (errno) { 2587789Sahrens 2588789Sahrens case EXDEV: 25892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25902082Seschrock "not an ealier snapshot from the same fs")); 25912082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2592789Sahrens 2593789Sahrens case EDQUOT: 2594789Sahrens case EFBIG: 2595789Sahrens case EIO: 2596789Sahrens case ENOLINK: 2597789Sahrens case ENOSPC: 2598789Sahrens case ENOSTR: 2599789Sahrens case ENXIO: 2600789Sahrens case EPIPE: 2601789Sahrens case ERANGE: 2602789Sahrens case EFAULT: 2603789Sahrens case EROFS: 26042082Seschrock zfs_error_aux(hdl, strerror(errno)); 26052082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2606789Sahrens 2607789Sahrens default: 26082082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2609789Sahrens } 2610789Sahrens } 2611789Sahrens 2612789Sahrens return (ret); 2613789Sahrens } 2614789Sahrens 2615789Sahrens /* 2616789Sahrens * Restores a backup of tosnap from stdin. 2617789Sahrens */ 2618789Sahrens int 26192082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 26202665Snd150628 int verbose, int dryrun, boolean_t force) 2621789Sahrens { 2622789Sahrens zfs_cmd_t zc = { 0 }; 2623789Sahrens time_t begin_time; 2624868Sahrens int ioctl_err, err, bytes, size; 2625789Sahrens char *cp; 2626789Sahrens dmu_replay_record_t drr; 2627789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 26282082Seschrock char errbuf[1024]; 26292665Snd150628 prop_changelist_t *clp; 2630789Sahrens 2631789Sahrens begin_time = time(NULL); 2632789Sahrens 26332082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26342082Seschrock "cannot receive")); 26352082Seschrock 2636789Sahrens /* trim off snapname, if any */ 26372676Seschrock (void) strlcpy(zc.zc_name, tosnap, sizeof (zc.zc_name)); 2638789Sahrens cp = strchr(zc.zc_name, '@'); 2639789Sahrens if (cp) 2640789Sahrens *cp = '\0'; 2641789Sahrens 2642789Sahrens /* read in the BEGIN record */ 2643789Sahrens cp = (char *)&drr; 2644789Sahrens bytes = 0; 2645789Sahrens do { 2646868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2647868Sahrens cp += size; 2648868Sahrens bytes += size; 2649868Sahrens } while (size > 0); 2650868Sahrens 2651868Sahrens if (size < 0 || bytes != sizeof (drr)) { 26522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26532082Seschrock "stream (failed to read first record)")); 26542082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2655789Sahrens } 2656789Sahrens 2657789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2658789Sahrens 2659789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2660789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 26612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26622082Seschrock "stream (bad magic number)")); 26632082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2664789Sahrens } 2665789Sahrens 2666789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2667789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 26682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 26692082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2670789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 26712082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2672789Sahrens } 2673789Sahrens 2674789Sahrens /* 2675789Sahrens * Determine name of destination snapshot. 2676789Sahrens */ 26772676Seschrock (void) strlcpy(zc.zc_value, tosnap, sizeof (zc.zc_value)); 2678789Sahrens if (isprefix) { 2679789Sahrens if (strchr(tosnap, '@') != NULL) { 26802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26812082Seschrock "destination must be a filesystem")); 26822082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2683789Sahrens } 2684789Sahrens 2685789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2686789Sahrens if (cp == NULL) 2687789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2688789Sahrens else 2689789Sahrens cp++; 2690789Sahrens 26912676Seschrock (void) strcat(zc.zc_value, "/"); 26922676Seschrock (void) strcat(zc.zc_value, cp); 2693789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2694789Sahrens /* 2695789Sahrens * they specified just a filesystem; tack on the 2696789Sahrens * snapname from the backup. 2697789Sahrens */ 2698789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 26992082Seschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 27002082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 27012676Seschrock (void) strcat(zc.zc_value, cp); 2702789Sahrens } 2703789Sahrens 2704789Sahrens if (drrb->drr_fromguid) { 2705789Sahrens zfs_handle_t *h; 2706789Sahrens /* incremental backup stream */ 2707789Sahrens 2708789Sahrens /* do the ioctl to the containing fs */ 27092676Seschrock (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name)); 2710789Sahrens cp = strchr(zc.zc_name, '@'); 2711789Sahrens *cp = '\0'; 2712789Sahrens 2713789Sahrens /* make sure destination fs exists */ 27142082Seschrock h = zfs_open(hdl, zc.zc_name, 27152082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 27162082Seschrock if (h == NULL) 2717789Sahrens return (-1); 2718868Sahrens if (!dryrun) { 27192665Snd150628 /* 27202665Snd150628 * We need to unmount all the dependents of the dataset 27212665Snd150628 * and the dataset itself. If it's a volume 27222665Snd150628 * then remove device link. 27232665Snd150628 */ 2724868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 27252665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 27262665Snd150628 if (clp == NULL) 27272665Snd150628 return (-1); 27282665Snd150628 if (changelist_prefix(clp) != 0) { 27292665Snd150628 changelist_free(clp); 27302665Snd150628 return (-1); 27312665Snd150628 } 2732868Sahrens } else { 27332082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2734868Sahrens } 2735868Sahrens } 2736789Sahrens zfs_close(h); 2737789Sahrens } else { 2738789Sahrens /* full backup stream */ 2739789Sahrens 27402676Seschrock (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name)); 2741868Sahrens 27421749Sahrens /* make sure they aren't trying to receive into the root */ 2743868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2744789Sahrens cp = strchr(zc.zc_name, '@'); 2745789Sahrens if (cp) 2746789Sahrens *cp = '\0'; 27472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27482082Seschrock "destination '%s' already exists"), zc.zc_name); 27492082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2750789Sahrens } 2751789Sahrens 2752789Sahrens if (isprefix) { 2753868Sahrens zfs_handle_t *h; 2754868Sahrens 2755789Sahrens /* make sure prefix exists */ 27562082Seschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 27572082Seschrock if (h == NULL) 2758789Sahrens return (-1); 27591544Seschrock zfs_close(h); 2760789Sahrens 2761789Sahrens /* create any necessary ancestors up to prefix */ 2762868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 27631544Seschrock 2764868Sahrens /* 2765868Sahrens * zc.zc_name is now the full name of the snap 27661544Seschrock * we're restoring into. Attempt to create, 27671544Seschrock * mount, and share any ancestor filesystems, up 27681544Seschrock * to the one that was named. 2769868Sahrens */ 27701544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 27711544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 27721544Seschrock const char *opname; 2773789Sahrens *cp = '\0'; 27741544Seschrock 27752082Seschrock opname = dgettext(TEXT_DOMAIN, "create"); 27762082Seschrock if (zfs_create(hdl, zc.zc_name, 27772676Seschrock ZFS_TYPE_FILESYSTEM, NULL) != 0) { 27781544Seschrock if (errno == EEXIST) 27791544Seschrock continue; 27801544Seschrock goto ancestorerr; 2781789Sahrens } 27821544Seschrock 27832082Seschrock opname = dgettext(TEXT_DOMAIN, "open"); 27842082Seschrock h = zfs_open(hdl, zc.zc_name, 27852082Seschrock ZFS_TYPE_FILESYSTEM); 27861544Seschrock if (h == NULL) 27871544Seschrock goto ancestorerr; 27881544Seschrock 27892082Seschrock opname = dgettext(TEXT_DOMAIN, "mount"); 27901544Seschrock if (zfs_mount(h, NULL, 0) != 0) 27911544Seschrock goto ancestorerr; 27921544Seschrock 27932082Seschrock opname = dgettext(TEXT_DOMAIN, "share"); 27941544Seschrock if (zfs_share(h) != 0) 27951544Seschrock goto ancestorerr; 27961544Seschrock 27971544Seschrock zfs_close(h); 27981544Seschrock 27991544Seschrock continue; 28001544Seschrock ancestorerr: 28012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28022082Seschrock "failed to %s ancestor '%s'"), opname, 28032082Seschrock zc.zc_name); 28042082Seschrock return (zfs_error(hdl, EZFS_BADRESTORE, 28052082Seschrock errbuf)); 2806789Sahrens } 2807789Sahrens } 2808868Sahrens 2809868Sahrens /* Make sure destination fs does not exist */ 2810868Sahrens cp = strchr(zc.zc_name, '@'); 2811868Sahrens *cp = '\0'; 28122082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 28132082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28142082Seschrock "destination '%s' exists"), zc.zc_name); 28152082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2816868Sahrens } 2817868Sahrens 2818868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2819868Sahrens cp = strrchr(zc.zc_name, '/'); 2820868Sahrens *cp = '\0'; 2821789Sahrens } 2822789Sahrens 2823789Sahrens zc.zc_cookie = STDIN_FILENO; 28242676Seschrock zc.zc_guid = force; 2825789Sahrens if (verbose) { 28261749Sahrens (void) printf("%s %s stream of %s into %s\n", 28271749Sahrens dryrun ? "would receive" : "receiving", 2828789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2829789Sahrens drr.drr_u.drr_begin.drr_toname, 28302676Seschrock zc.zc_value); 2831789Sahrens (void) fflush(stdout); 2832789Sahrens } 2833789Sahrens if (dryrun) 2834789Sahrens return (0); 28352082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2836868Sahrens if (ioctl_err != 0) { 2837789Sahrens switch (errno) { 2838789Sahrens case ENODEV: 28392082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28402082Seschrock "most recent snapshot does not match incremental " 28412082Seschrock "source")); 28422082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2843789Sahrens break; 2844789Sahrens case ETXTBSY: 28452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28462082Seschrock "destination has been modified since most recent " 28472082Seschrock "snapshot")); 28482082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2849789Sahrens break; 2850789Sahrens case EEXIST: 2851789Sahrens if (drrb->drr_fromguid == 0) { 2852789Sahrens /* it's the containing fs that exists */ 28532676Seschrock cp = strchr(zc.zc_value, '@'); 2854789Sahrens *cp = '\0'; 2855789Sahrens } 28562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28572082Seschrock "destination already exists")); 28582082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 28592676Seschrock "cannot restore to %s"), zc.zc_value); 2860789Sahrens break; 2861789Sahrens case EINVAL: 28622082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2863868Sahrens break; 28641544Seschrock case ECKSUM: 28652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28662082Seschrock "invalid stream (checksum mismatch)")); 28672082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2868789Sahrens break; 2869789Sahrens default: 28702082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2871789Sahrens } 2872789Sahrens } 2873789Sahrens 2874789Sahrens /* 2875868Sahrens * Mount or recreate the /dev links for the target filesystem 2876868Sahrens * (if created, or if we tore them down to do an incremental 2877868Sahrens * restore), and the /dev links for the new snapshot (if 28782665Snd150628 * created). Also mount any children of the target filesystem 28792665Snd150628 * if we did an incremental receive. 2880789Sahrens */ 28812676Seschrock cp = strchr(zc.zc_value, '@'); 2882868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2883789Sahrens zfs_handle_t *h; 2884789Sahrens 2885789Sahrens *cp = '\0'; 28862676Seschrock h = zfs_open(hdl, zc.zc_value, 2887789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2888868Sahrens *cp = '@'; 2889789Sahrens if (h) { 28902665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 28912082Seschrock err = zvol_create_link(hdl, h->zfs_name); 28921544Seschrock if (err == 0 && ioctl_err == 0) 28932082Seschrock err = zvol_create_link(hdl, 28942676Seschrock zc.zc_value); 28952665Snd150628 } else { 28962665Snd150628 if (drrb->drr_fromguid) { 28972665Snd150628 err = changelist_postfix(clp); 28982665Snd150628 changelist_free(clp); 28992665Snd150628 } else { 29002665Snd150628 err = zfs_mount(h, NULL, 0); 29012665Snd150628 } 2902868Sahrens } 29032665Snd150628 zfs_close(h); 2904789Sahrens } 2905789Sahrens } 2906789Sahrens 2907868Sahrens if (err || ioctl_err) 2908868Sahrens return (-1); 2909789Sahrens 2910789Sahrens if (verbose) { 2911789Sahrens char buf1[64]; 2912789Sahrens char buf2[64]; 2913789Sahrens uint64_t bytes = zc.zc_cookie; 2914789Sahrens time_t delta = time(NULL) - begin_time; 2915789Sahrens if (delta == 0) 2916789Sahrens delta = 1; 2917789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2918789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2919789Sahrens 29201749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2921789Sahrens buf1, delta, buf2); 2922789Sahrens } 29232665Snd150628 2924789Sahrens return (0); 2925789Sahrens } 2926789Sahrens 2927789Sahrens /* 29281294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 29291294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 29301294Slling * is a dependent and we should just destroy it without checking the transaction 29311294Slling * group. 2932789Sahrens */ 29331294Slling typedef struct rollback_data { 29341294Slling const char *cb_target; /* the snapshot */ 29351294Slling uint64_t cb_create; /* creation time reference */ 29361294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 29371294Slling int cb_error; 29382082Seschrock boolean_t cb_dependent; 29391294Slling } rollback_data_t; 29401294Slling 29411294Slling static int 29421294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 29431294Slling { 29441294Slling rollback_data_t *cbp = data; 29451294Slling 29461294Slling if (!cbp->cb_dependent) { 29471294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 29481294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 29491294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 29501294Slling cbp->cb_create) { 29511294Slling 29522082Seschrock cbp->cb_dependent = B_TRUE; 29532474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 29542474Seschrock cbp) != 0) 29552474Seschrock cbp->cb_error = 1; 29562082Seschrock cbp->cb_dependent = B_FALSE; 29571294Slling 29581294Slling if (zfs_destroy(zhp) != 0) 29591294Slling cbp->cb_error = 1; 29601294Slling else 29611294Slling changelist_remove(zhp, cbp->cb_clp); 29621294Slling } 29631294Slling } else { 29641294Slling if (zfs_destroy(zhp) != 0) 29651294Slling cbp->cb_error = 1; 29661294Slling else 29671294Slling changelist_remove(zhp, cbp->cb_clp); 29681294Slling } 29691294Slling 29701294Slling zfs_close(zhp); 29711294Slling return (0); 29721294Slling } 29731294Slling 29741294Slling /* 29751294Slling * Rollback the dataset to its latest snapshot. 29761294Slling */ 29771294Slling static int 29781294Slling do_rollback(zfs_handle_t *zhp) 2979789Sahrens { 2980789Sahrens int ret; 2981789Sahrens zfs_cmd_t zc = { 0 }; 2982789Sahrens 2983789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2984789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2985789Sahrens 2986789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 29872082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2988789Sahrens return (-1); 2989789Sahrens 2990789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2991789Sahrens 29922676Seschrock if (ZFS_IS_VOLUME(zhp)) 2993789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2994789Sahrens else 2995789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2996789Sahrens 2997789Sahrens /* 2998789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2999789Sahrens * for the given dataset. Given these constraints, we can simply pass 3000789Sahrens * the name on to the ioctl() call. There is still an unlikely race 3001789Sahrens * condition where the user has taken a snapshot since we verified that 3002789Sahrens * this was the most recent. 3003789Sahrens */ 30042082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 30052082Seschrock &zc)) != 0) { 30062082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 30072082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 30082082Seschrock zhp->zfs_name); 3009789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 30102082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3011789Sahrens } 3012789Sahrens 3013789Sahrens return (ret); 3014789Sahrens } 3015789Sahrens 3016789Sahrens /* 30171294Slling * Given a dataset, rollback to a specific snapshot, discarding any 30181294Slling * data changes since then and making it the active dataset. 30191294Slling * 30201294Slling * Any snapshots more recent than the target are destroyed, along with 30211294Slling * their dependents. 30221294Slling */ 30231294Slling int 30241294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 30251294Slling { 30261294Slling int ret; 30271294Slling rollback_data_t cb = { 0 }; 30281294Slling prop_changelist_t *clp; 30291294Slling 30301294Slling /* 30311294Slling * Unmount all dependendents of the dataset and the dataset itself. 30321294Slling * The list we need to gather is the same as for doing rename 30331294Slling */ 30341294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 30351294Slling if (clp == NULL) 30361294Slling return (-1); 30371294Slling 30381294Slling if ((ret = changelist_prefix(clp)) != 0) 30391294Slling goto out; 30401294Slling 30411294Slling /* 30421294Slling * Destroy all recent snapshots and its dependends. 30431294Slling */ 30441294Slling cb.cb_target = snap->zfs_name; 30451294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 30461294Slling cb.cb_clp = clp; 30471294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 30481294Slling 30491294Slling if ((ret = cb.cb_error) != 0) { 30501294Slling (void) changelist_postfix(clp); 30511294Slling goto out; 30521294Slling } 30531294Slling 30541294Slling /* 30551294Slling * Now that we have verified that the snapshot is the latest, 30561294Slling * rollback to the given snapshot. 30571294Slling */ 30581294Slling ret = do_rollback(zhp); 30591294Slling 30601294Slling if (ret != 0) { 30611294Slling (void) changelist_postfix(clp); 30621294Slling goto out; 30631294Slling } 30641294Slling 30651294Slling /* 30661294Slling * We only want to re-mount the filesystem if it was mounted in the 30671294Slling * first place. 30681294Slling */ 30691294Slling ret = changelist_postfix(clp); 30701294Slling 30711294Slling out: 30721294Slling changelist_free(clp); 30731294Slling return (ret); 30741294Slling } 30751294Slling 30761294Slling /* 3077789Sahrens * Iterate over all dependents for a given dataset. This includes both 3078789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3079789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3080789Sahrens * libzfs_graph.c. 3081789Sahrens */ 3082789Sahrens int 30832474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 30842474Seschrock zfs_iter_f func, void *data) 3085789Sahrens { 3086789Sahrens char **dependents; 3087789Sahrens size_t count; 3088789Sahrens int i; 3089789Sahrens zfs_handle_t *child; 3090789Sahrens int ret = 0; 3091789Sahrens 30922474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 30932474Seschrock &dependents, &count) != 0) 30942474Seschrock return (-1); 30952474Seschrock 3096789Sahrens for (i = 0; i < count; i++) { 30972082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 30982082Seschrock dependents[i])) == NULL) 3099789Sahrens continue; 3100789Sahrens 3101789Sahrens if ((ret = func(child, data)) != 0) 3102789Sahrens break; 3103789Sahrens } 3104789Sahrens 3105789Sahrens for (i = 0; i < count; i++) 3106789Sahrens free(dependents[i]); 3107789Sahrens free(dependents); 3108789Sahrens 3109789Sahrens return (ret); 3110789Sahrens } 3111789Sahrens 3112789Sahrens /* 3113789Sahrens * Renames the given dataset. 3114789Sahrens */ 3115789Sahrens int 3116789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3117789Sahrens { 3118789Sahrens int ret; 3119789Sahrens zfs_cmd_t zc = { 0 }; 3120789Sahrens char *delim; 3121789Sahrens prop_changelist_t *cl; 3122789Sahrens char parent[ZFS_MAXNAMELEN]; 31232082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 31242082Seschrock char errbuf[1024]; 3125789Sahrens 3126789Sahrens /* if we have the same exact name, just return success */ 3127789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3128789Sahrens return (0); 3129789Sahrens 31302082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31312082Seschrock "cannot rename to '%s'"), target); 31322082Seschrock 3133789Sahrens /* 3134789Sahrens * Make sure the target name is valid 3135789Sahrens */ 3136789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 31372665Snd150628 if ((strchr(target, '@') == NULL) || 31382665Snd150628 *target == '@') { 31392665Snd150628 /* 31402665Snd150628 * Snapshot target name is abbreviated, 31412665Snd150628 * reconstruct full dataset name 31422665Snd150628 */ 31432665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 31442665Snd150628 sizeof (parent)); 31452665Snd150628 delim = strchr(parent, '@'); 31462665Snd150628 if (strchr(target, '@') == NULL) 31472665Snd150628 *(++delim) = '\0'; 31482665Snd150628 else 31492665Snd150628 *delim = '\0'; 31502665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 31512665Snd150628 target = parent; 31522665Snd150628 } else { 31532665Snd150628 /* 31542665Snd150628 * Make sure we're renaming within the same dataset. 31552665Snd150628 */ 31562665Snd150628 delim = strchr(target, '@'); 31572665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 31582665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 31592665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31602665Snd150628 "snapshots must be part of same " 31612665Snd150628 "dataset")); 31622665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 31632665Snd150628 errbuf)); 31642665Snd150628 } 3165789Sahrens } 31662665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31672665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3168789Sahrens } else { 31692665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31702665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31712676Seschrock uint64_t unused; 31722676Seschrock 3173789Sahrens /* validate parents */ 31742676Seschrock if (check_parents(hdl, target, &unused) != 0) 3175789Sahrens return (-1); 3176789Sahrens 3177789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3178789Sahrens 3179789Sahrens /* make sure we're in the same pool */ 3180789Sahrens verify((delim = strchr(target, '/')) != NULL); 3181789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3182789Sahrens zhp->zfs_name[delim - target] != '/') { 31832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31842082Seschrock "datasets must be within same pool")); 31852082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3186789Sahrens } 31872440Snd150628 31882440Snd150628 /* new name cannot be a child of the current dataset name */ 31892440Snd150628 if (strncmp(parent, zhp->zfs_name, 31902440Snd150628 strlen(zhp->zfs_name)) == 0) { 31912440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31922440Snd150628 "New dataset name cannot be a descendent of " 31932440Snd150628 "current dataset name")); 31942440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31952440Snd150628 } 3196789Sahrens } 3197789Sahrens 31982082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 31992082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 32002082Seschrock 3201789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3202789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 32032082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32042082Seschrock "dataset is used in a non-global zone")); 32052082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3206789Sahrens } 3207789Sahrens 3208789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 32092082Seschrock return (-1); 3210789Sahrens 3211789Sahrens if (changelist_haszonedchild(cl)) { 32122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32132082Seschrock "child dataset with inherited mountpoint is used " 32142082Seschrock "in a non-global zone")); 32152676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3216789Sahrens goto error; 3217789Sahrens } 3218789Sahrens 3219789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3220789Sahrens goto error; 3221789Sahrens 32222676Seschrock if (ZFS_IS_VOLUME(zhp)) 3223789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3224789Sahrens else 3225789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3226789Sahrens 32272665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 32282676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 32292665Snd150628 32302082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 32312082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3232789Sahrens 3233789Sahrens /* 3234789Sahrens * On failure, we still want to remount any filesystems that 3235789Sahrens * were previously mounted, so we don't alter the system state. 3236789Sahrens */ 3237789Sahrens (void) changelist_postfix(cl); 3238789Sahrens } else { 3239789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3240789Sahrens 3241789Sahrens ret = changelist_postfix(cl); 3242789Sahrens } 3243789Sahrens 3244789Sahrens error: 3245789Sahrens changelist_free(cl); 3246789Sahrens return (ret); 3247789Sahrens } 3248789Sahrens 3249789Sahrens /* 3250789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3251789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3252789Sahrens */ 3253789Sahrens int 32542082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3255789Sahrens { 3256789Sahrens zfs_cmd_t zc = { 0 }; 32572082Seschrock di_devlink_handle_t dhdl; 3258789Sahrens 3259789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3260789Sahrens 3261789Sahrens /* 3262789Sahrens * Issue the appropriate ioctl. 3263789Sahrens */ 32642082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3265789Sahrens switch (errno) { 3266789Sahrens case EEXIST: 3267789Sahrens /* 3268789Sahrens * Silently ignore the case where the link already 3269789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3270789Sahrens * times without errors. 3271789Sahrens */ 3272789Sahrens return (0); 3273789Sahrens 3274789Sahrens default: 32752082Seschrock return (zfs_standard_error(hdl, errno, 32762082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32772082Seschrock "for '%s'"), dataset)); 3278789Sahrens } 3279789Sahrens } 3280789Sahrens 3281789Sahrens /* 3282789Sahrens * Call devfsadm and wait for the links to magically appear. 3283789Sahrens */ 32842082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 32852082Seschrock zfs_error_aux(hdl, strerror(errno)); 32862082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 32872082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32882082Seschrock "for '%s'"), dataset); 32892082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3290789Sahrens return (-1); 3291789Sahrens } else { 32922082Seschrock (void) di_devlink_fini(&dhdl); 3293789Sahrens } 3294789Sahrens 3295789Sahrens return (0); 3296789Sahrens } 3297789Sahrens 3298789Sahrens /* 3299789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3300789Sahrens */ 3301789Sahrens int 33022082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3303789Sahrens { 3304789Sahrens zfs_cmd_t zc = { 0 }; 3305789Sahrens 3306789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3307789Sahrens 33082082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3309789Sahrens switch (errno) { 3310789Sahrens case ENXIO: 3311789Sahrens /* 3312789Sahrens * Silently ignore the case where the link no longer 3313789Sahrens * exists, so that 'zfs volfini' can be run multiple 3314789Sahrens * times without errors. 3315789Sahrens */ 3316789Sahrens return (0); 3317789Sahrens 3318789Sahrens default: 33192082Seschrock return (zfs_standard_error(hdl, errno, 33202082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 33212082Seschrock "links for '%s'"), dataset)); 3322789Sahrens } 3323789Sahrens } 3324789Sahrens 3325789Sahrens return (0); 3326789Sahrens } 33272676Seschrock 33282676Seschrock nvlist_t * 33292676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 33302676Seschrock { 33312676Seschrock return (zhp->zfs_user_props); 33322676Seschrock } 33332676Seschrock 33342676Seschrock /* 33352676Seschrock * Given a comma-separated list of properties, contruct a property list 33362676Seschrock * containing both user-defined and native properties. This function will 33372676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 33382676Seschrock * per-dataset basis by zfs_expand_proplist(). 33392676Seschrock */ 33402676Seschrock int 33412676Seschrock zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 33422676Seschrock { 33432676Seschrock int i; 33442676Seschrock size_t len; 33452676Seschrock char *s, *p; 33462676Seschrock char c; 33472676Seschrock zfs_prop_t prop; 33482676Seschrock zfs_proplist_t *entry; 33492676Seschrock zfs_proplist_t **last; 33502676Seschrock 33512676Seschrock *listp = NULL; 33522676Seschrock last = listp; 33532676Seschrock 33542676Seschrock /* 33552676Seschrock * If 'all' is specified, return a NULL list. 33562676Seschrock */ 33572676Seschrock if (strcmp(fields, "all") == 0) 33582676Seschrock return (0); 33592676Seschrock 33602676Seschrock /* 33612676Seschrock * If no fields were specified, return an error. 33622676Seschrock */ 33632676Seschrock if (fields[0] == '\0') { 33642676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33652676Seschrock "no properties specified")); 33662676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 33672676Seschrock "bad property list"))); 33682676Seschrock } 33692676Seschrock 33702676Seschrock /* 33712676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 33722676Seschrock * aliases makes this more effort than it's worth. 33732676Seschrock */ 33742676Seschrock s = fields; 33752676Seschrock while (*s != '\0') { 33762676Seschrock if ((p = strchr(s, ',')) == NULL) { 33772676Seschrock len = strlen(s); 33782676Seschrock p = s + len; 33792676Seschrock } else { 33802676Seschrock len = p - s; 33812676Seschrock } 33822676Seschrock 33832676Seschrock /* 33842676Seschrock * Check for empty options. 33852676Seschrock */ 33862676Seschrock if (len == 0) { 33872676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33882676Seschrock "empty property name")); 33892676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 33902676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 33912676Seschrock } 33922676Seschrock 33932676Seschrock /* 33942676Seschrock * Check all regular property names. 33952676Seschrock */ 33962676Seschrock c = s[len]; 33972676Seschrock s[len] = '\0'; 33982676Seschrock for (i = 0; i < ZFS_NPROP_ALL; i++) { 33992676Seschrock if ((prop = zfs_name_to_prop(s)) != ZFS_PROP_INVAL) 34002676Seschrock break; 34012676Seschrock } 34022676Seschrock 34032676Seschrock /* 34042676Seschrock * If no column is specified, and this isn't a user property, 34052676Seschrock * return failure. 34062676Seschrock */ 34072676Seschrock if (i == ZFS_NPROP_ALL && !zfs_prop_user(s)) { 34082676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34092676Seschrock "invalid property '%s'"), s); 34102676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 34112676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 34122676Seschrock } 34132676Seschrock 34142676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 34152676Seschrock return (-1); 34162676Seschrock 34172676Seschrock entry->pl_prop = prop; 34182676Seschrock if (prop == ZFS_PROP_INVAL) { 34192676Seschrock if ((entry->pl_user_prop = 34202676Seschrock zfs_strdup(hdl, s)) == NULL) { 34212676Seschrock free(entry); 34222676Seschrock return (-1); 34232676Seschrock } 34242676Seschrock entry->pl_width = strlen(s); 34252676Seschrock } else { 34262676Seschrock entry->pl_width = zfs_prop_width(prop, 34272676Seschrock &entry->pl_fixed); 34282676Seschrock } 34292676Seschrock 34302676Seschrock *last = entry; 34312676Seschrock last = &entry->pl_next; 34322676Seschrock 34332676Seschrock s = p; 34342676Seschrock if (c == ',') 34352676Seschrock s++; 34362676Seschrock } 34372676Seschrock 34382676Seschrock return (0); 34392676Seschrock } 34402676Seschrock 34412676Seschrock void 34422676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 34432676Seschrock { 34442676Seschrock zfs_proplist_t *next; 34452676Seschrock 34462676Seschrock while (pl != NULL) { 34472676Seschrock next = pl->pl_next; 34482676Seschrock free(pl->pl_user_prop); 34492676Seschrock free(pl); 34502676Seschrock pl = next; 34512676Seschrock } 34522676Seschrock } 34532676Seschrock 34542676Seschrock /* 34552676Seschrock * This function is used by 'zfs list' to determine the exact set of columns to 34562676Seschrock * display, and their maximum widths. This does two main things: 34572676Seschrock * 34582676Seschrock * - If this is a list of all properties, then expand the list to include 34592676Seschrock * all native properties, and set a flag so that for each dataset we look 34602676Seschrock * for new unique user properties and add them to the list. 34612676Seschrock * 34622676Seschrock * - For non fixed-width properties, keep track of the maximum width seen 34632676Seschrock * so that we can size the column appropriately. 34642676Seschrock */ 34652676Seschrock int 34662676Seschrock zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 34672676Seschrock { 34682676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 34692676Seschrock zfs_prop_t prop; 34702676Seschrock zfs_proplist_t *entry; 34712676Seschrock zfs_proplist_t **last, **start; 34722676Seschrock nvlist_t *userprops, *propval; 34732676Seschrock nvpair_t *elem; 34742676Seschrock char *strval; 34752676Seschrock char buf[ZFS_MAXPROPLEN]; 34762676Seschrock 34772676Seschrock if (*plp == NULL) { 34782676Seschrock /* 34792676Seschrock * If this is the very first time we've been called for an 'all' 34802676Seschrock * specification, expand the list to include all native 34812676Seschrock * properties. 34822676Seschrock */ 34832676Seschrock last = plp; 34842676Seschrock for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) { 34852676Seschrock if ((entry = zfs_alloc(hdl, 34862676Seschrock sizeof (zfs_proplist_t))) == NULL) 34872676Seschrock return (-1); 34882676Seschrock 34892676Seschrock entry->pl_prop = prop; 34902676Seschrock entry->pl_width = zfs_prop_width(prop, 34912676Seschrock &entry->pl_fixed); 34922676Seschrock entry->pl_all = B_TRUE; 34932676Seschrock 34942676Seschrock *last = entry; 34952676Seschrock last = &entry->pl_next; 34962676Seschrock } 34972676Seschrock 34982676Seschrock /* 34992676Seschrock * Add 'name' to the beginning of the list, which is handled 35002676Seschrock * specially. 35012676Seschrock */ 35022676Seschrock if ((entry = zfs_alloc(hdl, 35032676Seschrock sizeof (zfs_proplist_t))) == NULL) 35042676Seschrock return (-1); 35052676Seschrock 35062676Seschrock entry->pl_prop = ZFS_PROP_NAME; 35072676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 35082676Seschrock &entry->pl_fixed); 35092676Seschrock entry->pl_all = B_TRUE; 35102676Seschrock entry->pl_next = *plp; 35112676Seschrock *plp = entry; 35122676Seschrock } 35132676Seschrock 35142676Seschrock userprops = zfs_get_user_props(zhp); 35152676Seschrock 35162676Seschrock entry = *plp; 35172676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 35182676Seschrock /* 35192676Seschrock * Go through and add any user properties as necessary. We 35202676Seschrock * start by incrementing our list pointer to the first 35212676Seschrock * non-native property. 35222676Seschrock */ 35232676Seschrock start = plp; 35242676Seschrock while (*start != NULL) { 35252676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 35262676Seschrock break; 35272676Seschrock start = &(*start)->pl_next; 35282676Seschrock } 35292676Seschrock 35302676Seschrock elem = NULL; 35312676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 35322676Seschrock /* 35332676Seschrock * See if we've already found this property in our list. 35342676Seschrock */ 35352676Seschrock for (last = start; *last != NULL; 35362676Seschrock last = &(*last)->pl_next) { 35372676Seschrock if (strcmp((*last)->pl_user_prop, 35382676Seschrock nvpair_name(elem)) == 0) 35392676Seschrock break; 35402676Seschrock } 35412676Seschrock 35422676Seschrock if (*last == NULL) { 35432676Seschrock if ((entry = zfs_alloc(hdl, 35442676Seschrock sizeof (zfs_proplist_t))) == NULL || 35452676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 35462676Seschrock nvpair_name(elem)))) == NULL) { 35472676Seschrock free(entry); 35482676Seschrock return (-1); 35492676Seschrock } 35502676Seschrock 35512676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 35522676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 35532676Seschrock entry->pl_all = B_TRUE; 35542676Seschrock *last = entry; 35552676Seschrock } 35562676Seschrock } 35572676Seschrock } 35582676Seschrock 35592676Seschrock /* 35602676Seschrock * Now go through and check the width of any non-fixed columns 35612676Seschrock */ 35622676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 35632676Seschrock if (entry->pl_fixed) 35642676Seschrock continue; 35652676Seschrock 35662676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 35672676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 35682676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 35692676Seschrock if (strlen(buf) > entry->pl_width) 35702676Seschrock entry->pl_width = strlen(buf); 35712676Seschrock } 35722676Seschrock } else if (nvlist_lookup_nvlist(userprops, 35732676Seschrock entry->pl_user_prop, &propval) == 0) { 35742676Seschrock verify(nvlist_lookup_string(propval, 35752676Seschrock ZFS_PROP_VALUE, &strval) == 0); 35762676Seschrock if (strlen(strval) > entry->pl_width) 35772676Seschrock entry->pl_width = strlen(strval); 35782676Seschrock } 35792676Seschrock } 35802676Seschrock 35812676Seschrock return (0); 35822676Seschrock } 3583