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 54*4007Smmusante static int zvol_create_link_common(libzfs_handle_t *, const char *, int); 55*4007Smmusante 56789Sahrens /* 57789Sahrens * Given a single type (not a mask of types), return the type in a human 58789Sahrens * readable form. 59789Sahrens */ 60789Sahrens const char * 61789Sahrens zfs_type_to_name(zfs_type_t type) 62789Sahrens { 63789Sahrens switch (type) { 64789Sahrens case ZFS_TYPE_FILESYSTEM: 65789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 66789Sahrens case ZFS_TYPE_SNAPSHOT: 67789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 68789Sahrens case ZFS_TYPE_VOLUME: 69789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 70789Sahrens } 71789Sahrens 72789Sahrens return (NULL); 73789Sahrens } 74789Sahrens 75789Sahrens /* 76789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 77789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 78789Sahrens * We guess what the type would have been based on the path and the mask of 79789Sahrens * acceptable types. 80789Sahrens */ 81789Sahrens static const char * 82789Sahrens path_to_str(const char *path, int types) 83789Sahrens { 84789Sahrens /* 85789Sahrens * When given a single type, always report the exact type. 86789Sahrens */ 87789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 88789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 89789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 90789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 91789Sahrens if (types == ZFS_TYPE_VOLUME) 92789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 93789Sahrens 94789Sahrens /* 95789Sahrens * The user is requesting more than one type of dataset. If this is the 96789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 97789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 98789Sahrens * snapshot attribute and try again. 99789Sahrens */ 100789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 101789Sahrens if (strchr(path, '@') != NULL) 102789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 103789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 104789Sahrens } 105789Sahrens 106789Sahrens 107789Sahrens /* 108789Sahrens * The user has requested either filesystems or volumes. 109789Sahrens * We have no way of knowing a priori what type this would be, so always 110789Sahrens * report it as "filesystem" or "volume", our two primitive types. 111789Sahrens */ 112789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 113789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 114789Sahrens 115789Sahrens assert(types & ZFS_TYPE_VOLUME); 116789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 117789Sahrens } 118789Sahrens 119789Sahrens /* 120789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 121789Sahrens * provide a more meaningful error message. We place a more useful message in 122789Sahrens * 'buf' detailing exactly why the name was not valid. 123789Sahrens */ 124789Sahrens static int 1252082Seschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 126789Sahrens { 127789Sahrens namecheck_err_t why; 128789Sahrens char what; 129789Sahrens 130789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 1312082Seschrock if (hdl != NULL) { 132789Sahrens switch (why) { 1331003Slling case NAME_ERR_TOOLONG: 1342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1352082Seschrock "name is too long")); 1361003Slling break; 1371003Slling 138789Sahrens case NAME_ERR_LEADING_SLASH: 1392082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1402082Seschrock "leading slash in name")); 141789Sahrens break; 142789Sahrens 143789Sahrens case NAME_ERR_EMPTY_COMPONENT: 1442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1452082Seschrock "empty component in name")); 146789Sahrens break; 147789Sahrens 148789Sahrens case NAME_ERR_TRAILING_SLASH: 1492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1502082Seschrock "trailing slash in name")); 151789Sahrens break; 152789Sahrens 153789Sahrens case NAME_ERR_INVALCHAR: 1542082Seschrock zfs_error_aux(hdl, 155789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 1562082Seschrock "'%c' in name"), what); 157789Sahrens break; 158789Sahrens 159789Sahrens case NAME_ERR_MULTIPLE_AT: 1602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1612082Seschrock "multiple '@' delimiters in name")); 162789Sahrens break; 1632856Snd150628 1642856Snd150628 case NAME_ERR_NOLETTER: 1652856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1662856Snd150628 "pool doesn't begin with a letter")); 1672856Snd150628 break; 1682856Snd150628 1692856Snd150628 case NAME_ERR_RESERVED: 1702856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1712856Snd150628 "name is reserved")); 1722856Snd150628 break; 1732856Snd150628 1742856Snd150628 case NAME_ERR_DISKLIKE: 1752856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1762856Snd150628 "reserved disk name")); 1772856Snd150628 break; 178789Sahrens } 179789Sahrens } 180789Sahrens 181789Sahrens return (0); 182789Sahrens } 183789Sahrens 184789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 1852082Seschrock if (hdl != NULL) 1862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1872082Seschrock "snapshot delimiter '@' in filesystem name")); 188789Sahrens return (0); 189789Sahrens } 190789Sahrens 1912199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1922199Sahrens if (hdl != NULL) 1932199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1943413Smmusante "missing '@' delimiter in snapshot name")); 1952199Sahrens return (0); 1962199Sahrens } 1972199Sahrens 1982082Seschrock return (-1); 199789Sahrens } 200789Sahrens 201789Sahrens int 202789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 203789Sahrens { 2042082Seschrock return (zfs_validate_name(NULL, name, type)); 205789Sahrens } 206789Sahrens 207789Sahrens /* 2082676Seschrock * This function takes the raw DSL properties, and filters out the user-defined 2092676Seschrock * properties into a separate nvlist. 2102676Seschrock */ 2112676Seschrock static int 2122676Seschrock process_user_props(zfs_handle_t *zhp) 2132676Seschrock { 2142676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2152676Seschrock nvpair_t *elem; 2162676Seschrock nvlist_t *propval; 2172676Seschrock 2182676Seschrock nvlist_free(zhp->zfs_user_props); 2192676Seschrock 2202676Seschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 2212676Seschrock return (no_memory(hdl)); 2222676Seschrock 2232676Seschrock elem = NULL; 2242676Seschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 2252676Seschrock if (!zfs_prop_user(nvpair_name(elem))) 2262676Seschrock continue; 2272676Seschrock 2282676Seschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 2292676Seschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 2302676Seschrock nvpair_name(elem), propval) != 0) 2312676Seschrock return (no_memory(hdl)); 2322676Seschrock } 2332676Seschrock 2342676Seschrock return (0); 2352676Seschrock } 2362676Seschrock 2372676Seschrock /* 238789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 239789Sahrens */ 240789Sahrens static int 241789Sahrens get_stats(zfs_handle_t *zhp) 242789Sahrens { 243789Sahrens zfs_cmd_t zc = { 0 }; 2442676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 245789Sahrens 246789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 247789Sahrens 2482676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 2492082Seschrock return (-1); 2501356Seschrock 2512082Seschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2521356Seschrock if (errno == ENOMEM) { 2532676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2542676Seschrock zcmd_free_nvlists(&zc); 2552082Seschrock return (-1); 2562676Seschrock } 2571356Seschrock } else { 2582676Seschrock zcmd_free_nvlists(&zc); 2591356Seschrock return (-1); 2601356Seschrock } 2611356Seschrock } 262789Sahrens 2632885Sahrens zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 264789Sahrens 2652676Seschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 2661544Seschrock 2672082Seschrock if (zhp->zfs_props) { 2682082Seschrock nvlist_free(zhp->zfs_props); 2692082Seschrock zhp->zfs_props = NULL; 2702082Seschrock } 2712082Seschrock 2722676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 2732676Seschrock zcmd_free_nvlists(&zc); 2742082Seschrock return (-1); 2752082Seschrock } 276789Sahrens 2772676Seschrock zcmd_free_nvlists(&zc); 2782676Seschrock 2792676Seschrock if (process_user_props(zhp) != 0) 2802676Seschrock return (-1); 2812082Seschrock 282789Sahrens return (0); 283789Sahrens } 284789Sahrens 285789Sahrens /* 286789Sahrens * Refresh the properties currently stored in the handle. 287789Sahrens */ 288789Sahrens void 289789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 290789Sahrens { 291789Sahrens (void) get_stats(zhp); 292789Sahrens } 293789Sahrens 294789Sahrens /* 295789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 296789Sahrens * zfs_iter_* to create child handles on the fly. 297789Sahrens */ 298789Sahrens zfs_handle_t * 2992082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 300789Sahrens { 3012082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 3022082Seschrock 3032082Seschrock if (zhp == NULL) 3042082Seschrock return (NULL); 3052082Seschrock 3062082Seschrock zhp->zfs_hdl = hdl; 307789Sahrens 3081758Sahrens top: 309789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 310789Sahrens 311789Sahrens if (get_stats(zhp) != 0) { 312789Sahrens free(zhp); 313789Sahrens return (NULL); 314789Sahrens } 315789Sahrens 3161758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 3171758Sahrens zfs_cmd_t zc = { 0 }; 3181758Sahrens 3191758Sahrens /* 3201758Sahrens * If it is dds_inconsistent, then we've caught it in 3211758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 3221758Sahrens * it is inconsistent from the ZPL's point of view, so 3231758Sahrens * can't be mounted. However, it could also be that we 3241758Sahrens * have crashed in the middle of one of those 3251758Sahrens * operations, in which case we need to get rid of the 3261758Sahrens * inconsistent state. We do that by either rolling 3271758Sahrens * back to the previous snapshot (which will fail if 3281758Sahrens * there is none), or destroying the filesystem. Note 3291758Sahrens * that if we are still in the middle of an active 3301758Sahrens * 'receive' or 'destroy', then the rollback and destroy 3311758Sahrens * will fail with EBUSY and we will drive on as usual. 3321758Sahrens */ 3331758Sahrens 3341758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3351758Sahrens 3362885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 3372082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 3381758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3391758Sahrens } else { 3401758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3411758Sahrens } 3421758Sahrens 3431758Sahrens /* If we can successfully roll it back, reget the stats */ 3442082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 3451758Sahrens goto top; 3461758Sahrens /* 3471758Sahrens * If we can sucessfully destroy it, pretend that it 3481758Sahrens * never existed. 3491758Sahrens */ 3502082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3511758Sahrens free(zhp); 3521758Sahrens errno = ENOENT; 3531758Sahrens return (NULL); 3541758Sahrens } 3551758Sahrens } 3561758Sahrens 357789Sahrens /* 358789Sahrens * We've managed to open the dataset and gather statistics. Determine 359789Sahrens * the high-level type. 360789Sahrens */ 3612885Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 3622885Sahrens zhp->zfs_head_type = ZFS_TYPE_VOLUME; 3632885Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 3642885Sahrens zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 3652885Sahrens else 3662885Sahrens abort(); 3672885Sahrens 368789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 369789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 370789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 371789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 372789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 373789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 374789Sahrens else 3752082Seschrock abort(); /* we should never see any other types */ 376789Sahrens 377789Sahrens return (zhp); 378789Sahrens } 379789Sahrens 380789Sahrens /* 381789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 382789Sahrens * argument is a mask of acceptable types. The function will print an 383789Sahrens * appropriate error message and return NULL if it can't be opened. 384789Sahrens */ 385789Sahrens zfs_handle_t * 3862082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 387789Sahrens { 388789Sahrens zfs_handle_t *zhp; 3892082Seschrock char errbuf[1024]; 3902082Seschrock 3912082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3922082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 393789Sahrens 394789Sahrens /* 3952082Seschrock * Validate the name before we even try to open it. 396789Sahrens */ 3972082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3982082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3992082Seschrock "invalid dataset name")); 4002082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 401789Sahrens return (NULL); 402789Sahrens } 403789Sahrens 404789Sahrens /* 405789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 406789Sahrens */ 407789Sahrens errno = 0; 4082082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 4093237Slling (void) zfs_standard_error(hdl, errno, errbuf); 410789Sahrens return (NULL); 411789Sahrens } 412789Sahrens 413789Sahrens if (!(types & zhp->zfs_type)) { 4142082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 4152142Seschrock zfs_close(zhp); 416789Sahrens return (NULL); 417789Sahrens } 418789Sahrens 419789Sahrens return (zhp); 420789Sahrens } 421789Sahrens 422789Sahrens /* 423789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 424789Sahrens */ 425789Sahrens void 426789Sahrens zfs_close(zfs_handle_t *zhp) 427789Sahrens { 428789Sahrens if (zhp->zfs_mntopts) 429789Sahrens free(zhp->zfs_mntopts); 4302676Seschrock nvlist_free(zhp->zfs_props); 4312676Seschrock nvlist_free(zhp->zfs_user_props); 432789Sahrens free(zhp); 433789Sahrens } 434789Sahrens 435789Sahrens /* 436789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 437789Sahrens * resulting value must be shifted. 438789Sahrens */ 439789Sahrens static int 4402082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 441789Sahrens { 442789Sahrens const char *ends = "BKMGTPEZ"; 443789Sahrens int i; 444789Sahrens 445789Sahrens if (buf[0] == '\0') 446789Sahrens return (0); 447789Sahrens for (i = 0; i < strlen(ends); i++) { 448789Sahrens if (toupper(buf[0]) == ends[i]) 449789Sahrens break; 450789Sahrens } 451789Sahrens if (i == strlen(ends)) { 4522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4532082Seschrock "invalid numeric suffix '%s'"), buf); 454789Sahrens return (-1); 455789Sahrens } 456789Sahrens 457789Sahrens /* 458789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 459789Sahrens * allow 'BB' - that's just weird. 460789Sahrens */ 461789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4622082Seschrock toupper(buf[0]) != 'B')) 463789Sahrens return (10*i); 4642082Seschrock 4652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4662082Seschrock "invalid numeric suffix '%s'"), buf); 467789Sahrens return (-1); 468789Sahrens } 469789Sahrens 470789Sahrens /* 471789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 472789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 473789Sahrens * message for the caller to use. 474789Sahrens */ 475789Sahrens static int 4762082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 477789Sahrens { 478789Sahrens char *end; 479789Sahrens int shift; 480789Sahrens 481789Sahrens *num = 0; 482789Sahrens 483789Sahrens /* Check to see if this looks like a number. */ 484789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4852082Seschrock if (hdl) 4862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4872082Seschrock "bad numeric value '%s'"), value); 488789Sahrens return (-1); 489789Sahrens } 490789Sahrens 491789Sahrens /* Rely on stroll() to process the numeric portion. */ 492789Sahrens errno = 0; 493789Sahrens *num = strtoll(value, &end, 10); 494789Sahrens 495789Sahrens /* 496789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 497789Sahrens * in a 64-bit value. 498789Sahrens */ 499789Sahrens if (errno == ERANGE) { 5002082Seschrock if (hdl) 5012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5022082Seschrock "numeric value is too large")); 503789Sahrens return (-1); 504789Sahrens } 505789Sahrens 506789Sahrens /* 507789Sahrens * If we have a decimal value, then do the computation with floating 508789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 509789Sahrens */ 510789Sahrens if (*end == '.') { 511789Sahrens double fval = strtod(value, &end); 512789Sahrens 5132082Seschrock if ((shift = str2shift(hdl, end)) == -1) 514789Sahrens return (-1); 515789Sahrens 516789Sahrens fval *= pow(2, shift); 517789Sahrens 518789Sahrens if (fval > UINT64_MAX) { 5192082Seschrock if (hdl) 5202082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5212082Seschrock "numeric value is too large")); 522789Sahrens return (-1); 523789Sahrens } 524789Sahrens 525789Sahrens *num = (uint64_t)fval; 526789Sahrens } else { 5272082Seschrock if ((shift = str2shift(hdl, end)) == -1) 528789Sahrens return (-1); 529789Sahrens 530789Sahrens /* Check for overflow */ 531789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5322082Seschrock if (hdl) 5332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5342082Seschrock "numeric value is too large")); 535789Sahrens return (-1); 536789Sahrens } 537789Sahrens 538789Sahrens *num <<= shift; 539789Sahrens } 540789Sahrens 541789Sahrens return (0); 542789Sahrens } 543789Sahrens 544789Sahrens int 5452676Seschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 5462676Seschrock { 5472676Seschrock return (nicestrtonum(hdl, str, val)); 5482676Seschrock } 5492676Seschrock 5502676Seschrock /* 5512676Seschrock * The prop_parse_*() functions are designed to allow flexibility in callers 5522676Seschrock * when setting properties. At the DSL layer, all properties are either 64-bit 5532676Seschrock * numbers or strings. We want the user to be able to ignore this fact and 5542676Seschrock * specify properties as native values (boolean, for example) or as strings (to 5552676Seschrock * simplify command line utilities). This also handles converting index types 5562676Seschrock * (compression, checksum, etc) from strings to their on-disk index. 5572676Seschrock */ 5582676Seschrock 5592676Seschrock static int 5602676Seschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 561789Sahrens { 5622676Seschrock uint64_t ret; 5632676Seschrock 5642676Seschrock switch (nvpair_type(elem)) { 5652676Seschrock case DATA_TYPE_STRING: 5662676Seschrock { 5672676Seschrock char *value; 5683363Sgw25295 verify(nvpair_value_string(elem, &value) == 0); 5692676Seschrock 5702676Seschrock if (strcmp(value, "on") == 0) { 5712676Seschrock ret = 1; 5722676Seschrock } else if (strcmp(value, "off") == 0) { 5732676Seschrock ret = 0; 5742676Seschrock } else { 5752676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5762676Seschrock "property '%s' must be 'on' or 'off'"), 5772676Seschrock nvpair_name(elem)); 5782676Seschrock return (-1); 5792676Seschrock } 5802676Seschrock break; 5812676Seschrock } 5822676Seschrock 5832676Seschrock case DATA_TYPE_UINT64: 5842676Seschrock { 5853363Sgw25295 verify(nvpair_value_uint64(elem, &ret) == 0); 5862676Seschrock if (ret > 1) { 5872676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5882676Seschrock "'%s' must be a boolean value"), 5892676Seschrock nvpair_name(elem)); 5902676Seschrock return (-1); 5912676Seschrock } 5922676Seschrock break; 5932676Seschrock } 5942676Seschrock 5952676Seschrock case DATA_TYPE_BOOLEAN_VALUE: 5962676Seschrock { 5972676Seschrock boolean_t value; 5983363Sgw25295 verify(nvpair_value_boolean_value(elem, &value) == 0); 5992676Seschrock ret = value; 6002676Seschrock break; 6012676Seschrock } 6022676Seschrock 6032676Seschrock default: 6042676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6052676Seschrock "'%s' must be a boolean value"), 6062676Seschrock nvpair_name(elem)); 6072676Seschrock return (-1); 6082676Seschrock } 6092676Seschrock 6102676Seschrock *val = ret; 6112676Seschrock return (0); 6122676Seschrock } 6132676Seschrock 6142676Seschrock static int 6152676Seschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6162676Seschrock uint64_t *val) 6172676Seschrock { 6182676Seschrock uint64_t ret; 6192676Seschrock boolean_t isnone = B_FALSE; 6202676Seschrock 6212676Seschrock switch (nvpair_type(elem)) { 6222676Seschrock case DATA_TYPE_STRING: 6232676Seschrock { 6242676Seschrock char *value; 6252676Seschrock (void) nvpair_value_string(elem, &value); 6262676Seschrock if (strcmp(value, "none") == 0) { 6272676Seschrock isnone = B_TRUE; 6282676Seschrock ret = 0; 6292676Seschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 6302676Seschrock return (-1); 6312676Seschrock } 6322676Seschrock break; 6332676Seschrock } 6342676Seschrock 6352676Seschrock case DATA_TYPE_UINT64: 6362676Seschrock (void) nvpair_value_uint64(elem, &ret); 6372676Seschrock break; 6382676Seschrock 6392676Seschrock default: 6402676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6412676Seschrock "'%s' must be a number"), 6422676Seschrock nvpair_name(elem)); 6432676Seschrock return (-1); 6442676Seschrock } 6452676Seschrock 6462676Seschrock /* 6472676Seschrock * Quota special: force 'none' and don't allow 0. 6482676Seschrock */ 6492676Seschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 6502676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6512676Seschrock "use 'none' to disable quota")); 6522676Seschrock return (-1); 6532676Seschrock } 6542676Seschrock 6552676Seschrock *val = ret; 6562676Seschrock return (0); 6572676Seschrock } 6582676Seschrock 6592676Seschrock static int 6602676Seschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6612676Seschrock uint64_t *val) 6622676Seschrock { 6632676Seschrock char *propname = nvpair_name(elem); 6642676Seschrock char *value; 6652676Seschrock 6662676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 6672676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6682676Seschrock "'%s' must be a string"), propname); 6692676Seschrock return (-1); 6702676Seschrock } 6712676Seschrock 6722676Seschrock (void) nvpair_value_string(elem, &value); 6732676Seschrock 6742676Seschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 6752676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6762676Seschrock "'%s' must be one of '%s'"), propname, 6772676Seschrock zfs_prop_values(prop)); 6782676Seschrock return (-1); 6792676Seschrock } 6802676Seschrock 6812676Seschrock return (0); 682789Sahrens } 683789Sahrens 684789Sahrens /* 6853912Slling * Check if the bootfs name has the same pool name as it is set to. 6863912Slling * Assuming bootfs is a valid dataset name. 6873912Slling */ 6883912Slling static boolean_t 6893912Slling bootfs_poolname_valid(char *pool, char *bootfs) 6903912Slling { 6913912Slling char ch, *pname; 6923912Slling 6933912Slling /* get the pool name from the bootfs name */ 6943912Slling pname = bootfs; 6953912Slling while (*bootfs && !isspace(*bootfs) && *bootfs != '/') 6963912Slling bootfs++; 6973912Slling 6983912Slling ch = *bootfs; 6993912Slling *bootfs = 0; 7003912Slling 7013912Slling if (strcmp(pool, pname) == 0) { 7023912Slling *bootfs = ch; 7033912Slling return (B_TRUE); 7043912Slling } 7053912Slling 7063912Slling *bootfs = ch; 7073912Slling return (B_FALSE); 7083912Slling } 7093912Slling 7103912Slling /* 7112676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 7122676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 7132676Seschrock * strings. 714789Sahrens */ 7153912Slling nvlist_t * 7163912Slling zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, 7173912Slling nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 718789Sahrens { 7192676Seschrock nvpair_t *elem; 7202676Seschrock const char *propname; 7212676Seschrock zfs_prop_t prop; 7222676Seschrock uint64_t intval; 7232676Seschrock char *strval; 7242676Seschrock nvlist_t *ret; 7253912Slling int isuser; 7262676Seschrock 7272676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 7282676Seschrock (void) no_memory(hdl); 7292676Seschrock return (NULL); 7302676Seschrock } 7312676Seschrock 7322676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 7332676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7343413Smmusante "snapshot properties cannot be modified")); 7352676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7362676Seschrock goto error; 737789Sahrens } 738789Sahrens 7392676Seschrock elem = NULL; 7402676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 7412676Seschrock propname = nvpair_name(elem); 7422676Seschrock 7432676Seschrock /* 7442676Seschrock * Make sure this property is valid and applies to this type. 7452676Seschrock */ 7463912Slling if ((prop = zfs_name_to_prop_common(propname, type)) 7473912Slling == ZFS_PROP_INVAL) { 7483912Slling isuser = zfs_prop_user(propname); 7493912Slling if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) { 7502676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7512676Seschrock "invalid property '%s'"), 7522676Seschrock propname); 7532676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7542676Seschrock goto error; 7552676Seschrock } else { 7562676Seschrock /* 7572676Seschrock * If this is a user property, make sure it's a 7582676Seschrock * string, and that it's less than 7592676Seschrock * ZAP_MAXNAMELEN. 7602676Seschrock */ 7612676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7622676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7632676Seschrock "'%s' must be a string"), 7642676Seschrock propname); 7652676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7662676Seschrock errbuf); 7672676Seschrock goto error; 7682676Seschrock } 7692676Seschrock 7702676Seschrock if (strlen(nvpair_name(elem)) >= 7712676Seschrock ZAP_MAXNAMELEN) { 7722676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7732676Seschrock "property name '%s' is too long"), 7742676Seschrock propname); 7752676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7762676Seschrock errbuf); 7772676Seschrock goto error; 7782676Seschrock } 7792676Seschrock } 7802676Seschrock 7812676Seschrock (void) nvpair_value_string(elem, &strval); 7822676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7832676Seschrock (void) no_memory(hdl); 7842676Seschrock goto error; 7852676Seschrock } 7862676Seschrock continue; 787789Sahrens } 7882676Seschrock 7892676Seschrock /* 7902676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7912676Seschrock */ 7922676Seschrock propname = zfs_prop_to_name(prop); 7932676Seschrock 7942676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7952676Seschrock zfs_error_aux(hdl, 7962676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7972676Seschrock "apply to datasets of this type"), propname); 7982676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7992676Seschrock goto error; 8002676Seschrock } 8012676Seschrock 8022676Seschrock if (zfs_prop_readonly(prop) && 8032676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 8042676Seschrock zfs_error_aux(hdl, 8052676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 8062676Seschrock propname); 8072676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 8082676Seschrock goto error; 8092676Seschrock } 8102676Seschrock 8112676Seschrock /* 8122676Seschrock * Convert any properties to the internal DSL value types. 8132676Seschrock */ 8142676Seschrock strval = NULL; 8152676Seschrock switch (zfs_prop_get_type(prop)) { 8162676Seschrock case prop_type_boolean: 8172676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 8182676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8192676Seschrock goto error; 8202676Seschrock } 821789Sahrens break; 8222676Seschrock 8232676Seschrock case prop_type_string: 8242676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 8252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8262676Seschrock "'%s' must be a string"), 8272676Seschrock propname); 8282676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8292676Seschrock goto error; 830789Sahrens } 8312676Seschrock (void) nvpair_value_string(elem, &strval); 8322676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 8332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8342676Seschrock "'%s' is too long"), propname); 8352676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8362676Seschrock goto error; 8372676Seschrock } 8382676Seschrock break; 8392676Seschrock 8402676Seschrock case prop_type_number: 8412676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 8422676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8432676Seschrock goto error; 8442676Seschrock } 8452676Seschrock break; 8462676Seschrock 8472676Seschrock case prop_type_index: 8482676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 8492676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8502676Seschrock goto error; 851789Sahrens } 852789Sahrens break; 853789Sahrens 8542676Seschrock default: 8552676Seschrock abort(); 8562676Seschrock } 8572676Seschrock 8582676Seschrock /* 8592676Seschrock * Add the result to our return set of properties. 8602676Seschrock */ 8612676Seschrock if (strval) { 8622676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8632676Seschrock (void) no_memory(hdl); 8642676Seschrock goto error; 865789Sahrens } 8662676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8672676Seschrock (void) no_memory(hdl); 8682676Seschrock goto error; 8692676Seschrock } 8702676Seschrock 8712676Seschrock /* 8722676Seschrock * Perform some additional checks for specific properties. 8732676Seschrock */ 8742676Seschrock switch (prop) { 8752676Seschrock case ZFS_PROP_RECORDSIZE: 8762676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8772676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8782676Seschrock if (intval < SPA_MINBLOCKSIZE || 8792676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8812676Seschrock "'%s' must be power of 2 from %u " 8822676Seschrock "to %uk"), propname, 8832676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8842676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8852676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8862676Seschrock goto error; 887789Sahrens } 888789Sahrens break; 889789Sahrens 8903126Sahl case ZFS_PROP_SHAREISCSI: 8913126Sahl if (strcmp(strval, "off") != 0 && 8923126Sahl strcmp(strval, "on") != 0 && 8933126Sahl strcmp(strval, "type=disk") != 0) { 8943126Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8953126Sahl "'%s' must be 'on', 'off', or 'type=disk'"), 8963126Sahl propname); 8973126Sahl (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8983126Sahl goto error; 8993126Sahl } 9003126Sahl 9013126Sahl break; 9023126Sahl 9032676Seschrock case ZFS_PROP_MOUNTPOINT: 9042676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 9052676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 9062676Seschrock break; 9072676Seschrock 9082676Seschrock if (strval[0] != '/') { 9092082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9102676Seschrock "'%s' must be an absolute path, " 9112676Seschrock "'none', or 'legacy'"), propname); 9122676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 9132676Seschrock goto error; 914789Sahrens } 9153126Sahl /*FALLTHRU*/ 9163126Sahl 9173126Sahl case ZFS_PROP_SHARENFS: 9183126Sahl /* 9193126Sahl * For the mountpoint and sharenfs properties, check if 9203126Sahl * it can be set in a global/non-global zone based on 9213126Sahl * the zoned property value: 9223126Sahl * 9233126Sahl * global zone non-global zone 9243126Sahl * -------------------------------------------------- 9253126Sahl * zoned=on mountpoint (no) mountpoint (yes) 9263126Sahl * sharenfs (no) sharenfs (no) 9273126Sahl * 9283126Sahl * zoned=off mountpoint (yes) N/A 9293126Sahl * sharenfs (yes) 9303126Sahl */ 9312676Seschrock if (zoned) { 9322676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 9332676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9342676Seschrock "'%s' cannot be set on " 9352676Seschrock "dataset in a non-global zone"), 9362676Seschrock propname); 9372676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9382676Seschrock errbuf); 9392676Seschrock goto error; 9402676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 9412676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9422676Seschrock "'%s' cannot be set in " 9432676Seschrock "a non-global zone"), propname); 9442676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 9452676Seschrock errbuf); 9462676Seschrock goto error; 9472676Seschrock } 9482676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 9492676Seschrock /* 9502676Seschrock * If zoned property is 'off', this must be in 9512676Seschrock * a globle zone. If not, something is wrong. 9522676Seschrock */ 9532676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9542676Seschrock "'%s' cannot be set while dataset " 9552676Seschrock "'zoned' property is set"), propname); 9562676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 9572676Seschrock goto error; 9582676Seschrock } 9593126Sahl 9603126Sahl break; 9613912Slling 9623912Slling case ZFS_PROP_BOOTFS: 9633912Slling /* 9643912Slling * bootfs property value has to be a dataset name and 9653912Slling * the dataset has to be in the same pool as it sets to. 9663912Slling */ 9673912Slling if (strval[0] != '\0' && (!zfs_name_valid(strval, 9683912Slling ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid( 9693912Slling pool_name, strval))) { 9703912Slling 9713912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 9723912Slling "is an invalid name"), strval); 9733912Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 9743912Slling goto error; 9753912Slling } 9763912Slling break; 9772676Seschrock } 9782676Seschrock 9792676Seschrock /* 9802676Seschrock * For changes to existing volumes, we have some additional 9812676Seschrock * checks to enforce. 9822676Seschrock */ 9832676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9842676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9852676Seschrock ZFS_PROP_VOLSIZE); 9862676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9872676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9882676Seschrock char buf[64]; 9892676Seschrock 9902676Seschrock switch (prop) { 9912676Seschrock case ZFS_PROP_RESERVATION: 9922676Seschrock if (intval > volsize) { 9932676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9942676Seschrock "'%s' is greater than current " 9952676Seschrock "volume size"), propname); 9962676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9972676Seschrock errbuf); 9982676Seschrock goto error; 9992676Seschrock } 10002676Seschrock break; 10012676Seschrock 10022676Seschrock case ZFS_PROP_VOLSIZE: 10032676Seschrock if (intval % blocksize != 0) { 10042676Seschrock zfs_nicenum(blocksize, buf, 10052676Seschrock sizeof (buf)); 10062676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10072676Seschrock "'%s' must be a multiple of " 10082676Seschrock "volume block size (%s)"), 10092676Seschrock propname, buf); 10102676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 10112676Seschrock errbuf); 10122676Seschrock goto error; 10132676Seschrock } 10142676Seschrock 10152676Seschrock if (intval == 0) { 10162676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10172676Seschrock "'%s' cannot be zero"), 10182676Seschrock propname); 10192676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 10202676Seschrock errbuf); 10212676Seschrock goto error; 1022789Sahrens } 10233126Sahl break; 1024789Sahrens } 1025789Sahrens } 1026789Sahrens } 1027789Sahrens 10282676Seschrock /* 10292676Seschrock * If this is an existing volume, and someone is setting the volsize, 10302676Seschrock * make sure that it matches the reservation, or add it if necessary. 10312676Seschrock */ 10322676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 10332676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 10342676Seschrock &intval) == 0) { 10352676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 10362676Seschrock ZFS_PROP_VOLSIZE); 10372676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 10382676Seschrock ZFS_PROP_RESERVATION); 10392676Seschrock uint64_t new_reservation; 10402676Seschrock 10412676Seschrock if (old_volsize == old_reservation && 10422676Seschrock nvlist_lookup_uint64(ret, 10432676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 10442676Seschrock &new_reservation) != 0) { 10452676Seschrock if (nvlist_add_uint64(ret, 10462676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 10472676Seschrock intval) != 0) { 10482676Seschrock (void) no_memory(hdl); 10492676Seschrock goto error; 10502676Seschrock } 10512676Seschrock } 10522676Seschrock } 10532676Seschrock 10542676Seschrock return (ret); 10552676Seschrock 10562676Seschrock error: 10572676Seschrock nvlist_free(ret); 10582676Seschrock return (NULL); 1059789Sahrens } 1060789Sahrens 1061789Sahrens /* 1062789Sahrens * Given a property name and value, set the property for the given dataset. 1063789Sahrens */ 1064789Sahrens int 10652676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1066789Sahrens { 1067789Sahrens zfs_cmd_t zc = { 0 }; 10682676Seschrock int ret = -1; 10692676Seschrock prop_changelist_t *cl = NULL; 10702082Seschrock char errbuf[1024]; 10712082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 10722676Seschrock nvlist_t *nvl = NULL, *realprops; 10732676Seschrock zfs_prop_t prop; 10742082Seschrock 10752082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 10762676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 10772082Seschrock zhp->zfs_name); 10782082Seschrock 10792676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 10802676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 10812676Seschrock (void) no_memory(hdl); 10822676Seschrock goto error; 1083789Sahrens } 1084789Sahrens 10853912Slling if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl, 10862676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10872676Seschrock goto error; 10882676Seschrock nvlist_free(nvl); 10892676Seschrock nvl = realprops; 10902676Seschrock 10912676Seschrock prop = zfs_name_to_prop(propname); 10922676Seschrock 1093789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10942676Seschrock goto error; 1095789Sahrens 1096789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10972082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10982082Seschrock "child dataset with inherited mountpoint is used " 10992082Seschrock "in a non-global zone")); 11002082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1101789Sahrens goto error; 1102789Sahrens } 1103789Sahrens 1104789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1105789Sahrens goto error; 1106789Sahrens 1107789Sahrens /* 1108789Sahrens * Execute the corresponding ioctl() to set this property. 1109789Sahrens */ 1110789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1111789Sahrens 11122676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 11132676Seschrock goto error; 11142676Seschrock 11152676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1116789Sahrens 1117789Sahrens if (ret != 0) { 1118789Sahrens switch (errno) { 1119789Sahrens 1120789Sahrens case ENOSPC: 1121789Sahrens /* 1122789Sahrens * For quotas and reservations, ENOSPC indicates 1123789Sahrens * something different; setting a quota or reservation 1124789Sahrens * doesn't use any disk space. 1125789Sahrens */ 1126789Sahrens switch (prop) { 1127789Sahrens case ZFS_PROP_QUOTA: 11282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11292082Seschrock "size is less than current used or " 11302082Seschrock "reserved space")); 11312082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1132789Sahrens break; 1133789Sahrens 1134789Sahrens case ZFS_PROP_RESERVATION: 11352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11362082Seschrock "size is greater than available space")); 11372082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1138789Sahrens break; 1139789Sahrens 1140789Sahrens default: 11412082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1142789Sahrens break; 1143789Sahrens } 1144789Sahrens break; 1145789Sahrens 1146789Sahrens case EBUSY: 11472082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 11482082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 11492082Seschrock else 11502676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1151789Sahrens break; 1152789Sahrens 11531175Slling case EROFS: 11542082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 11551175Slling break; 11561175Slling 11573886Sahl case ENOTSUP: 11583886Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11593886Sahl "pool must be upgraded to allow gzip compression")); 11603886Sahl (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 11613886Sahl break; 11623886Sahl 1163789Sahrens case EOVERFLOW: 1164789Sahrens /* 1165789Sahrens * This platform can't address a volume this big. 1166789Sahrens */ 1167789Sahrens #ifdef _ILP32 1168789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 11692082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1170789Sahrens break; 1171789Sahrens } 1172789Sahrens #endif 11732082Seschrock /* FALLTHROUGH */ 1174789Sahrens default: 11752082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1176789Sahrens } 1177789Sahrens } else { 1178789Sahrens /* 1179789Sahrens * Refresh the statistics so the new property value 1180789Sahrens * is reflected. 1181789Sahrens */ 11822676Seschrock if ((ret = changelist_postfix(cl)) == 0) 11832676Seschrock (void) get_stats(zhp); 1184789Sahrens } 1185789Sahrens 1186789Sahrens error: 11872676Seschrock nvlist_free(nvl); 11882676Seschrock zcmd_free_nvlists(&zc); 11892676Seschrock if (cl) 11902676Seschrock changelist_free(cl); 1191789Sahrens return (ret); 1192789Sahrens } 1193789Sahrens 1194789Sahrens /* 1195789Sahrens * Given a property, inherit the value from the parent dataset. 1196789Sahrens */ 1197789Sahrens int 11982676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1199789Sahrens { 1200789Sahrens zfs_cmd_t zc = { 0 }; 1201789Sahrens int ret; 1202789Sahrens prop_changelist_t *cl; 12032082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 12042082Seschrock char errbuf[1024]; 12052676Seschrock zfs_prop_t prop; 12062082Seschrock 12072082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 12082082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1209789Sahrens 12102676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 12112676Seschrock /* 12122676Seschrock * For user properties, the amount of work we have to do is very 12132676Seschrock * small, so just do it here. 12142676Seschrock */ 12152676Seschrock if (!zfs_prop_user(propname)) { 12162676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12172676Seschrock "invalid property")); 12182676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 12192676Seschrock } 12202676Seschrock 12212676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 12222676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 12232676Seschrock 12242676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 12252676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 12262676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 12272676Seschrock 12282676Seschrock return (0); 12292676Seschrock } 12302676Seschrock 1231789Sahrens /* 1232789Sahrens * Verify that this property is inheritable. 1233789Sahrens */ 12342082Seschrock if (zfs_prop_readonly(prop)) 12352082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 12362082Seschrock 12372082Seschrock if (!zfs_prop_inheritable(prop)) 12382082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1239789Sahrens 1240789Sahrens /* 1241789Sahrens * Check to see if the value applies to this type 1242789Sahrens */ 12432082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 12442082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1245789Sahrens 12463443Srm160521 /* 12473443Srm160521 * Normalize the name, to get rid of shorthand abbrevations. 12483443Srm160521 */ 12493443Srm160521 propname = zfs_prop_to_name(prop); 1250789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 12512676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1252789Sahrens 1253789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1254789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 12552082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12562082Seschrock "dataset is used in a non-global zone")); 12572082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1258789Sahrens } 1259789Sahrens 1260789Sahrens /* 1261789Sahrens * Determine datasets which will be affected by this change, if any. 1262789Sahrens */ 1263789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1264789Sahrens return (-1); 1265789Sahrens 1266789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 12672082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 12682082Seschrock "child dataset with inherited mountpoint is used " 12692082Seschrock "in a non-global zone")); 12702082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1271789Sahrens goto error; 1272789Sahrens } 1273789Sahrens 1274789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1275789Sahrens goto error; 1276789Sahrens 12772082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 12782082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 12792082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1280789Sahrens } else { 1281789Sahrens 12822169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1283789Sahrens goto error; 1284789Sahrens 1285789Sahrens /* 1286789Sahrens * Refresh the statistics so the new property is reflected. 1287789Sahrens */ 1288789Sahrens (void) get_stats(zhp); 1289789Sahrens } 1290789Sahrens 1291789Sahrens error: 1292789Sahrens changelist_free(cl); 1293789Sahrens return (ret); 1294789Sahrens } 1295789Sahrens 12963912Slling void 1297789Sahrens nicebool(int value, char *buf, size_t buflen) 1298789Sahrens { 1299789Sahrens if (value) 1300789Sahrens (void) strlcpy(buf, "on", buflen); 1301789Sahrens else 1302789Sahrens (void) strlcpy(buf, "off", buflen); 1303789Sahrens } 1304789Sahrens 1305789Sahrens /* 13061356Seschrock * True DSL properties are stored in an nvlist. The following two functions 13071356Seschrock * extract them appropriately. 13081356Seschrock */ 13091356Seschrock static uint64_t 13101356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13111356Seschrock { 13121356Seschrock nvlist_t *nv; 13131356Seschrock uint64_t value; 13141356Seschrock 13152885Sahrens *source = NULL; 13161356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13171356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 13181356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 13192885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13201356Seschrock } else { 13211356Seschrock value = zfs_prop_default_numeric(prop); 13221356Seschrock *source = ""; 13231356Seschrock } 13241356Seschrock 13251356Seschrock return (value); 13261356Seschrock } 13271356Seschrock 13281356Seschrock static char * 13291356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13301356Seschrock { 13311356Seschrock nvlist_t *nv; 13321356Seschrock char *value; 13331356Seschrock 13342885Sahrens *source = NULL; 13351356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13361356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 13371356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 13382885Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13391356Seschrock } else { 13401356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 13411356Seschrock value = ""; 13421356Seschrock *source = ""; 13431356Seschrock } 13441356Seschrock 13451356Seschrock return (value); 13461356Seschrock } 13471356Seschrock 13481356Seschrock /* 1349789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1350789Sahrens * zfs_prop_get_int() are built using this interface. 1351789Sahrens * 1352789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1353789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1354789Sahrens * If they differ from the on-disk values, report the current values and mark 1355789Sahrens * the source "temporary". 1356789Sahrens */ 13572082Seschrock static int 1358789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 13592082Seschrock char **source, uint64_t *val) 1360789Sahrens { 1361789Sahrens struct mnttab mnt; 13623265Sahrens char *mntopt_on = NULL; 13633265Sahrens char *mntopt_off = NULL; 1364789Sahrens 1365789Sahrens *source = NULL; 1366789Sahrens 13673265Sahrens switch (prop) { 13683265Sahrens case ZFS_PROP_ATIME: 13693265Sahrens mntopt_on = MNTOPT_ATIME; 13703265Sahrens mntopt_off = MNTOPT_NOATIME; 13713265Sahrens break; 13723265Sahrens 13733265Sahrens case ZFS_PROP_DEVICES: 13743265Sahrens mntopt_on = MNTOPT_DEVICES; 13753265Sahrens mntopt_off = MNTOPT_NODEVICES; 13763265Sahrens break; 13773265Sahrens 13783265Sahrens case ZFS_PROP_EXEC: 13793265Sahrens mntopt_on = MNTOPT_EXEC; 13803265Sahrens mntopt_off = MNTOPT_NOEXEC; 13813265Sahrens break; 13823265Sahrens 13833265Sahrens case ZFS_PROP_READONLY: 13843265Sahrens mntopt_on = MNTOPT_RO; 13853265Sahrens mntopt_off = MNTOPT_RW; 13863265Sahrens break; 13873265Sahrens 13883265Sahrens case ZFS_PROP_SETUID: 13893265Sahrens mntopt_on = MNTOPT_SETUID; 13903265Sahrens mntopt_off = MNTOPT_NOSETUID; 13913265Sahrens break; 13923265Sahrens 13933265Sahrens case ZFS_PROP_XATTR: 13943265Sahrens mntopt_on = MNTOPT_XATTR; 13953265Sahrens mntopt_off = MNTOPT_NOXATTR; 13963265Sahrens break; 13973265Sahrens } 13983265Sahrens 13992474Seschrock /* 14002474Seschrock * Because looking up the mount options is potentially expensive 14012474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 14022474Seschrock * we're looking up a property which requires its presence. 14032474Seschrock */ 14042474Seschrock if (!zhp->zfs_mntcheck && 14053265Sahrens (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 14063265Sahrens struct mnttab entry, search = { 0 }; 14073265Sahrens FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 14082474Seschrock 14092474Seschrock search.mnt_special = (char *)zhp->zfs_name; 14102474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 14113265Sahrens rewind(mnttab); 14123265Sahrens 14133265Sahrens if (getmntany(mnttab, &entry, &search) == 0) { 14143265Sahrens zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 14153265Sahrens entry.mnt_mntopts); 14163265Sahrens if (zhp->zfs_mntopts == NULL) 14173265Sahrens return (-1); 14183265Sahrens } 14192474Seschrock 14202474Seschrock zhp->zfs_mntcheck = B_TRUE; 14212474Seschrock } 14222474Seschrock 1423789Sahrens if (zhp->zfs_mntopts == NULL) 1424789Sahrens mnt.mnt_mntopts = ""; 1425789Sahrens else 1426789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1427789Sahrens 1428789Sahrens switch (prop) { 1429789Sahrens case ZFS_PROP_ATIME: 14303265Sahrens case ZFS_PROP_DEVICES: 14313265Sahrens case ZFS_PROP_EXEC: 14323265Sahrens case ZFS_PROP_READONLY: 14333265Sahrens case ZFS_PROP_SETUID: 14343265Sahrens case ZFS_PROP_XATTR: 14352082Seschrock *val = getprop_uint64(zhp, prop, source); 14362082Seschrock 14373265Sahrens if (hasmntopt(&mnt, mntopt_on) && !*val) { 14382082Seschrock *val = B_TRUE; 1439789Sahrens if (src) 1440789Sahrens *src = ZFS_SRC_TEMPORARY; 14413265Sahrens } else if (hasmntopt(&mnt, mntopt_off) && *val) { 14422082Seschrock *val = B_FALSE; 1443789Sahrens if (src) 1444789Sahrens *src = ZFS_SRC_TEMPORARY; 1445789Sahrens } 14462082Seschrock break; 1447789Sahrens 1448789Sahrens case ZFS_PROP_RECORDSIZE: 1449789Sahrens case ZFS_PROP_COMPRESSION: 14501356Seschrock case ZFS_PROP_ZONED: 14512885Sahrens case ZFS_PROP_CREATION: 14522885Sahrens case ZFS_PROP_COMPRESSRATIO: 14532885Sahrens case ZFS_PROP_REFERENCED: 14542885Sahrens case ZFS_PROP_USED: 14552885Sahrens case ZFS_PROP_CREATETXG: 14562885Sahrens case ZFS_PROP_AVAILABLE: 14572885Sahrens case ZFS_PROP_VOLSIZE: 14582885Sahrens case ZFS_PROP_VOLBLOCKSIZE: 14593417Srm160521 *val = getprop_uint64(zhp, prop, source); 14603417Srm160521 break; 14613417Srm160521 14623265Sahrens case ZFS_PROP_CANMOUNT: 14632082Seschrock *val = getprop_uint64(zhp, prop, source); 14643417Srm160521 if (*val == 0) 14653417Srm160521 *source = zhp->zfs_name; 14663417Srm160521 else 14673417Srm160521 *source = ""; /* default */ 14682082Seschrock break; 1469789Sahrens 1470789Sahrens case ZFS_PROP_QUOTA: 1471789Sahrens case ZFS_PROP_RESERVATION: 14722885Sahrens *val = getprop_uint64(zhp, prop, source); 14732885Sahrens if (*val == 0) 1474789Sahrens *source = ""; /* default */ 1475789Sahrens else 1476789Sahrens *source = zhp->zfs_name; 14772082Seschrock break; 1478789Sahrens 1479789Sahrens case ZFS_PROP_MOUNTED: 14802082Seschrock *val = (zhp->zfs_mntopts != NULL); 14812082Seschrock break; 1482789Sahrens 14833377Seschrock case ZFS_PROP_NUMCLONES: 14843377Seschrock *val = zhp->zfs_dmustats.dds_num_clones; 14853377Seschrock break; 14863377Seschrock 1487789Sahrens default: 14882082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14892082Seschrock "cannot get non-numeric property")); 14902082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14912082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1492789Sahrens } 1493789Sahrens 1494789Sahrens return (0); 1495789Sahrens } 1496789Sahrens 1497789Sahrens /* 1498789Sahrens * Calculate the source type, given the raw source string. 1499789Sahrens */ 1500789Sahrens static void 1501789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1502789Sahrens char *statbuf, size_t statlen) 1503789Sahrens { 1504789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1505789Sahrens return; 1506789Sahrens 1507789Sahrens if (source == NULL) { 1508789Sahrens *srctype = ZFS_SRC_NONE; 1509789Sahrens } else if (source[0] == '\0') { 1510789Sahrens *srctype = ZFS_SRC_DEFAULT; 1511789Sahrens } else { 1512789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1513789Sahrens *srctype = ZFS_SRC_LOCAL; 1514789Sahrens } else { 1515789Sahrens (void) strlcpy(statbuf, source, statlen); 1516789Sahrens *srctype = ZFS_SRC_INHERITED; 1517789Sahrens } 1518789Sahrens } 1519789Sahrens 1520789Sahrens } 1521789Sahrens 1522789Sahrens /* 1523789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1524789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1525789Sahrens * human-readable form. 1526789Sahrens * 1527789Sahrens * Returns 0 on success, or -1 on error. 1528789Sahrens */ 1529789Sahrens int 1530789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 15312082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1532789Sahrens { 1533789Sahrens char *source = NULL; 1534789Sahrens uint64_t val; 1535789Sahrens char *str; 1536789Sahrens const char *root; 15372676Seschrock const char *strval; 1538789Sahrens 1539789Sahrens /* 1540789Sahrens * Check to see if this property applies to our object 1541789Sahrens */ 1542789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1543789Sahrens return (-1); 1544789Sahrens 1545789Sahrens if (src) 1546789Sahrens *src = ZFS_SRC_NONE; 1547789Sahrens 1548789Sahrens switch (prop) { 1549789Sahrens case ZFS_PROP_ATIME: 1550789Sahrens case ZFS_PROP_READONLY: 1551789Sahrens case ZFS_PROP_SETUID: 1552789Sahrens case ZFS_PROP_ZONED: 1553789Sahrens case ZFS_PROP_DEVICES: 1554789Sahrens case ZFS_PROP_EXEC: 15552676Seschrock case ZFS_PROP_CANMOUNT: 15563234Sck153898 case ZFS_PROP_XATTR: 1557789Sahrens /* 1558789Sahrens * Basic boolean values are built on top of 1559789Sahrens * get_numeric_property(). 1560789Sahrens */ 15612082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15622082Seschrock return (-1); 15632082Seschrock nicebool(val, propbuf, proplen); 1564789Sahrens 1565789Sahrens break; 1566789Sahrens 1567789Sahrens case ZFS_PROP_AVAILABLE: 1568789Sahrens case ZFS_PROP_RECORDSIZE: 1569789Sahrens case ZFS_PROP_CREATETXG: 1570789Sahrens case ZFS_PROP_REFERENCED: 1571789Sahrens case ZFS_PROP_USED: 1572789Sahrens case ZFS_PROP_VOLSIZE: 1573789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 15743377Seschrock case ZFS_PROP_NUMCLONES: 1575789Sahrens /* 1576789Sahrens * Basic numeric values are built on top of 1577789Sahrens * get_numeric_property(). 1578789Sahrens */ 15792082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15802082Seschrock return (-1); 1581789Sahrens if (literal) 15822856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 15833912Slling (u_longlong_t)val); 1584789Sahrens else 1585789Sahrens zfs_nicenum(val, propbuf, proplen); 1586789Sahrens break; 1587789Sahrens 1588789Sahrens case ZFS_PROP_COMPRESSION: 1589789Sahrens case ZFS_PROP_CHECKSUM: 1590789Sahrens case ZFS_PROP_SNAPDIR: 1591789Sahrens case ZFS_PROP_ACLMODE: 1592789Sahrens case ZFS_PROP_ACLINHERIT: 15933835Sahrens case ZFS_PROP_COPIES: 15941356Seschrock val = getprop_uint64(zhp, prop, &source); 15952676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15962676Seschrock (void) strlcpy(propbuf, strval, proplen); 1597789Sahrens break; 1598789Sahrens 1599789Sahrens case ZFS_PROP_CREATION: 1600789Sahrens /* 1601789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1602789Sahrens * this into a string unless 'literal' is specified. 1603789Sahrens */ 1604789Sahrens { 16052885Sahrens val = getprop_uint64(zhp, prop, &source); 16062885Sahrens time_t time = (time_t)val; 1607789Sahrens struct tm t; 1608789Sahrens 1609789Sahrens if (literal || 1610789Sahrens localtime_r(&time, &t) == NULL || 1611789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1612789Sahrens &t) == 0) 16132885Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1614789Sahrens } 1615789Sahrens break; 1616789Sahrens 1617789Sahrens case ZFS_PROP_MOUNTPOINT: 1618789Sahrens /* 1619789Sahrens * Getting the precise mountpoint can be tricky. 1620789Sahrens * 1621789Sahrens * - for 'none' or 'legacy', return those values. 1622789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1623789Sahrens * - for inherited mountpoints, we want to take everything 1624789Sahrens * after our ancestor and append it to the inherited value. 1625789Sahrens * 1626789Sahrens * If the pool has an alternate root, we want to prepend that 1627789Sahrens * root to any values we return. 1628789Sahrens */ 16291544Seschrock root = zhp->zfs_root; 16301356Seschrock str = getprop_string(zhp, prop, &source); 16311356Seschrock 16321356Seschrock if (str[0] == '\0') { 1633789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1634789Sahrens root, zhp->zfs_name); 16351356Seschrock } else if (str[0] == '/') { 16361356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1637789Sahrens 1638789Sahrens if (relpath[0] == '/') 1639789Sahrens relpath++; 16401356Seschrock if (str[1] == '\0') 16411356Seschrock str++; 1642789Sahrens 1643789Sahrens if (relpath[0] == '\0') 1644789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 16451356Seschrock root, str); 1646789Sahrens else 1647789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16481356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1649789Sahrens relpath); 1650789Sahrens } else { 1651789Sahrens /* 'legacy' or 'none' */ 16521356Seschrock (void) strlcpy(propbuf, str, proplen); 1653789Sahrens } 1654789Sahrens 1655789Sahrens break; 1656789Sahrens 1657789Sahrens case ZFS_PROP_SHARENFS: 16583126Sahl case ZFS_PROP_SHAREISCSI: 16593126Sahl case ZFS_PROP_ISCSIOPTIONS: 16601356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16611356Seschrock proplen); 1662789Sahrens break; 1663789Sahrens 1664789Sahrens case ZFS_PROP_ORIGIN: 16652885Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1666789Sahrens proplen); 1667789Sahrens /* 1668789Sahrens * If there is no parent at all, return failure to indicate that 1669789Sahrens * it doesn't apply to this dataset. 1670789Sahrens */ 1671789Sahrens if (propbuf[0] == '\0') 1672789Sahrens return (-1); 1673789Sahrens break; 1674789Sahrens 1675789Sahrens case ZFS_PROP_QUOTA: 1676789Sahrens case ZFS_PROP_RESERVATION: 16772082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16782082Seschrock return (-1); 1679789Sahrens 1680789Sahrens /* 1681789Sahrens * If quota or reservation is 0, we translate this into 'none' 1682789Sahrens * (unless literal is set), and indicate that it's the default 1683789Sahrens * value. Otherwise, we print the number nicely and indicate 1684789Sahrens * that its set locally. 1685789Sahrens */ 1686789Sahrens if (val == 0) { 1687789Sahrens if (literal) 1688789Sahrens (void) strlcpy(propbuf, "0", proplen); 1689789Sahrens else 1690789Sahrens (void) strlcpy(propbuf, "none", proplen); 1691789Sahrens } else { 1692789Sahrens if (literal) 16932856Snd150628 (void) snprintf(propbuf, proplen, "%llu", 16943912Slling (u_longlong_t)val); 1695789Sahrens else 1696789Sahrens zfs_nicenum(val, propbuf, proplen); 1697789Sahrens } 1698789Sahrens break; 1699789Sahrens 1700789Sahrens case ZFS_PROP_COMPRESSRATIO: 17012082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 17022082Seschrock return (-1); 17032856Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 17042856Snd150628 val / 100, (longlong_t)val % 100); 1705789Sahrens break; 1706789Sahrens 1707789Sahrens case ZFS_PROP_TYPE: 1708789Sahrens switch (zhp->zfs_type) { 1709789Sahrens case ZFS_TYPE_FILESYSTEM: 1710789Sahrens str = "filesystem"; 1711789Sahrens break; 1712789Sahrens case ZFS_TYPE_VOLUME: 1713789Sahrens str = "volume"; 1714789Sahrens break; 1715789Sahrens case ZFS_TYPE_SNAPSHOT: 1716789Sahrens str = "snapshot"; 1717789Sahrens break; 1718789Sahrens default: 17192082Seschrock abort(); 1720789Sahrens } 1721789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1722789Sahrens break; 1723789Sahrens 1724789Sahrens case ZFS_PROP_MOUNTED: 1725789Sahrens /* 1726789Sahrens * The 'mounted' property is a pseudo-property that described 1727789Sahrens * whether the filesystem is currently mounted. Even though 1728789Sahrens * it's a boolean value, the typical values of "on" and "off" 1729789Sahrens * don't make sense, so we translate to "yes" and "no". 1730789Sahrens */ 17312082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 17322082Seschrock src, &source, &val) != 0) 17332082Seschrock return (-1); 17342082Seschrock if (val) 1735789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1736789Sahrens else 1737789Sahrens (void) strlcpy(propbuf, "no", proplen); 1738789Sahrens break; 1739789Sahrens 1740789Sahrens case ZFS_PROP_NAME: 1741789Sahrens /* 1742789Sahrens * The 'name' property is a pseudo-property derived from the 1743789Sahrens * dataset name. It is presented as a real property to simplify 1744789Sahrens * consumers. 1745789Sahrens */ 1746789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1747789Sahrens break; 1748789Sahrens 1749789Sahrens default: 17502082Seschrock abort(); 1751789Sahrens } 1752789Sahrens 1753789Sahrens get_source(zhp, src, source, statbuf, statlen); 1754789Sahrens 1755789Sahrens return (0); 1756789Sahrens } 1757789Sahrens 1758789Sahrens /* 1759789Sahrens * Utility function to get the given numeric property. Does no validation that 1760789Sahrens * the given property is the appropriate type; should only be used with 1761789Sahrens * hard-coded property types. 1762789Sahrens */ 1763789Sahrens uint64_t 1764789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1765789Sahrens { 1766789Sahrens char *source; 1767789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17682082Seschrock uint64_t val; 17692082Seschrock 17702082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17712082Seschrock 17722082Seschrock return (val); 1773789Sahrens } 1774789Sahrens 1775789Sahrens /* 1776789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1777789Sahrens */ 1778789Sahrens int 1779789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1780789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1781789Sahrens { 1782789Sahrens char *source; 1783789Sahrens 1784789Sahrens /* 1785789Sahrens * Check to see if this property applies to our object 1786789Sahrens */ 1787789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17883237Slling return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 17892082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17902082Seschrock zfs_prop_to_name(prop))); 1791789Sahrens 1792789Sahrens if (src) 1793789Sahrens *src = ZFS_SRC_NONE; 1794789Sahrens 17952082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17962082Seschrock return (-1); 1797789Sahrens 1798789Sahrens get_source(zhp, src, source, statbuf, statlen); 1799789Sahrens 1800789Sahrens return (0); 1801789Sahrens } 1802789Sahrens 1803789Sahrens /* 1804789Sahrens * Returns the name of the given zfs handle. 1805789Sahrens */ 1806789Sahrens const char * 1807789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1808789Sahrens { 1809789Sahrens return (zhp->zfs_name); 1810789Sahrens } 1811789Sahrens 1812789Sahrens /* 1813789Sahrens * Returns the type of the given zfs handle. 1814789Sahrens */ 1815789Sahrens zfs_type_t 1816789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1817789Sahrens { 1818789Sahrens return (zhp->zfs_type); 1819789Sahrens } 1820789Sahrens 1821789Sahrens /* 18221356Seschrock * Iterate over all child filesystems 1823789Sahrens */ 1824789Sahrens int 18251356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1826789Sahrens { 1827789Sahrens zfs_cmd_t zc = { 0 }; 1828789Sahrens zfs_handle_t *nzhp; 1829789Sahrens int ret; 1830789Sahrens 1831789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18322082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1833789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1834789Sahrens /* 1835789Sahrens * Ignore private dataset names. 1836789Sahrens */ 1837789Sahrens if (dataset_name_hidden(zc.zc_name)) 1838789Sahrens continue; 1839789Sahrens 1840789Sahrens /* 1841789Sahrens * Silently ignore errors, as the only plausible explanation is 1842789Sahrens * that the pool has since been removed. 1843789Sahrens */ 18442082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18452082Seschrock zc.zc_name)) == NULL) 1846789Sahrens continue; 1847789Sahrens 1848789Sahrens if ((ret = func(nzhp, data)) != 0) 1849789Sahrens return (ret); 1850789Sahrens } 1851789Sahrens 1852789Sahrens /* 1853789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1854789Sahrens * returned, then the underlying dataset has been removed since we 1855789Sahrens * obtained the handle. 1856789Sahrens */ 1857789Sahrens if (errno != ESRCH && errno != ENOENT) 18582082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18592082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1860789Sahrens 18611356Seschrock return (0); 18621356Seschrock } 18631356Seschrock 18641356Seschrock /* 18651356Seschrock * Iterate over all snapshots 18661356Seschrock */ 18671356Seschrock int 18681356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18691356Seschrock { 18701356Seschrock zfs_cmd_t zc = { 0 }; 18711356Seschrock zfs_handle_t *nzhp; 18721356Seschrock int ret; 1873789Sahrens 1874789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18752082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18762082Seschrock &zc) == 0; 1877789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1878789Sahrens 18792082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18802082Seschrock zc.zc_name)) == NULL) 1881789Sahrens continue; 1882789Sahrens 1883789Sahrens if ((ret = func(nzhp, data)) != 0) 1884789Sahrens return (ret); 1885789Sahrens } 1886789Sahrens 1887789Sahrens /* 1888789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1889789Sahrens * returned, then the underlying dataset has been removed since we 1890789Sahrens * obtained the handle. Silently ignore this case, and return success. 1891789Sahrens */ 1892789Sahrens if (errno != ESRCH && errno != ENOENT) 18932082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18942082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1895789Sahrens 1896789Sahrens return (0); 1897789Sahrens } 1898789Sahrens 1899789Sahrens /* 19001356Seschrock * Iterate over all children, snapshots and filesystems 19011356Seschrock */ 19021356Seschrock int 19031356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 19041356Seschrock { 19051356Seschrock int ret; 19061356Seschrock 19071356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 19081356Seschrock return (ret); 19091356Seschrock 19101356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 19111356Seschrock } 19121356Seschrock 19131356Seschrock /* 1914789Sahrens * Given a complete name, return just the portion that refers to the parent. 1915789Sahrens * Can return NULL if this is a pool. 1916789Sahrens */ 1917789Sahrens static int 1918789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1919789Sahrens { 1920789Sahrens char *loc; 1921789Sahrens 1922789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1923789Sahrens return (-1); 1924789Sahrens 1925789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1926789Sahrens buf[loc - path] = '\0'; 1927789Sahrens 1928789Sahrens return (0); 1929789Sahrens } 1930789Sahrens 1931789Sahrens /* 19322676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 19332676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 19342676Seschrock * when creating new datasets. 1935789Sahrens */ 1936789Sahrens static int 19372676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1938789Sahrens { 1939789Sahrens zfs_cmd_t zc = { 0 }; 1940789Sahrens char parent[ZFS_MAXNAMELEN]; 1941789Sahrens char *slash; 19421356Seschrock zfs_handle_t *zhp; 19432082Seschrock char errbuf[1024]; 19442082Seschrock 19452082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 19462082Seschrock path); 1947789Sahrens 1948789Sahrens /* get parent, and check to see if this is just a pool */ 1949789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 19502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19512082Seschrock "missing dataset name")); 19522082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1953789Sahrens } 1954789Sahrens 1955789Sahrens /* check to see if the pool exists */ 1956789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1957789Sahrens slash = parent + strlen(parent); 1958789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1959789Sahrens zc.zc_name[slash - parent] = '\0'; 19602082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1961789Sahrens errno == ENOENT) { 19622082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19632082Seschrock "no such pool '%s'"), zc.zc_name); 19642082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1965789Sahrens } 1966789Sahrens 1967789Sahrens /* check to see if the parent dataset exists */ 19682082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1969789Sahrens switch (errno) { 1970789Sahrens case ENOENT: 19712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19722082Seschrock "parent does not exist")); 19732082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1974789Sahrens 1975789Sahrens default: 19762082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1977789Sahrens } 1978789Sahrens } 1979789Sahrens 19802676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1981789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19822676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19832082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19841356Seschrock zfs_close(zhp); 1985789Sahrens return (-1); 1986789Sahrens } 1987789Sahrens 1988789Sahrens /* make sure parent is a filesystem */ 19891356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19912082Seschrock "parent is not a filesystem")); 19922082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19931356Seschrock zfs_close(zhp); 1994789Sahrens return (-1); 1995789Sahrens } 1996789Sahrens 19971356Seschrock zfs_close(zhp); 1998789Sahrens return (0); 1999789Sahrens } 2000789Sahrens 2001789Sahrens /* 20022676Seschrock * Create a new filesystem or volume. 2003789Sahrens */ 2004789Sahrens int 20052082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 20062676Seschrock nvlist_t *props) 2007789Sahrens { 2008789Sahrens zfs_cmd_t zc = { 0 }; 2009789Sahrens int ret; 2010789Sahrens uint64_t size = 0; 2011789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 20122082Seschrock char errbuf[1024]; 20132676Seschrock uint64_t zoned; 20142082Seschrock 20152082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 20162082Seschrock "cannot create '%s'"), path); 2017789Sahrens 2018789Sahrens /* validate the path, taking care to note the extended error message */ 20192082Seschrock if (!zfs_validate_name(hdl, path, type)) 20202082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2021789Sahrens 2022789Sahrens /* validate parents exist */ 20232676Seschrock if (check_parents(hdl, path, &zoned) != 0) 2024789Sahrens return (-1); 2025789Sahrens 2026789Sahrens /* 2027789Sahrens * The failure modes when creating a dataset of a different type over 2028789Sahrens * one that already exists is a little strange. In particular, if you 2029789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 2030789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 2031789Sahrens * first try to see if the dataset exists. 2032789Sahrens */ 2033789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 20342082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 20352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20362082Seschrock "dataset already exists")); 20372082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2038789Sahrens } 2039789Sahrens 2040789Sahrens if (type == ZFS_TYPE_VOLUME) 2041789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2042789Sahrens else 2043789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2044789Sahrens 20453912Slling if (props && (props = zfs_validate_properties(hdl, type, NULL, props, 20463912Slling zoned, NULL, errbuf)) == 0) 20472676Seschrock return (-1); 20482676Seschrock 2049789Sahrens if (type == ZFS_TYPE_VOLUME) { 20501133Seschrock /* 20511133Seschrock * If we are creating a volume, the size and block size must 20521133Seschrock * satisfy a few restraints. First, the blocksize must be a 20531133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20541133Seschrock * volsize must be a multiple of the block size, and cannot be 20551133Seschrock * zero. 20561133Seschrock */ 20572676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 20582676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 20592676Seschrock nvlist_free(props); 20602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20612676Seschrock "missing volume size")); 20622676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2063789Sahrens } 2064789Sahrens 20652676Seschrock if ((ret = nvlist_lookup_uint64(props, 20662676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20672676Seschrock &blocksize)) != 0) { 20682676Seschrock if (ret == ENOENT) { 20692676Seschrock blocksize = zfs_prop_default_numeric( 20702676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20712676Seschrock } else { 20722676Seschrock nvlist_free(props); 20732676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20742676Seschrock "missing volume block size")); 20752676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20762676Seschrock } 20772676Seschrock } 20782676Seschrock 20792676Seschrock if (size == 0) { 20802676Seschrock nvlist_free(props); 20812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20822676Seschrock "volume size cannot be zero")); 20832676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20841133Seschrock } 20851133Seschrock 20861133Seschrock if (size % blocksize != 0) { 20872676Seschrock nvlist_free(props); 20882082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20892676Seschrock "volume size must be a multiple of volume block " 20902676Seschrock "size")); 20912676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20921133Seschrock } 2093789Sahrens } 2094789Sahrens 20952676Seschrock if (props && 20962676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20972676Seschrock return (-1); 20982676Seschrock nvlist_free(props); 20992676Seschrock 2100789Sahrens /* create the dataset */ 21012082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2102789Sahrens 21033912Slling if (ret == 0 && type == ZFS_TYPE_VOLUME) { 21042082Seschrock ret = zvol_create_link(hdl, path); 21053912Slling if (ret) { 21063912Slling (void) zfs_standard_error(hdl, errno, 21073912Slling dgettext(TEXT_DOMAIN, 21083912Slling "Volume successfully created, but device links " 21093912Slling "were not created")); 21103912Slling zcmd_free_nvlists(&zc); 21113912Slling return (-1); 21123912Slling } 21133912Slling } 2114789Sahrens 21152676Seschrock zcmd_free_nvlists(&zc); 21162676Seschrock 2117789Sahrens /* check for failure */ 2118789Sahrens if (ret != 0) { 2119789Sahrens char parent[ZFS_MAXNAMELEN]; 2120789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2121789Sahrens 2122789Sahrens switch (errno) { 2123789Sahrens case ENOENT: 21242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21252082Seschrock "no such parent '%s'"), parent); 21262082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2127789Sahrens 2128789Sahrens case EINVAL: 21292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21303413Smmusante "parent '%s' is not a filesystem"), parent); 21312082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2132789Sahrens 2133789Sahrens case EDOM: 21342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21352676Seschrock "volume block size must be power of 2 from " 21362676Seschrock "%u to %uk"), 2137789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2138789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 21392082Seschrock 21402676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 21412082Seschrock 2142789Sahrens #ifdef _ILP32 2143789Sahrens case EOVERFLOW: 2144789Sahrens /* 2145789Sahrens * This platform can't address a volume this big. 2146789Sahrens */ 21472082Seschrock if (type == ZFS_TYPE_VOLUME) 21482082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 21492082Seschrock errbuf)); 2150789Sahrens #endif 21512082Seschrock /* FALLTHROUGH */ 2152789Sahrens default: 21532082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2154789Sahrens } 2155789Sahrens } 2156789Sahrens 2157789Sahrens return (0); 2158789Sahrens } 2159789Sahrens 2160789Sahrens /* 2161789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2162789Sahrens * isn't mounted, and that there are no active dependents. 2163789Sahrens */ 2164789Sahrens int 2165789Sahrens zfs_destroy(zfs_handle_t *zhp) 2166789Sahrens { 2167789Sahrens zfs_cmd_t zc = { 0 }; 2168789Sahrens 2169789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2170789Sahrens 21712676Seschrock if (ZFS_IS_VOLUME(zhp)) { 21723126Sahl /* 21733126Sahl * Unconditionally unshare this zvol ignoring failure as it 21743126Sahl * indicates only that the volume wasn't shared initially. 21753126Sahl */ 21763126Sahl (void) zfs_unshare_iscsi(zhp); 21773126Sahl 21782082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2179789Sahrens return (-1); 2180789Sahrens 2181789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2182789Sahrens } else { 2183789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2184789Sahrens } 2185789Sahrens 21863126Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 21873237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 21882082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21892082Seschrock zhp->zfs_name)); 21902199Sahrens } 2191789Sahrens 2192789Sahrens remove_mountpoint(zhp); 2193789Sahrens 2194789Sahrens return (0); 2195789Sahrens } 2196789Sahrens 21972199Sahrens struct destroydata { 21982199Sahrens char *snapname; 21992199Sahrens boolean_t gotone; 22003265Sahrens boolean_t closezhp; 22012199Sahrens }; 22022199Sahrens 22032199Sahrens static int 22042199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 22052199Sahrens { 22062199Sahrens struct destroydata *dd = arg; 22072199Sahrens zfs_handle_t *szhp; 22082199Sahrens char name[ZFS_MAXNAMELEN]; 22093265Sahrens boolean_t closezhp = dd->closezhp; 22103265Sahrens int rv; 22112199Sahrens 22122676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 22132676Seschrock (void) strlcat(name, "@", sizeof (name)); 22142676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 22152199Sahrens 22162199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 22172199Sahrens if (szhp) { 22182199Sahrens dd->gotone = B_TRUE; 22192199Sahrens zfs_close(szhp); 22202199Sahrens } 22212199Sahrens 22222199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 22232199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 22242199Sahrens /* 22252199Sahrens * NB: this is simply a best-effort. We don't want to 22262199Sahrens * return an error, because then we wouldn't visit all 22272199Sahrens * the volumes. 22282199Sahrens */ 22292199Sahrens } 22302199Sahrens 22313265Sahrens dd->closezhp = B_TRUE; 22323265Sahrens rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 22333265Sahrens if (closezhp) 22343265Sahrens zfs_close(zhp); 22353265Sahrens return (rv); 22362199Sahrens } 22372199Sahrens 22382199Sahrens /* 22392199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 22402199Sahrens */ 22412199Sahrens int 22422199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 22432199Sahrens { 22442199Sahrens zfs_cmd_t zc = { 0 }; 22452199Sahrens int ret; 22462199Sahrens struct destroydata dd = { 0 }; 22472199Sahrens 22482199Sahrens dd.snapname = snapname; 22492199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 22502199Sahrens 22512199Sahrens if (!dd.gotone) { 22523237Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 22532199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 22542199Sahrens zhp->zfs_name, snapname)); 22552199Sahrens } 22562199Sahrens 22572199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 22582676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 22592199Sahrens 22602199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 22612199Sahrens if (ret != 0) { 22622199Sahrens char errbuf[1024]; 22632199Sahrens 22642199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22652199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22662199Sahrens 22672199Sahrens switch (errno) { 22682199Sahrens case EEXIST: 22692199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22702199Sahrens "snapshot is cloned")); 22712199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22722199Sahrens 22732199Sahrens default: 22742199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22752199Sahrens errbuf)); 22762199Sahrens } 22772199Sahrens } 22782199Sahrens 22792199Sahrens return (0); 22802199Sahrens } 22812199Sahrens 2282789Sahrens /* 2283789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2284789Sahrens */ 2285789Sahrens int 22862676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2287789Sahrens { 2288789Sahrens zfs_cmd_t zc = { 0 }; 2289789Sahrens char parent[ZFS_MAXNAMELEN]; 2290789Sahrens int ret; 22912082Seschrock char errbuf[1024]; 22922082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22932676Seschrock zfs_type_t type; 22942676Seschrock uint64_t zoned; 2295789Sahrens 2296789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2297789Sahrens 22982082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22992082Seschrock "cannot create '%s'"), target); 23002082Seschrock 2301789Sahrens /* validate the target name */ 23022082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 23032082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2304789Sahrens 2305789Sahrens /* validate parents exist */ 23062676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2307789Sahrens return (-1); 2308789Sahrens 2309789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2310789Sahrens 2311789Sahrens /* do the clone */ 23122676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2313789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 23142744Snn35248 type = ZFS_TYPE_VOLUME; 23152676Seschrock } else { 2316789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 23172744Snn35248 type = ZFS_TYPE_FILESYSTEM; 23182676Seschrock } 23192676Seschrock 23202676Seschrock if (props) { 23213912Slling if ((props = zfs_validate_properties(hdl, type, NULL, props, 23223912Slling zoned, zhp, errbuf)) == NULL) 23232676Seschrock return (-1); 23242676Seschrock 23252676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 23262676Seschrock nvlist_free(props); 23272676Seschrock return (-1); 23282676Seschrock } 23292676Seschrock 23302676Seschrock nvlist_free(props); 23312676Seschrock } 2332789Sahrens 2333789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 23342676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 23352082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2336789Sahrens 23372676Seschrock zcmd_free_nvlists(&zc); 23382676Seschrock 2339789Sahrens if (ret != 0) { 2340789Sahrens switch (errno) { 2341789Sahrens 2342789Sahrens case ENOENT: 2343789Sahrens /* 2344789Sahrens * The parent doesn't exist. We should have caught this 2345789Sahrens * above, but there may a race condition that has since 2346789Sahrens * destroyed the parent. 2347789Sahrens * 2348789Sahrens * At this point, we don't know whether it's the source 2349789Sahrens * that doesn't exist anymore, or whether the target 2350789Sahrens * dataset doesn't exist. 2351789Sahrens */ 23522082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23532082Seschrock "no such parent '%s'"), parent); 23542082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 23552082Seschrock 23562082Seschrock case EXDEV: 23572082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23582082Seschrock "source and target pools differ")); 23592082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 23602082Seschrock errbuf)); 23612082Seschrock 23622082Seschrock default: 23632082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 23642082Seschrock errbuf)); 23652082Seschrock } 23662676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 23672082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 23682082Seschrock } 23692082Seschrock 23702082Seschrock return (ret); 23712082Seschrock } 23722082Seschrock 23732082Seschrock typedef struct promote_data { 23742082Seschrock char cb_mountpoint[MAXPATHLEN]; 23752082Seschrock const char *cb_target; 23762082Seschrock const char *cb_errbuf; 23772082Seschrock uint64_t cb_pivot_txg; 23782082Seschrock } promote_data_t; 23792082Seschrock 23802082Seschrock static int 23812082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 23822082Seschrock { 23832082Seschrock promote_data_t *pd = data; 23842082Seschrock zfs_handle_t *szhp; 23852082Seschrock char snapname[MAXPATHLEN]; 23863265Sahrens int rv = 0; 23872082Seschrock 23882082Seschrock /* We don't care about snapshots after the pivot point */ 23893265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 23903265Sahrens zfs_close(zhp); 23912082Seschrock return (0); 23923265Sahrens } 23932082Seschrock 23942417Sahrens /* Remove the device link if it's a zvol. */ 23952676Seschrock if (ZFS_IS_VOLUME(zhp)) 23962417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23972082Seschrock 23982082Seschrock /* Check for conflicting names */ 23992676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 24002676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 24012082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 24022082Seschrock if (szhp != NULL) { 24032082Seschrock zfs_close(szhp); 24042082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 24052082Seschrock "snapshot name '%s' from origin \n" 24062082Seschrock "conflicts with '%s' from target"), 24072082Seschrock zhp->zfs_name, snapname); 24083265Sahrens rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 24092082Seschrock } 24103265Sahrens zfs_close(zhp); 24113265Sahrens return (rv); 24122082Seschrock } 24132082Seschrock 24142417Sahrens static int 24152417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 24162417Sahrens { 24172417Sahrens promote_data_t *pd = data; 24182417Sahrens 24192417Sahrens /* We don't care about snapshots after the pivot point */ 24203265Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 24213265Sahrens /* Create the device link if it's a zvol. */ 24223265Sahrens if (ZFS_IS_VOLUME(zhp)) 24233265Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 24243265Sahrens } 24253265Sahrens 24263265Sahrens zfs_close(zhp); 24272417Sahrens return (0); 24282417Sahrens } 24292417Sahrens 24302082Seschrock /* 24312082Seschrock * Promotes the given clone fs to be the clone parent. 24322082Seschrock */ 24332082Seschrock int 24342082Seschrock zfs_promote(zfs_handle_t *zhp) 24352082Seschrock { 24362082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 24372082Seschrock zfs_cmd_t zc = { 0 }; 24382082Seschrock char parent[MAXPATHLEN]; 24392082Seschrock char *cp; 24402082Seschrock int ret; 24412082Seschrock zfs_handle_t *pzhp; 24422082Seschrock promote_data_t pd; 24432082Seschrock char errbuf[1024]; 24442082Seschrock 24452082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24462082Seschrock "cannot promote '%s'"), zhp->zfs_name); 24472082Seschrock 24482082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 24492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24502082Seschrock "snapshots can not be promoted")); 24512082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24522082Seschrock } 24532082Seschrock 24542676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 24552082Seschrock if (parent[0] == '\0') { 24562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24572082Seschrock "not a cloned filesystem")); 24582082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 24592082Seschrock } 24602082Seschrock cp = strchr(parent, '@'); 24612082Seschrock *cp = '\0'; 24622082Seschrock 24632082Seschrock /* Walk the snapshots we will be moving */ 24642082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 24652082Seschrock if (pzhp == NULL) 24662082Seschrock return (-1); 24672082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 24682082Seschrock zfs_close(pzhp); 24692082Seschrock pd.cb_target = zhp->zfs_name; 24702082Seschrock pd.cb_errbuf = errbuf; 24712082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 24722082Seschrock if (pzhp == NULL) 24732082Seschrock return (-1); 24742082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 24752082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 24762082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24772417Sahrens if (ret != 0) { 24782417Sahrens zfs_close(pzhp); 24792082Seschrock return (-1); 24802417Sahrens } 24812082Seschrock 24822082Seschrock /* issue the ioctl */ 24832676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 24842676Seschrock sizeof (zc.zc_value)); 24852082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24862082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 24872082Seschrock 24882082Seschrock if (ret != 0) { 24892417Sahrens int save_errno = errno; 24902417Sahrens 24912417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24922417Sahrens zfs_close(pzhp); 24932417Sahrens 24942417Sahrens switch (save_errno) { 2495789Sahrens case EEXIST: 2496789Sahrens /* 24972082Seschrock * There is a conflicting snapshot name. We 24982082Seschrock * should have caught this above, but they could 24992082Seschrock * have renamed something in the mean time. 2500789Sahrens */ 25012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25022082Seschrock "conflicting snapshot name from parent '%s'"), 25032082Seschrock parent); 25042082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2505789Sahrens 2506789Sahrens default: 25072417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2508789Sahrens } 25092417Sahrens } else { 25102417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2511789Sahrens } 2512789Sahrens 25132417Sahrens zfs_close(pzhp); 2514789Sahrens return (ret); 2515789Sahrens } 2516789Sahrens 2517*4007Smmusante struct createdata { 2518*4007Smmusante const char *cd_snapname; 2519*4007Smmusante int cd_ifexists; 2520*4007Smmusante }; 2521*4007Smmusante 25222199Sahrens static int 25232199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 25242199Sahrens { 2525*4007Smmusante struct createdata *cd = arg; 25262676Seschrock int ret; 25272199Sahrens 25282199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 25292199Sahrens char name[MAXPATHLEN]; 25302199Sahrens 25312676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 25322676Seschrock (void) strlcat(name, "@", sizeof (name)); 2533*4007Smmusante (void) strlcat(name, cd->cd_snapname, sizeof (name)); 2534*4007Smmusante (void) zvol_create_link_common(zhp->zfs_hdl, name, 2535*4007Smmusante cd->cd_ifexists); 25362199Sahrens /* 25372199Sahrens * NB: this is simply a best-effort. We don't want to 25382199Sahrens * return an error, because then we wouldn't visit all 25392199Sahrens * the volumes. 25402199Sahrens */ 25412199Sahrens } 25422676Seschrock 2543*4007Smmusante ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd); 25442676Seschrock 25452676Seschrock zfs_close(zhp); 25462676Seschrock 25472676Seschrock return (ret); 25482199Sahrens } 25492199Sahrens 2550789Sahrens /* 25513504Sahl * Takes a snapshot of the given dataset. 2552789Sahrens */ 2553789Sahrens int 25542199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2555789Sahrens { 2556789Sahrens const char *delim; 2557789Sahrens char *parent; 2558789Sahrens zfs_handle_t *zhp; 2559789Sahrens zfs_cmd_t zc = { 0 }; 2560789Sahrens int ret; 25612082Seschrock char errbuf[1024]; 25622082Seschrock 25632082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25642082Seschrock "cannot snapshot '%s'"), path); 25652082Seschrock 25662082Seschrock /* validate the target name */ 25672082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 25682082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2569789Sahrens 2570789Sahrens /* make sure the parent exists and is of the appropriate type */ 25712199Sahrens delim = strchr(path, '@'); 25722082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 25732082Seschrock return (-1); 2574789Sahrens (void) strncpy(parent, path, delim - path); 2575789Sahrens parent[delim - path] = '\0'; 2576789Sahrens 25772082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2578789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2579789Sahrens free(parent); 2580789Sahrens return (-1); 2581789Sahrens } 2582789Sahrens 25832199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25842676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25852199Sahrens zc.zc_cookie = recursive; 25862199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 25872199Sahrens 25882199Sahrens /* 25892199Sahrens * if it was recursive, the one that actually failed will be in 25902199Sahrens * zc.zc_name. 25912199Sahrens */ 25922199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25932676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25942199Sahrens if (ret == 0 && recursive) { 2595*4007Smmusante struct createdata cd; 2596*4007Smmusante 2597*4007Smmusante cd.cd_snapname = delim + 1; 2598*4007Smmusante cd.cd_ifexists = B_FALSE; 2599*4007Smmusante (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 26002199Sahrens } 2601789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 26022082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 26032199Sahrens if (ret != 0) { 26042082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 26052082Seschrock &zc); 26062199Sahrens } 2607789Sahrens } 2608789Sahrens 26092082Seschrock if (ret != 0) 26102082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2611789Sahrens 2612789Sahrens free(parent); 2613789Sahrens zfs_close(zhp); 2614789Sahrens 2615789Sahrens return (ret); 2616789Sahrens } 2617789Sahrens 2618789Sahrens /* 26193504Sahl * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 26203504Sahl * NULL) to the file descriptor specified by outfd. 2621789Sahrens */ 2622789Sahrens int 26233504Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2624789Sahrens { 2625789Sahrens zfs_cmd_t zc = { 0 }; 26262082Seschrock char errbuf[1024]; 26272885Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 26282082Seschrock 26293504Sahl assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 26303504Sahl 26312885Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 26322885Sahrens if (fromsnap) 26332885Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 26343504Sahl zc.zc_cookie = outfd; 26353504Sahl 26363504Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 26373504Sahl (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26383504Sahl "cannot send '%s'"), zhp->zfs_name); 26393504Sahl 2640789Sahrens switch (errno) { 2641789Sahrens 2642789Sahrens case EXDEV: 26432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26443413Smmusante "not an earlier snapshot from the same fs")); 26452082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2646789Sahrens 2647789Sahrens case EDQUOT: 2648789Sahrens case EFBIG: 2649789Sahrens case EIO: 2650789Sahrens case ENOLINK: 2651789Sahrens case ENOSPC: 2652789Sahrens case ENOSTR: 2653789Sahrens case ENXIO: 2654789Sahrens case EPIPE: 2655789Sahrens case ERANGE: 2656789Sahrens case EFAULT: 2657789Sahrens case EROFS: 26582082Seschrock zfs_error_aux(hdl, strerror(errno)); 26592082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2660789Sahrens 2661789Sahrens default: 26622082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2663789Sahrens } 2664789Sahrens } 2665789Sahrens 26663504Sahl return (0); 2667789Sahrens } 2668789Sahrens 2669789Sahrens /* 26702885Sahrens * Create ancestors of 'target', but not target itself, and not 26712885Sahrens * ancestors whose names are shorter than prefixlen. Die if 26722885Sahrens * prefixlen-ancestor does not exist. 26732885Sahrens */ 26742885Sahrens static int 26752885Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 26762885Sahrens { 26772885Sahrens zfs_handle_t *h; 26782885Sahrens char *cp; 26792885Sahrens 26802885Sahrens /* make sure prefix exists */ 26812885Sahrens cp = strchr(target + prefixlen, '/'); 26822885Sahrens *cp = '\0'; 26832885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 26842885Sahrens *cp = '/'; 26852885Sahrens if (h == NULL) 26862885Sahrens return (-1); 26872885Sahrens zfs_close(h); 26882885Sahrens 26892885Sahrens /* 26902885Sahrens * Attempt to create, mount, and share any ancestor filesystems, 26912885Sahrens * up to the prefixlen-long one. 26922885Sahrens */ 26932885Sahrens for (cp = target + prefixlen + 1; 26942885Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 26952885Sahrens const char *opname; 26962885Sahrens 26972885Sahrens *cp = '\0'; 26982885Sahrens 26992885Sahrens h = make_dataset_handle(hdl, target); 27002885Sahrens if (h) { 27012885Sahrens /* it already exists, nothing to do here */ 27022885Sahrens zfs_close(h); 27032885Sahrens continue; 27042885Sahrens } 27052885Sahrens 27062885Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 27072885Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 27082885Sahrens NULL) != 0) 27092885Sahrens goto ancestorerr; 27102885Sahrens 27112885Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 27122885Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 27132885Sahrens if (h == NULL) 27142885Sahrens goto ancestorerr; 27152885Sahrens 27162885Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 27172885Sahrens if (zfs_mount(h, NULL, 0) != 0) 27182885Sahrens goto ancestorerr; 27192885Sahrens 27202885Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 27212885Sahrens if (zfs_share(h) != 0) 27222885Sahrens goto ancestorerr; 27232885Sahrens 27242885Sahrens zfs_close(h); 27252885Sahrens 27262885Sahrens continue; 27272885Sahrens ancestorerr: 27282885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27292885Sahrens "failed to %s ancestor '%s'"), opname, target); 27302885Sahrens return (-1); 27312885Sahrens } 27322885Sahrens 27332885Sahrens return (0); 27342885Sahrens } 27352885Sahrens 27362885Sahrens /* 27373504Sahl * Restores a backup of tosnap from the file descriptor specified by infd. 2738789Sahrens */ 2739789Sahrens int 27402082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 27413504Sahl int verbose, int dryrun, boolean_t force, int infd) 2742789Sahrens { 2743789Sahrens zfs_cmd_t zc = { 0 }; 2744789Sahrens time_t begin_time; 27452885Sahrens int ioctl_err, err, bytes, size, choplen; 2746789Sahrens char *cp; 2747789Sahrens dmu_replay_record_t drr; 2748789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 27492082Seschrock char errbuf[1024]; 27502665Snd150628 prop_changelist_t *clp; 27512885Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2752789Sahrens 2753789Sahrens begin_time = time(NULL); 2754789Sahrens 27552082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 27562082Seschrock "cannot receive")); 27572082Seschrock 2758789Sahrens /* read in the BEGIN record */ 2759789Sahrens cp = (char *)&drr; 2760789Sahrens bytes = 0; 2761789Sahrens do { 27623504Sahl size = read(infd, cp, sizeof (drr) - bytes); 2763868Sahrens cp += size; 2764868Sahrens bytes += size; 2765868Sahrens } while (size > 0); 2766868Sahrens 2767868Sahrens if (size < 0 || bytes != sizeof (drr)) { 27682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27692082Seschrock "stream (failed to read first record)")); 27702082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2771789Sahrens } 2772789Sahrens 2773789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2774789Sahrens 2775789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2776789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 27772082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27782082Seschrock "stream (bad magic number)")); 27792082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2780789Sahrens } 2781789Sahrens 2782789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2783789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 27842082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 27852082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2786789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 27872082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2788789Sahrens } 2789789Sahrens 27902885Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 27912885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 27923912Slling "stream (bad snapshot name)")); 27932885Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 27942885Sahrens } 2795789Sahrens /* 27962885Sahrens * Determine how much of the snapshot name stored in the stream 27972885Sahrens * we are going to tack on to the name they specified on the 27982885Sahrens * command line, and how much we are going to chop off. 27992885Sahrens * 28002885Sahrens * If they specified a snapshot, chop the entire name stored in 28012885Sahrens * the stream. 2802789Sahrens */ 28032885Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2804789Sahrens if (isprefix) { 28052885Sahrens /* 28062885Sahrens * They specified a fs with -d, we want to tack on 28072885Sahrens * everything but the pool name stored in the stream 28082885Sahrens */ 28092885Sahrens if (strchr(tosnap, '@')) { 28102885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 28112885Sahrens "argument - snapshot not allowed with -d")); 28122885Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2813789Sahrens } 28142885Sahrens cp = strchr(chopprefix, '/'); 2815789Sahrens if (cp == NULL) 28162885Sahrens cp = strchr(chopprefix, '@'); 28172885Sahrens *cp = '\0'; 2818789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2819789Sahrens /* 28202885Sahrens * If they specified a filesystem without -d, we want to 28212885Sahrens * tack on everything after the fs specified in the 28222885Sahrens * first name from the stream. 2823789Sahrens */ 28242885Sahrens cp = strchr(chopprefix, '@'); 28252885Sahrens *cp = '\0'; 2826789Sahrens } 28272885Sahrens choplen = strlen(chopprefix); 28282885Sahrens 28292885Sahrens /* 28302885Sahrens * Determine name of destination snapshot, store in zc_value. 28312885Sahrens */ 28322885Sahrens (void) strcpy(zc.zc_value, tosnap); 28332885Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 28342885Sahrens sizeof (zc.zc_value)); 28353265Sahrens if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 28363265Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 28372885Sahrens 28382885Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2839789Sahrens if (drrb->drr_fromguid) { 2840789Sahrens /* incremental backup stream */ 28412885Sahrens zfs_handle_t *h; 28422885Sahrens 28432885Sahrens /* do the recvbackup ioctl to the containing fs */ 28442885Sahrens *strchr(zc.zc_name, '@') = '\0'; 2845789Sahrens 2846789Sahrens /* make sure destination fs exists */ 28472082Seschrock h = zfs_open(hdl, zc.zc_name, 28482082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 28492082Seschrock if (h == NULL) 2850789Sahrens return (-1); 2851868Sahrens if (!dryrun) { 28522665Snd150628 /* 28532665Snd150628 * We need to unmount all the dependents of the dataset 28542665Snd150628 * and the dataset itself. If it's a volume 28552665Snd150628 * then remove device link. 28562665Snd150628 */ 2857868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 28582665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 28592665Snd150628 if (clp == NULL) 28602665Snd150628 return (-1); 28612665Snd150628 if (changelist_prefix(clp) != 0) { 28622665Snd150628 changelist_free(clp); 28632665Snd150628 return (-1); 28642665Snd150628 } 2865868Sahrens } else { 28662082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2867868Sahrens } 2868868Sahrens } 2869789Sahrens zfs_close(h); 2870789Sahrens } else { 2871789Sahrens /* full backup stream */ 2872789Sahrens 2873868Sahrens /* Make sure destination fs does not exist */ 28742885Sahrens *strchr(zc.zc_name, '@') = '\0'; 28752082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 28762082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28772082Seschrock "destination '%s' exists"), zc.zc_name); 28782082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2879868Sahrens } 2880868Sahrens 28812885Sahrens if (strchr(zc.zc_name, '/') == NULL) { 28822885Sahrens /* 28832885Sahrens * they're trying to do a recv into a 28842885Sahrens * nonexistant topmost filesystem. 28852885Sahrens */ 28862885Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28872885Sahrens "destination does not exist"), zc.zc_name); 28882885Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 28892885Sahrens } 28902885Sahrens 2891868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 28922885Sahrens *strrchr(zc.zc_name, '/') = '\0'; 28932885Sahrens 28942885Sahrens if (isprefix && (err = create_parents(hdl, 28952885Sahrens zc.zc_value, strlen(tosnap))) != 0) { 28962885Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 28972885Sahrens } 28982885Sahrens 2899789Sahrens } 2900789Sahrens 29013504Sahl zc.zc_cookie = infd; 29022676Seschrock zc.zc_guid = force; 2903789Sahrens if (verbose) { 29041749Sahrens (void) printf("%s %s stream of %s into %s\n", 29051749Sahrens dryrun ? "would receive" : "receiving", 2906789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2907789Sahrens drr.drr_u.drr_begin.drr_toname, 29082676Seschrock zc.zc_value); 2909789Sahrens (void) fflush(stdout); 2910789Sahrens } 2911789Sahrens if (dryrun) 2912789Sahrens return (0); 29132082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2914868Sahrens if (ioctl_err != 0) { 2915789Sahrens switch (errno) { 2916789Sahrens case ENODEV: 29172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29182082Seschrock "most recent snapshot does not match incremental " 29192082Seschrock "source")); 29202082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2921789Sahrens break; 2922789Sahrens case ETXTBSY: 29232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29242082Seschrock "destination has been modified since most recent " 29252082Seschrock "snapshot")); 29262082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2927789Sahrens break; 2928789Sahrens case EEXIST: 2929789Sahrens if (drrb->drr_fromguid == 0) { 2930789Sahrens /* it's the containing fs that exists */ 29312676Seschrock cp = strchr(zc.zc_value, '@'); 2932789Sahrens *cp = '\0'; 2933789Sahrens } 29342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29352082Seschrock "destination already exists")); 29363237Slling (void) zfs_error_fmt(hdl, EZFS_EXISTS, 29373237Slling dgettext(TEXT_DOMAIN, "cannot restore to %s"), 29383237Slling zc.zc_value); 2939789Sahrens break; 2940789Sahrens case EINVAL: 29412082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2942868Sahrens break; 29431544Seschrock case ECKSUM: 29442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29452082Seschrock "invalid stream (checksum mismatch)")); 29462082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2947789Sahrens break; 2948789Sahrens default: 29492082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2950789Sahrens } 2951789Sahrens } 2952789Sahrens 2953789Sahrens /* 2954868Sahrens * Mount or recreate the /dev links for the target filesystem 2955868Sahrens * (if created, or if we tore them down to do an incremental 2956868Sahrens * restore), and the /dev links for the new snapshot (if 29572665Snd150628 * created). Also mount any children of the target filesystem 29582665Snd150628 * if we did an incremental receive. 2959789Sahrens */ 29602676Seschrock cp = strchr(zc.zc_value, '@'); 2961868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2962789Sahrens zfs_handle_t *h; 2963789Sahrens 2964789Sahrens *cp = '\0'; 29652676Seschrock h = zfs_open(hdl, zc.zc_value, 2966789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2967868Sahrens *cp = '@'; 2968789Sahrens if (h) { 29692665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 29702082Seschrock err = zvol_create_link(hdl, h->zfs_name); 29711544Seschrock if (err == 0 && ioctl_err == 0) 29722082Seschrock err = zvol_create_link(hdl, 29732676Seschrock zc.zc_value); 29742665Snd150628 } else { 29752665Snd150628 if (drrb->drr_fromguid) { 29762665Snd150628 err = changelist_postfix(clp); 29772665Snd150628 changelist_free(clp); 29782665Snd150628 } else { 29792665Snd150628 err = zfs_mount(h, NULL, 0); 29802665Snd150628 } 2981868Sahrens } 29822665Snd150628 zfs_close(h); 2983789Sahrens } 2984789Sahrens } 2985789Sahrens 2986868Sahrens if (err || ioctl_err) 2987868Sahrens return (-1); 2988789Sahrens 2989789Sahrens if (verbose) { 2990789Sahrens char buf1[64]; 2991789Sahrens char buf2[64]; 2992789Sahrens uint64_t bytes = zc.zc_cookie; 2993789Sahrens time_t delta = time(NULL) - begin_time; 2994789Sahrens if (delta == 0) 2995789Sahrens delta = 1; 2996789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2997789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2998789Sahrens 29991749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 3000789Sahrens buf1, delta, buf2); 3001789Sahrens } 30022665Snd150628 3003789Sahrens return (0); 3004789Sahrens } 3005789Sahrens 3006789Sahrens /* 30071294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 30081294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 30091294Slling * is a dependent and we should just destroy it without checking the transaction 30101294Slling * group. 3011789Sahrens */ 30121294Slling typedef struct rollback_data { 30131294Slling const char *cb_target; /* the snapshot */ 30141294Slling uint64_t cb_create; /* creation time reference */ 30151294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 30161294Slling int cb_error; 30172082Seschrock boolean_t cb_dependent; 30181294Slling } rollback_data_t; 30191294Slling 30201294Slling static int 30211294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 30221294Slling { 30231294Slling rollback_data_t *cbp = data; 30241294Slling 30251294Slling if (!cbp->cb_dependent) { 30261294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 30271294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 30281294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 30291294Slling cbp->cb_create) { 30301294Slling 30312082Seschrock cbp->cb_dependent = B_TRUE; 30322474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 30332474Seschrock cbp) != 0) 30342474Seschrock cbp->cb_error = 1; 30352082Seschrock cbp->cb_dependent = B_FALSE; 30361294Slling 30371294Slling if (zfs_destroy(zhp) != 0) 30381294Slling cbp->cb_error = 1; 30391294Slling else 30401294Slling changelist_remove(zhp, cbp->cb_clp); 30411294Slling } 30421294Slling } else { 30431294Slling if (zfs_destroy(zhp) != 0) 30441294Slling cbp->cb_error = 1; 30451294Slling else 30461294Slling changelist_remove(zhp, cbp->cb_clp); 30471294Slling } 30481294Slling 30491294Slling zfs_close(zhp); 30501294Slling return (0); 30511294Slling } 30521294Slling 30531294Slling /* 30541294Slling * Rollback the dataset to its latest snapshot. 30551294Slling */ 30561294Slling static int 30571294Slling do_rollback(zfs_handle_t *zhp) 3058789Sahrens { 3059789Sahrens int ret; 3060789Sahrens zfs_cmd_t zc = { 0 }; 3061789Sahrens 3062789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3063789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 3064789Sahrens 3065789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 30662082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3067789Sahrens return (-1); 3068789Sahrens 3069789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3070789Sahrens 30712676Seschrock if (ZFS_IS_VOLUME(zhp)) 3072789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3073789Sahrens else 3074789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3075789Sahrens 3076789Sahrens /* 3077789Sahrens * We rely on the consumer to verify that there are no newer snapshots 3078789Sahrens * for the given dataset. Given these constraints, we can simply pass 3079789Sahrens * the name on to the ioctl() call. There is still an unlikely race 3080789Sahrens * condition where the user has taken a snapshot since we verified that 3081789Sahrens * this was the most recent. 3082789Sahrens */ 30832082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 30842082Seschrock &zc)) != 0) { 30853237Slling (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 30862082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 30872082Seschrock zhp->zfs_name); 3088789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 30892082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3090789Sahrens } 3091789Sahrens 3092789Sahrens return (ret); 3093789Sahrens } 3094789Sahrens 3095789Sahrens /* 30961294Slling * Given a dataset, rollback to a specific snapshot, discarding any 30971294Slling * data changes since then and making it the active dataset. 30981294Slling * 30991294Slling * Any snapshots more recent than the target are destroyed, along with 31001294Slling * their dependents. 31011294Slling */ 31021294Slling int 31031294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 31041294Slling { 31051294Slling int ret; 31061294Slling rollback_data_t cb = { 0 }; 31071294Slling prop_changelist_t *clp; 31081294Slling 31091294Slling /* 31101294Slling * Unmount all dependendents of the dataset and the dataset itself. 31111294Slling * The list we need to gather is the same as for doing rename 31121294Slling */ 31131294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 31141294Slling if (clp == NULL) 31151294Slling return (-1); 31161294Slling 31171294Slling if ((ret = changelist_prefix(clp)) != 0) 31181294Slling goto out; 31191294Slling 31201294Slling /* 31211294Slling * Destroy all recent snapshots and its dependends. 31221294Slling */ 31231294Slling cb.cb_target = snap->zfs_name; 31241294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 31251294Slling cb.cb_clp = clp; 31261294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 31271294Slling 31281294Slling if ((ret = cb.cb_error) != 0) { 31291294Slling (void) changelist_postfix(clp); 31301294Slling goto out; 31311294Slling } 31321294Slling 31331294Slling /* 31341294Slling * Now that we have verified that the snapshot is the latest, 31351294Slling * rollback to the given snapshot. 31361294Slling */ 31371294Slling ret = do_rollback(zhp); 31381294Slling 31391294Slling if (ret != 0) { 31401294Slling (void) changelist_postfix(clp); 31411294Slling goto out; 31421294Slling } 31431294Slling 31441294Slling /* 31451294Slling * We only want to re-mount the filesystem if it was mounted in the 31461294Slling * first place. 31471294Slling */ 31481294Slling ret = changelist_postfix(clp); 31491294Slling 31501294Slling out: 31511294Slling changelist_free(clp); 31521294Slling return (ret); 31531294Slling } 31541294Slling 31551294Slling /* 3156789Sahrens * Iterate over all dependents for a given dataset. This includes both 3157789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3158789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3159789Sahrens * libzfs_graph.c. 3160789Sahrens */ 3161789Sahrens int 31622474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 31632474Seschrock zfs_iter_f func, void *data) 3164789Sahrens { 3165789Sahrens char **dependents; 3166789Sahrens size_t count; 3167789Sahrens int i; 3168789Sahrens zfs_handle_t *child; 3169789Sahrens int ret = 0; 3170789Sahrens 31712474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 31722474Seschrock &dependents, &count) != 0) 31732474Seschrock return (-1); 31742474Seschrock 3175789Sahrens for (i = 0; i < count; i++) { 31762082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 31772082Seschrock dependents[i])) == NULL) 3178789Sahrens continue; 3179789Sahrens 3180789Sahrens if ((ret = func(child, data)) != 0) 3181789Sahrens break; 3182789Sahrens } 3183789Sahrens 3184789Sahrens for (i = 0; i < count; i++) 3185789Sahrens free(dependents[i]); 3186789Sahrens free(dependents); 3187789Sahrens 3188789Sahrens return (ret); 3189789Sahrens } 3190789Sahrens 3191789Sahrens /* 3192789Sahrens * Renames the given dataset. 3193789Sahrens */ 3194789Sahrens int 3195*4007Smmusante zfs_rename(zfs_handle_t *zhp, const char *target, int recursive) 3196789Sahrens { 3197789Sahrens int ret; 3198789Sahrens zfs_cmd_t zc = { 0 }; 3199789Sahrens char *delim; 3200*4007Smmusante prop_changelist_t *cl = NULL; 3201*4007Smmusante zfs_handle_t *zhrp = NULL; 3202*4007Smmusante char *parentname = NULL; 3203789Sahrens char parent[ZFS_MAXNAMELEN]; 32042082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 32052082Seschrock char errbuf[1024]; 3206789Sahrens 3207789Sahrens /* if we have the same exact name, just return success */ 3208789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3209789Sahrens return (0); 3210789Sahrens 32112082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 32122082Seschrock "cannot rename to '%s'"), target); 32132082Seschrock 3214789Sahrens /* 3215789Sahrens * Make sure the target name is valid 3216789Sahrens */ 3217789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 32182665Snd150628 if ((strchr(target, '@') == NULL) || 32192665Snd150628 *target == '@') { 32202665Snd150628 /* 32212665Snd150628 * Snapshot target name is abbreviated, 32222665Snd150628 * reconstruct full dataset name 32232665Snd150628 */ 32242665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 32252665Snd150628 sizeof (parent)); 32262665Snd150628 delim = strchr(parent, '@'); 32272665Snd150628 if (strchr(target, '@') == NULL) 32282665Snd150628 *(++delim) = '\0'; 32292665Snd150628 else 32302665Snd150628 *delim = '\0'; 32312665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 32322665Snd150628 target = parent; 32332665Snd150628 } else { 32342665Snd150628 /* 32352665Snd150628 * Make sure we're renaming within the same dataset. 32362665Snd150628 */ 32372665Snd150628 delim = strchr(target, '@'); 32382665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 32392665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 32402665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32412665Snd150628 "snapshots must be part of same " 32422665Snd150628 "dataset")); 32432665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 32443912Slling errbuf)); 32452665Snd150628 } 3246789Sahrens } 32472665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 32482665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3249789Sahrens } else { 3250*4007Smmusante if (recursive) { 3251*4007Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3252*4007Smmusante "recursive rename must be a snapshot")); 3253*4007Smmusante return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3254*4007Smmusante } 3255*4007Smmusante 32562665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 32572665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 32582676Seschrock uint64_t unused; 32592676Seschrock 3260789Sahrens /* validate parents */ 32612676Seschrock if (check_parents(hdl, target, &unused) != 0) 3262789Sahrens return (-1); 3263789Sahrens 3264789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3265789Sahrens 3266789Sahrens /* make sure we're in the same pool */ 3267789Sahrens verify((delim = strchr(target, '/')) != NULL); 3268789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3269789Sahrens zhp->zfs_name[delim - target] != '/') { 32702082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32712082Seschrock "datasets must be within same pool")); 32722082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3273789Sahrens } 32742440Snd150628 32752440Snd150628 /* new name cannot be a child of the current dataset name */ 32762440Snd150628 if (strncmp(parent, zhp->zfs_name, 32773912Slling strlen(zhp->zfs_name)) == 0) { 32782440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32792440Snd150628 "New dataset name cannot be a descendent of " 32802440Snd150628 "current dataset name")); 32812440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 32822440Snd150628 } 3283789Sahrens } 3284789Sahrens 32852082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 32862082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 32872082Seschrock 3288789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3289789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 32902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32912082Seschrock "dataset is used in a non-global zone")); 32922082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3293789Sahrens } 3294789Sahrens 3295*4007Smmusante if (recursive) { 3296*4007Smmusante struct destroydata dd; 3297*4007Smmusante 3298*4007Smmusante parentname = strdup(zhp->zfs_name); 3299*4007Smmusante delim = strchr(parentname, '@'); 3300*4007Smmusante *delim = '\0'; 3301*4007Smmusante zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY); 3302*4007Smmusante if (zhrp == NULL) { 3303*4007Smmusante return (-1); 3304*4007Smmusante } 3305*4007Smmusante 3306*4007Smmusante dd.snapname = delim + 1; 3307*4007Smmusante dd.gotone = B_FALSE; 3308*4007Smmusante dd.closezhp = B_FALSE; 3309*4007Smmusante 3310*4007Smmusante /* We remove any zvol links prior to renaming them */ 3311*4007Smmusante ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3312*4007Smmusante if (ret) { 3313*4007Smmusante goto error; 3314*4007Smmusante } 3315*4007Smmusante } else { 3316*4007Smmusante if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 3317*4007Smmusante return (-1); 3318*4007Smmusante 3319*4007Smmusante if (changelist_haszonedchild(cl)) { 3320*4007Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3321*4007Smmusante "child dataset with inherited mountpoint is used " 3322*4007Smmusante "in a non-global zone")); 3323*4007Smmusante (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3324*4007Smmusante goto error; 3325*4007Smmusante } 3326*4007Smmusante 3327*4007Smmusante if ((ret = changelist_prefix(cl)) != 0) 3328*4007Smmusante goto error; 3329789Sahrens } 3330789Sahrens 33312676Seschrock if (ZFS_IS_VOLUME(zhp)) 3332789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3333789Sahrens else 3334789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3335789Sahrens 33362665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 33372676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 33382665Snd150628 3339*4007Smmusante zc.zc_cookie = recursive; 3340*4007Smmusante 33412082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 3342*4007Smmusante /* 3343*4007Smmusante * if it was recursive, the one that actually failed will 3344*4007Smmusante * be in zc.zc_name 3345*4007Smmusante */ 3346*4007Smmusante (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3347*4007Smmusante "cannot rename to '%s'"), zc.zc_name); 3348*4007Smmusante 3349*4007Smmusante if (recursive && errno == EEXIST) { 3350*4007Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3351*4007Smmusante "a child dataset already has a snapshot " 3352*4007Smmusante "with the new name")); 3353*4007Smmusante (void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf); 3354*4007Smmusante } else { 3355*4007Smmusante (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3356*4007Smmusante } 3357789Sahrens 3358789Sahrens /* 3359789Sahrens * On failure, we still want to remount any filesystems that 3360789Sahrens * were previously mounted, so we don't alter the system state. 3361789Sahrens */ 3362*4007Smmusante if (recursive) { 3363*4007Smmusante struct createdata cd; 3364*4007Smmusante 3365*4007Smmusante /* only create links for datasets that had existed */ 3366*4007Smmusante cd.cd_snapname = delim + 1; 3367*4007Smmusante cd.cd_ifexists = B_TRUE; 3368*4007Smmusante (void) zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3369*4007Smmusante &cd); 3370*4007Smmusante } else { 3371*4007Smmusante (void) changelist_postfix(cl); 3372*4007Smmusante } 3373789Sahrens } else { 3374*4007Smmusante if (recursive) { 3375*4007Smmusante struct createdata cd; 3376*4007Smmusante 3377*4007Smmusante /* only create links for datasets that had existed */ 3378*4007Smmusante cd.cd_snapname = strchr(target, '@') + 1; 3379*4007Smmusante cd.cd_ifexists = B_TRUE; 3380*4007Smmusante ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3381*4007Smmusante &cd); 3382*4007Smmusante } else { 3383*4007Smmusante changelist_rename(cl, zfs_get_name(zhp), target); 3384*4007Smmusante ret = changelist_postfix(cl); 3385*4007Smmusante } 3386789Sahrens } 3387789Sahrens 3388789Sahrens error: 3389*4007Smmusante if (parentname) { 3390*4007Smmusante free(parentname); 3391*4007Smmusante } 3392*4007Smmusante if (zhrp) { 3393*4007Smmusante zfs_close(zhrp); 3394*4007Smmusante } 3395*4007Smmusante if (cl) { 3396*4007Smmusante changelist_free(cl); 3397*4007Smmusante } 3398789Sahrens return (ret); 3399789Sahrens } 3400789Sahrens 3401789Sahrens /* 3402789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3403789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3404789Sahrens */ 3405789Sahrens int 34062082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3407789Sahrens { 3408*4007Smmusante return (zvol_create_link_common(hdl, dataset, B_FALSE)); 3409*4007Smmusante } 3410*4007Smmusante 3411*4007Smmusante static int 3412*4007Smmusante zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3413*4007Smmusante { 3414789Sahrens zfs_cmd_t zc = { 0 }; 34152082Seschrock di_devlink_handle_t dhdl; 3416789Sahrens 3417789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3418789Sahrens 3419789Sahrens /* 3420789Sahrens * Issue the appropriate ioctl. 3421789Sahrens */ 34222082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3423789Sahrens switch (errno) { 3424789Sahrens case EEXIST: 3425789Sahrens /* 3426789Sahrens * Silently ignore the case where the link already 3427789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3428789Sahrens * times without errors. 3429789Sahrens */ 3430789Sahrens return (0); 3431789Sahrens 3432*4007Smmusante case ENOENT: 3433*4007Smmusante /* 3434*4007Smmusante * Dataset does not exist in the kernel. If we 3435*4007Smmusante * don't care (see zfs_rename), then ignore the 3436*4007Smmusante * error quietly. 3437*4007Smmusante */ 3438*4007Smmusante if (ifexists) { 3439*4007Smmusante return (0); 3440*4007Smmusante } 3441*4007Smmusante 3442*4007Smmusante /* FALLTHROUGH */ 3443*4007Smmusante 3444789Sahrens default: 34453237Slling return (zfs_standard_error_fmt(hdl, errno, 34462082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 34472082Seschrock "for '%s'"), dataset)); 3448789Sahrens } 3449789Sahrens } 3450789Sahrens 3451789Sahrens /* 3452789Sahrens * Call devfsadm and wait for the links to magically appear. 3453789Sahrens */ 34542082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 34552082Seschrock zfs_error_aux(hdl, strerror(errno)); 34563237Slling (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 34572082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 34582082Seschrock "for '%s'"), dataset); 34592082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3460789Sahrens return (-1); 3461789Sahrens } else { 34622082Seschrock (void) di_devlink_fini(&dhdl); 3463789Sahrens } 3464789Sahrens 3465789Sahrens return (0); 3466789Sahrens } 3467789Sahrens 3468789Sahrens /* 3469789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3470789Sahrens */ 3471789Sahrens int 34722082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3473789Sahrens { 3474789Sahrens zfs_cmd_t zc = { 0 }; 3475789Sahrens 3476789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3477789Sahrens 34782082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3479789Sahrens switch (errno) { 3480789Sahrens case ENXIO: 3481789Sahrens /* 3482789Sahrens * Silently ignore the case where the link no longer 3483789Sahrens * exists, so that 'zfs volfini' can be run multiple 3484789Sahrens * times without errors. 3485789Sahrens */ 3486789Sahrens return (0); 3487789Sahrens 3488789Sahrens default: 34893237Slling return (zfs_standard_error_fmt(hdl, errno, 34902082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 34912082Seschrock "links for '%s'"), dataset)); 3492789Sahrens } 3493789Sahrens } 3494789Sahrens 3495789Sahrens return (0); 3496789Sahrens } 34972676Seschrock 34982676Seschrock nvlist_t * 34992676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 35002676Seschrock { 35012676Seschrock return (zhp->zfs_user_props); 35022676Seschrock } 35032676Seschrock 35042676Seschrock /* 35052676Seschrock * Given a comma-separated list of properties, contruct a property list 35062676Seschrock * containing both user-defined and native properties. This function will 35072676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 35082676Seschrock * per-dataset basis by zfs_expand_proplist(). 35092676Seschrock */ 35102676Seschrock int 35113912Slling zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields, 35123912Slling zfs_proplist_t **listp, zfs_type_t type) 35132676Seschrock { 35142676Seschrock size_t len; 35152676Seschrock char *s, *p; 35162676Seschrock char c; 35172676Seschrock zfs_prop_t prop; 35182676Seschrock zfs_proplist_t *entry; 35192676Seschrock zfs_proplist_t **last; 35202676Seschrock 35212676Seschrock *listp = NULL; 35222676Seschrock last = listp; 35232676Seschrock 35242676Seschrock /* 35252676Seschrock * If 'all' is specified, return a NULL list. 35262676Seschrock */ 35272676Seschrock if (strcmp(fields, "all") == 0) 35282676Seschrock return (0); 35292676Seschrock 35302676Seschrock /* 35312676Seschrock * If no fields were specified, return an error. 35322676Seschrock */ 35332676Seschrock if (fields[0] == '\0') { 35342676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35352676Seschrock "no properties specified")); 35362676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 35372676Seschrock "bad property list"))); 35382676Seschrock } 35392676Seschrock 35402676Seschrock /* 35412676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 35422676Seschrock * aliases makes this more effort than it's worth. 35432676Seschrock */ 35442676Seschrock s = fields; 35452676Seschrock while (*s != '\0') { 35462676Seschrock if ((p = strchr(s, ',')) == NULL) { 35472676Seschrock len = strlen(s); 35482676Seschrock p = s + len; 35492676Seschrock } else { 35502676Seschrock len = p - s; 35512676Seschrock } 35522676Seschrock 35532676Seschrock /* 35542676Seschrock * Check for empty options. 35552676Seschrock */ 35562676Seschrock if (len == 0) { 35572676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35582676Seschrock "empty property name")); 35592676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 35602676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 35612676Seschrock } 35622676Seschrock 35632676Seschrock /* 35642676Seschrock * Check all regular property names. 35652676Seschrock */ 35662676Seschrock c = s[len]; 35672676Seschrock s[len] = '\0'; 35683912Slling prop = zfs_name_to_prop_common(s, type); 35693912Slling 35703912Slling if (prop != ZFS_PROP_INVAL && 35713912Slling !zfs_prop_valid_for_type(prop, type)) 35723912Slling prop = ZFS_PROP_INVAL; 35732676Seschrock 35742676Seschrock /* 35753912Slling * When no property table entry can be found, return failure if 35763912Slling * this is a pool property or if this isn't a user-defined 35773912Slling * dataset property, 35782676Seschrock */ 35793912Slling if (prop == ZFS_PROP_INVAL && 35803912Slling (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) { 35812676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35822676Seschrock "invalid property '%s'"), s); 35832676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 35842676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 35852676Seschrock } 35862676Seschrock 35872676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 35882676Seschrock return (-1); 35892676Seschrock 35902676Seschrock entry->pl_prop = prop; 35912676Seschrock if (prop == ZFS_PROP_INVAL) { 35922676Seschrock if ((entry->pl_user_prop = 35932676Seschrock zfs_strdup(hdl, s)) == NULL) { 35942676Seschrock free(entry); 35952676Seschrock return (-1); 35962676Seschrock } 35972676Seschrock entry->pl_width = strlen(s); 35982676Seschrock } else { 35992676Seschrock entry->pl_width = zfs_prop_width(prop, 36002676Seschrock &entry->pl_fixed); 36012676Seschrock } 36022676Seschrock 36032676Seschrock *last = entry; 36042676Seschrock last = &entry->pl_next; 36052676Seschrock 36062676Seschrock s = p; 36072676Seschrock if (c == ',') 36082676Seschrock s++; 36092676Seschrock } 36102676Seschrock 36112676Seschrock return (0); 36122676Seschrock } 36132676Seschrock 36143912Slling int 36153912Slling zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 36163912Slling { 36173912Slling return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY)); 36183912Slling } 36193912Slling 36202676Seschrock void 36212676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 36222676Seschrock { 36232676Seschrock zfs_proplist_t *next; 36242676Seschrock 36252676Seschrock while (pl != NULL) { 36262676Seschrock next = pl->pl_next; 36272676Seschrock free(pl->pl_user_prop); 36282676Seschrock free(pl); 36292676Seschrock pl = next; 36302676Seschrock } 36312676Seschrock } 36322676Seschrock 36333654Sgw25295 typedef struct expand_data { 36343654Sgw25295 zfs_proplist_t **last; 36353654Sgw25295 libzfs_handle_t *hdl; 36363654Sgw25295 } expand_data_t; 36373654Sgw25295 36383654Sgw25295 static zfs_prop_t 36393654Sgw25295 zfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 36403654Sgw25295 { 36413654Sgw25295 zfs_proplist_t *entry; 36423654Sgw25295 expand_data_t *edp = cb; 36433654Sgw25295 36443654Sgw25295 if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 36453654Sgw25295 return (ZFS_PROP_INVAL); 36463654Sgw25295 36473654Sgw25295 entry->pl_prop = prop; 36483654Sgw25295 entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 36493654Sgw25295 entry->pl_all = B_TRUE; 36503654Sgw25295 36513654Sgw25295 *(edp->last) = entry; 36523654Sgw25295 edp->last = &entry->pl_next; 36533654Sgw25295 36543654Sgw25295 return (ZFS_PROP_CONT); 36553654Sgw25295 } 36563654Sgw25295 36572676Seschrock int 36583912Slling zfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp, 36593912Slling zfs_type_t type) 36602676Seschrock { 36612676Seschrock zfs_proplist_t *entry; 36623912Slling zfs_proplist_t **last; 36633654Sgw25295 expand_data_t exp; 36642676Seschrock 36652676Seschrock if (*plp == NULL) { 36662676Seschrock /* 36672676Seschrock * If this is the very first time we've been called for an 'all' 36682676Seschrock * specification, expand the list to include all native 36692676Seschrock * properties. 36702676Seschrock */ 36712676Seschrock last = plp; 36723654Sgw25295 36733654Sgw25295 exp.last = last; 36743654Sgw25295 exp.hdl = hdl; 36753654Sgw25295 36763912Slling if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type, 36773654Sgw25295 B_FALSE) == ZFS_PROP_INVAL) 36783654Sgw25295 return (-1); 36792676Seschrock 36802676Seschrock /* 36812676Seschrock * Add 'name' to the beginning of the list, which is handled 36822676Seschrock * specially. 36832676Seschrock */ 36842676Seschrock if ((entry = zfs_alloc(hdl, 36852676Seschrock sizeof (zfs_proplist_t))) == NULL) 36862676Seschrock return (-1); 36872676Seschrock 36882676Seschrock entry->pl_prop = ZFS_PROP_NAME; 36892676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 36902676Seschrock &entry->pl_fixed); 36912676Seschrock entry->pl_all = B_TRUE; 36922676Seschrock entry->pl_next = *plp; 36932676Seschrock *plp = entry; 36942676Seschrock } 36953912Slling return (0); 36963912Slling } 36973912Slling 36983912Slling /* 36993912Slling * This function is used by 'zfs list' to determine the exact set of columns to 37003912Slling * display, and their maximum widths. This does two main things: 37013912Slling * 37023912Slling * - If this is a list of all properties, then expand the list to include 37033912Slling * all native properties, and set a flag so that for each dataset we look 37043912Slling * for new unique user properties and add them to the list. 37053912Slling * 37063912Slling * - For non fixed-width properties, keep track of the maximum width seen 37073912Slling * so that we can size the column appropriately. 37083912Slling */ 37093912Slling int 37103912Slling zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 37113912Slling { 37123912Slling libzfs_handle_t *hdl = zhp->zfs_hdl; 37133912Slling zfs_proplist_t *entry; 37143912Slling zfs_proplist_t **last, **start; 37153912Slling nvlist_t *userprops, *propval; 37163912Slling nvpair_t *elem; 37173912Slling char *strval; 37183912Slling char buf[ZFS_MAXPROPLEN]; 37193912Slling 37203912Slling if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0) 37213912Slling return (-1); 37222676Seschrock 37232676Seschrock userprops = zfs_get_user_props(zhp); 37242676Seschrock 37252676Seschrock entry = *plp; 37262676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 37272676Seschrock /* 37282676Seschrock * Go through and add any user properties as necessary. We 37292676Seschrock * start by incrementing our list pointer to the first 37302676Seschrock * non-native property. 37312676Seschrock */ 37322676Seschrock start = plp; 37332676Seschrock while (*start != NULL) { 37342676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 37352676Seschrock break; 37362676Seschrock start = &(*start)->pl_next; 37372676Seschrock } 37382676Seschrock 37392676Seschrock elem = NULL; 37402676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 37412676Seschrock /* 37422676Seschrock * See if we've already found this property in our list. 37432676Seschrock */ 37442676Seschrock for (last = start; *last != NULL; 37452676Seschrock last = &(*last)->pl_next) { 37462676Seschrock if (strcmp((*last)->pl_user_prop, 37472676Seschrock nvpair_name(elem)) == 0) 37482676Seschrock break; 37492676Seschrock } 37502676Seschrock 37512676Seschrock if (*last == NULL) { 37522676Seschrock if ((entry = zfs_alloc(hdl, 37532676Seschrock sizeof (zfs_proplist_t))) == NULL || 37542676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 37552676Seschrock nvpair_name(elem)))) == NULL) { 37562676Seschrock free(entry); 37572676Seschrock return (-1); 37582676Seschrock } 37592676Seschrock 37602676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 37612676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 37622676Seschrock entry->pl_all = B_TRUE; 37632676Seschrock *last = entry; 37642676Seschrock } 37652676Seschrock } 37662676Seschrock } 37672676Seschrock 37682676Seschrock /* 37692676Seschrock * Now go through and check the width of any non-fixed columns 37702676Seschrock */ 37712676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 37722676Seschrock if (entry->pl_fixed) 37732676Seschrock continue; 37742676Seschrock 37752676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 37762676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 37772676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 37782676Seschrock if (strlen(buf) > entry->pl_width) 37792676Seschrock entry->pl_width = strlen(buf); 37802676Seschrock } 37812676Seschrock } else if (nvlist_lookup_nvlist(userprops, 37822676Seschrock entry->pl_user_prop, &propval) == 0) { 37832676Seschrock verify(nvlist_lookup_string(propval, 37842676Seschrock ZFS_PROP_VALUE, &strval) == 0); 37852676Seschrock if (strlen(strval) > entry->pl_width) 37862676Seschrock entry->pl_width = strlen(strval); 37872676Seschrock } 37882676Seschrock } 37892676Seschrock 37902676Seschrock return (0); 37912676Seschrock } 3792