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 */ 213126Sahl 22789Sahrens /* 233363Sgw25295 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens #include <assert.h> 30789Sahrens #include <ctype.h> 31789Sahrens #include <errno.h> 32789Sahrens #include <libdevinfo.h> 33789Sahrens #include <libintl.h> 34789Sahrens #include <math.h> 35789Sahrens #include <stdio.h> 36789Sahrens #include <stdlib.h> 37789Sahrens #include <strings.h> 38789Sahrens #include <unistd.h> 39789Sahrens #include <zone.h> 402082Seschrock #include <fcntl.h> 41789Sahrens #include <sys/mntent.h> 42789Sahrens #include <sys/mnttab.h> 431294Slling #include <sys/mount.h> 44789Sahrens 45789Sahrens #include <sys/spa.h> 46789Sahrens #include <sys/zio.h> 472676Seschrock #include <sys/zap.h> 48789Sahrens #include <libzfs.h> 49789Sahrens 50789Sahrens #include "zfs_namecheck.h" 51789Sahrens #include "zfs_prop.h" 52789Sahrens #include "libzfs_impl.h" 53789Sahrens 54789Sahrens /* 55789Sahrens * Given a single type (not a mask of types), return the type in a human 56789Sahrens * readable form. 57789Sahrens */ 58789Sahrens const char * 59789Sahrens zfs_type_to_name(zfs_type_t type) 60789Sahrens { 61789Sahrens switch (type) { 62789Sahrens case ZFS_TYPE_FILESYSTEM: 63789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 64789Sahrens case ZFS_TYPE_SNAPSHOT: 65789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 66789Sahrens case ZFS_TYPE_VOLUME: 67789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 68789Sahrens } 69789Sahrens 70789Sahrens return (NULL); 71789Sahrens } 72789Sahrens 73789Sahrens /* 74789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 75789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 76789Sahrens * We guess what the type would have been based on the path and the mask of 77789Sahrens * acceptable types. 78789Sahrens */ 79789Sahrens static const char * 80789Sahrens path_to_str(const char *path, int types) 81789Sahrens { 82789Sahrens /* 83789Sahrens * When given a single type, always report the exact type. 84789Sahrens */ 85789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 86789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 87789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 88789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 89789Sahrens if (types == ZFS_TYPE_VOLUME) 90789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 91789Sahrens 92789Sahrens /* 93789Sahrens * The user is requesting more than one type of dataset. If this is the 94789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 95789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 96789Sahrens * snapshot attribute and try again. 97789Sahrens */ 98789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 99789Sahrens if (strchr(path, '@') != NULL) 100789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 101789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 102789Sahrens } 103789Sahrens 104789Sahrens 105789Sahrens /* 106789Sahrens * The user has requested either filesystems or volumes. 107789Sahrens * We have no way of knowing a priori what type this would be, so always 108789Sahrens * report it as "filesystem" or "volume", our two primitive types. 109789Sahrens */ 110789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 111789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 112789Sahrens 113789Sahrens assert(types & ZFS_TYPE_VOLUME); 114789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 115789Sahrens } 116789Sahrens 117789Sahrens /* 118789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 119789Sahrens * provide a more meaningful error message. We place a more useful message in 120789Sahrens * 'buf' detailing exactly why the name was not valid. 121789Sahrens */ 122789Sahrens static int 1232082Seschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 124789Sahrens { 125789Sahrens namecheck_err_t why; 126789Sahrens char what; 127789Sahrens 128789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 1292082Seschrock if (hdl != NULL) { 130789Sahrens switch (why) { 1311003Slling case NAME_ERR_TOOLONG: 1322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1332082Seschrock "name is too long")); 1341003Slling break; 1351003Slling 136789Sahrens case NAME_ERR_LEADING_SLASH: 1372082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1382082Seschrock "leading slash in name")); 139789Sahrens break; 140789Sahrens 141789Sahrens case NAME_ERR_EMPTY_COMPONENT: 1422082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1432082Seschrock "empty component in name")); 144789Sahrens break; 145789Sahrens 146789Sahrens case NAME_ERR_TRAILING_SLASH: 1472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1482082Seschrock "trailing slash in name")); 149789Sahrens break; 150789Sahrens 151789Sahrens case NAME_ERR_INVALCHAR: 1522082Seschrock zfs_error_aux(hdl, 153789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 1542082Seschrock "'%c' in name"), what); 155789Sahrens break; 156789Sahrens 157789Sahrens case NAME_ERR_MULTIPLE_AT: 1582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1592082Seschrock "multiple '@' delimiters in name")); 160789Sahrens break; 1612856Snd150628 1622856Snd150628 case NAME_ERR_NOLETTER: 1632856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1642856Snd150628 "pool doesn't begin with a letter")); 1652856Snd150628 break; 1662856Snd150628 1672856Snd150628 case NAME_ERR_RESERVED: 1682856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1692856Snd150628 "name is reserved")); 1702856Snd150628 break; 1712856Snd150628 1722856Snd150628 case NAME_ERR_DISKLIKE: 1732856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1742856Snd150628 "reserved disk name")); 1752856Snd150628 break; 176789Sahrens } 177789Sahrens } 178789Sahrens 179789Sahrens return (0); 180789Sahrens } 181789Sahrens 182789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 1832082Seschrock if (hdl != NULL) 1842082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1852082Seschrock "snapshot delimiter '@' in filesystem name")); 186789Sahrens return (0); 187789Sahrens } 188789Sahrens 1892199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1902199Sahrens if (hdl != NULL) 1912199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1923413Smmusante "missing '@' delimiter in snapshot name")); 1932199Sahrens return (0); 1942199Sahrens } 1952199Sahrens 1962082Seschrock return (-1); 197789Sahrens } 198789Sahrens 199789Sahrens int 200789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 201789Sahrens { 2022082Seschrock return (zfs_validate_name(NULL, name, type)); 203789Sahrens } 204789Sahrens 205789Sahrens /* 2062676Seschrock * This function takes the raw DSL properties, and filters out the user-defined 2072676Seschrock * properties into a separate nvlist. 2082676Seschrock */ 2092676Seschrock static int 2102676Seschrock process_user_props(zfs_handle_t *zhp) 2112676Seschrock { 2122676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2132676Seschrock nvpair_t *elem; 2142676Seschrock nvlist_t *propval; 2152676Seschrock 2162676Seschrock nvlist_free(zhp->zfs_user_props); 2172676Seschrock 2182676Seschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 2192676Seschrock return (no_memory(hdl)); 2202676Seschrock 2212676Seschrock elem = NULL; 2222676Seschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 2232676Seschrock if (!zfs_prop_user(nvpair_name(elem))) 2242676Seschrock continue; 2252676Seschrock 2262676Seschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 2272676Seschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 2282676Seschrock nvpair_name(elem), propval) != 0) 2292676Seschrock return (no_memory(hdl)); 2302676Seschrock } 2312676Seschrock 2322676Seschrock return (0); 2332676Seschrock } 2342676Seschrock 2352676Seschrock /* 236789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 237789Sahrens */ 238789Sahrens static int 239789Sahrens get_stats(zfs_handle_t *zhp) 240789Sahrens { 241789Sahrens zfs_cmd_t zc = { 0 }; 2422676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 243789Sahrens 244789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 245789Sahrens 2462676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 2472082Seschrock return (-1); 2481356Seschrock 2492082Seschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2501356Seschrock if (errno == ENOMEM) { 2512676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2522676Seschrock zcmd_free_nvlists(&zc); 2532082Seschrock return (-1); 2542676Seschrock } 2551356Seschrock } else { 2562676Seschrock zcmd_free_nvlists(&zc); 2571356Seschrock return (-1); 2581356Seschrock } 2591356Seschrock } 260789Sahrens 2612885Sahrens zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 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 if (process_user_props(zhp) != 0) 2782676Seschrock return (-1); 2792082Seschrock 280789Sahrens return (0); 281789Sahrens } 282789Sahrens 283789Sahrens /* 284789Sahrens * Refresh the properties currently stored in the handle. 285789Sahrens */ 286789Sahrens void 287789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 288789Sahrens { 289789Sahrens (void) get_stats(zhp); 290789Sahrens } 291789Sahrens 292789Sahrens /* 293789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 294789Sahrens * zfs_iter_* to create child handles on the fly. 295789Sahrens */ 296789Sahrens zfs_handle_t * 2972082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 298789Sahrens { 2992082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 3002082Seschrock 3012082Seschrock if (zhp == NULL) 3022082Seschrock return (NULL); 3032082Seschrock 3042082Seschrock zhp->zfs_hdl = hdl; 305789Sahrens 3061758Sahrens top: 307789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 308789Sahrens 309789Sahrens if (get_stats(zhp) != 0) { 310789Sahrens free(zhp); 311789Sahrens return (NULL); 312789Sahrens } 313789Sahrens 3141758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 3151758Sahrens zfs_cmd_t zc = { 0 }; 3161758Sahrens 3171758Sahrens /* 3181758Sahrens * If it is dds_inconsistent, then we've caught it in 3191758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 3201758Sahrens * it is inconsistent from the ZPL's point of view, so 3211758Sahrens * can't be mounted. However, it could also be that we 3221758Sahrens * have crashed in the middle of one of those 3231758Sahrens * operations, in which case we need to get rid of the 3241758Sahrens * inconsistent state. We do that by either rolling 3251758Sahrens * back to the previous snapshot (which will fail if 3261758Sahrens * there is none), or destroying the filesystem. Note 3271758Sahrens * that if we are still in the middle of an active 3281758Sahrens * 'receive' or 'destroy', then the rollback and destroy 3291758Sahrens * will fail with EBUSY and we will drive on as usual. 3301758Sahrens */ 3311758Sahrens 3321758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3331758Sahrens 3342885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 3352082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 3361758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3371758Sahrens } else { 3381758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3391758Sahrens } 3401758Sahrens 3411758Sahrens /* If we can successfully roll it back, reget the stats */ 3422082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 3431758Sahrens goto top; 3441758Sahrens /* 3451758Sahrens * If we can sucessfully destroy it, pretend that it 3461758Sahrens * never existed. 3471758Sahrens */ 3482082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3491758Sahrens free(zhp); 3501758Sahrens errno = ENOENT; 3511758Sahrens return (NULL); 3521758Sahrens } 3531758Sahrens } 3541758Sahrens 355789Sahrens /* 356789Sahrens * We've managed to open the dataset and gather statistics. Determine 357789Sahrens * the high-level type. 358789Sahrens */ 3592885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 3602885Sahrens zhp->zfs_head_type = ZFS_TYPE_VOLUME; 3612885Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 3622885Sahrens zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 3632885Sahrens else 3642885Sahrens abort(); 3652885Sahrens 366789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 367789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 368789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 369789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 370789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 371789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 372789Sahrens else 3732082Seschrock abort(); /* we should never see any other types */ 374789Sahrens 375789Sahrens return (zhp); 376789Sahrens } 377789Sahrens 378789Sahrens /* 379789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 380789Sahrens * argument is a mask of acceptable types. The function will print an 381789Sahrens * appropriate error message and return NULL if it can't be opened. 382789Sahrens */ 383789Sahrens zfs_handle_t * 3842082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 385789Sahrens { 386789Sahrens zfs_handle_t *zhp; 3872082Seschrock char errbuf[1024]; 3882082Seschrock 3892082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3902082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 391789Sahrens 392789Sahrens /* 3932082Seschrock * Validate the name before we even try to open it. 394789Sahrens */ 3952082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3962082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3972082Seschrock "invalid dataset name")); 3982082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 399789Sahrens return (NULL); 400789Sahrens } 401789Sahrens 402789Sahrens /* 403789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 404789Sahrens */ 405789Sahrens errno = 0; 4062082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 4073237Slling (void) zfs_standard_error(hdl, errno, errbuf); 408789Sahrens return (NULL); 409789Sahrens } 410789Sahrens 411789Sahrens if (!(types & zhp->zfs_type)) { 4122082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4132142Seschrock zfs_close(zhp); 414789Sahrens return (NULL); 415789Sahrens } 416789Sahrens 417789Sahrens return (zhp); 418789Sahrens } 419789Sahrens 420789Sahrens /* 421789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 422789Sahrens */ 423789Sahrens void 424789Sahrens zfs_close(zfs_handle_t *zhp) 425789Sahrens { 426789Sahrens if (zhp->zfs_mntopts) 427789Sahrens free(zhp->zfs_mntopts); 4282676Seschrock nvlist_free(zhp->zfs_props); 4292676Seschrock nvlist_free(zhp->zfs_user_props); 430789Sahrens free(zhp); 431789Sahrens } 432789Sahrens 433789Sahrens /* 434789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 435789Sahrens * resulting value must be shifted. 436789Sahrens */ 437789Sahrens static int 4382082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 439789Sahrens { 440789Sahrens const char *ends = "BKMGTPEZ"; 441789Sahrens int i; 442789Sahrens 443789Sahrens if (buf[0] == '\0') 444789Sahrens return (0); 445789Sahrens for (i = 0; i < strlen(ends); i++) { 446789Sahrens if (toupper(buf[0]) == ends[i]) 447789Sahrens break; 448789Sahrens } 449789Sahrens if (i == strlen(ends)) { 4502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4512082Seschrock "invalid numeric suffix '%s'"), buf); 452789Sahrens return (-1); 453789Sahrens } 454789Sahrens 455789Sahrens /* 456789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 457789Sahrens * allow 'BB' - that's just weird. 458789Sahrens */ 459789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4602082Seschrock toupper(buf[0]) != 'B')) 461789Sahrens return (10*i); 4622082Seschrock 4632082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4642082Seschrock "invalid numeric suffix '%s'"), buf); 465789Sahrens return (-1); 466789Sahrens } 467789Sahrens 468789Sahrens /* 469789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 470789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 471789Sahrens * message for the caller to use. 472789Sahrens */ 473789Sahrens static int 4742082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 475789Sahrens { 476789Sahrens char *end; 477789Sahrens int shift; 478789Sahrens 479789Sahrens *num = 0; 480789Sahrens 481789Sahrens /* Check to see if this looks like a number. */ 482789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4832082Seschrock if (hdl) 4842082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4852082Seschrock "bad numeric value '%s'"), value); 486789Sahrens return (-1); 487789Sahrens } 488789Sahrens 489789Sahrens /* Rely on stroll() to process the numeric portion. */ 490789Sahrens errno = 0; 491789Sahrens *num = strtoll(value, &end, 10); 492789Sahrens 493789Sahrens /* 494789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 495789Sahrens * in a 64-bit value. 496789Sahrens */ 497789Sahrens if (errno == ERANGE) { 4982082Seschrock if (hdl) 4992082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5002082Seschrock "numeric value is too large")); 501789Sahrens return (-1); 502789Sahrens } 503789Sahrens 504789Sahrens /* 505789Sahrens * If we have a decimal value, then do the computation with floating 506789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 507789Sahrens */ 508789Sahrens if (*end == '.') { 509789Sahrens double fval = strtod(value, &end); 510789Sahrens 5112082Seschrock if ((shift = str2shift(hdl, end)) == -1) 512789Sahrens return (-1); 513789Sahrens 514789Sahrens fval *= pow(2, shift); 515789Sahrens 516789Sahrens if (fval > UINT64_MAX) { 5172082Seschrock if (hdl) 5182082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5192082Seschrock "numeric value is too large")); 520789Sahrens return (-1); 521789Sahrens } 522789Sahrens 523789Sahrens *num = (uint64_t)fval; 524789Sahrens } else { 5252082Seschrock if ((shift = str2shift(hdl, end)) == -1) 526789Sahrens return (-1); 527789Sahrens 528789Sahrens /* Check for overflow */ 529789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5302082Seschrock if (hdl) 5312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5322082Seschrock "numeric value is too large")); 533789Sahrens return (-1); 534789Sahrens } 535789Sahrens 536789Sahrens *num <<= shift; 537789Sahrens } 538789Sahrens 539789Sahrens return (0); 540789Sahrens } 541789Sahrens 542789Sahrens int 5432676Seschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 5442676Seschrock { 5452676Seschrock return (nicestrtonum(hdl, str, val)); 5462676Seschrock } 5472676Seschrock 5482676Seschrock /* 5492676Seschrock * The prop_parse_*() functions are designed to allow flexibility in callers 5502676Seschrock * when setting properties. At the DSL layer, all properties are either 64-bit 5512676Seschrock * numbers or strings. We want the user to be able to ignore this fact and 5522676Seschrock * specify properties as native values (boolean, for example) or as strings (to 5532676Seschrock * simplify command line utilities). This also handles converting index types 5542676Seschrock * (compression, checksum, etc) from strings to their on-disk index. 5552676Seschrock */ 5562676Seschrock 5572676Seschrock static int 5582676Seschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 559789Sahrens { 5602676Seschrock uint64_t ret; 5612676Seschrock 5622676Seschrock switch (nvpair_type(elem)) { 5632676Seschrock case DATA_TYPE_STRING: 5642676Seschrock { 5652676Seschrock char *value; 5663363Sgw25295 verify(nvpair_value_string(elem, &value) == 0); 5672676Seschrock 5682676Seschrock if (strcmp(value, "on") == 0) { 5692676Seschrock ret = 1; 5702676Seschrock } else if (strcmp(value, "off") == 0) { 5712676Seschrock ret = 0; 5722676Seschrock } else { 5732676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5742676Seschrock "property '%s' must be 'on' or 'off'"), 5752676Seschrock nvpair_name(elem)); 5762676Seschrock return (-1); 5772676Seschrock } 5782676Seschrock break; 5792676Seschrock } 5802676Seschrock 5812676Seschrock case DATA_TYPE_UINT64: 5822676Seschrock { 5833363Sgw25295 verify(nvpair_value_uint64(elem, &ret) == 0); 5842676Seschrock if (ret > 1) { 5852676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5862676Seschrock "'%s' must be a boolean value"), 5872676Seschrock nvpair_name(elem)); 5882676Seschrock return (-1); 5892676Seschrock } 5902676Seschrock break; 5912676Seschrock } 5922676Seschrock 5932676Seschrock case DATA_TYPE_BOOLEAN_VALUE: 5942676Seschrock { 5952676Seschrock boolean_t value; 5963363Sgw25295 verify(nvpair_value_boolean_value(elem, &value) == 0); 5972676Seschrock ret = value; 5982676Seschrock break; 5992676Seschrock } 6002676Seschrock 6012676Seschrock default: 6022676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6032676Seschrock "'%s' must be a boolean value"), 6042676Seschrock nvpair_name(elem)); 6052676Seschrock return (-1); 6062676Seschrock } 6072676Seschrock 6082676Seschrock *val = ret; 6092676Seschrock return (0); 6102676Seschrock } 6112676Seschrock 6122676Seschrock static int 6132676Seschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6142676Seschrock uint64_t *val) 6152676Seschrock { 6162676Seschrock uint64_t ret; 6172676Seschrock boolean_t isnone = B_FALSE; 6182676Seschrock 6192676Seschrock switch (nvpair_type(elem)) { 6202676Seschrock case DATA_TYPE_STRING: 6212676Seschrock { 6222676Seschrock char *value; 6232676Seschrock (void) nvpair_value_string(elem, &value); 6242676Seschrock if (strcmp(value, "none") == 0) { 6252676Seschrock isnone = B_TRUE; 6262676Seschrock ret = 0; 6272676Seschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 6282676Seschrock return (-1); 6292676Seschrock } 6302676Seschrock break; 6312676Seschrock } 6322676Seschrock 6332676Seschrock case DATA_TYPE_UINT64: 6342676Seschrock (void) nvpair_value_uint64(elem, &ret); 6352676Seschrock break; 6362676Seschrock 6372676Seschrock default: 6382676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6392676Seschrock "'%s' must be a number"), 6402676Seschrock nvpair_name(elem)); 6412676Seschrock return (-1); 6422676Seschrock } 6432676Seschrock 6442676Seschrock /* 6452676Seschrock * Quota special: force 'none' and don't allow 0. 6462676Seschrock */ 6472676Seschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 6482676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6492676Seschrock "use 'none' to disable quota")); 6502676Seschrock return (-1); 6512676Seschrock } 6522676Seschrock 6532676Seschrock *val = ret; 6542676Seschrock return (0); 6552676Seschrock } 6562676Seschrock 6572676Seschrock static int 6582676Seschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6592676Seschrock uint64_t *val) 6602676Seschrock { 6612676Seschrock char *propname = nvpair_name(elem); 6622676Seschrock char *value; 6632676Seschrock 6642676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 6652676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6662676Seschrock "'%s' must be a string"), propname); 6672676Seschrock return (-1); 6682676Seschrock } 6692676Seschrock 6702676Seschrock (void) nvpair_value_string(elem, &value); 6712676Seschrock 6722676Seschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 6732676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6742676Seschrock "'%s' must be one of '%s'"), propname, 6752676Seschrock zfs_prop_values(prop)); 6762676Seschrock return (-1); 6772676Seschrock } 6782676Seschrock 6792676Seschrock return (0); 680789Sahrens } 681789Sahrens 682789Sahrens /* 6832676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 6842676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 6852676Seschrock * strings. 686789Sahrens */ 6872676Seschrock static nvlist_t * 6882676Seschrock zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 6892676Seschrock uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 690789Sahrens { 6912676Seschrock nvpair_t *elem; 6922676Seschrock const char *propname; 6932676Seschrock zfs_prop_t prop; 6942676Seschrock uint64_t intval; 6952676Seschrock char *strval; 6962676Seschrock nvlist_t *ret; 6972676Seschrock 6982676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 6992676Seschrock (void) no_memory(hdl); 7002676Seschrock return (NULL); 7012676Seschrock } 7022676Seschrock 7032676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 7042676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7053413Smmusante "snapshot properties cannot be modified")); 7062676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7072676Seschrock goto error; 708789Sahrens } 709789Sahrens 7102676Seschrock elem = NULL; 7112676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 7122676Seschrock propname = nvpair_name(elem); 7132676Seschrock 7142676Seschrock /* 7152676Seschrock * Make sure this property is valid and applies to this type. 7162676Seschrock */ 7172676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 7182676Seschrock if (!zfs_prop_user(propname)) { 7192676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7202676Seschrock "invalid property '%s'"), 7212676Seschrock propname); 7222676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7232676Seschrock goto error; 7242676Seschrock } else { 7252676Seschrock /* 7262676Seschrock * If this is a user property, make sure it's a 7272676Seschrock * string, and that it's less than 7282676Seschrock * ZAP_MAXNAMELEN. 7292676Seschrock */ 7302676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7312676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7322676Seschrock "'%s' must be a string"), 7332676Seschrock propname); 7342676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7352676Seschrock errbuf); 7362676Seschrock goto error; 7372676Seschrock } 7382676Seschrock 7392676Seschrock if (strlen(nvpair_name(elem)) >= 7402676Seschrock ZAP_MAXNAMELEN) { 7412676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7422676Seschrock "property name '%s' is too long"), 7432676Seschrock propname); 7442676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7452676Seschrock errbuf); 7462676Seschrock goto error; 7472676Seschrock } 7482676Seschrock } 7492676Seschrock 7502676Seschrock (void) nvpair_value_string(elem, &strval); 7512676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7522676Seschrock (void) no_memory(hdl); 7532676Seschrock goto error; 7542676Seschrock } 7552676Seschrock continue; 756789Sahrens } 7572676Seschrock 7582676Seschrock /* 7592676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7602676Seschrock */ 7612676Seschrock propname = zfs_prop_to_name(prop); 7622676Seschrock 7632676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7642676Seschrock zfs_error_aux(hdl, 7652676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7662676Seschrock "apply to datasets of this type"), propname); 7672676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7682676Seschrock goto error; 7692676Seschrock } 7702676Seschrock 7712676Seschrock if (zfs_prop_readonly(prop) && 7722676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 7732676Seschrock zfs_error_aux(hdl, 7742676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 7752676Seschrock propname); 7762676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 7772676Seschrock goto error; 7782676Seschrock } 7792676Seschrock 7802676Seschrock /* 7812676Seschrock * Convert any properties to the internal DSL value types. 7822676Seschrock */ 7832676Seschrock strval = NULL; 7842676Seschrock switch (zfs_prop_get_type(prop)) { 7852676Seschrock case prop_type_boolean: 7862676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 7872676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7882676Seschrock goto error; 7892676Seschrock } 790789Sahrens break; 7912676Seschrock 7922676Seschrock case prop_type_string: 7932676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7952676Seschrock "'%s' must be a string"), 7962676Seschrock propname); 7972676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7982676Seschrock goto error; 799789Sahrens } 8002676Seschrock (void) nvpair_value_string(elem, &strval); 8012676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 8022082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8032676Seschrock "'%s' is too long"), propname); 8042676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8052676Seschrock goto error; 8062676Seschrock } 8072676Seschrock break; 8082676Seschrock 8092676Seschrock case prop_type_number: 8102676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 8112676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8122676Seschrock goto error; 8132676Seschrock } 8142676Seschrock break; 8152676Seschrock 8162676Seschrock case prop_type_index: 8172676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 8182676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8192676Seschrock goto error; 820789Sahrens } 821789Sahrens break; 822789Sahrens 8232676Seschrock default: 8242676Seschrock abort(); 8252676Seschrock } 8262676Seschrock 8272676Seschrock /* 8282676Seschrock * Add the result to our return set of properties. 8292676Seschrock */ 8302676Seschrock if (strval) { 8312676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8322676Seschrock (void) no_memory(hdl); 8332676Seschrock goto error; 834789Sahrens } 8352676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8362676Seschrock (void) no_memory(hdl); 8372676Seschrock goto error; 8382676Seschrock } 8392676Seschrock 8402676Seschrock /* 8412676Seschrock * Perform some additional checks for specific properties. 8422676Seschrock */ 8432676Seschrock switch (prop) { 8442676Seschrock case ZFS_PROP_RECORDSIZE: 8452676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8462676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8472676Seschrock if (intval < SPA_MINBLOCKSIZE || 8482676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8502676Seschrock "'%s' must be power of 2 from %u " 8512676Seschrock "to %uk"), propname, 8522676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8532676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8542676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8552676Seschrock goto error; 856789Sahrens } 857789Sahrens break; 858789Sahrens 8593126Sahl case ZFS_PROP_SHAREISCSI: 8603126Sahl if (strcmp(strval, "off") != 0 && 8613126Sahl strcmp(strval, "on") != 0 && 8623126Sahl strcmp(strval, "type=disk") != 0) { 8633126Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8643126Sahl "'%s' must be 'on', 'off', or 'type=disk'"), 8653126Sahl propname); 8663126Sahl (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8673126Sahl goto error; 8683126Sahl } 8693126Sahl 8703126Sahl break; 8713126Sahl 8722676Seschrock case ZFS_PROP_MOUNTPOINT: 8732676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 8742676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 8752676Seschrock break; 8762676Seschrock 8772676Seschrock if (strval[0] != '/') { 8782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8792676Seschrock "'%s' must be an absolute path, " 8802676Seschrock "'none', or 'legacy'"), propname); 8812676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8822676Seschrock goto error; 883789Sahrens } 8843126Sahl /*FALLTHRU*/ 8853126Sahl 8863126Sahl case ZFS_PROP_SHARENFS: 8873126Sahl /* 8883126Sahl * For the mountpoint and sharenfs properties, check if 8893126Sahl * it can be set in a global/non-global zone based on 8903126Sahl * the zoned property value: 8913126Sahl * 8923126Sahl * global zone non-global zone 8933126Sahl * -------------------------------------------------- 8943126Sahl * zoned=on mountpoint (no) mountpoint (yes) 8953126Sahl * sharenfs (no) sharenfs (no) 8963126Sahl * 8973126Sahl * zoned=off mountpoint (yes) N/A 8983126Sahl * sharenfs (yes) 8993126Sahl */ 9002676Seschrock if (zoned) { 9012676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 9022676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9032676Seschrock "'%s' cannot be set on " 9042676Seschrock "dataset in a non-global zone"), 9052676Seschrock propname); 9062676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9072676Seschrock errbuf); 9082676Seschrock goto error; 9092676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 9102676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9112676Seschrock "'%s' cannot be set in " 9122676Seschrock "a non-global zone"), propname); 9132676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9142676Seschrock errbuf); 9152676Seschrock goto error; 9162676Seschrock } 9172676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 9182676Seschrock /* 9192676Seschrock * If zoned property is 'off', this must be in 9202676Seschrock * a globle zone. If not, something is wrong. 9212676Seschrock */ 9222676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9232676Seschrock "'%s' cannot be set while dataset " 9242676Seschrock "'zoned' property is set"), propname); 9252676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 9262676Seschrock goto error; 9272676Seschrock } 9283126Sahl 9293126Sahl break; 9302676Seschrock } 9312676Seschrock 9322676Seschrock /* 9332676Seschrock * For changes to existing volumes, we have some additional 9342676Seschrock * checks to enforce. 9352676Seschrock */ 9362676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9372676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9382676Seschrock ZFS_PROP_VOLSIZE); 9392676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9402676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9412676Seschrock char buf[64]; 9422676Seschrock 9432676Seschrock switch (prop) { 9442676Seschrock case ZFS_PROP_RESERVATION: 9452676Seschrock if (intval > volsize) { 9462676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9472676Seschrock "'%s' is greater than current " 9482676Seschrock "volume size"), propname); 9492676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9502676Seschrock errbuf); 9512676Seschrock goto error; 9522676Seschrock } 9532676Seschrock break; 9542676Seschrock 9552676Seschrock case ZFS_PROP_VOLSIZE: 9562676Seschrock if (intval % blocksize != 0) { 9572676Seschrock zfs_nicenum(blocksize, buf, 9582676Seschrock sizeof (buf)); 9592676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9602676Seschrock "'%s' must be a multiple of " 9612676Seschrock "volume block size (%s)"), 9622676Seschrock propname, buf); 9632676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9642676Seschrock errbuf); 9652676Seschrock goto error; 9662676Seschrock } 9672676Seschrock 9682676Seschrock if (intval == 0) { 9692676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9702676Seschrock "'%s' cannot be zero"), 9712676Seschrock propname); 9722676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9732676Seschrock errbuf); 9742676Seschrock goto error; 975789Sahrens } 9763126Sahl break; 977789Sahrens } 978789Sahrens } 979789Sahrens } 980789Sahrens 9812676Seschrock /* 9822676Seschrock * If this is an existing volume, and someone is setting the volsize, 9832676Seschrock * make sure that it matches the reservation, or add it if necessary. 9842676Seschrock */ 9852676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 9862676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 9872676Seschrock &intval) == 0) { 9882676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 9892676Seschrock ZFS_PROP_VOLSIZE); 9902676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 9912676Seschrock ZFS_PROP_RESERVATION); 9922676Seschrock uint64_t new_reservation; 9932676Seschrock 9942676Seschrock if (old_volsize == old_reservation && 9952676Seschrock nvlist_lookup_uint64(ret, 9962676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9972676Seschrock &new_reservation) != 0) { 9982676Seschrock if (nvlist_add_uint64(ret, 9992676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 10002676Seschrock intval) != 0) { 10012676Seschrock (void) no_memory(hdl); 10022676Seschrock goto error; 10032676Seschrock } 10042676Seschrock } 10052676Seschrock } 10062676Seschrock 10072676Seschrock return (ret); 10082676Seschrock 10092676Seschrock error: 10102676Seschrock nvlist_free(ret); 10112676Seschrock return (NULL); 1012789Sahrens } 1013789Sahrens 1014789Sahrens /* 1015789Sahrens * Given a property name and value, set the property for the given dataset. 1016789Sahrens */ 1017789Sahrens int 10182676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1019789Sahrens { 1020789Sahrens zfs_cmd_t zc = { 0 }; 10212676Seschrock int ret = -1; 10222676Seschrock prop_changelist_t *cl = NULL; 10232082Seschrock char errbuf[1024]; 10242082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 10252676Seschrock nvlist_t *nvl = NULL, *realprops; 10262676Seschrock zfs_prop_t prop; 10272082Seschrock 10282082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 10292676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 10302082Seschrock zhp->zfs_name); 10312082Seschrock 10322676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 10332676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 10342676Seschrock (void) no_memory(hdl); 10352676Seschrock goto error; 1036789Sahrens } 1037789Sahrens 10382676Seschrock if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl, 10392676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10402676Seschrock goto error; 10412676Seschrock nvlist_free(nvl); 10422676Seschrock nvl = realprops; 10432676Seschrock 10442676Seschrock prop = zfs_name_to_prop(propname); 10452676Seschrock 1046789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10472676Seschrock goto error; 1048789Sahrens 1049789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10512082Seschrock "child dataset with inherited mountpoint is used " 10522082Seschrock "in a non-global zone")); 10532082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1054789Sahrens goto error; 1055789Sahrens } 1056789Sahrens 1057789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1058789Sahrens goto error; 1059789Sahrens 1060789Sahrens /* 1061789Sahrens * Execute the corresponding ioctl() to set this property. 1062789Sahrens */ 1063789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1064789Sahrens 10652676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 10662676Seschrock goto error; 10672676Seschrock 10682676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1069789Sahrens 1070789Sahrens if (ret != 0) { 1071789Sahrens switch (errno) { 1072789Sahrens 1073789Sahrens case ENOSPC: 1074789Sahrens /* 1075789Sahrens * For quotas and reservations, ENOSPC indicates 1076789Sahrens * something different; setting a quota or reservation 1077789Sahrens * doesn't use any disk space. 1078789Sahrens */ 1079789Sahrens switch (prop) { 1080789Sahrens case ZFS_PROP_QUOTA: 10812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10822082Seschrock "size is less than current used or " 10832082Seschrock "reserved space")); 10842082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1085789Sahrens break; 1086789Sahrens 1087789Sahrens case ZFS_PROP_RESERVATION: 10882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10892082Seschrock "size is greater than available space")); 10902082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1091789Sahrens break; 1092789Sahrens 1093789Sahrens default: 10942082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1095789Sahrens break; 1096789Sahrens } 1097789Sahrens break; 1098789Sahrens 1099789Sahrens case EBUSY: 11002082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 11012082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 11022082Seschrock else 11032676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1104789Sahrens break; 1105789Sahrens 11061175Slling case EROFS: 11072082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 11081175Slling break; 11091175Slling 1110*3886Sahl case ENOTSUP: 1111*3886Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1112*3886Sahl "pool must be upgraded to allow gzip compression")); 1113*3886Sahl (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1114*3886Sahl break; 1115*3886Sahl 1116789Sahrens case EOVERFLOW: 1117789Sahrens /* 1118789Sahrens * This platform can't address a volume this big. 1119789Sahrens */ 1120789Sahrens #ifdef _ILP32 1121789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 11222082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1123789Sahrens break; 1124789Sahrens } 1125789Sahrens #endif 11262082Seschrock /* FALLTHROUGH */ 1127789Sahrens default: 11282082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1129789Sahrens } 1130789Sahrens } else { 1131789Sahrens /* 1132789Sahrens * Refresh the statistics so the new property value 1133789Sahrens * is reflected. 1134789Sahrens */ 11352676Seschrock if ((ret = changelist_postfix(cl)) == 0) 11362676Seschrock (void) get_stats(zhp); 1137789Sahrens } 1138789Sahrens 1139789Sahrens error: 11402676Seschrock nvlist_free(nvl); 11412676Seschrock zcmd_free_nvlists(&zc); 11422676Seschrock if (cl) 11432676Seschrock changelist_free(cl); 1144789Sahrens return (ret); 1145789Sahrens } 1146789Sahrens 1147789Sahrens /* 1148789Sahrens * Given a property, inherit the value from the parent dataset. 1149789Sahrens */ 1150789Sahrens int 11512676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1152789Sahrens { 1153789Sahrens zfs_cmd_t zc = { 0 }; 1154789Sahrens int ret; 1155789Sahrens prop_changelist_t *cl; 11562082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 11572082Seschrock char errbuf[1024]; 11582676Seschrock zfs_prop_t prop; 11592082Seschrock 11602082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 11612082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1162789Sahrens 11632676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 11642676Seschrock /* 11652676Seschrock * For user properties, the amount of work we have to do is very 11662676Seschrock * small, so just do it here. 11672676Seschrock */ 11682676Seschrock if (!zfs_prop_user(propname)) { 11692676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11702676Seschrock "invalid property")); 11712676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 11722676Seschrock } 11732676Seschrock 11742676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11752676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 11762676Seschrock 11772676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 11782676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 11792676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 11802676Seschrock 11812676Seschrock return (0); 11822676Seschrock } 11832676Seschrock 1184789Sahrens /* 1185789Sahrens * Verify that this property is inheritable. 1186789Sahrens */ 11872082Seschrock if (zfs_prop_readonly(prop)) 11882082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 11892082Seschrock 11902082Seschrock if (!zfs_prop_inheritable(prop)) 11912082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1192789Sahrens 1193789Sahrens /* 1194789Sahrens * Check to see if the value applies to this type 1195789Sahrens */ 11962082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 11972082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1198789Sahrens 11993443Srm160521 /* 12003443Srm160521 * Normalize the name, to get rid of shorthand abbrevations. 12013443Srm160521 */ 12023443Srm160521 propname = zfs_prop_to_name(prop); 1203789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 12042676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1205789Sahrens 1206789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1207789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 12082082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12092082Seschrock "dataset is used in a non-global zone")); 12102082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1211789Sahrens } 1212789Sahrens 1213789Sahrens /* 1214789Sahrens * Determine datasets which will be affected by this change, if any. 1215789Sahrens */ 1216789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1217789Sahrens return (-1); 1218789Sahrens 1219789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 12202082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12212082Seschrock "child dataset with inherited mountpoint is used " 12222082Seschrock "in a non-global zone")); 12232082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1224789Sahrens goto error; 1225789Sahrens } 1226789Sahrens 1227789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1228789Sahrens goto error; 1229789Sahrens 12302082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 12312082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 12322082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1233789Sahrens } else { 1234789Sahrens 12352169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1236789Sahrens goto error; 1237789Sahrens 1238789Sahrens /* 1239789Sahrens * Refresh the statistics so the new property is reflected. 1240789Sahrens */ 1241789Sahrens (void) get_stats(zhp); 1242789Sahrens } 1243789Sahrens 1244789Sahrens error: 1245789Sahrens changelist_free(cl); 1246789Sahrens return (ret); 1247789Sahrens } 1248789Sahrens 1249789Sahrens static void 1250789Sahrens nicebool(int value, char *buf, size_t buflen) 1251789Sahrens { 1252789Sahrens if (value) 1253789Sahrens (void) strlcpy(buf, "on", buflen); 1254789Sahrens else 1255789Sahrens (void) strlcpy(buf, "off", buflen); 1256789Sahrens } 1257789Sahrens 1258789Sahrens /* 12591356Seschrock * True DSL properties are stored in an nvlist. The following two functions 12601356Seschrock * extract them appropriately. 12611356Seschrock */ 12621356Seschrock static uint64_t 12631356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12641356Seschrock { 12651356Seschrock nvlist_t *nv; 12661356Seschrock uint64_t value; 12671356Seschrock 12682885Sahrens *source = NULL; 12691356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12701356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12711356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 12722885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12731356Seschrock } else { 12741356Seschrock value = zfs_prop_default_numeric(prop); 12751356Seschrock *source = ""; 12761356Seschrock } 12771356Seschrock 12781356Seschrock return (value); 12791356Seschrock } 12801356Seschrock 12811356Seschrock static char * 12821356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12831356Seschrock { 12841356Seschrock nvlist_t *nv; 12851356Seschrock char *value; 12861356Seschrock 12872885Sahrens *source = NULL; 12881356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12891356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12901356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 12912885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12921356Seschrock } else { 12931356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 12941356Seschrock value = ""; 12951356Seschrock *source = ""; 12961356Seschrock } 12971356Seschrock 12981356Seschrock return (value); 12991356Seschrock } 13001356Seschrock 13011356Seschrock /* 1302789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1303789Sahrens * zfs_prop_get_int() are built using this interface. 1304789Sahrens * 1305789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1306789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1307789Sahrens * If they differ from the on-disk values, report the current values and mark 1308789Sahrens * the source "temporary". 1309789Sahrens */ 13102082Seschrock static int 1311789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 13122082Seschrock char **source, uint64_t *val) 1313789Sahrens { 1314789Sahrens struct mnttab mnt; 13153265Sahrens char *mntopt_on = NULL; 13163265Sahrens char *mntopt_off = NULL; 1317789Sahrens 1318789Sahrens *source = NULL; 1319789Sahrens 13203265Sahrens switch (prop) { 13213265Sahrens case ZFS_PROP_ATIME: 13223265Sahrens mntopt_on = MNTOPT_ATIME; 13233265Sahrens mntopt_off = MNTOPT_NOATIME; 13243265Sahrens break; 13253265Sahrens 13263265Sahrens case ZFS_PROP_DEVICES: 13273265Sahrens mntopt_on = MNTOPT_DEVICES; 13283265Sahrens mntopt_off = MNTOPT_NODEVICES; 13293265Sahrens break; 13303265Sahrens 13313265Sahrens case ZFS_PROP_EXEC: 13323265Sahrens mntopt_on = MNTOPT_EXEC; 13333265Sahrens mntopt_off = MNTOPT_NOEXEC; 13343265Sahrens break; 13353265Sahrens 13363265Sahrens case ZFS_PROP_READONLY: 13373265Sahrens mntopt_on = MNTOPT_RO; 13383265Sahrens mntopt_off = MNTOPT_RW; 13393265Sahrens break; 13403265Sahrens 13413265Sahrens case ZFS_PROP_SETUID: 13423265Sahrens mntopt_on = MNTOPT_SETUID; 13433265Sahrens mntopt_off = MNTOPT_NOSETUID; 13443265Sahrens break; 13453265Sahrens 13463265Sahrens case ZFS_PROP_XATTR: 13473265Sahrens mntopt_on = MNTOPT_XATTR; 13483265Sahrens mntopt_off = MNTOPT_NOXATTR; 13493265Sahrens break; 13503265Sahrens } 13513265Sahrens 13522474Seschrock /* 13532474Seschrock * Because looking up the mount options is potentially expensive 13542474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 13552474Seschrock * we're looking up a property which requires its presence. 13562474Seschrock */ 13572474Seschrock if (!zhp->zfs_mntcheck && 13583265Sahrens (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 13593265Sahrens struct mnttab entry, search = { 0 }; 13603265Sahrens FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 13612474Seschrock 13622474Seschrock search.mnt_special = (char *)zhp->zfs_name; 13632474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 13643265Sahrens rewind(mnttab); 13653265Sahrens 13663265Sahrens if (getmntany(mnttab, &entry, &search) == 0) { 13673265Sahrens zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 13683265Sahrens entry.mnt_mntopts); 13693265Sahrens if (zhp->zfs_mntopts == NULL) 13703265Sahrens return (-1); 13713265Sahrens } 13722474Seschrock 13732474Seschrock zhp->zfs_mntcheck = B_TRUE; 13742474Seschrock } 13752474Seschrock 1376789Sahrens if (zhp->zfs_mntopts == NULL) 1377789Sahrens mnt.mnt_mntopts = ""; 1378789Sahrens else 1379789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1380789Sahrens 1381789Sahrens switch (prop) { 1382789Sahrens case ZFS_PROP_ATIME: 13833265Sahrens case ZFS_PROP_DEVICES: 13843265Sahrens case ZFS_PROP_EXEC: 13853265Sahrens case ZFS_PROP_READONLY: 13863265Sahrens case ZFS_PROP_SETUID: 13873265Sahrens case ZFS_PROP_XATTR: 13882082Seschrock *val = getprop_uint64(zhp, prop, source); 13892082Seschrock 13903265Sahrens if (hasmntopt(&mnt, mntopt_on) && !*val) { 13912082Seschrock *val = B_TRUE; 1392789Sahrens if (src) 1393789Sahrens *src = ZFS_SRC_TEMPORARY; 13943265Sahrens } else if (hasmntopt(&mnt, mntopt_off) && *val) { 13952082Seschrock *val = B_FALSE; 1396789Sahrens if (src) 1397789Sahrens *src = ZFS_SRC_TEMPORARY; 1398789Sahrens } 13992082Seschrock break; 1400789Sahrens 1401789Sahrens case ZFS_PROP_RECORDSIZE: 1402789Sahrens case ZFS_PROP_COMPRESSION: 14031356Seschrock case ZFS_PROP_ZONED: 14042885Sahrens case ZFS_PROP_CREATION: 14052885Sahrens case ZFS_PROP_COMPRESSRATIO: 14062885Sahrens case ZFS_PROP_REFERENCED: 14072885Sahrens case ZFS_PROP_USED: 14082885Sahrens case ZFS_PROP_CREATETXG: 14092885Sahrens case ZFS_PROP_AVAILABLE: 14102885Sahrens case ZFS_PROP_VOLSIZE: 14112885Sahrens case ZFS_PROP_VOLBLOCKSIZE: 14123417Srm160521 *val = getprop_uint64(zhp, prop, source); 14133417Srm160521 break; 14143417Srm160521 14153265Sahrens case ZFS_PROP_CANMOUNT: 14162082Seschrock *val = getprop_uint64(zhp, prop, source); 14173417Srm160521 if (*val == 0) 14183417Srm160521 *source = zhp->zfs_name; 14193417Srm160521 else 14203417Srm160521 *source = ""; /* default */ 14212082Seschrock break; 1422789Sahrens 1423789Sahrens case ZFS_PROP_QUOTA: 1424789Sahrens case ZFS_PROP_RESERVATION: 14252885Sahrens *val = getprop_uint64(zhp, prop, source); 14262885Sahrens if (*val == 0) 1427789Sahrens *source = ""; /* default */ 1428789Sahrens else 1429789Sahrens *source = zhp->zfs_name; 14302082Seschrock break; 1431789Sahrens 1432789Sahrens case ZFS_PROP_MOUNTED: 14332082Seschrock *val = (zhp->zfs_mntopts != NULL); 14342082Seschrock break; 1435789Sahrens 14363377Seschrock case ZFS_PROP_NUMCLONES: 14373377Seschrock *val = zhp->zfs_dmustats.dds_num_clones; 14383377Seschrock break; 14393377Seschrock 1440789Sahrens default: 14412082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14422082Seschrock "cannot get non-numeric property")); 14432082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14442082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1445789Sahrens } 1446789Sahrens 1447789Sahrens return (0); 1448789Sahrens } 1449789Sahrens 1450789Sahrens /* 1451789Sahrens * Calculate the source type, given the raw source string. 1452789Sahrens */ 1453789Sahrens static void 1454789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1455789Sahrens char *statbuf, size_t statlen) 1456789Sahrens { 1457789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1458789Sahrens return; 1459789Sahrens 1460789Sahrens if (source == NULL) { 1461789Sahrens *srctype = ZFS_SRC_NONE; 1462789Sahrens } else if (source[0] == '\0') { 1463789Sahrens *srctype = ZFS_SRC_DEFAULT; 1464789Sahrens } else { 1465789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1466789Sahrens *srctype = ZFS_SRC_LOCAL; 1467789Sahrens } else { 1468789Sahrens (void) strlcpy(statbuf, source, statlen); 1469789Sahrens *srctype = ZFS_SRC_INHERITED; 1470789Sahrens } 1471789Sahrens } 1472789Sahrens 1473789Sahrens } 1474789Sahrens 1475789Sahrens /* 1476789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1477789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1478789Sahrens * human-readable form. 1479789Sahrens * 1480789Sahrens * Returns 0 on success, or -1 on error. 1481789Sahrens */ 1482789Sahrens int 1483789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 14842082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1485789Sahrens { 1486789Sahrens char *source = NULL; 1487789Sahrens uint64_t val; 1488789Sahrens char *str; 1489789Sahrens const char *root; 14902676Seschrock const char *strval; 1491789Sahrens 1492789Sahrens /* 1493789Sahrens * Check to see if this property applies to our object 1494789Sahrens */ 1495789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1496789Sahrens return (-1); 1497789Sahrens 1498789Sahrens if (src) 1499789Sahrens *src = ZFS_SRC_NONE; 1500789Sahrens 1501789Sahrens switch (prop) { 1502789Sahrens case ZFS_PROP_ATIME: 1503789Sahrens case ZFS_PROP_READONLY: 1504789Sahrens case ZFS_PROP_SETUID: 1505789Sahrens case ZFS_PROP_ZONED: 1506789Sahrens case ZFS_PROP_DEVICES: 1507789Sahrens case ZFS_PROP_EXEC: 15082676Seschrock case ZFS_PROP_CANMOUNT: 15093234Sck153898 case ZFS_PROP_XATTR: 1510789Sahrens /* 1511789Sahrens * Basic boolean values are built on top of 1512789Sahrens * get_numeric_property(). 1513789Sahrens */ 15142082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15152082Seschrock return (-1); 15162082Seschrock nicebool(val, propbuf, proplen); 1517789Sahrens 1518789Sahrens break; 1519789Sahrens 1520789Sahrens case ZFS_PROP_AVAILABLE: 1521789Sahrens case ZFS_PROP_RECORDSIZE: 1522789Sahrens case ZFS_PROP_CREATETXG: 1523789Sahrens case ZFS_PROP_REFERENCED: 1524789Sahrens case ZFS_PROP_USED: 1525789Sahrens case ZFS_PROP_VOLSIZE: 1526789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 15273377Seschrock case ZFS_PROP_NUMCLONES: 1528789Sahrens /* 1529789Sahrens * Basic numeric values are built on top of 1530789Sahrens * get_numeric_property(). 1531789Sahrens */ 15322082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15332082Seschrock return (-1); 1534789Sahrens if (literal) 15352856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 15362856Snd150628 (u_longlong_t)val); 1537789Sahrens else 1538789Sahrens zfs_nicenum(val, propbuf, proplen); 1539789Sahrens break; 1540789Sahrens 1541789Sahrens case ZFS_PROP_COMPRESSION: 1542789Sahrens case ZFS_PROP_CHECKSUM: 1543789Sahrens case ZFS_PROP_SNAPDIR: 1544789Sahrens case ZFS_PROP_ACLMODE: 1545789Sahrens case ZFS_PROP_ACLINHERIT: 15463835Sahrens case ZFS_PROP_COPIES: 15471356Seschrock val = getprop_uint64(zhp, prop, &source); 15482676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15492676Seschrock (void) strlcpy(propbuf, strval, proplen); 1550789Sahrens break; 1551789Sahrens 1552789Sahrens case ZFS_PROP_CREATION: 1553789Sahrens /* 1554789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1555789Sahrens * this into a string unless 'literal' is specified. 1556789Sahrens */ 1557789Sahrens { 15582885Sahrens val = getprop_uint64(zhp, prop, &source); 15592885Sahrens time_t time = (time_t)val; 1560789Sahrens struct tm t; 1561789Sahrens 1562789Sahrens if (literal || 1563789Sahrens localtime_r(&time, &t) == NULL || 1564789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1565789Sahrens &t) == 0) 15662885Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1567789Sahrens } 1568789Sahrens break; 1569789Sahrens 1570789Sahrens case ZFS_PROP_MOUNTPOINT: 1571789Sahrens /* 1572789Sahrens * Getting the precise mountpoint can be tricky. 1573789Sahrens * 1574789Sahrens * - for 'none' or 'legacy', return those values. 1575789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1576789Sahrens * - for inherited mountpoints, we want to take everything 1577789Sahrens * after our ancestor and append it to the inherited value. 1578789Sahrens * 1579789Sahrens * If the pool has an alternate root, we want to prepend that 1580789Sahrens * root to any values we return. 1581789Sahrens */ 15821544Seschrock root = zhp->zfs_root; 15831356Seschrock str = getprop_string(zhp, prop, &source); 15841356Seschrock 15851356Seschrock if (str[0] == '\0') { 1586789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1587789Sahrens root, zhp->zfs_name); 15881356Seschrock } else if (str[0] == '/') { 15891356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1590789Sahrens 1591789Sahrens if (relpath[0] == '/') 1592789Sahrens relpath++; 15931356Seschrock if (str[1] == '\0') 15941356Seschrock str++; 1595789Sahrens 1596789Sahrens if (relpath[0] == '\0') 1597789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 15981356Seschrock root, str); 1599789Sahrens else 1600789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16011356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1602789Sahrens relpath); 1603789Sahrens } else { 1604789Sahrens /* 'legacy' or 'none' */ 16051356Seschrock (void) strlcpy(propbuf, str, proplen); 1606789Sahrens } 1607789Sahrens 1608789Sahrens break; 1609789Sahrens 1610789Sahrens case ZFS_PROP_SHARENFS: 16113126Sahl case ZFS_PROP_SHAREISCSI: 16123126Sahl case ZFS_PROP_ISCSIOPTIONS: 16131356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16141356Seschrock proplen); 1615789Sahrens break; 1616789Sahrens 1617789Sahrens case ZFS_PROP_ORIGIN: 16182885Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1619789Sahrens proplen); 1620789Sahrens /* 1621789Sahrens * If there is no parent at all, return failure to indicate that 1622789Sahrens * it doesn't apply to this dataset. 1623789Sahrens */ 1624789Sahrens if (propbuf[0] == '\0') 1625789Sahrens return (-1); 1626789Sahrens break; 1627789Sahrens 1628789Sahrens case ZFS_PROP_QUOTA: 1629789Sahrens case ZFS_PROP_RESERVATION: 16302082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16312082Seschrock return (-1); 1632789Sahrens 1633789Sahrens /* 1634789Sahrens * If quota or reservation is 0, we translate this into 'none' 1635789Sahrens * (unless literal is set), and indicate that it's the default 1636789Sahrens * value. Otherwise, we print the number nicely and indicate 1637789Sahrens * that its set locally. 1638789Sahrens */ 1639789Sahrens if (val == 0) { 1640789Sahrens if (literal) 1641789Sahrens (void) strlcpy(propbuf, "0", proplen); 1642789Sahrens else 1643789Sahrens (void) strlcpy(propbuf, "none", proplen); 1644789Sahrens } else { 1645789Sahrens if (literal) 16462856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 16472856Snd150628 (u_longlong_t)val); 1648789Sahrens else 1649789Sahrens zfs_nicenum(val, propbuf, proplen); 1650789Sahrens } 1651789Sahrens break; 1652789Sahrens 1653789Sahrens case ZFS_PROP_COMPRESSRATIO: 16542082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16552082Seschrock return (-1); 16562856Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 16572856Snd150628 val / 100, (longlong_t)val % 100); 1658789Sahrens break; 1659789Sahrens 1660789Sahrens case ZFS_PROP_TYPE: 1661789Sahrens switch (zhp->zfs_type) { 1662789Sahrens case ZFS_TYPE_FILESYSTEM: 1663789Sahrens str = "filesystem"; 1664789Sahrens break; 1665789Sahrens case ZFS_TYPE_VOLUME: 1666789Sahrens str = "volume"; 1667789Sahrens break; 1668789Sahrens case ZFS_TYPE_SNAPSHOT: 1669789Sahrens str = "snapshot"; 1670789Sahrens break; 1671789Sahrens default: 16722082Seschrock abort(); 1673789Sahrens } 1674789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1675789Sahrens break; 1676789Sahrens 1677789Sahrens case ZFS_PROP_MOUNTED: 1678789Sahrens /* 1679789Sahrens * The 'mounted' property is a pseudo-property that described 1680789Sahrens * whether the filesystem is currently mounted. Even though 1681789Sahrens * it's a boolean value, the typical values of "on" and "off" 1682789Sahrens * don't make sense, so we translate to "yes" and "no". 1683789Sahrens */ 16842082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 16852082Seschrock src, &source, &val) != 0) 16862082Seschrock return (-1); 16872082Seschrock if (val) 1688789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1689789Sahrens else 1690789Sahrens (void) strlcpy(propbuf, "no", proplen); 1691789Sahrens break; 1692789Sahrens 1693789Sahrens case ZFS_PROP_NAME: 1694789Sahrens /* 1695789Sahrens * The 'name' property is a pseudo-property derived from the 1696789Sahrens * dataset name. It is presented as a real property to simplify 1697789Sahrens * consumers. 1698789Sahrens */ 1699789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1700789Sahrens break; 1701789Sahrens 1702789Sahrens default: 17032082Seschrock abort(); 1704789Sahrens } 1705789Sahrens 1706789Sahrens get_source(zhp, src, source, statbuf, statlen); 1707789Sahrens 1708789Sahrens return (0); 1709789Sahrens } 1710789Sahrens 1711789Sahrens /* 1712789Sahrens * Utility function to get the given numeric property. Does no validation that 1713789Sahrens * the given property is the appropriate type; should only be used with 1714789Sahrens * hard-coded property types. 1715789Sahrens */ 1716789Sahrens uint64_t 1717789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1718789Sahrens { 1719789Sahrens char *source; 1720789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17212082Seschrock uint64_t val; 17222082Seschrock 17232082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17242082Seschrock 17252082Seschrock return (val); 1726789Sahrens } 1727789Sahrens 1728789Sahrens /* 1729789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1730789Sahrens */ 1731789Sahrens int 1732789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1733789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1734789Sahrens { 1735789Sahrens char *source; 1736789Sahrens 1737789Sahrens /* 1738789Sahrens * Check to see if this property applies to our object 1739789Sahrens */ 1740789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17413237Slling return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 17422082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17432082Seschrock zfs_prop_to_name(prop))); 1744789Sahrens 1745789Sahrens if (src) 1746789Sahrens *src = ZFS_SRC_NONE; 1747789Sahrens 17482082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17492082Seschrock return (-1); 1750789Sahrens 1751789Sahrens get_source(zhp, src, source, statbuf, statlen); 1752789Sahrens 1753789Sahrens return (0); 1754789Sahrens } 1755789Sahrens 1756789Sahrens /* 1757789Sahrens * Returns the name of the given zfs handle. 1758789Sahrens */ 1759789Sahrens const char * 1760789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1761789Sahrens { 1762789Sahrens return (zhp->zfs_name); 1763789Sahrens } 1764789Sahrens 1765789Sahrens /* 1766789Sahrens * Returns the type of the given zfs handle. 1767789Sahrens */ 1768789Sahrens zfs_type_t 1769789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1770789Sahrens { 1771789Sahrens return (zhp->zfs_type); 1772789Sahrens } 1773789Sahrens 1774789Sahrens /* 17751356Seschrock * Iterate over all child filesystems 1776789Sahrens */ 1777789Sahrens int 17781356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1779789Sahrens { 1780789Sahrens zfs_cmd_t zc = { 0 }; 1781789Sahrens zfs_handle_t *nzhp; 1782789Sahrens int ret; 1783789Sahrens 1784789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 17852082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1786789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1787789Sahrens /* 1788789Sahrens * Ignore private dataset names. 1789789Sahrens */ 1790789Sahrens if (dataset_name_hidden(zc.zc_name)) 1791789Sahrens continue; 1792789Sahrens 1793789Sahrens /* 1794789Sahrens * Silently ignore errors, as the only plausible explanation is 1795789Sahrens * that the pool has since been removed. 1796789Sahrens */ 17972082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 17982082Seschrock zc.zc_name)) == NULL) 1799789Sahrens continue; 1800789Sahrens 1801789Sahrens if ((ret = func(nzhp, data)) != 0) 1802789Sahrens return (ret); 1803789Sahrens } 1804789Sahrens 1805789Sahrens /* 1806789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1807789Sahrens * returned, then the underlying dataset has been removed since we 1808789Sahrens * obtained the handle. 1809789Sahrens */ 1810789Sahrens if (errno != ESRCH && errno != ENOENT) 18112082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18122082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1813789Sahrens 18141356Seschrock return (0); 18151356Seschrock } 18161356Seschrock 18171356Seschrock /* 18181356Seschrock * Iterate over all snapshots 18191356Seschrock */ 18201356Seschrock int 18211356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18221356Seschrock { 18231356Seschrock zfs_cmd_t zc = { 0 }; 18241356Seschrock zfs_handle_t *nzhp; 18251356Seschrock int ret; 1826789Sahrens 1827789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18282082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18292082Seschrock &zc) == 0; 1830789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1831789Sahrens 18322082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18332082Seschrock zc.zc_name)) == NULL) 1834789Sahrens continue; 1835789Sahrens 1836789Sahrens if ((ret = func(nzhp, data)) != 0) 1837789Sahrens return (ret); 1838789Sahrens } 1839789Sahrens 1840789Sahrens /* 1841789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1842789Sahrens * returned, then the underlying dataset has been removed since we 1843789Sahrens * obtained the handle. Silently ignore this case, and return success. 1844789Sahrens */ 1845789Sahrens if (errno != ESRCH && errno != ENOENT) 18462082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18472082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1848789Sahrens 1849789Sahrens return (0); 1850789Sahrens } 1851789Sahrens 1852789Sahrens /* 18531356Seschrock * Iterate over all children, snapshots and filesystems 18541356Seschrock */ 18551356Seschrock int 18561356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18571356Seschrock { 18581356Seschrock int ret; 18591356Seschrock 18601356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 18611356Seschrock return (ret); 18621356Seschrock 18631356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 18641356Seschrock } 18651356Seschrock 18661356Seschrock /* 1867789Sahrens * Given a complete name, return just the portion that refers to the parent. 1868789Sahrens * Can return NULL if this is a pool. 1869789Sahrens */ 1870789Sahrens static int 1871789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1872789Sahrens { 1873789Sahrens char *loc; 1874789Sahrens 1875789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1876789Sahrens return (-1); 1877789Sahrens 1878789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1879789Sahrens buf[loc - path] = '\0'; 1880789Sahrens 1881789Sahrens return (0); 1882789Sahrens } 1883789Sahrens 1884789Sahrens /* 18852676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 18862676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 18872676Seschrock * when creating new datasets. 1888789Sahrens */ 1889789Sahrens static int 18902676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1891789Sahrens { 1892789Sahrens zfs_cmd_t zc = { 0 }; 1893789Sahrens char parent[ZFS_MAXNAMELEN]; 1894789Sahrens char *slash; 18951356Seschrock zfs_handle_t *zhp; 18962082Seschrock char errbuf[1024]; 18972082Seschrock 18982082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 18992082Seschrock path); 1900789Sahrens 1901789Sahrens /* get parent, and check to see if this is just a pool */ 1902789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 19032082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19042082Seschrock "missing dataset name")); 19052082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1906789Sahrens } 1907789Sahrens 1908789Sahrens /* check to see if the pool exists */ 1909789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1910789Sahrens slash = parent + strlen(parent); 1911789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1912789Sahrens zc.zc_name[slash - parent] = '\0'; 19132082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1914789Sahrens errno == ENOENT) { 19152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19162082Seschrock "no such pool '%s'"), zc.zc_name); 19172082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1918789Sahrens } 1919789Sahrens 1920789Sahrens /* check to see if the parent dataset exists */ 19212082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1922789Sahrens switch (errno) { 1923789Sahrens case ENOENT: 19242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19252082Seschrock "parent does not exist")); 19262082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1927789Sahrens 1928789Sahrens default: 19292082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1930789Sahrens } 1931789Sahrens } 1932789Sahrens 19332676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1934789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19352676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19362082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19371356Seschrock zfs_close(zhp); 1938789Sahrens return (-1); 1939789Sahrens } 1940789Sahrens 1941789Sahrens /* make sure parent is a filesystem */ 19421356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19442082Seschrock "parent is not a filesystem")); 19452082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19461356Seschrock zfs_close(zhp); 1947789Sahrens return (-1); 1948789Sahrens } 1949789Sahrens 19501356Seschrock zfs_close(zhp); 1951789Sahrens return (0); 1952789Sahrens } 1953789Sahrens 1954789Sahrens /* 19552676Seschrock * Create a new filesystem or volume. 1956789Sahrens */ 1957789Sahrens int 19582082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 19592676Seschrock nvlist_t *props) 1960789Sahrens { 1961789Sahrens zfs_cmd_t zc = { 0 }; 1962789Sahrens int ret; 1963789Sahrens uint64_t size = 0; 1964789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 19652082Seschrock char errbuf[1024]; 19662676Seschrock uint64_t zoned; 19672082Seschrock 19682082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 19692082Seschrock "cannot create '%s'"), path); 1970789Sahrens 1971789Sahrens /* validate the path, taking care to note the extended error message */ 19722082Seschrock if (!zfs_validate_name(hdl, path, type)) 19732082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1974789Sahrens 1975789Sahrens /* validate parents exist */ 19762676Seschrock if (check_parents(hdl, path, &zoned) != 0) 1977789Sahrens return (-1); 1978789Sahrens 1979789Sahrens /* 1980789Sahrens * The failure modes when creating a dataset of a different type over 1981789Sahrens * one that already exists is a little strange. In particular, if you 1982789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1983789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1984789Sahrens * first try to see if the dataset exists. 1985789Sahrens */ 1986789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 19872082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 19882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19892082Seschrock "dataset already exists")); 19902082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1991789Sahrens } 1992789Sahrens 1993789Sahrens if (type == ZFS_TYPE_VOLUME) 1994789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1995789Sahrens else 1996789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1997789Sahrens 19982676Seschrock if (props && (props = zfs_validate_properties(hdl, type, props, zoned, 19992676Seschrock NULL, errbuf)) == 0) 20002676Seschrock return (-1); 20012676Seschrock 2002789Sahrens if (type == ZFS_TYPE_VOLUME) { 20031133Seschrock /* 20041133Seschrock * If we are creating a volume, the size and block size must 20051133Seschrock * satisfy a few restraints. First, the blocksize must be a 20061133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20071133Seschrock * volsize must be a multiple of the block size, and cannot be 20081133Seschrock * zero. 20091133Seschrock */ 20102676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 20112676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 20122676Seschrock nvlist_free(props); 20132082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20142676Seschrock "missing volume size")); 20152676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2016789Sahrens } 2017789Sahrens 20182676Seschrock if ((ret = nvlist_lookup_uint64(props, 20192676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20202676Seschrock &blocksize)) != 0) { 20212676Seschrock if (ret == ENOENT) { 20222676Seschrock blocksize = zfs_prop_default_numeric( 20232676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20242676Seschrock } else { 20252676Seschrock nvlist_free(props); 20262676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20272676Seschrock "missing volume block size")); 20282676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20292676Seschrock } 20302676Seschrock } 20312676Seschrock 20322676Seschrock if (size == 0) { 20332676Seschrock nvlist_free(props); 20342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20352676Seschrock "volume size cannot be zero")); 20362676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20371133Seschrock } 20381133Seschrock 20391133Seschrock if (size % blocksize != 0) { 20402676Seschrock nvlist_free(props); 20412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20422676Seschrock "volume size must be a multiple of volume block " 20432676Seschrock "size")); 20442676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20451133Seschrock } 2046789Sahrens } 2047789Sahrens 20482676Seschrock if (props && 20492676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20502676Seschrock return (-1); 20512676Seschrock nvlist_free(props); 20522676Seschrock 2053789Sahrens /* create the dataset */ 20542082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2055789Sahrens 2056789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 20572082Seschrock ret = zvol_create_link(hdl, path); 2058789Sahrens 20592676Seschrock zcmd_free_nvlists(&zc); 20602676Seschrock 2061789Sahrens /* check for failure */ 2062789Sahrens if (ret != 0) { 2063789Sahrens char parent[ZFS_MAXNAMELEN]; 2064789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2065789Sahrens 2066789Sahrens switch (errno) { 2067789Sahrens case ENOENT: 20682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20692082Seschrock "no such parent '%s'"), parent); 20702082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2071789Sahrens 2072789Sahrens case EINVAL: 20732082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20743413Smmusante "parent '%s' is not a filesystem"), parent); 20752082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2076789Sahrens 2077789Sahrens case EDOM: 20782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20792676Seschrock "volume block size must be power of 2 from " 20802676Seschrock "%u to %uk"), 2081789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2082789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 20832082Seschrock 20842676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20852082Seschrock 2086789Sahrens #ifdef _ILP32 2087789Sahrens case EOVERFLOW: 2088789Sahrens /* 2089789Sahrens * This platform can't address a volume this big. 2090789Sahrens */ 20912082Seschrock if (type == ZFS_TYPE_VOLUME) 20922082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 20932082Seschrock errbuf)); 2094789Sahrens #endif 20952082Seschrock /* FALLTHROUGH */ 2096789Sahrens default: 20972082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2098789Sahrens } 2099789Sahrens } 2100789Sahrens 2101789Sahrens return (0); 2102789Sahrens } 2103789Sahrens 2104789Sahrens /* 2105789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2106789Sahrens * isn't mounted, and that there are no active dependents. 2107789Sahrens */ 2108789Sahrens int 2109789Sahrens zfs_destroy(zfs_handle_t *zhp) 2110789Sahrens { 2111789Sahrens zfs_cmd_t zc = { 0 }; 2112789Sahrens 2113789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2114789Sahrens 21152676Seschrock if (ZFS_IS_VOLUME(zhp)) { 21163126Sahl /* 21173126Sahl * Unconditionally unshare this zvol ignoring failure as it 21183126Sahl * indicates only that the volume wasn't shared initially. 21193126Sahl */ 21203126Sahl (void) zfs_unshare_iscsi(zhp); 21213126Sahl 21222082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2123789Sahrens return (-1); 2124789Sahrens 2125789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2126789Sahrens } else { 2127789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2128789Sahrens } 2129789Sahrens 21303126Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 21313237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 21322082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21332082Seschrock zhp->zfs_name)); 21342199Sahrens } 2135789Sahrens 2136789Sahrens remove_mountpoint(zhp); 2137789Sahrens 2138789Sahrens return (0); 2139789Sahrens } 2140789Sahrens 21412199Sahrens struct destroydata { 21422199Sahrens char *snapname; 21432199Sahrens boolean_t gotone; 21443265Sahrens boolean_t closezhp; 21452199Sahrens }; 21462199Sahrens 21472199Sahrens static int 21482199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 21492199Sahrens { 21502199Sahrens struct destroydata *dd = arg; 21512199Sahrens zfs_handle_t *szhp; 21522199Sahrens char name[ZFS_MAXNAMELEN]; 21533265Sahrens boolean_t closezhp = dd->closezhp; 21543265Sahrens int rv; 21552199Sahrens 21562676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 21572676Seschrock (void) strlcat(name, "@", sizeof (name)); 21582676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 21592199Sahrens 21602199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 21612199Sahrens if (szhp) { 21622199Sahrens dd->gotone = B_TRUE; 21632199Sahrens zfs_close(szhp); 21642199Sahrens } 21652199Sahrens 21662199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 21672199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 21682199Sahrens /* 21692199Sahrens * NB: this is simply a best-effort. We don't want to 21702199Sahrens * return an error, because then we wouldn't visit all 21712199Sahrens * the volumes. 21722199Sahrens */ 21732199Sahrens } 21742199Sahrens 21753265Sahrens dd->closezhp = B_TRUE; 21763265Sahrens rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 21773265Sahrens if (closezhp) 21783265Sahrens zfs_close(zhp); 21793265Sahrens return (rv); 21802199Sahrens } 21812199Sahrens 21822199Sahrens /* 21832199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 21842199Sahrens */ 21852199Sahrens int 21862199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 21872199Sahrens { 21882199Sahrens zfs_cmd_t zc = { 0 }; 21892199Sahrens int ret; 21902199Sahrens struct destroydata dd = { 0 }; 21912199Sahrens 21922199Sahrens dd.snapname = snapname; 21932199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 21942199Sahrens 21952199Sahrens if (!dd.gotone) { 21963237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 21972199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 21982199Sahrens zhp->zfs_name, snapname)); 21992199Sahrens } 22002199Sahrens 22012199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22022676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 22032199Sahrens 22042199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 22052199Sahrens if (ret != 0) { 22062199Sahrens char errbuf[1024]; 22072199Sahrens 22082199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22092199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22102199Sahrens 22112199Sahrens switch (errno) { 22122199Sahrens case EEXIST: 22132199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22142199Sahrens "snapshot is cloned")); 22152199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22162199Sahrens 22172199Sahrens default: 22182199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22192199Sahrens errbuf)); 22202199Sahrens } 22212199Sahrens } 22222199Sahrens 22232199Sahrens return (0); 22242199Sahrens } 22252199Sahrens 2226789Sahrens /* 2227789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2228789Sahrens */ 2229789Sahrens int 22302676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2231789Sahrens { 2232789Sahrens zfs_cmd_t zc = { 0 }; 2233789Sahrens char parent[ZFS_MAXNAMELEN]; 2234789Sahrens int ret; 22352082Seschrock char errbuf[1024]; 22362082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22372676Seschrock zfs_type_t type; 22382676Seschrock uint64_t zoned; 2239789Sahrens 2240789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2241789Sahrens 22422082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22432082Seschrock "cannot create '%s'"), target); 22442082Seschrock 2245789Sahrens /* validate the target name */ 22462082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 22472082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2248789Sahrens 2249789Sahrens /* validate parents exist */ 22502676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2251789Sahrens return (-1); 2252789Sahrens 2253789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2254789Sahrens 2255789Sahrens /* do the clone */ 22562676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2257789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 22582744Snn35248 type = ZFS_TYPE_VOLUME; 22592676Seschrock } else { 2260789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 22612744Snn35248 type = ZFS_TYPE_FILESYSTEM; 22622676Seschrock } 22632676Seschrock 22642676Seschrock if (props) { 22652676Seschrock if ((props = zfs_validate_properties(hdl, type, props, zoned, 22662676Seschrock zhp, errbuf)) == NULL) 22672676Seschrock return (-1); 22682676Seschrock 22692676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 22702676Seschrock nvlist_free(props); 22712676Seschrock return (-1); 22722676Seschrock } 22732676Seschrock 22742676Seschrock nvlist_free(props); 22752676Seschrock } 2276789Sahrens 2277789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 22782676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 22792082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2280789Sahrens 22812676Seschrock zcmd_free_nvlists(&zc); 22822676Seschrock 2283789Sahrens if (ret != 0) { 2284789Sahrens switch (errno) { 2285789Sahrens 2286789Sahrens case ENOENT: 2287789Sahrens /* 2288789Sahrens * The parent doesn't exist. We should have caught this 2289789Sahrens * above, but there may a race condition that has since 2290789Sahrens * destroyed the parent. 2291789Sahrens * 2292789Sahrens * At this point, we don't know whether it's the source 2293789Sahrens * that doesn't exist anymore, or whether the target 2294789Sahrens * dataset doesn't exist. 2295789Sahrens */ 22962082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22972082Seschrock "no such parent '%s'"), parent); 22982082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 22992082Seschrock 23002082Seschrock case EXDEV: 23012082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23022082Seschrock "source and target pools differ")); 23032082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 23042082Seschrock errbuf)); 23052082Seschrock 23062082Seschrock default: 23072082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 23082082Seschrock errbuf)); 23092082Seschrock } 23102676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 23112082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 23122082Seschrock } 23132082Seschrock 23142082Seschrock return (ret); 23152082Seschrock } 23162082Seschrock 23172082Seschrock typedef struct promote_data { 23182082Seschrock char cb_mountpoint[MAXPATHLEN]; 23192082Seschrock const char *cb_target; 23202082Seschrock const char *cb_errbuf; 23212082Seschrock uint64_t cb_pivot_txg; 23222082Seschrock } promote_data_t; 23232082Seschrock 23242082Seschrock static int 23252082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 23262082Seschrock { 23272082Seschrock promote_data_t *pd = data; 23282082Seschrock zfs_handle_t *szhp; 23292082Seschrock char snapname[MAXPATHLEN]; 23303265Sahrens int rv = 0; 23312082Seschrock 23322082Seschrock /* We don't care about snapshots after the pivot point */ 23333265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 23343265Sahrens zfs_close(zhp); 23352082Seschrock return (0); 23363265Sahrens } 23372082Seschrock 23382417Sahrens /* Remove the device link if it's a zvol. */ 23392676Seschrock if (ZFS_IS_VOLUME(zhp)) 23402417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23412082Seschrock 23422082Seschrock /* Check for conflicting names */ 23432676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 23442676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 23452082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 23462082Seschrock if (szhp != NULL) { 23472082Seschrock zfs_close(szhp); 23482082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23492082Seschrock "snapshot name '%s' from origin \n" 23502082Seschrock "conflicts with '%s' from target"), 23512082Seschrock zhp->zfs_name, snapname); 23523265Sahrens rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 23532082Seschrock } 23543265Sahrens zfs_close(zhp); 23553265Sahrens return (rv); 23562082Seschrock } 23572082Seschrock 23582417Sahrens static int 23592417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 23602417Sahrens { 23612417Sahrens promote_data_t *pd = data; 23622417Sahrens 23632417Sahrens /* We don't care about snapshots after the pivot point */ 23643265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 23653265Sahrens /* Create the device link if it's a zvol. */ 23663265Sahrens if (ZFS_IS_VOLUME(zhp)) 23673265Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 23683265Sahrens } 23693265Sahrens 23703265Sahrens zfs_close(zhp); 23712417Sahrens return (0); 23722417Sahrens } 23732417Sahrens 23742082Seschrock /* 23752082Seschrock * Promotes the given clone fs to be the clone parent. 23762082Seschrock */ 23772082Seschrock int 23782082Seschrock zfs_promote(zfs_handle_t *zhp) 23792082Seschrock { 23802082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 23812082Seschrock zfs_cmd_t zc = { 0 }; 23822082Seschrock char parent[MAXPATHLEN]; 23832082Seschrock char *cp; 23842082Seschrock int ret; 23852082Seschrock zfs_handle_t *pzhp; 23862082Seschrock promote_data_t pd; 23872082Seschrock char errbuf[1024]; 23882082Seschrock 23892082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23902082Seschrock "cannot promote '%s'"), zhp->zfs_name); 23912082Seschrock 23922082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 23932082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23942082Seschrock "snapshots can not be promoted")); 23952082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 23962082Seschrock } 23972082Seschrock 23982676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 23992082Seschrock if (parent[0] == '\0') { 24002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24012082Seschrock "not a cloned filesystem")); 24022082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24032082Seschrock } 24042082Seschrock cp = strchr(parent, '@'); 24052082Seschrock *cp = '\0'; 24062082Seschrock 24072082Seschrock /* Walk the snapshots we will be moving */ 24082082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 24092082Seschrock if (pzhp == NULL) 24102082Seschrock return (-1); 24112082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 24122082Seschrock zfs_close(pzhp); 24132082Seschrock pd.cb_target = zhp->zfs_name; 24142082Seschrock pd.cb_errbuf = errbuf; 24152082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 24162082Seschrock if (pzhp == NULL) 24172082Seschrock return (-1); 24182082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 24192082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 24202082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24212417Sahrens if (ret != 0) { 24222417Sahrens zfs_close(pzhp); 24232082Seschrock return (-1); 24242417Sahrens } 24252082Seschrock 24262082Seschrock /* issue the ioctl */ 24272676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 24282676Seschrock sizeof (zc.zc_value)); 24292082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24302082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 24312082Seschrock 24322082Seschrock if (ret != 0) { 24332417Sahrens int save_errno = errno; 24342417Sahrens 24352417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24362417Sahrens zfs_close(pzhp); 24372417Sahrens 24382417Sahrens switch (save_errno) { 2439789Sahrens case EEXIST: 2440789Sahrens /* 24412082Seschrock * There is a conflicting snapshot name. We 24422082Seschrock * should have caught this above, but they could 24432082Seschrock * have renamed something in the mean time. 2444789Sahrens */ 24452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24462082Seschrock "conflicting snapshot name from parent '%s'"), 24472082Seschrock parent); 24482082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2449789Sahrens 2450789Sahrens default: 24512417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2452789Sahrens } 24532417Sahrens } else { 24542417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2455789Sahrens } 2456789Sahrens 24572417Sahrens zfs_close(pzhp); 2458789Sahrens return (ret); 2459789Sahrens } 2460789Sahrens 24612199Sahrens static int 24622199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 24632199Sahrens { 24642199Sahrens char *snapname = arg; 24652676Seschrock int ret; 24662199Sahrens 24672199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 24682199Sahrens char name[MAXPATHLEN]; 24692199Sahrens 24702676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 24712676Seschrock (void) strlcat(name, "@", sizeof (name)); 24722676Seschrock (void) strlcat(name, snapname, sizeof (name)); 24732199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 24742199Sahrens /* 24752199Sahrens * NB: this is simply a best-effort. We don't want to 24762199Sahrens * return an error, because then we wouldn't visit all 24772199Sahrens * the volumes. 24782199Sahrens */ 24792199Sahrens } 24802676Seschrock 24812676Seschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 24822676Seschrock 24832676Seschrock zfs_close(zhp); 24842676Seschrock 24852676Seschrock return (ret); 24862199Sahrens } 24872199Sahrens 2488789Sahrens /* 24893504Sahl * Takes a snapshot of the given dataset. 2490789Sahrens */ 2491789Sahrens int 24922199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2493789Sahrens { 2494789Sahrens const char *delim; 2495789Sahrens char *parent; 2496789Sahrens zfs_handle_t *zhp; 2497789Sahrens zfs_cmd_t zc = { 0 }; 2498789Sahrens int ret; 24992082Seschrock char errbuf[1024]; 25002082Seschrock 25012082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25022082Seschrock "cannot snapshot '%s'"), path); 25032082Seschrock 25042082Seschrock /* validate the target name */ 25052082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 25062082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2507789Sahrens 2508789Sahrens /* make sure the parent exists and is of the appropriate type */ 25092199Sahrens delim = strchr(path, '@'); 25102082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 25112082Seschrock return (-1); 2512789Sahrens (void) strncpy(parent, path, delim - path); 2513789Sahrens parent[delim - path] = '\0'; 2514789Sahrens 25152082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2516789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2517789Sahrens free(parent); 2518789Sahrens return (-1); 2519789Sahrens } 2520789Sahrens 25212199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25222676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25232199Sahrens zc.zc_cookie = recursive; 25242199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 25252199Sahrens 25262199Sahrens /* 25272199Sahrens * if it was recursive, the one that actually failed will be in 25282199Sahrens * zc.zc_name. 25292199Sahrens */ 25302199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25312676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25322199Sahrens if (ret == 0 && recursive) { 25332199Sahrens (void) zfs_iter_filesystems(zhp, 25342199Sahrens zfs_create_link_cb, (char *)delim+1); 25352199Sahrens } 2536789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 25372082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25382199Sahrens if (ret != 0) { 25392082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 25402082Seschrock &zc); 25412199Sahrens } 2542789Sahrens } 2543789Sahrens 25442082Seschrock if (ret != 0) 25452082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2546789Sahrens 2547789Sahrens free(parent); 2548789Sahrens zfs_close(zhp); 2549789Sahrens 2550789Sahrens return (ret); 2551789Sahrens } 2552789Sahrens 2553789Sahrens /* 25543504Sahl * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 25553504Sahl * NULL) to the file descriptor specified by outfd. 2556789Sahrens */ 2557789Sahrens int 25583504Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2559789Sahrens { 2560789Sahrens zfs_cmd_t zc = { 0 }; 25612082Seschrock char errbuf[1024]; 25622885Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 25632082Seschrock 25643504Sahl assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 25653504Sahl 25662885Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25672885Sahrens if (fromsnap) 25682885Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 25693504Sahl zc.zc_cookie = outfd; 25703504Sahl 25713504Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 25723504Sahl (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25733504Sahl "cannot send '%s'"), zhp->zfs_name); 25743504Sahl 2575789Sahrens switch (errno) { 2576789Sahrens 2577789Sahrens case EXDEV: 25782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25793413Smmusante "not an earlier snapshot from the same fs")); 25802082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2581789Sahrens 2582789Sahrens case EDQUOT: 2583789Sahrens case EFBIG: 2584789Sahrens case EIO: 2585789Sahrens case ENOLINK: 2586789Sahrens case ENOSPC: 2587789Sahrens case ENOSTR: 2588789Sahrens case ENXIO: 2589789Sahrens case EPIPE: 2590789Sahrens case ERANGE: 2591789Sahrens case EFAULT: 2592789Sahrens case EROFS: 25932082Seschrock zfs_error_aux(hdl, strerror(errno)); 25942082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2595789Sahrens 2596789Sahrens default: 25972082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2598789Sahrens } 2599789Sahrens } 2600789Sahrens 26013504Sahl return (0); 2602789Sahrens } 2603789Sahrens 2604789Sahrens /* 26052885Sahrens * Create ancestors of 'target', but not target itself, and not 26062885Sahrens * ancestors whose names are shorter than prefixlen. Die if 26072885Sahrens * prefixlen-ancestor does not exist. 26082885Sahrens */ 26092885Sahrens static int 26102885Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 26112885Sahrens { 26122885Sahrens zfs_handle_t *h; 26132885Sahrens char *cp; 26142885Sahrens 26152885Sahrens /* make sure prefix exists */ 26162885Sahrens cp = strchr(target + prefixlen, '/'); 26172885Sahrens *cp = '\0'; 26182885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 26192885Sahrens *cp = '/'; 26202885Sahrens if (h == NULL) 26212885Sahrens return (-1); 26222885Sahrens zfs_close(h); 26232885Sahrens 26242885Sahrens /* 26252885Sahrens * Attempt to create, mount, and share any ancestor filesystems, 26262885Sahrens * up to the prefixlen-long one. 26272885Sahrens */ 26282885Sahrens for (cp = target + prefixlen + 1; 26292885Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 26302885Sahrens const char *opname; 26312885Sahrens 26322885Sahrens *cp = '\0'; 26332885Sahrens 26342885Sahrens h = make_dataset_handle(hdl, target); 26352885Sahrens if (h) { 26362885Sahrens /* it already exists, nothing to do here */ 26372885Sahrens zfs_close(h); 26382885Sahrens continue; 26392885Sahrens } 26402885Sahrens 26412885Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 26422885Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 26432885Sahrens NULL) != 0) 26442885Sahrens goto ancestorerr; 26452885Sahrens 26462885Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 26472885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 26482885Sahrens if (h == NULL) 26492885Sahrens goto ancestorerr; 26502885Sahrens 26512885Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 26522885Sahrens if (zfs_mount(h, NULL, 0) != 0) 26532885Sahrens goto ancestorerr; 26542885Sahrens 26552885Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 26562885Sahrens if (zfs_share(h) != 0) 26572885Sahrens goto ancestorerr; 26582885Sahrens 26592885Sahrens zfs_close(h); 26602885Sahrens 26612885Sahrens continue; 26622885Sahrens ancestorerr: 26632885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26642885Sahrens "failed to %s ancestor '%s'"), opname, target); 26652885Sahrens return (-1); 26662885Sahrens } 26672885Sahrens 26682885Sahrens return (0); 26692885Sahrens } 26702885Sahrens 26712885Sahrens /* 26723504Sahl * Restores a backup of tosnap from the file descriptor specified by infd. 2673789Sahrens */ 2674789Sahrens int 26752082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 26763504Sahl int verbose, int dryrun, boolean_t force, int infd) 2677789Sahrens { 2678789Sahrens zfs_cmd_t zc = { 0 }; 2679789Sahrens time_t begin_time; 26802885Sahrens int ioctl_err, err, bytes, size, choplen; 2681789Sahrens char *cp; 2682789Sahrens dmu_replay_record_t drr; 2683789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 26842082Seschrock char errbuf[1024]; 26852665Snd150628 prop_changelist_t *clp; 26862885Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2687789Sahrens 2688789Sahrens begin_time = time(NULL); 2689789Sahrens 26902082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26912082Seschrock "cannot receive")); 26922082Seschrock 2693789Sahrens /* read in the BEGIN record */ 2694789Sahrens cp = (char *)&drr; 2695789Sahrens bytes = 0; 2696789Sahrens do { 26973504Sahl size = read(infd, cp, sizeof (drr) - bytes); 2698868Sahrens cp += size; 2699868Sahrens bytes += size; 2700868Sahrens } while (size > 0); 2701868Sahrens 2702868Sahrens if (size < 0 || bytes != sizeof (drr)) { 27032082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27042082Seschrock "stream (failed to read first record)")); 27052082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2706789Sahrens } 2707789Sahrens 2708789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2709789Sahrens 2710789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2711789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 27122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27132082Seschrock "stream (bad magic number)")); 27142082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2715789Sahrens } 2716789Sahrens 2717789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2718789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 27192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 27202082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2721789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 27222082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2723789Sahrens } 2724789Sahrens 27252885Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 27262885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27272885Sahrens "stream (bad snapshot name)")); 27282885Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 27292885Sahrens } 2730789Sahrens /* 27312885Sahrens * Determine how much of the snapshot name stored in the stream 27322885Sahrens * we are going to tack on to the name they specified on the 27332885Sahrens * command line, and how much we are going to chop off. 27342885Sahrens * 27352885Sahrens * If they specified a snapshot, chop the entire name stored in 27362885Sahrens * the stream. 2737789Sahrens */ 27382885Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2739789Sahrens if (isprefix) { 27402885Sahrens /* 27412885Sahrens * They specified a fs with -d, we want to tack on 27422885Sahrens * everything but the pool name stored in the stream 27432885Sahrens */ 27442885Sahrens if (strchr(tosnap, '@')) { 27452885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27462885Sahrens "argument - snapshot not allowed with -d")); 27472885Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2748789Sahrens } 27492885Sahrens cp = strchr(chopprefix, '/'); 2750789Sahrens if (cp == NULL) 27512885Sahrens cp = strchr(chopprefix, '@'); 27522885Sahrens *cp = '\0'; 2753789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2754789Sahrens /* 27552885Sahrens * If they specified a filesystem without -d, we want to 27562885Sahrens * tack on everything after the fs specified in the 27572885Sahrens * first name from the stream. 2758789Sahrens */ 27592885Sahrens cp = strchr(chopprefix, '@'); 27602885Sahrens *cp = '\0'; 2761789Sahrens } 27622885Sahrens choplen = strlen(chopprefix); 27632885Sahrens 27642885Sahrens /* 27652885Sahrens * Determine name of destination snapshot, store in zc_value. 27662885Sahrens */ 27672885Sahrens (void) strcpy(zc.zc_value, tosnap); 27682885Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 27692885Sahrens sizeof (zc.zc_value)); 27703265Sahrens if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 27713265Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 27722885Sahrens 27732885Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2774789Sahrens if (drrb->drr_fromguid) { 2775789Sahrens /* incremental backup stream */ 27762885Sahrens zfs_handle_t *h; 27772885Sahrens 27782885Sahrens /* do the recvbackup ioctl to the containing fs */ 27792885Sahrens *strchr(zc.zc_name, '@') = '\0'; 2780789Sahrens 2781789Sahrens /* make sure destination fs exists */ 27822082Seschrock h = zfs_open(hdl, zc.zc_name, 27832082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 27842082Seschrock if (h == NULL) 2785789Sahrens return (-1); 2786868Sahrens if (!dryrun) { 27872665Snd150628 /* 27882665Snd150628 * We need to unmount all the dependents of the dataset 27892665Snd150628 * and the dataset itself. If it's a volume 27902665Snd150628 * then remove device link. 27912665Snd150628 */ 2792868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 27932665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 27942665Snd150628 if (clp == NULL) 27952665Snd150628 return (-1); 27962665Snd150628 if (changelist_prefix(clp) != 0) { 27972665Snd150628 changelist_free(clp); 27982665Snd150628 return (-1); 27992665Snd150628 } 2800868Sahrens } else { 28012082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2802868Sahrens } 2803868Sahrens } 2804789Sahrens zfs_close(h); 2805789Sahrens } else { 2806789Sahrens /* full backup stream */ 2807789Sahrens 2808868Sahrens /* Make sure destination fs does not exist */ 28092885Sahrens *strchr(zc.zc_name, '@') = '\0'; 28102082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 28112082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28122082Seschrock "destination '%s' exists"), zc.zc_name); 28132082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2814868Sahrens } 2815868Sahrens 28162885Sahrens if (strchr(zc.zc_name, '/') == NULL) { 28172885Sahrens /* 28182885Sahrens * they're trying to do a recv into a 28192885Sahrens * nonexistant topmost filesystem. 28202885Sahrens */ 28212885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28222885Sahrens "destination does not exist"), zc.zc_name); 28232885Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 28242885Sahrens } 28252885Sahrens 2826868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 28272885Sahrens *strrchr(zc.zc_name, '/') = '\0'; 28282885Sahrens 28292885Sahrens if (isprefix && (err = create_parents(hdl, 28302885Sahrens zc.zc_value, strlen(tosnap))) != 0) { 28312885Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 28322885Sahrens } 28332885Sahrens 2834789Sahrens } 2835789Sahrens 28363504Sahl zc.zc_cookie = infd; 28372676Seschrock zc.zc_guid = force; 2838789Sahrens if (verbose) { 28391749Sahrens (void) printf("%s %s stream of %s into %s\n", 28401749Sahrens dryrun ? "would receive" : "receiving", 2841789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2842789Sahrens drr.drr_u.drr_begin.drr_toname, 28432676Seschrock zc.zc_value); 2844789Sahrens (void) fflush(stdout); 2845789Sahrens } 2846789Sahrens if (dryrun) 2847789Sahrens return (0); 28482082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2849868Sahrens if (ioctl_err != 0) { 2850789Sahrens switch (errno) { 2851789Sahrens case ENODEV: 28522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28532082Seschrock "most recent snapshot does not match incremental " 28542082Seschrock "source")); 28552082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2856789Sahrens break; 2857789Sahrens case ETXTBSY: 28582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28592082Seschrock "destination has been modified since most recent " 28602082Seschrock "snapshot")); 28612082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2862789Sahrens break; 2863789Sahrens case EEXIST: 2864789Sahrens if (drrb->drr_fromguid == 0) { 2865789Sahrens /* it's the containing fs that exists */ 28662676Seschrock cp = strchr(zc.zc_value, '@'); 2867789Sahrens *cp = '\0'; 2868789Sahrens } 28692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28702082Seschrock "destination already exists")); 28713237Slling (void) zfs_error_fmt(hdl, EZFS_EXISTS, 28723237Slling dgettext(TEXT_DOMAIN, "cannot restore to %s"), 28733237Slling zc.zc_value); 2874789Sahrens break; 2875789Sahrens case EINVAL: 28762082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2877868Sahrens break; 28781544Seschrock case ECKSUM: 28792082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28802082Seschrock "invalid stream (checksum mismatch)")); 28812082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2882789Sahrens break; 2883789Sahrens default: 28842082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2885789Sahrens } 2886789Sahrens } 2887789Sahrens 2888789Sahrens /* 2889868Sahrens * Mount or recreate the /dev links for the target filesystem 2890868Sahrens * (if created, or if we tore them down to do an incremental 2891868Sahrens * restore), and the /dev links for the new snapshot (if 28922665Snd150628 * created). Also mount any children of the target filesystem 28932665Snd150628 * if we did an incremental receive. 2894789Sahrens */ 28952676Seschrock cp = strchr(zc.zc_value, '@'); 2896868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2897789Sahrens zfs_handle_t *h; 2898789Sahrens 2899789Sahrens *cp = '\0'; 29002676Seschrock h = zfs_open(hdl, zc.zc_value, 2901789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2902868Sahrens *cp = '@'; 2903789Sahrens if (h) { 29042665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 29052082Seschrock err = zvol_create_link(hdl, h->zfs_name); 29061544Seschrock if (err == 0 && ioctl_err == 0) 29072082Seschrock err = zvol_create_link(hdl, 29082676Seschrock zc.zc_value); 29092665Snd150628 } else { 29102665Snd150628 if (drrb->drr_fromguid) { 29112665Snd150628 err = changelist_postfix(clp); 29122665Snd150628 changelist_free(clp); 29132665Snd150628 } else { 29142665Snd150628 err = zfs_mount(h, NULL, 0); 29152665Snd150628 } 2916868Sahrens } 29172665Snd150628 zfs_close(h); 2918789Sahrens } 2919789Sahrens } 2920789Sahrens 2921868Sahrens if (err || ioctl_err) 2922868Sahrens return (-1); 2923789Sahrens 2924789Sahrens if (verbose) { 2925789Sahrens char buf1[64]; 2926789Sahrens char buf2[64]; 2927789Sahrens uint64_t bytes = zc.zc_cookie; 2928789Sahrens time_t delta = time(NULL) - begin_time; 2929789Sahrens if (delta == 0) 2930789Sahrens delta = 1; 2931789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2932789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2933789Sahrens 29341749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2935789Sahrens buf1, delta, buf2); 2936789Sahrens } 29372665Snd150628 2938789Sahrens return (0); 2939789Sahrens } 2940789Sahrens 2941789Sahrens /* 29421294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 29431294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 29441294Slling * is a dependent and we should just destroy it without checking the transaction 29451294Slling * group. 2946789Sahrens */ 29471294Slling typedef struct rollback_data { 29481294Slling const char *cb_target; /* the snapshot */ 29491294Slling uint64_t cb_create; /* creation time reference */ 29501294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 29511294Slling int cb_error; 29522082Seschrock boolean_t cb_dependent; 29531294Slling } rollback_data_t; 29541294Slling 29551294Slling static int 29561294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 29571294Slling { 29581294Slling rollback_data_t *cbp = data; 29591294Slling 29601294Slling if (!cbp->cb_dependent) { 29611294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 29621294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 29631294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 29641294Slling cbp->cb_create) { 29651294Slling 29662082Seschrock cbp->cb_dependent = B_TRUE; 29672474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 29682474Seschrock cbp) != 0) 29692474Seschrock cbp->cb_error = 1; 29702082Seschrock cbp->cb_dependent = B_FALSE; 29711294Slling 29721294Slling if (zfs_destroy(zhp) != 0) 29731294Slling cbp->cb_error = 1; 29741294Slling else 29751294Slling changelist_remove(zhp, cbp->cb_clp); 29761294Slling } 29771294Slling } else { 29781294Slling if (zfs_destroy(zhp) != 0) 29791294Slling cbp->cb_error = 1; 29801294Slling else 29811294Slling changelist_remove(zhp, cbp->cb_clp); 29821294Slling } 29831294Slling 29841294Slling zfs_close(zhp); 29851294Slling return (0); 29861294Slling } 29871294Slling 29881294Slling /* 29891294Slling * Rollback the dataset to its latest snapshot. 29901294Slling */ 29911294Slling static int 29921294Slling do_rollback(zfs_handle_t *zhp) 2993789Sahrens { 2994789Sahrens int ret; 2995789Sahrens zfs_cmd_t zc = { 0 }; 2996789Sahrens 2997789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2998789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2999789Sahrens 3000789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 30012082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3002789Sahrens return (-1); 3003789Sahrens 3004789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3005789Sahrens 30062676Seschrock if (ZFS_IS_VOLUME(zhp)) 3007789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3008789Sahrens else 3009789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3010789Sahrens 3011789Sahrens /* 3012789Sahrens * We rely on the consumer to verify that there are no newer snapshots 3013789Sahrens * for the given dataset. Given these constraints, we can simply pass 3014789Sahrens * the name on to the ioctl() call. There is still an unlikely race 3015789Sahrens * condition where the user has taken a snapshot since we verified that 3016789Sahrens * this was the most recent. 3017789Sahrens */ 30182082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 30192082Seschrock &zc)) != 0) { 30203237Slling (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 30212082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 30222082Seschrock zhp->zfs_name); 3023789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 30242082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3025789Sahrens } 3026789Sahrens 3027789Sahrens return (ret); 3028789Sahrens } 3029789Sahrens 3030789Sahrens /* 30311294Slling * Given a dataset, rollback to a specific snapshot, discarding any 30321294Slling * data changes since then and making it the active dataset. 30331294Slling * 30341294Slling * Any snapshots more recent than the target are destroyed, along with 30351294Slling * their dependents. 30361294Slling */ 30371294Slling int 30381294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 30391294Slling { 30401294Slling int ret; 30411294Slling rollback_data_t cb = { 0 }; 30421294Slling prop_changelist_t *clp; 30431294Slling 30441294Slling /* 30451294Slling * Unmount all dependendents of the dataset and the dataset itself. 30461294Slling * The list we need to gather is the same as for doing rename 30471294Slling */ 30481294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 30491294Slling if (clp == NULL) 30501294Slling return (-1); 30511294Slling 30521294Slling if ((ret = changelist_prefix(clp)) != 0) 30531294Slling goto out; 30541294Slling 30551294Slling /* 30561294Slling * Destroy all recent snapshots and its dependends. 30571294Slling */ 30581294Slling cb.cb_target = snap->zfs_name; 30591294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 30601294Slling cb.cb_clp = clp; 30611294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 30621294Slling 30631294Slling if ((ret = cb.cb_error) != 0) { 30641294Slling (void) changelist_postfix(clp); 30651294Slling goto out; 30661294Slling } 30671294Slling 30681294Slling /* 30691294Slling * Now that we have verified that the snapshot is the latest, 30701294Slling * rollback to the given snapshot. 30711294Slling */ 30721294Slling ret = do_rollback(zhp); 30731294Slling 30741294Slling if (ret != 0) { 30751294Slling (void) changelist_postfix(clp); 30761294Slling goto out; 30771294Slling } 30781294Slling 30791294Slling /* 30801294Slling * We only want to re-mount the filesystem if it was mounted in the 30811294Slling * first place. 30821294Slling */ 30831294Slling ret = changelist_postfix(clp); 30841294Slling 30851294Slling out: 30861294Slling changelist_free(clp); 30871294Slling return (ret); 30881294Slling } 30891294Slling 30901294Slling /* 3091789Sahrens * Iterate over all dependents for a given dataset. This includes both 3092789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3093789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3094789Sahrens * libzfs_graph.c. 3095789Sahrens */ 3096789Sahrens int 30972474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 30982474Seschrock zfs_iter_f func, void *data) 3099789Sahrens { 3100789Sahrens char **dependents; 3101789Sahrens size_t count; 3102789Sahrens int i; 3103789Sahrens zfs_handle_t *child; 3104789Sahrens int ret = 0; 3105789Sahrens 31062474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 31072474Seschrock &dependents, &count) != 0) 31082474Seschrock return (-1); 31092474Seschrock 3110789Sahrens for (i = 0; i < count; i++) { 31112082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 31122082Seschrock dependents[i])) == NULL) 3113789Sahrens continue; 3114789Sahrens 3115789Sahrens if ((ret = func(child, data)) != 0) 3116789Sahrens break; 3117789Sahrens } 3118789Sahrens 3119789Sahrens for (i = 0; i < count; i++) 3120789Sahrens free(dependents[i]); 3121789Sahrens free(dependents); 3122789Sahrens 3123789Sahrens return (ret); 3124789Sahrens } 3125789Sahrens 3126789Sahrens /* 3127789Sahrens * Renames the given dataset. 3128789Sahrens */ 3129789Sahrens int 3130789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3131789Sahrens { 3132789Sahrens int ret; 3133789Sahrens zfs_cmd_t zc = { 0 }; 3134789Sahrens char *delim; 3135789Sahrens prop_changelist_t *cl; 3136789Sahrens char parent[ZFS_MAXNAMELEN]; 31372082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 31382082Seschrock char errbuf[1024]; 3139789Sahrens 3140789Sahrens /* if we have the same exact name, just return success */ 3141789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3142789Sahrens return (0); 3143789Sahrens 31442082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31452082Seschrock "cannot rename to '%s'"), target); 31462082Seschrock 3147789Sahrens /* 3148789Sahrens * Make sure the target name is valid 3149789Sahrens */ 3150789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 31512665Snd150628 if ((strchr(target, '@') == NULL) || 31522665Snd150628 *target == '@') { 31532665Snd150628 /* 31542665Snd150628 * Snapshot target name is abbreviated, 31552665Snd150628 * reconstruct full dataset name 31562665Snd150628 */ 31572665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 31582665Snd150628 sizeof (parent)); 31592665Snd150628 delim = strchr(parent, '@'); 31602665Snd150628 if (strchr(target, '@') == NULL) 31612665Snd150628 *(++delim) = '\0'; 31622665Snd150628 else 31632665Snd150628 *delim = '\0'; 31642665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 31652665Snd150628 target = parent; 31662665Snd150628 } else { 31672665Snd150628 /* 31682665Snd150628 * Make sure we're renaming within the same dataset. 31692665Snd150628 */ 31702665Snd150628 delim = strchr(target, '@'); 31712665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 31722665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 31732665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31742665Snd150628 "snapshots must be part of same " 31752665Snd150628 "dataset")); 31762665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 31772665Snd150628 errbuf)); 31782665Snd150628 } 3179789Sahrens } 31802665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31812665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3182789Sahrens } else { 31832665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31842665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31852676Seschrock uint64_t unused; 31862676Seschrock 3187789Sahrens /* validate parents */ 31882676Seschrock if (check_parents(hdl, target, &unused) != 0) 3189789Sahrens return (-1); 3190789Sahrens 3191789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3192789Sahrens 3193789Sahrens /* make sure we're in the same pool */ 3194789Sahrens verify((delim = strchr(target, '/')) != NULL); 3195789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3196789Sahrens zhp->zfs_name[delim - target] != '/') { 31972082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31982082Seschrock "datasets must be within same pool")); 31992082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3200789Sahrens } 32012440Snd150628 32022440Snd150628 /* new name cannot be a child of the current dataset name */ 32032440Snd150628 if (strncmp(parent, zhp->zfs_name, 32042440Snd150628 strlen(zhp->zfs_name)) == 0) { 32052440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32062440Snd150628 "New dataset name cannot be a descendent of " 32072440Snd150628 "current dataset name")); 32082440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 32092440Snd150628 } 3210789Sahrens } 3211789Sahrens 32122082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 32132082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 32142082Seschrock 3215789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3216789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 32172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32182082Seschrock "dataset is used in a non-global zone")); 32192082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3220789Sahrens } 3221789Sahrens 3222789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 32232082Seschrock return (-1); 3224789Sahrens 3225789Sahrens if (changelist_haszonedchild(cl)) { 32262082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32272082Seschrock "child dataset with inherited mountpoint is used " 32282082Seschrock "in a non-global zone")); 32292676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3230789Sahrens goto error; 3231789Sahrens } 3232789Sahrens 3233789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3234789Sahrens goto error; 3235789Sahrens 32362676Seschrock if (ZFS_IS_VOLUME(zhp)) 3237789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3238789Sahrens else 3239789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3240789Sahrens 32412665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 32422676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 32432665Snd150628 32442082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 32452082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3246789Sahrens 3247789Sahrens /* 3248789Sahrens * On failure, we still want to remount any filesystems that 3249789Sahrens * were previously mounted, so we don't alter the system state. 3250789Sahrens */ 3251789Sahrens (void) changelist_postfix(cl); 3252789Sahrens } else { 3253789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3254789Sahrens 3255789Sahrens ret = changelist_postfix(cl); 3256789Sahrens } 3257789Sahrens 3258789Sahrens error: 3259789Sahrens changelist_free(cl); 3260789Sahrens return (ret); 3261789Sahrens } 3262789Sahrens 3263789Sahrens /* 3264789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3265789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3266789Sahrens */ 3267789Sahrens int 32682082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3269789Sahrens { 3270789Sahrens zfs_cmd_t zc = { 0 }; 32712082Seschrock di_devlink_handle_t dhdl; 3272789Sahrens 3273789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3274789Sahrens 3275789Sahrens /* 3276789Sahrens * Issue the appropriate ioctl. 3277789Sahrens */ 32782082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3279789Sahrens switch (errno) { 3280789Sahrens case EEXIST: 3281789Sahrens /* 3282789Sahrens * Silently ignore the case where the link already 3283789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3284789Sahrens * times without errors. 3285789Sahrens */ 3286789Sahrens return (0); 3287789Sahrens 3288789Sahrens default: 32893237Slling return (zfs_standard_error_fmt(hdl, errno, 32902082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32912082Seschrock "for '%s'"), dataset)); 3292789Sahrens } 3293789Sahrens } 3294789Sahrens 3295789Sahrens /* 3296789Sahrens * Call devfsadm and wait for the links to magically appear. 3297789Sahrens */ 32982082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 32992082Seschrock zfs_error_aux(hdl, strerror(errno)); 33003237Slling (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 33012082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 33022082Seschrock "for '%s'"), dataset); 33032082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3304789Sahrens return (-1); 3305789Sahrens } else { 33062082Seschrock (void) di_devlink_fini(&dhdl); 3307789Sahrens } 3308789Sahrens 3309789Sahrens return (0); 3310789Sahrens } 3311789Sahrens 3312789Sahrens /* 3313789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3314789Sahrens */ 3315789Sahrens int 33162082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3317789Sahrens { 3318789Sahrens zfs_cmd_t zc = { 0 }; 3319789Sahrens 3320789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3321789Sahrens 33222082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3323789Sahrens switch (errno) { 3324789Sahrens case ENXIO: 3325789Sahrens /* 3326789Sahrens * Silently ignore the case where the link no longer 3327789Sahrens * exists, so that 'zfs volfini' can be run multiple 3328789Sahrens * times without errors. 3329789Sahrens */ 3330789Sahrens return (0); 3331789Sahrens 3332789Sahrens default: 33333237Slling return (zfs_standard_error_fmt(hdl, errno, 33342082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 33352082Seschrock "links for '%s'"), dataset)); 3336789Sahrens } 3337789Sahrens } 3338789Sahrens 3339789Sahrens return (0); 3340789Sahrens } 33412676Seschrock 33422676Seschrock nvlist_t * 33432676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 33442676Seschrock { 33452676Seschrock return (zhp->zfs_user_props); 33462676Seschrock } 33472676Seschrock 33482676Seschrock /* 33492676Seschrock * Given a comma-separated list of properties, contruct a property list 33502676Seschrock * containing both user-defined and native properties. This function will 33512676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 33522676Seschrock * per-dataset basis by zfs_expand_proplist(). 33532676Seschrock */ 33542676Seschrock int 33552676Seschrock zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 33562676Seschrock { 33572676Seschrock size_t len; 33582676Seschrock char *s, *p; 33592676Seschrock char c; 33602676Seschrock zfs_prop_t prop; 33612676Seschrock zfs_proplist_t *entry; 33622676Seschrock zfs_proplist_t **last; 33632676Seschrock 33642676Seschrock *listp = NULL; 33652676Seschrock last = listp; 33662676Seschrock 33672676Seschrock /* 33682676Seschrock * If 'all' is specified, return a NULL list. 33692676Seschrock */ 33702676Seschrock if (strcmp(fields, "all") == 0) 33712676Seschrock return (0); 33722676Seschrock 33732676Seschrock /* 33742676Seschrock * If no fields were specified, return an error. 33752676Seschrock */ 33762676Seschrock if (fields[0] == '\0') { 33772676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33782676Seschrock "no properties specified")); 33792676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 33802676Seschrock "bad property list"))); 33812676Seschrock } 33822676Seschrock 33832676Seschrock /* 33842676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 33852676Seschrock * aliases makes this more effort than it's worth. 33862676Seschrock */ 33872676Seschrock s = fields; 33882676Seschrock while (*s != '\0') { 33892676Seschrock if ((p = strchr(s, ',')) == NULL) { 33902676Seschrock len = strlen(s); 33912676Seschrock p = s + len; 33922676Seschrock } else { 33932676Seschrock len = p - s; 33942676Seschrock } 33952676Seschrock 33962676Seschrock /* 33972676Seschrock * Check for empty options. 33982676Seschrock */ 33992676Seschrock if (len == 0) { 34002676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34012676Seschrock "empty property name")); 34022676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 34032676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 34042676Seschrock } 34052676Seschrock 34062676Seschrock /* 34072676Seschrock * Check all regular property names. 34082676Seschrock */ 34092676Seschrock c = s[len]; 34102676Seschrock s[len] = '\0'; 34113654Sgw25295 prop = zfs_name_to_prop(s); 34122676Seschrock 34132676Seschrock /* 34142676Seschrock * If no column is specified, and this isn't a user property, 34152676Seschrock * return failure. 34162676Seschrock */ 34173654Sgw25295 if (prop == ZFS_PROP_INVAL && !zfs_prop_user(s)) { 34182676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34192676Seschrock "invalid property '%s'"), s); 34202676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 34212676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 34222676Seschrock } 34232676Seschrock 34242676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 34252676Seschrock return (-1); 34262676Seschrock 34272676Seschrock entry->pl_prop = prop; 34282676Seschrock if (prop == ZFS_PROP_INVAL) { 34292676Seschrock if ((entry->pl_user_prop = 34302676Seschrock zfs_strdup(hdl, s)) == NULL) { 34312676Seschrock free(entry); 34322676Seschrock return (-1); 34332676Seschrock } 34342676Seschrock entry->pl_width = strlen(s); 34352676Seschrock } else { 34362676Seschrock entry->pl_width = zfs_prop_width(prop, 34372676Seschrock &entry->pl_fixed); 34382676Seschrock } 34392676Seschrock 34402676Seschrock *last = entry; 34412676Seschrock last = &entry->pl_next; 34422676Seschrock 34432676Seschrock s = p; 34442676Seschrock if (c == ',') 34452676Seschrock s++; 34462676Seschrock } 34472676Seschrock 34482676Seschrock return (0); 34492676Seschrock } 34502676Seschrock 34512676Seschrock void 34522676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 34532676Seschrock { 34542676Seschrock zfs_proplist_t *next; 34552676Seschrock 34562676Seschrock while (pl != NULL) { 34572676Seschrock next = pl->pl_next; 34582676Seschrock free(pl->pl_user_prop); 34592676Seschrock free(pl); 34602676Seschrock pl = next; 34612676Seschrock } 34622676Seschrock } 34632676Seschrock 34643654Sgw25295 typedef struct expand_data { 34653654Sgw25295 zfs_proplist_t **last; 34663654Sgw25295 libzfs_handle_t *hdl; 34673654Sgw25295 } expand_data_t; 34683654Sgw25295 34693654Sgw25295 static zfs_prop_t 34703654Sgw25295 zfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 34713654Sgw25295 { 34723654Sgw25295 zfs_proplist_t *entry; 34733654Sgw25295 expand_data_t *edp = cb; 34743654Sgw25295 34753654Sgw25295 if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 34763654Sgw25295 return (ZFS_PROP_INVAL); 34773654Sgw25295 34783654Sgw25295 entry->pl_prop = prop; 34793654Sgw25295 entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 34803654Sgw25295 entry->pl_all = B_TRUE; 34813654Sgw25295 34823654Sgw25295 *(edp->last) = entry; 34833654Sgw25295 edp->last = &entry->pl_next; 34843654Sgw25295 34853654Sgw25295 return (ZFS_PROP_CONT); 34863654Sgw25295 } 34873654Sgw25295 34882676Seschrock /* 34892676Seschrock * This function is used by 'zfs list' to determine the exact set of columns to 34902676Seschrock * display, and their maximum widths. This does two main things: 34912676Seschrock * 34922676Seschrock * - If this is a list of all properties, then expand the list to include 34932676Seschrock * all native properties, and set a flag so that for each dataset we look 34942676Seschrock * for new unique user properties and add them to the list. 34952676Seschrock * 34962676Seschrock * - For non fixed-width properties, keep track of the maximum width seen 34972676Seschrock * so that we can size the column appropriately. 34982676Seschrock */ 34992676Seschrock int 35002676Seschrock zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 35012676Seschrock { 35022676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 35032676Seschrock zfs_proplist_t *entry; 35042676Seschrock zfs_proplist_t **last, **start; 35052676Seschrock nvlist_t *userprops, *propval; 35062676Seschrock nvpair_t *elem; 35072676Seschrock char *strval; 35082676Seschrock char buf[ZFS_MAXPROPLEN]; 35093654Sgw25295 expand_data_t exp; 35102676Seschrock 35112676Seschrock if (*plp == NULL) { 35122676Seschrock /* 35132676Seschrock * If this is the very first time we've been called for an 'all' 35142676Seschrock * specification, expand the list to include all native 35152676Seschrock * properties. 35162676Seschrock */ 35172676Seschrock last = plp; 35183654Sgw25295 35193654Sgw25295 exp.last = last; 35203654Sgw25295 exp.hdl = hdl; 35213654Sgw25295 35223654Sgw25295 if (zfs_prop_iter(zfs_expand_proplist_cb, &exp, 35233654Sgw25295 B_FALSE) == ZFS_PROP_INVAL) 35243654Sgw25295 return (-1); 35252676Seschrock 35262676Seschrock /* 35272676Seschrock * Add 'name' to the beginning of the list, which is handled 35282676Seschrock * specially. 35292676Seschrock */ 35302676Seschrock if ((entry = zfs_alloc(hdl, 35312676Seschrock sizeof (zfs_proplist_t))) == NULL) 35322676Seschrock return (-1); 35332676Seschrock 35342676Seschrock entry->pl_prop = ZFS_PROP_NAME; 35352676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 35362676Seschrock &entry->pl_fixed); 35372676Seschrock entry->pl_all = B_TRUE; 35382676Seschrock entry->pl_next = *plp; 35392676Seschrock *plp = entry; 35402676Seschrock } 35412676Seschrock 35422676Seschrock userprops = zfs_get_user_props(zhp); 35432676Seschrock 35442676Seschrock entry = *plp; 35452676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 35462676Seschrock /* 35472676Seschrock * Go through and add any user properties as necessary. We 35482676Seschrock * start by incrementing our list pointer to the first 35492676Seschrock * non-native property. 35502676Seschrock */ 35512676Seschrock start = plp; 35522676Seschrock while (*start != NULL) { 35532676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 35542676Seschrock break; 35552676Seschrock start = &(*start)->pl_next; 35562676Seschrock } 35572676Seschrock 35582676Seschrock elem = NULL; 35592676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 35602676Seschrock /* 35612676Seschrock * See if we've already found this property in our list. 35622676Seschrock */ 35632676Seschrock for (last = start; *last != NULL; 35642676Seschrock last = &(*last)->pl_next) { 35652676Seschrock if (strcmp((*last)->pl_user_prop, 35662676Seschrock nvpair_name(elem)) == 0) 35672676Seschrock break; 35682676Seschrock } 35692676Seschrock 35702676Seschrock if (*last == NULL) { 35712676Seschrock if ((entry = zfs_alloc(hdl, 35722676Seschrock sizeof (zfs_proplist_t))) == NULL || 35732676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 35742676Seschrock nvpair_name(elem)))) == NULL) { 35752676Seschrock free(entry); 35762676Seschrock return (-1); 35772676Seschrock } 35782676Seschrock 35792676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 35802676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 35812676Seschrock entry->pl_all = B_TRUE; 35822676Seschrock *last = entry; 35832676Seschrock } 35842676Seschrock } 35852676Seschrock } 35862676Seschrock 35872676Seschrock /* 35882676Seschrock * Now go through and check the width of any non-fixed columns 35892676Seschrock */ 35902676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 35912676Seschrock if (entry->pl_fixed) 35922676Seschrock continue; 35932676Seschrock 35942676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 35952676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 35962676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 35972676Seschrock if (strlen(buf) > entry->pl_width) 35982676Seschrock entry->pl_width = strlen(buf); 35992676Seschrock } 36002676Seschrock } else if (nvlist_lookup_nvlist(userprops, 36012676Seschrock entry->pl_user_prop, &propval) == 0) { 36022676Seschrock verify(nvlist_lookup_string(propval, 36032676Seschrock ZFS_PROP_VALUE, &strval) == 0); 36042676Seschrock if (strlen(strval) > entry->pl_width) 36052676Seschrock entry->pl_width = strlen(strval); 36062676Seschrock } 36072676Seschrock } 36082676Seschrock 36092676Seschrock return (0); 36102676Seschrock } 3611