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 /* 683*3912Slling * Check if the bootfs name has the same pool name as it is set to. 684*3912Slling * Assuming bootfs is a valid dataset name. 685*3912Slling */ 686*3912Slling static boolean_t 687*3912Slling bootfs_poolname_valid(char *pool, char *bootfs) 688*3912Slling { 689*3912Slling char ch, *pname; 690*3912Slling 691*3912Slling /* get the pool name from the bootfs name */ 692*3912Slling pname = bootfs; 693*3912Slling while (*bootfs && !isspace(*bootfs) && *bootfs != '/') 694*3912Slling bootfs++; 695*3912Slling 696*3912Slling ch = *bootfs; 697*3912Slling *bootfs = 0; 698*3912Slling 699*3912Slling if (strcmp(pool, pname) == 0) { 700*3912Slling *bootfs = ch; 701*3912Slling return (B_TRUE); 702*3912Slling } 703*3912Slling 704*3912Slling *bootfs = ch; 705*3912Slling return (B_FALSE); 706*3912Slling } 707*3912Slling 708*3912Slling /* 7092676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 7102676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 7112676Seschrock * strings. 712789Sahrens */ 713*3912Slling nvlist_t * 714*3912Slling zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, 715*3912Slling nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 716789Sahrens { 7172676Seschrock nvpair_t *elem; 7182676Seschrock const char *propname; 7192676Seschrock zfs_prop_t prop; 7202676Seschrock uint64_t intval; 7212676Seschrock char *strval; 7222676Seschrock nvlist_t *ret; 723*3912Slling int isuser; 7242676Seschrock 7252676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 7262676Seschrock (void) no_memory(hdl); 7272676Seschrock return (NULL); 7282676Seschrock } 7292676Seschrock 7302676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 7312676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7323413Smmusante "snapshot properties cannot be modified")); 7332676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7342676Seschrock goto error; 735789Sahrens } 736789Sahrens 7372676Seschrock elem = NULL; 7382676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 7392676Seschrock propname = nvpair_name(elem); 7402676Seschrock 7412676Seschrock /* 7422676Seschrock * Make sure this property is valid and applies to this type. 7432676Seschrock */ 744*3912Slling if ((prop = zfs_name_to_prop_common(propname, type)) 745*3912Slling == ZFS_PROP_INVAL) { 746*3912Slling isuser = zfs_prop_user(propname); 747*3912Slling if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) { 7482676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7492676Seschrock "invalid property '%s'"), 7502676Seschrock propname); 7512676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7522676Seschrock goto error; 7532676Seschrock } else { 7542676Seschrock /* 7552676Seschrock * If this is a user property, make sure it's a 7562676Seschrock * string, and that it's less than 7572676Seschrock * ZAP_MAXNAMELEN. 7582676Seschrock */ 7592676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7602676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7612676Seschrock "'%s' must be a string"), 7622676Seschrock propname); 7632676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7642676Seschrock errbuf); 7652676Seschrock goto error; 7662676Seschrock } 7672676Seschrock 7682676Seschrock if (strlen(nvpair_name(elem)) >= 7692676Seschrock ZAP_MAXNAMELEN) { 7702676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7712676Seschrock "property name '%s' is too long"), 7722676Seschrock propname); 7732676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7742676Seschrock errbuf); 7752676Seschrock goto error; 7762676Seschrock } 7772676Seschrock } 7782676Seschrock 7792676Seschrock (void) nvpair_value_string(elem, &strval); 7802676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7812676Seschrock (void) no_memory(hdl); 7822676Seschrock goto error; 7832676Seschrock } 7842676Seschrock continue; 785789Sahrens } 7862676Seschrock 7872676Seschrock /* 7882676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7892676Seschrock */ 7902676Seschrock propname = zfs_prop_to_name(prop); 7912676Seschrock 7922676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7932676Seschrock zfs_error_aux(hdl, 7942676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7952676Seschrock "apply to datasets of this type"), propname); 7962676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7972676Seschrock goto error; 7982676Seschrock } 7992676Seschrock 8002676Seschrock if (zfs_prop_readonly(prop) && 8012676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 8022676Seschrock zfs_error_aux(hdl, 8032676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 8042676Seschrock propname); 8052676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 8062676Seschrock goto error; 8072676Seschrock } 8082676Seschrock 8092676Seschrock /* 8102676Seschrock * Convert any properties to the internal DSL value types. 8112676Seschrock */ 8122676Seschrock strval = NULL; 8132676Seschrock switch (zfs_prop_get_type(prop)) { 8142676Seschrock case prop_type_boolean: 8152676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 8162676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8172676Seschrock goto error; 8182676Seschrock } 819789Sahrens break; 8202676Seschrock 8212676Seschrock case prop_type_string: 8222676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 8232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8242676Seschrock "'%s' must be a string"), 8252676Seschrock propname); 8262676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8272676Seschrock goto error; 828789Sahrens } 8292676Seschrock (void) nvpair_value_string(elem, &strval); 8302676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 8312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8322676Seschrock "'%s' is too long"), propname); 8332676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8342676Seschrock goto error; 8352676Seschrock } 8362676Seschrock break; 8372676Seschrock 8382676Seschrock case prop_type_number: 8392676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 8402676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8412676Seschrock goto error; 8422676Seschrock } 8432676Seschrock break; 8442676Seschrock 8452676Seschrock case prop_type_index: 8462676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 8472676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8482676Seschrock goto error; 849789Sahrens } 850789Sahrens break; 851789Sahrens 8522676Seschrock default: 8532676Seschrock abort(); 8542676Seschrock } 8552676Seschrock 8562676Seschrock /* 8572676Seschrock * Add the result to our return set of properties. 8582676Seschrock */ 8592676Seschrock if (strval) { 8602676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8612676Seschrock (void) no_memory(hdl); 8622676Seschrock goto error; 863789Sahrens } 8642676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8652676Seschrock (void) no_memory(hdl); 8662676Seschrock goto error; 8672676Seschrock } 8682676Seschrock 8692676Seschrock /* 8702676Seschrock * Perform some additional checks for specific properties. 8712676Seschrock */ 8722676Seschrock switch (prop) { 8732676Seschrock case ZFS_PROP_RECORDSIZE: 8742676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8752676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8762676Seschrock if (intval < SPA_MINBLOCKSIZE || 8772676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8792676Seschrock "'%s' must be power of 2 from %u " 8802676Seschrock "to %uk"), propname, 8812676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8822676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8832676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8842676Seschrock goto error; 885789Sahrens } 886789Sahrens break; 887789Sahrens 8883126Sahl case ZFS_PROP_SHAREISCSI: 8893126Sahl if (strcmp(strval, "off") != 0 && 8903126Sahl strcmp(strval, "on") != 0 && 8913126Sahl strcmp(strval, "type=disk") != 0) { 8923126Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8933126Sahl "'%s' must be 'on', 'off', or 'type=disk'"), 8943126Sahl propname); 8953126Sahl (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8963126Sahl goto error; 8973126Sahl } 8983126Sahl 8993126Sahl break; 9003126Sahl 9012676Seschrock case ZFS_PROP_MOUNTPOINT: 9022676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 9032676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 9042676Seschrock break; 9052676Seschrock 9062676Seschrock if (strval[0] != '/') { 9072082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9082676Seschrock "'%s' must be an absolute path, " 9092676Seschrock "'none', or 'legacy'"), propname); 9102676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 9112676Seschrock goto error; 912789Sahrens } 9133126Sahl /*FALLTHRU*/ 9143126Sahl 9153126Sahl case ZFS_PROP_SHARENFS: 9163126Sahl /* 9173126Sahl * For the mountpoint and sharenfs properties, check if 9183126Sahl * it can be set in a global/non-global zone based on 9193126Sahl * the zoned property value: 9203126Sahl * 9213126Sahl * global zone non-global zone 9223126Sahl * -------------------------------------------------- 9233126Sahl * zoned=on mountpoint (no) mountpoint (yes) 9243126Sahl * sharenfs (no) sharenfs (no) 9253126Sahl * 9263126Sahl * zoned=off mountpoint (yes) N/A 9273126Sahl * sharenfs (yes) 9283126Sahl */ 9292676Seschrock if (zoned) { 9302676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 9312676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9322676Seschrock "'%s' cannot be set on " 9332676Seschrock "dataset in a non-global zone"), 9342676Seschrock propname); 9352676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9362676Seschrock errbuf); 9372676Seschrock goto error; 9382676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 9392676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9402676Seschrock "'%s' cannot be set in " 9412676Seschrock "a non-global zone"), propname); 9422676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9432676Seschrock errbuf); 9442676Seschrock goto error; 9452676Seschrock } 9462676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 9472676Seschrock /* 9482676Seschrock * If zoned property is 'off', this must be in 9492676Seschrock * a globle zone. If not, something is wrong. 9502676Seschrock */ 9512676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9522676Seschrock "'%s' cannot be set while dataset " 9532676Seschrock "'zoned' property is set"), propname); 9542676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 9552676Seschrock goto error; 9562676Seschrock } 9573126Sahl 9583126Sahl break; 959*3912Slling 960*3912Slling case ZFS_PROP_BOOTFS: 961*3912Slling /* 962*3912Slling * bootfs property value has to be a dataset name and 963*3912Slling * the dataset has to be in the same pool as it sets to. 964*3912Slling */ 965*3912Slling if (strval[0] != '\0' && (!zfs_name_valid(strval, 966*3912Slling ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid( 967*3912Slling pool_name, strval))) { 968*3912Slling 969*3912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 970*3912Slling "is an invalid name"), strval); 971*3912Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 972*3912Slling goto error; 973*3912Slling } 974*3912Slling break; 9752676Seschrock } 9762676Seschrock 9772676Seschrock /* 9782676Seschrock * For changes to existing volumes, we have some additional 9792676Seschrock * checks to enforce. 9802676Seschrock */ 9812676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9822676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9832676Seschrock ZFS_PROP_VOLSIZE); 9842676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9852676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9862676Seschrock char buf[64]; 9872676Seschrock 9882676Seschrock switch (prop) { 9892676Seschrock case ZFS_PROP_RESERVATION: 9902676Seschrock if (intval > volsize) { 9912676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9922676Seschrock "'%s' is greater than current " 9932676Seschrock "volume size"), propname); 9942676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9952676Seschrock errbuf); 9962676Seschrock goto error; 9972676Seschrock } 9982676Seschrock break; 9992676Seschrock 10002676Seschrock case ZFS_PROP_VOLSIZE: 10012676Seschrock if (intval % blocksize != 0) { 10022676Seschrock zfs_nicenum(blocksize, buf, 10032676Seschrock sizeof (buf)); 10042676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10052676Seschrock "'%s' must be a multiple of " 10062676Seschrock "volume block size (%s)"), 10072676Seschrock propname, buf); 10082676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 10092676Seschrock errbuf); 10102676Seschrock goto error; 10112676Seschrock } 10122676Seschrock 10132676Seschrock if (intval == 0) { 10142676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10152676Seschrock "'%s' cannot be zero"), 10162676Seschrock propname); 10172676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 10182676Seschrock errbuf); 10192676Seschrock goto error; 1020789Sahrens } 10213126Sahl break; 1022789Sahrens } 1023789Sahrens } 1024789Sahrens } 1025789Sahrens 10262676Seschrock /* 10272676Seschrock * If this is an existing volume, and someone is setting the volsize, 10282676Seschrock * make sure that it matches the reservation, or add it if necessary. 10292676Seschrock */ 10302676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 10312676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 10322676Seschrock &intval) == 0) { 10332676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 10342676Seschrock ZFS_PROP_VOLSIZE); 10352676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 10362676Seschrock ZFS_PROP_RESERVATION); 10372676Seschrock uint64_t new_reservation; 10382676Seschrock 10392676Seschrock if (old_volsize == old_reservation && 10402676Seschrock nvlist_lookup_uint64(ret, 10412676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 10422676Seschrock &new_reservation) != 0) { 10432676Seschrock if (nvlist_add_uint64(ret, 10442676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 10452676Seschrock intval) != 0) { 10462676Seschrock (void) no_memory(hdl); 10472676Seschrock goto error; 10482676Seschrock } 10492676Seschrock } 10502676Seschrock } 10512676Seschrock 10522676Seschrock return (ret); 10532676Seschrock 10542676Seschrock error: 10552676Seschrock nvlist_free(ret); 10562676Seschrock return (NULL); 1057789Sahrens } 1058789Sahrens 1059789Sahrens /* 1060789Sahrens * Given a property name and value, set the property for the given dataset. 1061789Sahrens */ 1062789Sahrens int 10632676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1064789Sahrens { 1065789Sahrens zfs_cmd_t zc = { 0 }; 10662676Seschrock int ret = -1; 10672676Seschrock prop_changelist_t *cl = NULL; 10682082Seschrock char errbuf[1024]; 10692082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 10702676Seschrock nvlist_t *nvl = NULL, *realprops; 10712676Seschrock zfs_prop_t prop; 10722082Seschrock 10732082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 10742676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 10752082Seschrock zhp->zfs_name); 10762082Seschrock 10772676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 10782676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 10792676Seschrock (void) no_memory(hdl); 10802676Seschrock goto error; 1081789Sahrens } 1082789Sahrens 1083*3912Slling if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl, 10842676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10852676Seschrock goto error; 10862676Seschrock nvlist_free(nvl); 10872676Seschrock nvl = realprops; 10882676Seschrock 10892676Seschrock prop = zfs_name_to_prop(propname); 10902676Seschrock 1091789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10922676Seschrock goto error; 1093789Sahrens 1094789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10962082Seschrock "child dataset with inherited mountpoint is used " 10972082Seschrock "in a non-global zone")); 10982082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1099789Sahrens goto error; 1100789Sahrens } 1101789Sahrens 1102789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1103789Sahrens goto error; 1104789Sahrens 1105789Sahrens /* 1106789Sahrens * Execute the corresponding ioctl() to set this property. 1107789Sahrens */ 1108789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1109789Sahrens 11102676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 11112676Seschrock goto error; 11122676Seschrock 11132676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1114789Sahrens 1115789Sahrens if (ret != 0) { 1116789Sahrens switch (errno) { 1117789Sahrens 1118789Sahrens case ENOSPC: 1119789Sahrens /* 1120789Sahrens * For quotas and reservations, ENOSPC indicates 1121789Sahrens * something different; setting a quota or reservation 1122789Sahrens * doesn't use any disk space. 1123789Sahrens */ 1124789Sahrens switch (prop) { 1125789Sahrens case ZFS_PROP_QUOTA: 11262082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11272082Seschrock "size is less than current used or " 11282082Seschrock "reserved space")); 11292082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1130789Sahrens break; 1131789Sahrens 1132789Sahrens case ZFS_PROP_RESERVATION: 11332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11342082Seschrock "size is greater than available space")); 11352082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1136789Sahrens break; 1137789Sahrens 1138789Sahrens default: 11392082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1140789Sahrens break; 1141789Sahrens } 1142789Sahrens break; 1143789Sahrens 1144789Sahrens case EBUSY: 11452082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 11462082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 11472082Seschrock else 11482676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1149789Sahrens break; 1150789Sahrens 11511175Slling case EROFS: 11522082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 11531175Slling break; 11541175Slling 11553886Sahl case ENOTSUP: 11563886Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11573886Sahl "pool must be upgraded to allow gzip compression")); 11583886Sahl (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 11593886Sahl break; 11603886Sahl 1161789Sahrens case EOVERFLOW: 1162789Sahrens /* 1163789Sahrens * This platform can't address a volume this big. 1164789Sahrens */ 1165789Sahrens #ifdef _ILP32 1166789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 11672082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1168789Sahrens break; 1169789Sahrens } 1170789Sahrens #endif 11712082Seschrock /* FALLTHROUGH */ 1172789Sahrens default: 11732082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1174789Sahrens } 1175789Sahrens } else { 1176789Sahrens /* 1177789Sahrens * Refresh the statistics so the new property value 1178789Sahrens * is reflected. 1179789Sahrens */ 11802676Seschrock if ((ret = changelist_postfix(cl)) == 0) 11812676Seschrock (void) get_stats(zhp); 1182789Sahrens } 1183789Sahrens 1184789Sahrens error: 11852676Seschrock nvlist_free(nvl); 11862676Seschrock zcmd_free_nvlists(&zc); 11872676Seschrock if (cl) 11882676Seschrock changelist_free(cl); 1189789Sahrens return (ret); 1190789Sahrens } 1191789Sahrens 1192789Sahrens /* 1193789Sahrens * Given a property, inherit the value from the parent dataset. 1194789Sahrens */ 1195789Sahrens int 11962676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1197789Sahrens { 1198789Sahrens zfs_cmd_t zc = { 0 }; 1199789Sahrens int ret; 1200789Sahrens prop_changelist_t *cl; 12012082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 12022082Seschrock char errbuf[1024]; 12032676Seschrock zfs_prop_t prop; 12042082Seschrock 12052082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 12062082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1207789Sahrens 12082676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 12092676Seschrock /* 12102676Seschrock * For user properties, the amount of work we have to do is very 12112676Seschrock * small, so just do it here. 12122676Seschrock */ 12132676Seschrock if (!zfs_prop_user(propname)) { 12142676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12152676Seschrock "invalid property")); 12162676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 12172676Seschrock } 12182676Seschrock 12192676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 12202676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 12212676Seschrock 12222676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 12232676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 12242676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 12252676Seschrock 12262676Seschrock return (0); 12272676Seschrock } 12282676Seschrock 1229789Sahrens /* 1230789Sahrens * Verify that this property is inheritable. 1231789Sahrens */ 12322082Seschrock if (zfs_prop_readonly(prop)) 12332082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 12342082Seschrock 12352082Seschrock if (!zfs_prop_inheritable(prop)) 12362082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1237789Sahrens 1238789Sahrens /* 1239789Sahrens * Check to see if the value applies to this type 1240789Sahrens */ 12412082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 12422082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1243789Sahrens 12443443Srm160521 /* 12453443Srm160521 * Normalize the name, to get rid of shorthand abbrevations. 12463443Srm160521 */ 12473443Srm160521 propname = zfs_prop_to_name(prop); 1248789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 12492676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1250789Sahrens 1251789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1252789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 12532082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12542082Seschrock "dataset is used in a non-global zone")); 12552082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1256789Sahrens } 1257789Sahrens 1258789Sahrens /* 1259789Sahrens * Determine datasets which will be affected by this change, if any. 1260789Sahrens */ 1261789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1262789Sahrens return (-1); 1263789Sahrens 1264789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 12652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12662082Seschrock "child dataset with inherited mountpoint is used " 12672082Seschrock "in a non-global zone")); 12682082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1269789Sahrens goto error; 1270789Sahrens } 1271789Sahrens 1272789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1273789Sahrens goto error; 1274789Sahrens 12752082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 12762082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 12772082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1278789Sahrens } else { 1279789Sahrens 12802169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1281789Sahrens goto error; 1282789Sahrens 1283789Sahrens /* 1284789Sahrens * Refresh the statistics so the new property is reflected. 1285789Sahrens */ 1286789Sahrens (void) get_stats(zhp); 1287789Sahrens } 1288789Sahrens 1289789Sahrens error: 1290789Sahrens changelist_free(cl); 1291789Sahrens return (ret); 1292789Sahrens } 1293789Sahrens 1294*3912Slling void 1295789Sahrens nicebool(int value, char *buf, size_t buflen) 1296789Sahrens { 1297789Sahrens if (value) 1298789Sahrens (void) strlcpy(buf, "on", buflen); 1299789Sahrens else 1300789Sahrens (void) strlcpy(buf, "off", buflen); 1301789Sahrens } 1302789Sahrens 1303789Sahrens /* 13041356Seschrock * True DSL properties are stored in an nvlist. The following two functions 13051356Seschrock * extract them appropriately. 13061356Seschrock */ 13071356Seschrock static uint64_t 13081356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13091356Seschrock { 13101356Seschrock nvlist_t *nv; 13111356Seschrock uint64_t value; 13121356Seschrock 13132885Sahrens *source = NULL; 13141356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13151356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 13161356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 13172885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13181356Seschrock } else { 13191356Seschrock value = zfs_prop_default_numeric(prop); 13201356Seschrock *source = ""; 13211356Seschrock } 13221356Seschrock 13231356Seschrock return (value); 13241356Seschrock } 13251356Seschrock 13261356Seschrock static char * 13271356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13281356Seschrock { 13291356Seschrock nvlist_t *nv; 13301356Seschrock char *value; 13311356Seschrock 13322885Sahrens *source = NULL; 13331356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13341356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 13351356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 13362885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13371356Seschrock } else { 13381356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 13391356Seschrock value = ""; 13401356Seschrock *source = ""; 13411356Seschrock } 13421356Seschrock 13431356Seschrock return (value); 13441356Seschrock } 13451356Seschrock 13461356Seschrock /* 1347789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1348789Sahrens * zfs_prop_get_int() are built using this interface. 1349789Sahrens * 1350789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1351789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1352789Sahrens * If they differ from the on-disk values, report the current values and mark 1353789Sahrens * the source "temporary". 1354789Sahrens */ 13552082Seschrock static int 1356789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 13572082Seschrock char **source, uint64_t *val) 1358789Sahrens { 1359789Sahrens struct mnttab mnt; 13603265Sahrens char *mntopt_on = NULL; 13613265Sahrens char *mntopt_off = NULL; 1362789Sahrens 1363789Sahrens *source = NULL; 1364789Sahrens 13653265Sahrens switch (prop) { 13663265Sahrens case ZFS_PROP_ATIME: 13673265Sahrens mntopt_on = MNTOPT_ATIME; 13683265Sahrens mntopt_off = MNTOPT_NOATIME; 13693265Sahrens break; 13703265Sahrens 13713265Sahrens case ZFS_PROP_DEVICES: 13723265Sahrens mntopt_on = MNTOPT_DEVICES; 13733265Sahrens mntopt_off = MNTOPT_NODEVICES; 13743265Sahrens break; 13753265Sahrens 13763265Sahrens case ZFS_PROP_EXEC: 13773265Sahrens mntopt_on = MNTOPT_EXEC; 13783265Sahrens mntopt_off = MNTOPT_NOEXEC; 13793265Sahrens break; 13803265Sahrens 13813265Sahrens case ZFS_PROP_READONLY: 13823265Sahrens mntopt_on = MNTOPT_RO; 13833265Sahrens mntopt_off = MNTOPT_RW; 13843265Sahrens break; 13853265Sahrens 13863265Sahrens case ZFS_PROP_SETUID: 13873265Sahrens mntopt_on = MNTOPT_SETUID; 13883265Sahrens mntopt_off = MNTOPT_NOSETUID; 13893265Sahrens break; 13903265Sahrens 13913265Sahrens case ZFS_PROP_XATTR: 13923265Sahrens mntopt_on = MNTOPT_XATTR; 13933265Sahrens mntopt_off = MNTOPT_NOXATTR; 13943265Sahrens break; 13953265Sahrens } 13963265Sahrens 13972474Seschrock /* 13982474Seschrock * Because looking up the mount options is potentially expensive 13992474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 14002474Seschrock * we're looking up a property which requires its presence. 14012474Seschrock */ 14022474Seschrock if (!zhp->zfs_mntcheck && 14033265Sahrens (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 14043265Sahrens struct mnttab entry, search = { 0 }; 14053265Sahrens FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 14062474Seschrock 14072474Seschrock search.mnt_special = (char *)zhp->zfs_name; 14082474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 14093265Sahrens rewind(mnttab); 14103265Sahrens 14113265Sahrens if (getmntany(mnttab, &entry, &search) == 0) { 14123265Sahrens zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 14133265Sahrens entry.mnt_mntopts); 14143265Sahrens if (zhp->zfs_mntopts == NULL) 14153265Sahrens return (-1); 14163265Sahrens } 14172474Seschrock 14182474Seschrock zhp->zfs_mntcheck = B_TRUE; 14192474Seschrock } 14202474Seschrock 1421789Sahrens if (zhp->zfs_mntopts == NULL) 1422789Sahrens mnt.mnt_mntopts = ""; 1423789Sahrens else 1424789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1425789Sahrens 1426789Sahrens switch (prop) { 1427789Sahrens case ZFS_PROP_ATIME: 14283265Sahrens case ZFS_PROP_DEVICES: 14293265Sahrens case ZFS_PROP_EXEC: 14303265Sahrens case ZFS_PROP_READONLY: 14313265Sahrens case ZFS_PROP_SETUID: 14323265Sahrens case ZFS_PROP_XATTR: 14332082Seschrock *val = getprop_uint64(zhp, prop, source); 14342082Seschrock 14353265Sahrens if (hasmntopt(&mnt, mntopt_on) && !*val) { 14362082Seschrock *val = B_TRUE; 1437789Sahrens if (src) 1438789Sahrens *src = ZFS_SRC_TEMPORARY; 14393265Sahrens } else if (hasmntopt(&mnt, mntopt_off) && *val) { 14402082Seschrock *val = B_FALSE; 1441789Sahrens if (src) 1442789Sahrens *src = ZFS_SRC_TEMPORARY; 1443789Sahrens } 14442082Seschrock break; 1445789Sahrens 1446789Sahrens case ZFS_PROP_RECORDSIZE: 1447789Sahrens case ZFS_PROP_COMPRESSION: 14481356Seschrock case ZFS_PROP_ZONED: 14492885Sahrens case ZFS_PROP_CREATION: 14502885Sahrens case ZFS_PROP_COMPRESSRATIO: 14512885Sahrens case ZFS_PROP_REFERENCED: 14522885Sahrens case ZFS_PROP_USED: 14532885Sahrens case ZFS_PROP_CREATETXG: 14542885Sahrens case ZFS_PROP_AVAILABLE: 14552885Sahrens case ZFS_PROP_VOLSIZE: 14562885Sahrens case ZFS_PROP_VOLBLOCKSIZE: 14573417Srm160521 *val = getprop_uint64(zhp, prop, source); 14583417Srm160521 break; 14593417Srm160521 14603265Sahrens case ZFS_PROP_CANMOUNT: 14612082Seschrock *val = getprop_uint64(zhp, prop, source); 14623417Srm160521 if (*val == 0) 14633417Srm160521 *source = zhp->zfs_name; 14643417Srm160521 else 14653417Srm160521 *source = ""; /* default */ 14662082Seschrock break; 1467789Sahrens 1468789Sahrens case ZFS_PROP_QUOTA: 1469789Sahrens case ZFS_PROP_RESERVATION: 14702885Sahrens *val = getprop_uint64(zhp, prop, source); 14712885Sahrens if (*val == 0) 1472789Sahrens *source = ""; /* default */ 1473789Sahrens else 1474789Sahrens *source = zhp->zfs_name; 14752082Seschrock break; 1476789Sahrens 1477789Sahrens case ZFS_PROP_MOUNTED: 14782082Seschrock *val = (zhp->zfs_mntopts != NULL); 14792082Seschrock break; 1480789Sahrens 14813377Seschrock case ZFS_PROP_NUMCLONES: 14823377Seschrock *val = zhp->zfs_dmustats.dds_num_clones; 14833377Seschrock break; 14843377Seschrock 1485789Sahrens default: 14862082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14872082Seschrock "cannot get non-numeric property")); 14882082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14892082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1490789Sahrens } 1491789Sahrens 1492789Sahrens return (0); 1493789Sahrens } 1494789Sahrens 1495789Sahrens /* 1496789Sahrens * Calculate the source type, given the raw source string. 1497789Sahrens */ 1498789Sahrens static void 1499789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1500789Sahrens char *statbuf, size_t statlen) 1501789Sahrens { 1502789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1503789Sahrens return; 1504789Sahrens 1505789Sahrens if (source == NULL) { 1506789Sahrens *srctype = ZFS_SRC_NONE; 1507789Sahrens } else if (source[0] == '\0') { 1508789Sahrens *srctype = ZFS_SRC_DEFAULT; 1509789Sahrens } else { 1510789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1511789Sahrens *srctype = ZFS_SRC_LOCAL; 1512789Sahrens } else { 1513789Sahrens (void) strlcpy(statbuf, source, statlen); 1514789Sahrens *srctype = ZFS_SRC_INHERITED; 1515789Sahrens } 1516789Sahrens } 1517789Sahrens 1518789Sahrens } 1519789Sahrens 1520789Sahrens /* 1521789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1522789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1523789Sahrens * human-readable form. 1524789Sahrens * 1525789Sahrens * Returns 0 on success, or -1 on error. 1526789Sahrens */ 1527789Sahrens int 1528789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 15292082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1530789Sahrens { 1531789Sahrens char *source = NULL; 1532789Sahrens uint64_t val; 1533789Sahrens char *str; 1534789Sahrens const char *root; 15352676Seschrock const char *strval; 1536789Sahrens 1537789Sahrens /* 1538789Sahrens * Check to see if this property applies to our object 1539789Sahrens */ 1540789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1541789Sahrens return (-1); 1542789Sahrens 1543789Sahrens if (src) 1544789Sahrens *src = ZFS_SRC_NONE; 1545789Sahrens 1546789Sahrens switch (prop) { 1547789Sahrens case ZFS_PROP_ATIME: 1548789Sahrens case ZFS_PROP_READONLY: 1549789Sahrens case ZFS_PROP_SETUID: 1550789Sahrens case ZFS_PROP_ZONED: 1551789Sahrens case ZFS_PROP_DEVICES: 1552789Sahrens case ZFS_PROP_EXEC: 15532676Seschrock case ZFS_PROP_CANMOUNT: 15543234Sck153898 case ZFS_PROP_XATTR: 1555789Sahrens /* 1556789Sahrens * Basic boolean values are built on top of 1557789Sahrens * get_numeric_property(). 1558789Sahrens */ 15592082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15602082Seschrock return (-1); 15612082Seschrock nicebool(val, propbuf, proplen); 1562789Sahrens 1563789Sahrens break; 1564789Sahrens 1565789Sahrens case ZFS_PROP_AVAILABLE: 1566789Sahrens case ZFS_PROP_RECORDSIZE: 1567789Sahrens case ZFS_PROP_CREATETXG: 1568789Sahrens case ZFS_PROP_REFERENCED: 1569789Sahrens case ZFS_PROP_USED: 1570789Sahrens case ZFS_PROP_VOLSIZE: 1571789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 15723377Seschrock case ZFS_PROP_NUMCLONES: 1573789Sahrens /* 1574789Sahrens * Basic numeric values are built on top of 1575789Sahrens * get_numeric_property(). 1576789Sahrens */ 15772082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15782082Seschrock return (-1); 1579789Sahrens if (literal) 15802856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 1581*3912Slling (u_longlong_t)val); 1582789Sahrens else 1583789Sahrens zfs_nicenum(val, propbuf, proplen); 1584789Sahrens break; 1585789Sahrens 1586789Sahrens case ZFS_PROP_COMPRESSION: 1587789Sahrens case ZFS_PROP_CHECKSUM: 1588789Sahrens case ZFS_PROP_SNAPDIR: 1589789Sahrens case ZFS_PROP_ACLMODE: 1590789Sahrens case ZFS_PROP_ACLINHERIT: 15913835Sahrens case ZFS_PROP_COPIES: 15921356Seschrock val = getprop_uint64(zhp, prop, &source); 15932676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15942676Seschrock (void) strlcpy(propbuf, strval, proplen); 1595789Sahrens break; 1596789Sahrens 1597789Sahrens case ZFS_PROP_CREATION: 1598789Sahrens /* 1599789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1600789Sahrens * this into a string unless 'literal' is specified. 1601789Sahrens */ 1602789Sahrens { 16032885Sahrens val = getprop_uint64(zhp, prop, &source); 16042885Sahrens time_t time = (time_t)val; 1605789Sahrens struct tm t; 1606789Sahrens 1607789Sahrens if (literal || 1608789Sahrens localtime_r(&time, &t) == NULL || 1609789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1610789Sahrens &t) == 0) 16112885Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1612789Sahrens } 1613789Sahrens break; 1614789Sahrens 1615789Sahrens case ZFS_PROP_MOUNTPOINT: 1616789Sahrens /* 1617789Sahrens * Getting the precise mountpoint can be tricky. 1618789Sahrens * 1619789Sahrens * - for 'none' or 'legacy', return those values. 1620789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1621789Sahrens * - for inherited mountpoints, we want to take everything 1622789Sahrens * after our ancestor and append it to the inherited value. 1623789Sahrens * 1624789Sahrens * If the pool has an alternate root, we want to prepend that 1625789Sahrens * root to any values we return. 1626789Sahrens */ 16271544Seschrock root = zhp->zfs_root; 16281356Seschrock str = getprop_string(zhp, prop, &source); 16291356Seschrock 16301356Seschrock if (str[0] == '\0') { 1631789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1632789Sahrens root, zhp->zfs_name); 16331356Seschrock } else if (str[0] == '/') { 16341356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1635789Sahrens 1636789Sahrens if (relpath[0] == '/') 1637789Sahrens relpath++; 16381356Seschrock if (str[1] == '\0') 16391356Seschrock str++; 1640789Sahrens 1641789Sahrens if (relpath[0] == '\0') 1642789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 16431356Seschrock root, str); 1644789Sahrens else 1645789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16461356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1647789Sahrens relpath); 1648789Sahrens } else { 1649789Sahrens /* 'legacy' or 'none' */ 16501356Seschrock (void) strlcpy(propbuf, str, proplen); 1651789Sahrens } 1652789Sahrens 1653789Sahrens break; 1654789Sahrens 1655789Sahrens case ZFS_PROP_SHARENFS: 16563126Sahl case ZFS_PROP_SHAREISCSI: 16573126Sahl case ZFS_PROP_ISCSIOPTIONS: 16581356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16591356Seschrock proplen); 1660789Sahrens break; 1661789Sahrens 1662789Sahrens case ZFS_PROP_ORIGIN: 16632885Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1664789Sahrens proplen); 1665789Sahrens /* 1666789Sahrens * If there is no parent at all, return failure to indicate that 1667789Sahrens * it doesn't apply to this dataset. 1668789Sahrens */ 1669789Sahrens if (propbuf[0] == '\0') 1670789Sahrens return (-1); 1671789Sahrens break; 1672789Sahrens 1673789Sahrens case ZFS_PROP_QUOTA: 1674789Sahrens case ZFS_PROP_RESERVATION: 16752082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16762082Seschrock return (-1); 1677789Sahrens 1678789Sahrens /* 1679789Sahrens * If quota or reservation is 0, we translate this into 'none' 1680789Sahrens * (unless literal is set), and indicate that it's the default 1681789Sahrens * value. Otherwise, we print the number nicely and indicate 1682789Sahrens * that its set locally. 1683789Sahrens */ 1684789Sahrens if (val == 0) { 1685789Sahrens if (literal) 1686789Sahrens (void) strlcpy(propbuf, "0", proplen); 1687789Sahrens else 1688789Sahrens (void) strlcpy(propbuf, "none", proplen); 1689789Sahrens } else { 1690789Sahrens if (literal) 16912856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 1692*3912Slling (u_longlong_t)val); 1693789Sahrens else 1694789Sahrens zfs_nicenum(val, propbuf, proplen); 1695789Sahrens } 1696789Sahrens break; 1697789Sahrens 1698789Sahrens case ZFS_PROP_COMPRESSRATIO: 16992082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 17002082Seschrock return (-1); 17012856Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 17022856Snd150628 val / 100, (longlong_t)val % 100); 1703789Sahrens break; 1704789Sahrens 1705789Sahrens case ZFS_PROP_TYPE: 1706789Sahrens switch (zhp->zfs_type) { 1707789Sahrens case ZFS_TYPE_FILESYSTEM: 1708789Sahrens str = "filesystem"; 1709789Sahrens break; 1710789Sahrens case ZFS_TYPE_VOLUME: 1711789Sahrens str = "volume"; 1712789Sahrens break; 1713789Sahrens case ZFS_TYPE_SNAPSHOT: 1714789Sahrens str = "snapshot"; 1715789Sahrens break; 1716789Sahrens default: 17172082Seschrock abort(); 1718789Sahrens } 1719789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1720789Sahrens break; 1721789Sahrens 1722789Sahrens case ZFS_PROP_MOUNTED: 1723789Sahrens /* 1724789Sahrens * The 'mounted' property is a pseudo-property that described 1725789Sahrens * whether the filesystem is currently mounted. Even though 1726789Sahrens * it's a boolean value, the typical values of "on" and "off" 1727789Sahrens * don't make sense, so we translate to "yes" and "no". 1728789Sahrens */ 17292082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 17302082Seschrock src, &source, &val) != 0) 17312082Seschrock return (-1); 17322082Seschrock if (val) 1733789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1734789Sahrens else 1735789Sahrens (void) strlcpy(propbuf, "no", proplen); 1736789Sahrens break; 1737789Sahrens 1738789Sahrens case ZFS_PROP_NAME: 1739789Sahrens /* 1740789Sahrens * The 'name' property is a pseudo-property derived from the 1741789Sahrens * dataset name. It is presented as a real property to simplify 1742789Sahrens * consumers. 1743789Sahrens */ 1744789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1745789Sahrens break; 1746789Sahrens 1747789Sahrens default: 17482082Seschrock abort(); 1749789Sahrens } 1750789Sahrens 1751789Sahrens get_source(zhp, src, source, statbuf, statlen); 1752789Sahrens 1753789Sahrens return (0); 1754789Sahrens } 1755789Sahrens 1756789Sahrens /* 1757789Sahrens * Utility function to get the given numeric property. Does no validation that 1758789Sahrens * the given property is the appropriate type; should only be used with 1759789Sahrens * hard-coded property types. 1760789Sahrens */ 1761789Sahrens uint64_t 1762789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1763789Sahrens { 1764789Sahrens char *source; 1765789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17662082Seschrock uint64_t val; 17672082Seschrock 17682082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17692082Seschrock 17702082Seschrock return (val); 1771789Sahrens } 1772789Sahrens 1773789Sahrens /* 1774789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1775789Sahrens */ 1776789Sahrens int 1777789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1778789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1779789Sahrens { 1780789Sahrens char *source; 1781789Sahrens 1782789Sahrens /* 1783789Sahrens * Check to see if this property applies to our object 1784789Sahrens */ 1785789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17863237Slling return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 17872082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17882082Seschrock zfs_prop_to_name(prop))); 1789789Sahrens 1790789Sahrens if (src) 1791789Sahrens *src = ZFS_SRC_NONE; 1792789Sahrens 17932082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17942082Seschrock return (-1); 1795789Sahrens 1796789Sahrens get_source(zhp, src, source, statbuf, statlen); 1797789Sahrens 1798789Sahrens return (0); 1799789Sahrens } 1800789Sahrens 1801789Sahrens /* 1802789Sahrens * Returns the name of the given zfs handle. 1803789Sahrens */ 1804789Sahrens const char * 1805789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1806789Sahrens { 1807789Sahrens return (zhp->zfs_name); 1808789Sahrens } 1809789Sahrens 1810789Sahrens /* 1811789Sahrens * Returns the type of the given zfs handle. 1812789Sahrens */ 1813789Sahrens zfs_type_t 1814789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1815789Sahrens { 1816789Sahrens return (zhp->zfs_type); 1817789Sahrens } 1818789Sahrens 1819789Sahrens /* 18201356Seschrock * Iterate over all child filesystems 1821789Sahrens */ 1822789Sahrens int 18231356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1824789Sahrens { 1825789Sahrens zfs_cmd_t zc = { 0 }; 1826789Sahrens zfs_handle_t *nzhp; 1827789Sahrens int ret; 1828789Sahrens 1829789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18302082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1831789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1832789Sahrens /* 1833789Sahrens * Ignore private dataset names. 1834789Sahrens */ 1835789Sahrens if (dataset_name_hidden(zc.zc_name)) 1836789Sahrens continue; 1837789Sahrens 1838789Sahrens /* 1839789Sahrens * Silently ignore errors, as the only plausible explanation is 1840789Sahrens * that the pool has since been removed. 1841789Sahrens */ 18422082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18432082Seschrock zc.zc_name)) == NULL) 1844789Sahrens continue; 1845789Sahrens 1846789Sahrens if ((ret = func(nzhp, data)) != 0) 1847789Sahrens return (ret); 1848789Sahrens } 1849789Sahrens 1850789Sahrens /* 1851789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1852789Sahrens * returned, then the underlying dataset has been removed since we 1853789Sahrens * obtained the handle. 1854789Sahrens */ 1855789Sahrens if (errno != ESRCH && errno != ENOENT) 18562082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18572082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1858789Sahrens 18591356Seschrock return (0); 18601356Seschrock } 18611356Seschrock 18621356Seschrock /* 18631356Seschrock * Iterate over all snapshots 18641356Seschrock */ 18651356Seschrock int 18661356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18671356Seschrock { 18681356Seschrock zfs_cmd_t zc = { 0 }; 18691356Seschrock zfs_handle_t *nzhp; 18701356Seschrock int ret; 1871789Sahrens 1872789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18732082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18742082Seschrock &zc) == 0; 1875789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1876789Sahrens 18772082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18782082Seschrock zc.zc_name)) == NULL) 1879789Sahrens continue; 1880789Sahrens 1881789Sahrens if ((ret = func(nzhp, data)) != 0) 1882789Sahrens return (ret); 1883789Sahrens } 1884789Sahrens 1885789Sahrens /* 1886789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1887789Sahrens * returned, then the underlying dataset has been removed since we 1888789Sahrens * obtained the handle. Silently ignore this case, and return success. 1889789Sahrens */ 1890789Sahrens if (errno != ESRCH && errno != ENOENT) 18912082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18922082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1893789Sahrens 1894789Sahrens return (0); 1895789Sahrens } 1896789Sahrens 1897789Sahrens /* 18981356Seschrock * Iterate over all children, snapshots and filesystems 18991356Seschrock */ 19001356Seschrock int 19011356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 19021356Seschrock { 19031356Seschrock int ret; 19041356Seschrock 19051356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 19061356Seschrock return (ret); 19071356Seschrock 19081356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 19091356Seschrock } 19101356Seschrock 19111356Seschrock /* 1912789Sahrens * Given a complete name, return just the portion that refers to the parent. 1913789Sahrens * Can return NULL if this is a pool. 1914789Sahrens */ 1915789Sahrens static int 1916789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1917789Sahrens { 1918789Sahrens char *loc; 1919789Sahrens 1920789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1921789Sahrens return (-1); 1922789Sahrens 1923789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1924789Sahrens buf[loc - path] = '\0'; 1925789Sahrens 1926789Sahrens return (0); 1927789Sahrens } 1928789Sahrens 1929789Sahrens /* 19302676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 19312676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 19322676Seschrock * when creating new datasets. 1933789Sahrens */ 1934789Sahrens static int 19352676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1936789Sahrens { 1937789Sahrens zfs_cmd_t zc = { 0 }; 1938789Sahrens char parent[ZFS_MAXNAMELEN]; 1939789Sahrens char *slash; 19401356Seschrock zfs_handle_t *zhp; 19412082Seschrock char errbuf[1024]; 19422082Seschrock 19432082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 19442082Seschrock path); 1945789Sahrens 1946789Sahrens /* get parent, and check to see if this is just a pool */ 1947789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 19482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19492082Seschrock "missing dataset name")); 19502082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1951789Sahrens } 1952789Sahrens 1953789Sahrens /* check to see if the pool exists */ 1954789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1955789Sahrens slash = parent + strlen(parent); 1956789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1957789Sahrens zc.zc_name[slash - parent] = '\0'; 19582082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1959789Sahrens errno == ENOENT) { 19602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19612082Seschrock "no such pool '%s'"), zc.zc_name); 19622082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1963789Sahrens } 1964789Sahrens 1965789Sahrens /* check to see if the parent dataset exists */ 19662082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1967789Sahrens switch (errno) { 1968789Sahrens case ENOENT: 19692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19702082Seschrock "parent does not exist")); 19712082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1972789Sahrens 1973789Sahrens default: 19742082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1975789Sahrens } 1976789Sahrens } 1977789Sahrens 19782676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1979789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19802676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19812082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19821356Seschrock zfs_close(zhp); 1983789Sahrens return (-1); 1984789Sahrens } 1985789Sahrens 1986789Sahrens /* make sure parent is a filesystem */ 19871356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19892082Seschrock "parent is not a filesystem")); 19902082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19911356Seschrock zfs_close(zhp); 1992789Sahrens return (-1); 1993789Sahrens } 1994789Sahrens 19951356Seschrock zfs_close(zhp); 1996789Sahrens return (0); 1997789Sahrens } 1998789Sahrens 1999789Sahrens /* 20002676Seschrock * Create a new filesystem or volume. 2001789Sahrens */ 2002789Sahrens int 20032082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 20042676Seschrock nvlist_t *props) 2005789Sahrens { 2006789Sahrens zfs_cmd_t zc = { 0 }; 2007789Sahrens int ret; 2008789Sahrens uint64_t size = 0; 2009789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 20102082Seschrock char errbuf[1024]; 20112676Seschrock uint64_t zoned; 20122082Seschrock 20132082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20142082Seschrock "cannot create '%s'"), path); 2015789Sahrens 2016789Sahrens /* validate the path, taking care to note the extended error message */ 20172082Seschrock if (!zfs_validate_name(hdl, path, type)) 20182082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2019789Sahrens 2020789Sahrens /* validate parents exist */ 20212676Seschrock if (check_parents(hdl, path, &zoned) != 0) 2022789Sahrens return (-1); 2023789Sahrens 2024789Sahrens /* 2025789Sahrens * The failure modes when creating a dataset of a different type over 2026789Sahrens * one that already exists is a little strange. In particular, if you 2027789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 2028789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 2029789Sahrens * first try to see if the dataset exists. 2030789Sahrens */ 2031789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 20322082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 20332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20342082Seschrock "dataset already exists")); 20352082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2036789Sahrens } 2037789Sahrens 2038789Sahrens if (type == ZFS_TYPE_VOLUME) 2039789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2040789Sahrens else 2041789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2042789Sahrens 2043*3912Slling if (props && (props = zfs_validate_properties(hdl, type, NULL, props, 2044*3912Slling zoned, NULL, errbuf)) == 0) 20452676Seschrock return (-1); 20462676Seschrock 2047789Sahrens if (type == ZFS_TYPE_VOLUME) { 20481133Seschrock /* 20491133Seschrock * If we are creating a volume, the size and block size must 20501133Seschrock * satisfy a few restraints. First, the blocksize must be a 20511133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20521133Seschrock * volsize must be a multiple of the block size, and cannot be 20531133Seschrock * zero. 20541133Seschrock */ 20552676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 20562676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 20572676Seschrock nvlist_free(props); 20582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20592676Seschrock "missing volume size")); 20602676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2061789Sahrens } 2062789Sahrens 20632676Seschrock if ((ret = nvlist_lookup_uint64(props, 20642676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20652676Seschrock &blocksize)) != 0) { 20662676Seschrock if (ret == ENOENT) { 20672676Seschrock blocksize = zfs_prop_default_numeric( 20682676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20692676Seschrock } else { 20702676Seschrock nvlist_free(props); 20712676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20722676Seschrock "missing volume block size")); 20732676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20742676Seschrock } 20752676Seschrock } 20762676Seschrock 20772676Seschrock if (size == 0) { 20782676Seschrock nvlist_free(props); 20792082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20802676Seschrock "volume size cannot be zero")); 20812676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20821133Seschrock } 20831133Seschrock 20841133Seschrock if (size % blocksize != 0) { 20852676Seschrock nvlist_free(props); 20862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20872676Seschrock "volume size must be a multiple of volume block " 20882676Seschrock "size")); 20892676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20901133Seschrock } 2091789Sahrens } 2092789Sahrens 20932676Seschrock if (props && 20942676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20952676Seschrock return (-1); 20962676Seschrock nvlist_free(props); 20972676Seschrock 2098789Sahrens /* create the dataset */ 20992082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2100789Sahrens 2101*3912Slling if (ret == 0 && type == ZFS_TYPE_VOLUME) { 21022082Seschrock ret = zvol_create_link(hdl, path); 2103*3912Slling if (ret) { 2104*3912Slling (void) zfs_standard_error(hdl, errno, 2105*3912Slling dgettext(TEXT_DOMAIN, 2106*3912Slling "Volume successfully created, but device links " 2107*3912Slling "were not created")); 2108*3912Slling zcmd_free_nvlists(&zc); 2109*3912Slling return (-1); 2110*3912Slling } 2111*3912Slling } 2112789Sahrens 21132676Seschrock zcmd_free_nvlists(&zc); 21142676Seschrock 2115789Sahrens /* check for failure */ 2116789Sahrens if (ret != 0) { 2117789Sahrens char parent[ZFS_MAXNAMELEN]; 2118789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2119789Sahrens 2120789Sahrens switch (errno) { 2121789Sahrens case ENOENT: 21222082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21232082Seschrock "no such parent '%s'"), parent); 21242082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2125789Sahrens 2126789Sahrens case EINVAL: 21272082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21283413Smmusante "parent '%s' is not a filesystem"), parent); 21292082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2130789Sahrens 2131789Sahrens case EDOM: 21322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21332676Seschrock "volume block size must be power of 2 from " 21342676Seschrock "%u to %uk"), 2135789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2136789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 21372082Seschrock 21382676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 21392082Seschrock 2140789Sahrens #ifdef _ILP32 2141789Sahrens case EOVERFLOW: 2142789Sahrens /* 2143789Sahrens * This platform can't address a volume this big. 2144789Sahrens */ 21452082Seschrock if (type == ZFS_TYPE_VOLUME) 21462082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 21472082Seschrock errbuf)); 2148789Sahrens #endif 21492082Seschrock /* FALLTHROUGH */ 2150789Sahrens default: 21512082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2152789Sahrens } 2153789Sahrens } 2154789Sahrens 2155789Sahrens return (0); 2156789Sahrens } 2157789Sahrens 2158789Sahrens /* 2159789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2160789Sahrens * isn't mounted, and that there are no active dependents. 2161789Sahrens */ 2162789Sahrens int 2163789Sahrens zfs_destroy(zfs_handle_t *zhp) 2164789Sahrens { 2165789Sahrens zfs_cmd_t zc = { 0 }; 2166789Sahrens 2167789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2168789Sahrens 21692676Seschrock if (ZFS_IS_VOLUME(zhp)) { 21703126Sahl /* 21713126Sahl * Unconditionally unshare this zvol ignoring failure as it 21723126Sahl * indicates only that the volume wasn't shared initially. 21733126Sahl */ 21743126Sahl (void) zfs_unshare_iscsi(zhp); 21753126Sahl 21762082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2177789Sahrens return (-1); 2178789Sahrens 2179789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2180789Sahrens } else { 2181789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2182789Sahrens } 2183789Sahrens 21843126Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 21853237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 21862082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21872082Seschrock zhp->zfs_name)); 21882199Sahrens } 2189789Sahrens 2190789Sahrens remove_mountpoint(zhp); 2191789Sahrens 2192789Sahrens return (0); 2193789Sahrens } 2194789Sahrens 21952199Sahrens struct destroydata { 21962199Sahrens char *snapname; 21972199Sahrens boolean_t gotone; 21983265Sahrens boolean_t closezhp; 21992199Sahrens }; 22002199Sahrens 22012199Sahrens static int 22022199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 22032199Sahrens { 22042199Sahrens struct destroydata *dd = arg; 22052199Sahrens zfs_handle_t *szhp; 22062199Sahrens char name[ZFS_MAXNAMELEN]; 22073265Sahrens boolean_t closezhp = dd->closezhp; 22083265Sahrens int rv; 22092199Sahrens 22102676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 22112676Seschrock (void) strlcat(name, "@", sizeof (name)); 22122676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 22132199Sahrens 22142199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 22152199Sahrens if (szhp) { 22162199Sahrens dd->gotone = B_TRUE; 22172199Sahrens zfs_close(szhp); 22182199Sahrens } 22192199Sahrens 22202199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 22212199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 22222199Sahrens /* 22232199Sahrens * NB: this is simply a best-effort. We don't want to 22242199Sahrens * return an error, because then we wouldn't visit all 22252199Sahrens * the volumes. 22262199Sahrens */ 22272199Sahrens } 22282199Sahrens 22293265Sahrens dd->closezhp = B_TRUE; 22303265Sahrens rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 22313265Sahrens if (closezhp) 22323265Sahrens zfs_close(zhp); 22333265Sahrens return (rv); 22342199Sahrens } 22352199Sahrens 22362199Sahrens /* 22372199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 22382199Sahrens */ 22392199Sahrens int 22402199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 22412199Sahrens { 22422199Sahrens zfs_cmd_t zc = { 0 }; 22432199Sahrens int ret; 22442199Sahrens struct destroydata dd = { 0 }; 22452199Sahrens 22462199Sahrens dd.snapname = snapname; 22472199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 22482199Sahrens 22492199Sahrens if (!dd.gotone) { 22503237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 22512199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 22522199Sahrens zhp->zfs_name, snapname)); 22532199Sahrens } 22542199Sahrens 22552199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22562676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 22572199Sahrens 22582199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 22592199Sahrens if (ret != 0) { 22602199Sahrens char errbuf[1024]; 22612199Sahrens 22622199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22632199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22642199Sahrens 22652199Sahrens switch (errno) { 22662199Sahrens case EEXIST: 22672199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22682199Sahrens "snapshot is cloned")); 22692199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22702199Sahrens 22712199Sahrens default: 22722199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22732199Sahrens errbuf)); 22742199Sahrens } 22752199Sahrens } 22762199Sahrens 22772199Sahrens return (0); 22782199Sahrens } 22792199Sahrens 2280789Sahrens /* 2281789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2282789Sahrens */ 2283789Sahrens int 22842676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2285789Sahrens { 2286789Sahrens zfs_cmd_t zc = { 0 }; 2287789Sahrens char parent[ZFS_MAXNAMELEN]; 2288789Sahrens int ret; 22892082Seschrock char errbuf[1024]; 22902082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22912676Seschrock zfs_type_t type; 22922676Seschrock uint64_t zoned; 2293789Sahrens 2294789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2295789Sahrens 22962082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22972082Seschrock "cannot create '%s'"), target); 22982082Seschrock 2299789Sahrens /* validate the target name */ 23002082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 23012082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2302789Sahrens 2303789Sahrens /* validate parents exist */ 23042676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2305789Sahrens return (-1); 2306789Sahrens 2307789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2308789Sahrens 2309789Sahrens /* do the clone */ 23102676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2311789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 23122744Snn35248 type = ZFS_TYPE_VOLUME; 23132676Seschrock } else { 2314789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 23152744Snn35248 type = ZFS_TYPE_FILESYSTEM; 23162676Seschrock } 23172676Seschrock 23182676Seschrock if (props) { 2319*3912Slling if ((props = zfs_validate_properties(hdl, type, NULL, props, 2320*3912Slling zoned, zhp, errbuf)) == NULL) 23212676Seschrock return (-1); 23222676Seschrock 23232676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 23242676Seschrock nvlist_free(props); 23252676Seschrock return (-1); 23262676Seschrock } 23272676Seschrock 23282676Seschrock nvlist_free(props); 23292676Seschrock } 2330789Sahrens 2331789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 23322676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 23332082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2334789Sahrens 23352676Seschrock zcmd_free_nvlists(&zc); 23362676Seschrock 2337789Sahrens if (ret != 0) { 2338789Sahrens switch (errno) { 2339789Sahrens 2340789Sahrens case ENOENT: 2341789Sahrens /* 2342789Sahrens * The parent doesn't exist. We should have caught this 2343789Sahrens * above, but there may a race condition that has since 2344789Sahrens * destroyed the parent. 2345789Sahrens * 2346789Sahrens * At this point, we don't know whether it's the source 2347789Sahrens * that doesn't exist anymore, or whether the target 2348789Sahrens * dataset doesn't exist. 2349789Sahrens */ 23502082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23512082Seschrock "no such parent '%s'"), parent); 23522082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 23532082Seschrock 23542082Seschrock case EXDEV: 23552082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23562082Seschrock "source and target pools differ")); 23572082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 23582082Seschrock errbuf)); 23592082Seschrock 23602082Seschrock default: 23612082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 23622082Seschrock errbuf)); 23632082Seschrock } 23642676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 23652082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 23662082Seschrock } 23672082Seschrock 23682082Seschrock return (ret); 23692082Seschrock } 23702082Seschrock 23712082Seschrock typedef struct promote_data { 23722082Seschrock char cb_mountpoint[MAXPATHLEN]; 23732082Seschrock const char *cb_target; 23742082Seschrock const char *cb_errbuf; 23752082Seschrock uint64_t cb_pivot_txg; 23762082Seschrock } promote_data_t; 23772082Seschrock 23782082Seschrock static int 23792082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 23802082Seschrock { 23812082Seschrock promote_data_t *pd = data; 23822082Seschrock zfs_handle_t *szhp; 23832082Seschrock char snapname[MAXPATHLEN]; 23843265Sahrens int rv = 0; 23852082Seschrock 23862082Seschrock /* We don't care about snapshots after the pivot point */ 23873265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 23883265Sahrens zfs_close(zhp); 23892082Seschrock return (0); 23903265Sahrens } 23912082Seschrock 23922417Sahrens /* Remove the device link if it's a zvol. */ 23932676Seschrock if (ZFS_IS_VOLUME(zhp)) 23942417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23952082Seschrock 23962082Seschrock /* Check for conflicting names */ 23972676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 23982676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 23992082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 24002082Seschrock if (szhp != NULL) { 24012082Seschrock zfs_close(szhp); 24022082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 24032082Seschrock "snapshot name '%s' from origin \n" 24042082Seschrock "conflicts with '%s' from target"), 24052082Seschrock zhp->zfs_name, snapname); 24063265Sahrens rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 24072082Seschrock } 24083265Sahrens zfs_close(zhp); 24093265Sahrens return (rv); 24102082Seschrock } 24112082Seschrock 24122417Sahrens static int 24132417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 24142417Sahrens { 24152417Sahrens promote_data_t *pd = data; 24162417Sahrens 24172417Sahrens /* We don't care about snapshots after the pivot point */ 24183265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 24193265Sahrens /* Create the device link if it's a zvol. */ 24203265Sahrens if (ZFS_IS_VOLUME(zhp)) 24213265Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 24223265Sahrens } 24233265Sahrens 24243265Sahrens zfs_close(zhp); 24252417Sahrens return (0); 24262417Sahrens } 24272417Sahrens 24282082Seschrock /* 24292082Seschrock * Promotes the given clone fs to be the clone parent. 24302082Seschrock */ 24312082Seschrock int 24322082Seschrock zfs_promote(zfs_handle_t *zhp) 24332082Seschrock { 24342082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 24352082Seschrock zfs_cmd_t zc = { 0 }; 24362082Seschrock char parent[MAXPATHLEN]; 24372082Seschrock char *cp; 24382082Seschrock int ret; 24392082Seschrock zfs_handle_t *pzhp; 24402082Seschrock promote_data_t pd; 24412082Seschrock char errbuf[1024]; 24422082Seschrock 24432082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24442082Seschrock "cannot promote '%s'"), zhp->zfs_name); 24452082Seschrock 24462082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 24472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24482082Seschrock "snapshots can not be promoted")); 24492082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24502082Seschrock } 24512082Seschrock 24522676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 24532082Seschrock if (parent[0] == '\0') { 24542082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24552082Seschrock "not a cloned filesystem")); 24562082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24572082Seschrock } 24582082Seschrock cp = strchr(parent, '@'); 24592082Seschrock *cp = '\0'; 24602082Seschrock 24612082Seschrock /* Walk the snapshots we will be moving */ 24622082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 24632082Seschrock if (pzhp == NULL) 24642082Seschrock return (-1); 24652082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 24662082Seschrock zfs_close(pzhp); 24672082Seschrock pd.cb_target = zhp->zfs_name; 24682082Seschrock pd.cb_errbuf = errbuf; 24692082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 24702082Seschrock if (pzhp == NULL) 24712082Seschrock return (-1); 24722082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 24732082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 24742082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24752417Sahrens if (ret != 0) { 24762417Sahrens zfs_close(pzhp); 24772082Seschrock return (-1); 24782417Sahrens } 24792082Seschrock 24802082Seschrock /* issue the ioctl */ 24812676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 24822676Seschrock sizeof (zc.zc_value)); 24832082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24842082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 24852082Seschrock 24862082Seschrock if (ret != 0) { 24872417Sahrens int save_errno = errno; 24882417Sahrens 24892417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24902417Sahrens zfs_close(pzhp); 24912417Sahrens 24922417Sahrens switch (save_errno) { 2493789Sahrens case EEXIST: 2494789Sahrens /* 24952082Seschrock * There is a conflicting snapshot name. We 24962082Seschrock * should have caught this above, but they could 24972082Seschrock * have renamed something in the mean time. 2498789Sahrens */ 24992082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25002082Seschrock "conflicting snapshot name from parent '%s'"), 25012082Seschrock parent); 25022082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2503789Sahrens 2504789Sahrens default: 25052417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2506789Sahrens } 25072417Sahrens } else { 25082417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2509789Sahrens } 2510789Sahrens 25112417Sahrens zfs_close(pzhp); 2512789Sahrens return (ret); 2513789Sahrens } 2514789Sahrens 25152199Sahrens static int 25162199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 25172199Sahrens { 25182199Sahrens char *snapname = arg; 25192676Seschrock int ret; 25202199Sahrens 25212199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 25222199Sahrens char name[MAXPATHLEN]; 25232199Sahrens 25242676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 25252676Seschrock (void) strlcat(name, "@", sizeof (name)); 25262676Seschrock (void) strlcat(name, snapname, sizeof (name)); 25272199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 25282199Sahrens /* 25292199Sahrens * NB: this is simply a best-effort. We don't want to 25302199Sahrens * return an error, because then we wouldn't visit all 25312199Sahrens * the volumes. 25322199Sahrens */ 25332199Sahrens } 25342676Seschrock 25352676Seschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 25362676Seschrock 25372676Seschrock zfs_close(zhp); 25382676Seschrock 25392676Seschrock return (ret); 25402199Sahrens } 25412199Sahrens 2542789Sahrens /* 25433504Sahl * Takes a snapshot of the given dataset. 2544789Sahrens */ 2545789Sahrens int 25462199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2547789Sahrens { 2548789Sahrens const char *delim; 2549789Sahrens char *parent; 2550789Sahrens zfs_handle_t *zhp; 2551789Sahrens zfs_cmd_t zc = { 0 }; 2552789Sahrens int ret; 25532082Seschrock char errbuf[1024]; 25542082Seschrock 25552082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25562082Seschrock "cannot snapshot '%s'"), path); 25572082Seschrock 25582082Seschrock /* validate the target name */ 25592082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 25602082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2561789Sahrens 2562789Sahrens /* make sure the parent exists and is of the appropriate type */ 25632199Sahrens delim = strchr(path, '@'); 25642082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 25652082Seschrock return (-1); 2566789Sahrens (void) strncpy(parent, path, delim - path); 2567789Sahrens parent[delim - path] = '\0'; 2568789Sahrens 25692082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2570789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2571789Sahrens free(parent); 2572789Sahrens return (-1); 2573789Sahrens } 2574789Sahrens 25752199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25762676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25772199Sahrens zc.zc_cookie = recursive; 25782199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 25792199Sahrens 25802199Sahrens /* 25812199Sahrens * if it was recursive, the one that actually failed will be in 25822199Sahrens * zc.zc_name. 25832199Sahrens */ 25842199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25852676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25862199Sahrens if (ret == 0 && recursive) { 25872199Sahrens (void) zfs_iter_filesystems(zhp, 25882199Sahrens zfs_create_link_cb, (char *)delim+1); 25892199Sahrens } 2590789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 25912082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25922199Sahrens if (ret != 0) { 25932082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 25942082Seschrock &zc); 25952199Sahrens } 2596789Sahrens } 2597789Sahrens 25982082Seschrock if (ret != 0) 25992082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2600789Sahrens 2601789Sahrens free(parent); 2602789Sahrens zfs_close(zhp); 2603789Sahrens 2604789Sahrens return (ret); 2605789Sahrens } 2606789Sahrens 2607789Sahrens /* 26083504Sahl * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 26093504Sahl * NULL) to the file descriptor specified by outfd. 2610789Sahrens */ 2611789Sahrens int 26123504Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2613789Sahrens { 2614789Sahrens zfs_cmd_t zc = { 0 }; 26152082Seschrock char errbuf[1024]; 26162885Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 26172082Seschrock 26183504Sahl assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 26193504Sahl 26202885Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 26212885Sahrens if (fromsnap) 26222885Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 26233504Sahl zc.zc_cookie = outfd; 26243504Sahl 26253504Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 26263504Sahl (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26273504Sahl "cannot send '%s'"), zhp->zfs_name); 26283504Sahl 2629789Sahrens switch (errno) { 2630789Sahrens 2631789Sahrens case EXDEV: 26322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26333413Smmusante "not an earlier snapshot from the same fs")); 26342082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2635789Sahrens 2636789Sahrens case EDQUOT: 2637789Sahrens case EFBIG: 2638789Sahrens case EIO: 2639789Sahrens case ENOLINK: 2640789Sahrens case ENOSPC: 2641789Sahrens case ENOSTR: 2642789Sahrens case ENXIO: 2643789Sahrens case EPIPE: 2644789Sahrens case ERANGE: 2645789Sahrens case EFAULT: 2646789Sahrens case EROFS: 26472082Seschrock zfs_error_aux(hdl, strerror(errno)); 26482082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2649789Sahrens 2650789Sahrens default: 26512082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2652789Sahrens } 2653789Sahrens } 2654789Sahrens 26553504Sahl return (0); 2656789Sahrens } 2657789Sahrens 2658789Sahrens /* 26592885Sahrens * Create ancestors of 'target', but not target itself, and not 26602885Sahrens * ancestors whose names are shorter than prefixlen. Die if 26612885Sahrens * prefixlen-ancestor does not exist. 26622885Sahrens */ 26632885Sahrens static int 26642885Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 26652885Sahrens { 26662885Sahrens zfs_handle_t *h; 26672885Sahrens char *cp; 26682885Sahrens 26692885Sahrens /* make sure prefix exists */ 26702885Sahrens cp = strchr(target + prefixlen, '/'); 26712885Sahrens *cp = '\0'; 26722885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 26732885Sahrens *cp = '/'; 26742885Sahrens if (h == NULL) 26752885Sahrens return (-1); 26762885Sahrens zfs_close(h); 26772885Sahrens 26782885Sahrens /* 26792885Sahrens * Attempt to create, mount, and share any ancestor filesystems, 26802885Sahrens * up to the prefixlen-long one. 26812885Sahrens */ 26822885Sahrens for (cp = target + prefixlen + 1; 26832885Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 26842885Sahrens const char *opname; 26852885Sahrens 26862885Sahrens *cp = '\0'; 26872885Sahrens 26882885Sahrens h = make_dataset_handle(hdl, target); 26892885Sahrens if (h) { 26902885Sahrens /* it already exists, nothing to do here */ 26912885Sahrens zfs_close(h); 26922885Sahrens continue; 26932885Sahrens } 26942885Sahrens 26952885Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 26962885Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 26972885Sahrens NULL) != 0) 26982885Sahrens goto ancestorerr; 26992885Sahrens 27002885Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 27012885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 27022885Sahrens if (h == NULL) 27032885Sahrens goto ancestorerr; 27042885Sahrens 27052885Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 27062885Sahrens if (zfs_mount(h, NULL, 0) != 0) 27072885Sahrens goto ancestorerr; 27082885Sahrens 27092885Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 27102885Sahrens if (zfs_share(h) != 0) 27112885Sahrens goto ancestorerr; 27122885Sahrens 27132885Sahrens zfs_close(h); 27142885Sahrens 27152885Sahrens continue; 27162885Sahrens ancestorerr: 27172885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27182885Sahrens "failed to %s ancestor '%s'"), opname, target); 27192885Sahrens return (-1); 27202885Sahrens } 27212885Sahrens 27222885Sahrens return (0); 27232885Sahrens } 27242885Sahrens 27252885Sahrens /* 27263504Sahl * Restores a backup of tosnap from the file descriptor specified by infd. 2727789Sahrens */ 2728789Sahrens int 27292082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 27303504Sahl int verbose, int dryrun, boolean_t force, int infd) 2731789Sahrens { 2732789Sahrens zfs_cmd_t zc = { 0 }; 2733789Sahrens time_t begin_time; 27342885Sahrens int ioctl_err, err, bytes, size, choplen; 2735789Sahrens char *cp; 2736789Sahrens dmu_replay_record_t drr; 2737789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 27382082Seschrock char errbuf[1024]; 27392665Snd150628 prop_changelist_t *clp; 27402885Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2741789Sahrens 2742789Sahrens begin_time = time(NULL); 2743789Sahrens 27442082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 27452082Seschrock "cannot receive")); 27462082Seschrock 2747789Sahrens /* read in the BEGIN record */ 2748789Sahrens cp = (char *)&drr; 2749789Sahrens bytes = 0; 2750789Sahrens do { 27513504Sahl size = read(infd, cp, sizeof (drr) - bytes); 2752868Sahrens cp += size; 2753868Sahrens bytes += size; 2754868Sahrens } while (size > 0); 2755868Sahrens 2756868Sahrens if (size < 0 || bytes != sizeof (drr)) { 27572082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27582082Seschrock "stream (failed to read first record)")); 27592082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2760789Sahrens } 2761789Sahrens 2762789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2763789Sahrens 2764789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2765789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 27662082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27672082Seschrock "stream (bad magic number)")); 27682082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2769789Sahrens } 2770789Sahrens 2771789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2772789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 27732082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 27742082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2775789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 27762082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2777789Sahrens } 2778789Sahrens 27792885Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 27802885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2781*3912Slling "stream (bad snapshot name)")); 27822885Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 27832885Sahrens } 2784789Sahrens /* 27852885Sahrens * Determine how much of the snapshot name stored in the stream 27862885Sahrens * we are going to tack on to the name they specified on the 27872885Sahrens * command line, and how much we are going to chop off. 27882885Sahrens * 27892885Sahrens * If they specified a snapshot, chop the entire name stored in 27902885Sahrens * the stream. 2791789Sahrens */ 27922885Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2793789Sahrens if (isprefix) { 27942885Sahrens /* 27952885Sahrens * They specified a fs with -d, we want to tack on 27962885Sahrens * everything but the pool name stored in the stream 27972885Sahrens */ 27982885Sahrens if (strchr(tosnap, '@')) { 27992885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 28002885Sahrens "argument - snapshot not allowed with -d")); 28012885Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2802789Sahrens } 28032885Sahrens cp = strchr(chopprefix, '/'); 2804789Sahrens if (cp == NULL) 28052885Sahrens cp = strchr(chopprefix, '@'); 28062885Sahrens *cp = '\0'; 2807789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2808789Sahrens /* 28092885Sahrens * If they specified a filesystem without -d, we want to 28102885Sahrens * tack on everything after the fs specified in the 28112885Sahrens * first name from the stream. 2812789Sahrens */ 28132885Sahrens cp = strchr(chopprefix, '@'); 28142885Sahrens *cp = '\0'; 2815789Sahrens } 28162885Sahrens choplen = strlen(chopprefix); 28172885Sahrens 28182885Sahrens /* 28192885Sahrens * Determine name of destination snapshot, store in zc_value. 28202885Sahrens */ 28212885Sahrens (void) strcpy(zc.zc_value, tosnap); 28222885Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 28232885Sahrens sizeof (zc.zc_value)); 28243265Sahrens if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 28253265Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 28262885Sahrens 28272885Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2828789Sahrens if (drrb->drr_fromguid) { 2829789Sahrens /* incremental backup stream */ 28302885Sahrens zfs_handle_t *h; 28312885Sahrens 28322885Sahrens /* do the recvbackup ioctl to the containing fs */ 28332885Sahrens *strchr(zc.zc_name, '@') = '\0'; 2834789Sahrens 2835789Sahrens /* make sure destination fs exists */ 28362082Seschrock h = zfs_open(hdl, zc.zc_name, 28372082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 28382082Seschrock if (h == NULL) 2839789Sahrens return (-1); 2840868Sahrens if (!dryrun) { 28412665Snd150628 /* 28422665Snd150628 * We need to unmount all the dependents of the dataset 28432665Snd150628 * and the dataset itself. If it's a volume 28442665Snd150628 * then remove device link. 28452665Snd150628 */ 2846868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 28472665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 28482665Snd150628 if (clp == NULL) 28492665Snd150628 return (-1); 28502665Snd150628 if (changelist_prefix(clp) != 0) { 28512665Snd150628 changelist_free(clp); 28522665Snd150628 return (-1); 28532665Snd150628 } 2854868Sahrens } else { 28552082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2856868Sahrens } 2857868Sahrens } 2858789Sahrens zfs_close(h); 2859789Sahrens } else { 2860789Sahrens /* full backup stream */ 2861789Sahrens 2862868Sahrens /* Make sure destination fs does not exist */ 28632885Sahrens *strchr(zc.zc_name, '@') = '\0'; 28642082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 28652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28662082Seschrock "destination '%s' exists"), zc.zc_name); 28672082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2868868Sahrens } 2869868Sahrens 28702885Sahrens if (strchr(zc.zc_name, '/') == NULL) { 28712885Sahrens /* 28722885Sahrens * they're trying to do a recv into a 28732885Sahrens * nonexistant topmost filesystem. 28742885Sahrens */ 28752885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28762885Sahrens "destination does not exist"), zc.zc_name); 28772885Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 28782885Sahrens } 28792885Sahrens 2880868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 28812885Sahrens *strrchr(zc.zc_name, '/') = '\0'; 28822885Sahrens 28832885Sahrens if (isprefix && (err = create_parents(hdl, 28842885Sahrens zc.zc_value, strlen(tosnap))) != 0) { 28852885Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 28862885Sahrens } 28872885Sahrens 2888789Sahrens } 2889789Sahrens 28903504Sahl zc.zc_cookie = infd; 28912676Seschrock zc.zc_guid = force; 2892789Sahrens if (verbose) { 28931749Sahrens (void) printf("%s %s stream of %s into %s\n", 28941749Sahrens dryrun ? "would receive" : "receiving", 2895789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2896789Sahrens drr.drr_u.drr_begin.drr_toname, 28972676Seschrock zc.zc_value); 2898789Sahrens (void) fflush(stdout); 2899789Sahrens } 2900789Sahrens if (dryrun) 2901789Sahrens return (0); 29022082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2903868Sahrens if (ioctl_err != 0) { 2904789Sahrens switch (errno) { 2905789Sahrens case ENODEV: 29062082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29072082Seschrock "most recent snapshot does not match incremental " 29082082Seschrock "source")); 29092082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2910789Sahrens break; 2911789Sahrens case ETXTBSY: 29122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29132082Seschrock "destination has been modified since most recent " 29142082Seschrock "snapshot")); 29152082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2916789Sahrens break; 2917789Sahrens case EEXIST: 2918789Sahrens if (drrb->drr_fromguid == 0) { 2919789Sahrens /* it's the containing fs that exists */ 29202676Seschrock cp = strchr(zc.zc_value, '@'); 2921789Sahrens *cp = '\0'; 2922789Sahrens } 29232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29242082Seschrock "destination already exists")); 29253237Slling (void) zfs_error_fmt(hdl, EZFS_EXISTS, 29263237Slling dgettext(TEXT_DOMAIN, "cannot restore to %s"), 29273237Slling zc.zc_value); 2928789Sahrens break; 2929789Sahrens case EINVAL: 29302082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2931868Sahrens break; 29321544Seschrock case ECKSUM: 29332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29342082Seschrock "invalid stream (checksum mismatch)")); 29352082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2936789Sahrens break; 2937789Sahrens default: 29382082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2939789Sahrens } 2940789Sahrens } 2941789Sahrens 2942789Sahrens /* 2943868Sahrens * Mount or recreate the /dev links for the target filesystem 2944868Sahrens * (if created, or if we tore them down to do an incremental 2945868Sahrens * restore), and the /dev links for the new snapshot (if 29462665Snd150628 * created). Also mount any children of the target filesystem 29472665Snd150628 * if we did an incremental receive. 2948789Sahrens */ 29492676Seschrock cp = strchr(zc.zc_value, '@'); 2950868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2951789Sahrens zfs_handle_t *h; 2952789Sahrens 2953789Sahrens *cp = '\0'; 29542676Seschrock h = zfs_open(hdl, zc.zc_value, 2955789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2956868Sahrens *cp = '@'; 2957789Sahrens if (h) { 29582665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 29592082Seschrock err = zvol_create_link(hdl, h->zfs_name); 29601544Seschrock if (err == 0 && ioctl_err == 0) 29612082Seschrock err = zvol_create_link(hdl, 29622676Seschrock zc.zc_value); 29632665Snd150628 } else { 29642665Snd150628 if (drrb->drr_fromguid) { 29652665Snd150628 err = changelist_postfix(clp); 29662665Snd150628 changelist_free(clp); 29672665Snd150628 } else { 29682665Snd150628 err = zfs_mount(h, NULL, 0); 29692665Snd150628 } 2970868Sahrens } 29712665Snd150628 zfs_close(h); 2972789Sahrens } 2973789Sahrens } 2974789Sahrens 2975868Sahrens if (err || ioctl_err) 2976868Sahrens return (-1); 2977789Sahrens 2978789Sahrens if (verbose) { 2979789Sahrens char buf1[64]; 2980789Sahrens char buf2[64]; 2981789Sahrens uint64_t bytes = zc.zc_cookie; 2982789Sahrens time_t delta = time(NULL) - begin_time; 2983789Sahrens if (delta == 0) 2984789Sahrens delta = 1; 2985789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2986789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2987789Sahrens 29881749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2989789Sahrens buf1, delta, buf2); 2990789Sahrens } 29912665Snd150628 2992789Sahrens return (0); 2993789Sahrens } 2994789Sahrens 2995789Sahrens /* 29961294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 29971294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 29981294Slling * is a dependent and we should just destroy it without checking the transaction 29991294Slling * group. 3000789Sahrens */ 30011294Slling typedef struct rollback_data { 30021294Slling const char *cb_target; /* the snapshot */ 30031294Slling uint64_t cb_create; /* creation time reference */ 30041294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 30051294Slling int cb_error; 30062082Seschrock boolean_t cb_dependent; 30071294Slling } rollback_data_t; 30081294Slling 30091294Slling static int 30101294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 30111294Slling { 30121294Slling rollback_data_t *cbp = data; 30131294Slling 30141294Slling if (!cbp->cb_dependent) { 30151294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 30161294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 30171294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 30181294Slling cbp->cb_create) { 30191294Slling 30202082Seschrock cbp->cb_dependent = B_TRUE; 30212474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 30222474Seschrock cbp) != 0) 30232474Seschrock cbp->cb_error = 1; 30242082Seschrock cbp->cb_dependent = B_FALSE; 30251294Slling 30261294Slling if (zfs_destroy(zhp) != 0) 30271294Slling cbp->cb_error = 1; 30281294Slling else 30291294Slling changelist_remove(zhp, cbp->cb_clp); 30301294Slling } 30311294Slling } else { 30321294Slling if (zfs_destroy(zhp) != 0) 30331294Slling cbp->cb_error = 1; 30341294Slling else 30351294Slling changelist_remove(zhp, cbp->cb_clp); 30361294Slling } 30371294Slling 30381294Slling zfs_close(zhp); 30391294Slling return (0); 30401294Slling } 30411294Slling 30421294Slling /* 30431294Slling * Rollback the dataset to its latest snapshot. 30441294Slling */ 30451294Slling static int 30461294Slling do_rollback(zfs_handle_t *zhp) 3047789Sahrens { 3048789Sahrens int ret; 3049789Sahrens zfs_cmd_t zc = { 0 }; 3050789Sahrens 3051789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3052789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 3053789Sahrens 3054789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 30552082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3056789Sahrens return (-1); 3057789Sahrens 3058789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3059789Sahrens 30602676Seschrock if (ZFS_IS_VOLUME(zhp)) 3061789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3062789Sahrens else 3063789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3064789Sahrens 3065789Sahrens /* 3066789Sahrens * We rely on the consumer to verify that there are no newer snapshots 3067789Sahrens * for the given dataset. Given these constraints, we can simply pass 3068789Sahrens * the name on to the ioctl() call. There is still an unlikely race 3069789Sahrens * condition where the user has taken a snapshot since we verified that 3070789Sahrens * this was the most recent. 3071789Sahrens */ 30722082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 30732082Seschrock &zc)) != 0) { 30743237Slling (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 30752082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 30762082Seschrock zhp->zfs_name); 3077789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 30782082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3079789Sahrens } 3080789Sahrens 3081789Sahrens return (ret); 3082789Sahrens } 3083789Sahrens 3084789Sahrens /* 30851294Slling * Given a dataset, rollback to a specific snapshot, discarding any 30861294Slling * data changes since then and making it the active dataset. 30871294Slling * 30881294Slling * Any snapshots more recent than the target are destroyed, along with 30891294Slling * their dependents. 30901294Slling */ 30911294Slling int 30921294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 30931294Slling { 30941294Slling int ret; 30951294Slling rollback_data_t cb = { 0 }; 30961294Slling prop_changelist_t *clp; 30971294Slling 30981294Slling /* 30991294Slling * Unmount all dependendents of the dataset and the dataset itself. 31001294Slling * The list we need to gather is the same as for doing rename 31011294Slling */ 31021294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 31031294Slling if (clp == NULL) 31041294Slling return (-1); 31051294Slling 31061294Slling if ((ret = changelist_prefix(clp)) != 0) 31071294Slling goto out; 31081294Slling 31091294Slling /* 31101294Slling * Destroy all recent snapshots and its dependends. 31111294Slling */ 31121294Slling cb.cb_target = snap->zfs_name; 31131294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 31141294Slling cb.cb_clp = clp; 31151294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 31161294Slling 31171294Slling if ((ret = cb.cb_error) != 0) { 31181294Slling (void) changelist_postfix(clp); 31191294Slling goto out; 31201294Slling } 31211294Slling 31221294Slling /* 31231294Slling * Now that we have verified that the snapshot is the latest, 31241294Slling * rollback to the given snapshot. 31251294Slling */ 31261294Slling ret = do_rollback(zhp); 31271294Slling 31281294Slling if (ret != 0) { 31291294Slling (void) changelist_postfix(clp); 31301294Slling goto out; 31311294Slling } 31321294Slling 31331294Slling /* 31341294Slling * We only want to re-mount the filesystem if it was mounted in the 31351294Slling * first place. 31361294Slling */ 31371294Slling ret = changelist_postfix(clp); 31381294Slling 31391294Slling out: 31401294Slling changelist_free(clp); 31411294Slling return (ret); 31421294Slling } 31431294Slling 31441294Slling /* 3145789Sahrens * Iterate over all dependents for a given dataset. This includes both 3146789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3147789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3148789Sahrens * libzfs_graph.c. 3149789Sahrens */ 3150789Sahrens int 31512474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 31522474Seschrock zfs_iter_f func, void *data) 3153789Sahrens { 3154789Sahrens char **dependents; 3155789Sahrens size_t count; 3156789Sahrens int i; 3157789Sahrens zfs_handle_t *child; 3158789Sahrens int ret = 0; 3159789Sahrens 31602474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 31612474Seschrock &dependents, &count) != 0) 31622474Seschrock return (-1); 31632474Seschrock 3164789Sahrens for (i = 0; i < count; i++) { 31652082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 31662082Seschrock dependents[i])) == NULL) 3167789Sahrens continue; 3168789Sahrens 3169789Sahrens if ((ret = func(child, data)) != 0) 3170789Sahrens break; 3171789Sahrens } 3172789Sahrens 3173789Sahrens for (i = 0; i < count; i++) 3174789Sahrens free(dependents[i]); 3175789Sahrens free(dependents); 3176789Sahrens 3177789Sahrens return (ret); 3178789Sahrens } 3179789Sahrens 3180789Sahrens /* 3181789Sahrens * Renames the given dataset. 3182789Sahrens */ 3183789Sahrens int 3184789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3185789Sahrens { 3186789Sahrens int ret; 3187789Sahrens zfs_cmd_t zc = { 0 }; 3188789Sahrens char *delim; 3189789Sahrens prop_changelist_t *cl; 3190789Sahrens char parent[ZFS_MAXNAMELEN]; 31912082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 31922082Seschrock char errbuf[1024]; 3193789Sahrens 3194789Sahrens /* if we have the same exact name, just return success */ 3195789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3196789Sahrens return (0); 3197789Sahrens 31982082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31992082Seschrock "cannot rename to '%s'"), target); 32002082Seschrock 3201789Sahrens /* 3202789Sahrens * Make sure the target name is valid 3203789Sahrens */ 3204789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 32052665Snd150628 if ((strchr(target, '@') == NULL) || 32062665Snd150628 *target == '@') { 32072665Snd150628 /* 32082665Snd150628 * Snapshot target name is abbreviated, 32092665Snd150628 * reconstruct full dataset name 32102665Snd150628 */ 32112665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 32122665Snd150628 sizeof (parent)); 32132665Snd150628 delim = strchr(parent, '@'); 32142665Snd150628 if (strchr(target, '@') == NULL) 32152665Snd150628 *(++delim) = '\0'; 32162665Snd150628 else 32172665Snd150628 *delim = '\0'; 32182665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 32192665Snd150628 target = parent; 32202665Snd150628 } else { 32212665Snd150628 /* 32222665Snd150628 * Make sure we're renaming within the same dataset. 32232665Snd150628 */ 32242665Snd150628 delim = strchr(target, '@'); 32252665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 32262665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 32272665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32282665Snd150628 "snapshots must be part of same " 32292665Snd150628 "dataset")); 32302665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 3231*3912Slling errbuf)); 32322665Snd150628 } 3233789Sahrens } 32342665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 32352665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3236789Sahrens } else { 32372665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 32382665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 32392676Seschrock uint64_t unused; 32402676Seschrock 3241789Sahrens /* validate parents */ 32422676Seschrock if (check_parents(hdl, target, &unused) != 0) 3243789Sahrens return (-1); 3244789Sahrens 3245789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3246789Sahrens 3247789Sahrens /* make sure we're in the same pool */ 3248789Sahrens verify((delim = strchr(target, '/')) != NULL); 3249789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3250789Sahrens zhp->zfs_name[delim - target] != '/') { 32512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32522082Seschrock "datasets must be within same pool")); 32532082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3254789Sahrens } 32552440Snd150628 32562440Snd150628 /* new name cannot be a child of the current dataset name */ 32572440Snd150628 if (strncmp(parent, zhp->zfs_name, 3258*3912Slling strlen(zhp->zfs_name)) == 0) { 32592440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32602440Snd150628 "New dataset name cannot be a descendent of " 32612440Snd150628 "current dataset name")); 32622440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 32632440Snd150628 } 3264789Sahrens } 3265789Sahrens 32662082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 32672082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 32682082Seschrock 3269789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3270789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 32712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32722082Seschrock "dataset is used in a non-global zone")); 32732082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3274789Sahrens } 3275789Sahrens 3276789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 32772082Seschrock return (-1); 3278789Sahrens 3279789Sahrens if (changelist_haszonedchild(cl)) { 32802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32812082Seschrock "child dataset with inherited mountpoint is used " 32822082Seschrock "in a non-global zone")); 32832676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3284789Sahrens goto error; 3285789Sahrens } 3286789Sahrens 3287789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3288789Sahrens goto error; 3289789Sahrens 32902676Seschrock if (ZFS_IS_VOLUME(zhp)) 3291789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3292789Sahrens else 3293789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3294789Sahrens 32952665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 32962676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 32972665Snd150628 32982082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 32992082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3300789Sahrens 3301789Sahrens /* 3302789Sahrens * On failure, we still want to remount any filesystems that 3303789Sahrens * were previously mounted, so we don't alter the system state. 3304789Sahrens */ 3305789Sahrens (void) changelist_postfix(cl); 3306789Sahrens } else { 3307789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3308789Sahrens 3309789Sahrens ret = changelist_postfix(cl); 3310789Sahrens } 3311789Sahrens 3312789Sahrens error: 3313789Sahrens changelist_free(cl); 3314789Sahrens return (ret); 3315789Sahrens } 3316789Sahrens 3317789Sahrens /* 3318789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3319789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3320789Sahrens */ 3321789Sahrens int 33222082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3323789Sahrens { 3324789Sahrens zfs_cmd_t zc = { 0 }; 33252082Seschrock di_devlink_handle_t dhdl; 3326789Sahrens 3327789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3328789Sahrens 3329789Sahrens /* 3330789Sahrens * Issue the appropriate ioctl. 3331789Sahrens */ 33322082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3333789Sahrens switch (errno) { 3334789Sahrens case EEXIST: 3335789Sahrens /* 3336789Sahrens * Silently ignore the case where the link already 3337789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3338789Sahrens * times without errors. 3339789Sahrens */ 3340789Sahrens return (0); 3341789Sahrens 3342789Sahrens default: 33433237Slling return (zfs_standard_error_fmt(hdl, errno, 33442082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 33452082Seschrock "for '%s'"), dataset)); 3346789Sahrens } 3347789Sahrens } 3348789Sahrens 3349789Sahrens /* 3350789Sahrens * Call devfsadm and wait for the links to magically appear. 3351789Sahrens */ 33522082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 33532082Seschrock zfs_error_aux(hdl, strerror(errno)); 33543237Slling (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 33552082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 33562082Seschrock "for '%s'"), dataset); 33572082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3358789Sahrens return (-1); 3359789Sahrens } else { 33602082Seschrock (void) di_devlink_fini(&dhdl); 3361789Sahrens } 3362789Sahrens 3363789Sahrens return (0); 3364789Sahrens } 3365789Sahrens 3366789Sahrens /* 3367789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3368789Sahrens */ 3369789Sahrens int 33702082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3371789Sahrens { 3372789Sahrens zfs_cmd_t zc = { 0 }; 3373789Sahrens 3374789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3375789Sahrens 33762082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3377789Sahrens switch (errno) { 3378789Sahrens case ENXIO: 3379789Sahrens /* 3380789Sahrens * Silently ignore the case where the link no longer 3381789Sahrens * exists, so that 'zfs volfini' can be run multiple 3382789Sahrens * times without errors. 3383789Sahrens */ 3384789Sahrens return (0); 3385789Sahrens 3386789Sahrens default: 33873237Slling return (zfs_standard_error_fmt(hdl, errno, 33882082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 33892082Seschrock "links for '%s'"), dataset)); 3390789Sahrens } 3391789Sahrens } 3392789Sahrens 3393789Sahrens return (0); 3394789Sahrens } 33952676Seschrock 33962676Seschrock nvlist_t * 33972676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 33982676Seschrock { 33992676Seschrock return (zhp->zfs_user_props); 34002676Seschrock } 34012676Seschrock 34022676Seschrock /* 34032676Seschrock * Given a comma-separated list of properties, contruct a property list 34042676Seschrock * containing both user-defined and native properties. This function will 34052676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 34062676Seschrock * per-dataset basis by zfs_expand_proplist(). 34072676Seschrock */ 34082676Seschrock int 3409*3912Slling zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields, 3410*3912Slling zfs_proplist_t **listp, zfs_type_t type) 34112676Seschrock { 34122676Seschrock size_t len; 34132676Seschrock char *s, *p; 34142676Seschrock char c; 34152676Seschrock zfs_prop_t prop; 34162676Seschrock zfs_proplist_t *entry; 34172676Seschrock zfs_proplist_t **last; 34182676Seschrock 34192676Seschrock *listp = NULL; 34202676Seschrock last = listp; 34212676Seschrock 34222676Seschrock /* 34232676Seschrock * If 'all' is specified, return a NULL list. 34242676Seschrock */ 34252676Seschrock if (strcmp(fields, "all") == 0) 34262676Seschrock return (0); 34272676Seschrock 34282676Seschrock /* 34292676Seschrock * If no fields were specified, return an error. 34302676Seschrock */ 34312676Seschrock if (fields[0] == '\0') { 34322676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34332676Seschrock "no properties specified")); 34342676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 34352676Seschrock "bad property list"))); 34362676Seschrock } 34372676Seschrock 34382676Seschrock /* 34392676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 34402676Seschrock * aliases makes this more effort than it's worth. 34412676Seschrock */ 34422676Seschrock s = fields; 34432676Seschrock while (*s != '\0') { 34442676Seschrock if ((p = strchr(s, ',')) == NULL) { 34452676Seschrock len = strlen(s); 34462676Seschrock p = s + len; 34472676Seschrock } else { 34482676Seschrock len = p - s; 34492676Seschrock } 34502676Seschrock 34512676Seschrock /* 34522676Seschrock * Check for empty options. 34532676Seschrock */ 34542676Seschrock if (len == 0) { 34552676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34562676Seschrock "empty property name")); 34572676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 34582676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 34592676Seschrock } 34602676Seschrock 34612676Seschrock /* 34622676Seschrock * Check all regular property names. 34632676Seschrock */ 34642676Seschrock c = s[len]; 34652676Seschrock s[len] = '\0'; 3466*3912Slling prop = zfs_name_to_prop_common(s, type); 3467*3912Slling 3468*3912Slling if (prop != ZFS_PROP_INVAL && 3469*3912Slling !zfs_prop_valid_for_type(prop, type)) 3470*3912Slling prop = ZFS_PROP_INVAL; 34712676Seschrock 34722676Seschrock /* 3473*3912Slling * When no property table entry can be found, return failure if 3474*3912Slling * this is a pool property or if this isn't a user-defined 3475*3912Slling * dataset property, 34762676Seschrock */ 3477*3912Slling if (prop == ZFS_PROP_INVAL && 3478*3912Slling (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) { 34792676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34802676Seschrock "invalid property '%s'"), s); 34812676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 34822676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 34832676Seschrock } 34842676Seschrock 34852676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 34862676Seschrock return (-1); 34872676Seschrock 34882676Seschrock entry->pl_prop = prop; 34892676Seschrock if (prop == ZFS_PROP_INVAL) { 34902676Seschrock if ((entry->pl_user_prop = 34912676Seschrock zfs_strdup(hdl, s)) == NULL) { 34922676Seschrock free(entry); 34932676Seschrock return (-1); 34942676Seschrock } 34952676Seschrock entry->pl_width = strlen(s); 34962676Seschrock } else { 34972676Seschrock entry->pl_width = zfs_prop_width(prop, 34982676Seschrock &entry->pl_fixed); 34992676Seschrock } 35002676Seschrock 35012676Seschrock *last = entry; 35022676Seschrock last = &entry->pl_next; 35032676Seschrock 35042676Seschrock s = p; 35052676Seschrock if (c == ',') 35062676Seschrock s++; 35072676Seschrock } 35082676Seschrock 35092676Seschrock return (0); 35102676Seschrock } 35112676Seschrock 3512*3912Slling int 3513*3912Slling zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 3514*3912Slling { 3515*3912Slling return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY)); 3516*3912Slling } 3517*3912Slling 35182676Seschrock void 35192676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 35202676Seschrock { 35212676Seschrock zfs_proplist_t *next; 35222676Seschrock 35232676Seschrock while (pl != NULL) { 35242676Seschrock next = pl->pl_next; 35252676Seschrock free(pl->pl_user_prop); 35262676Seschrock free(pl); 35272676Seschrock pl = next; 35282676Seschrock } 35292676Seschrock } 35302676Seschrock 35313654Sgw25295 typedef struct expand_data { 35323654Sgw25295 zfs_proplist_t **last; 35333654Sgw25295 libzfs_handle_t *hdl; 35343654Sgw25295 } expand_data_t; 35353654Sgw25295 35363654Sgw25295 static zfs_prop_t 35373654Sgw25295 zfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 35383654Sgw25295 { 35393654Sgw25295 zfs_proplist_t *entry; 35403654Sgw25295 expand_data_t *edp = cb; 35413654Sgw25295 35423654Sgw25295 if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 35433654Sgw25295 return (ZFS_PROP_INVAL); 35443654Sgw25295 35453654Sgw25295 entry->pl_prop = prop; 35463654Sgw25295 entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 35473654Sgw25295 entry->pl_all = B_TRUE; 35483654Sgw25295 35493654Sgw25295 *(edp->last) = entry; 35503654Sgw25295 edp->last = &entry->pl_next; 35513654Sgw25295 35523654Sgw25295 return (ZFS_PROP_CONT); 35533654Sgw25295 } 35543654Sgw25295 35552676Seschrock int 3556*3912Slling zfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp, 3557*3912Slling zfs_type_t type) 35582676Seschrock { 35592676Seschrock zfs_proplist_t *entry; 3560*3912Slling zfs_proplist_t **last; 35613654Sgw25295 expand_data_t exp; 35622676Seschrock 35632676Seschrock if (*plp == NULL) { 35642676Seschrock /* 35652676Seschrock * If this is the very first time we've been called for an 'all' 35662676Seschrock * specification, expand the list to include all native 35672676Seschrock * properties. 35682676Seschrock */ 35692676Seschrock last = plp; 35703654Sgw25295 35713654Sgw25295 exp.last = last; 35723654Sgw25295 exp.hdl = hdl; 35733654Sgw25295 3574*3912Slling if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type, 35753654Sgw25295 B_FALSE) == ZFS_PROP_INVAL) 35763654Sgw25295 return (-1); 35772676Seschrock 35782676Seschrock /* 35792676Seschrock * Add 'name' to the beginning of the list, which is handled 35802676Seschrock * specially. 35812676Seschrock */ 35822676Seschrock if ((entry = zfs_alloc(hdl, 35832676Seschrock sizeof (zfs_proplist_t))) == NULL) 35842676Seschrock return (-1); 35852676Seschrock 35862676Seschrock entry->pl_prop = ZFS_PROP_NAME; 35872676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 35882676Seschrock &entry->pl_fixed); 35892676Seschrock entry->pl_all = B_TRUE; 35902676Seschrock entry->pl_next = *plp; 35912676Seschrock *plp = entry; 35922676Seschrock } 3593*3912Slling return (0); 3594*3912Slling } 3595*3912Slling 3596*3912Slling /* 3597*3912Slling * This function is used by 'zfs list' to determine the exact set of columns to 3598*3912Slling * display, and their maximum widths. This does two main things: 3599*3912Slling * 3600*3912Slling * - If this is a list of all properties, then expand the list to include 3601*3912Slling * all native properties, and set a flag so that for each dataset we look 3602*3912Slling * for new unique user properties and add them to the list. 3603*3912Slling * 3604*3912Slling * - For non fixed-width properties, keep track of the maximum width seen 3605*3912Slling * so that we can size the column appropriately. 3606*3912Slling */ 3607*3912Slling int 3608*3912Slling zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 3609*3912Slling { 3610*3912Slling libzfs_handle_t *hdl = zhp->zfs_hdl; 3611*3912Slling zfs_proplist_t *entry; 3612*3912Slling zfs_proplist_t **last, **start; 3613*3912Slling nvlist_t *userprops, *propval; 3614*3912Slling nvpair_t *elem; 3615*3912Slling char *strval; 3616*3912Slling char buf[ZFS_MAXPROPLEN]; 3617*3912Slling 3618*3912Slling if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0) 3619*3912Slling return (-1); 36202676Seschrock 36212676Seschrock userprops = zfs_get_user_props(zhp); 36222676Seschrock 36232676Seschrock entry = *plp; 36242676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 36252676Seschrock /* 36262676Seschrock * Go through and add any user properties as necessary. We 36272676Seschrock * start by incrementing our list pointer to the first 36282676Seschrock * non-native property. 36292676Seschrock */ 36302676Seschrock start = plp; 36312676Seschrock while (*start != NULL) { 36322676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 36332676Seschrock break; 36342676Seschrock start = &(*start)->pl_next; 36352676Seschrock } 36362676Seschrock 36372676Seschrock elem = NULL; 36382676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 36392676Seschrock /* 36402676Seschrock * See if we've already found this property in our list. 36412676Seschrock */ 36422676Seschrock for (last = start; *last != NULL; 36432676Seschrock last = &(*last)->pl_next) { 36442676Seschrock if (strcmp((*last)->pl_user_prop, 36452676Seschrock nvpair_name(elem)) == 0) 36462676Seschrock break; 36472676Seschrock } 36482676Seschrock 36492676Seschrock if (*last == NULL) { 36502676Seschrock if ((entry = zfs_alloc(hdl, 36512676Seschrock sizeof (zfs_proplist_t))) == NULL || 36522676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 36532676Seschrock nvpair_name(elem)))) == NULL) { 36542676Seschrock free(entry); 36552676Seschrock return (-1); 36562676Seschrock } 36572676Seschrock 36582676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 36592676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 36602676Seschrock entry->pl_all = B_TRUE; 36612676Seschrock *last = entry; 36622676Seschrock } 36632676Seschrock } 36642676Seschrock } 36652676Seschrock 36662676Seschrock /* 36672676Seschrock * Now go through and check the width of any non-fixed columns 36682676Seschrock */ 36692676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 36702676Seschrock if (entry->pl_fixed) 36712676Seschrock continue; 36722676Seschrock 36732676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 36742676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 36752676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 36762676Seschrock if (strlen(buf) > entry->pl_width) 36772676Seschrock entry->pl_width = strlen(buf); 36782676Seschrock } 36792676Seschrock } else if (nvlist_lookup_nvlist(userprops, 36802676Seschrock entry->pl_user_prop, &propval) == 0) { 36812676Seschrock verify(nvlist_lookup_string(propval, 36822676Seschrock ZFS_PROP_VALUE, &strval) == 0); 36832676Seschrock if (strlen(strval) > entry->pl_width) 36842676Seschrock entry->pl_width = strlen(strval); 36852676Seschrock } 36862676Seschrock } 36872676Seschrock 36882676Seschrock return (0); 36892676Seschrock } 3690