1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21f3861e1aSahl 22fa9e4066Sahrens /* 23798d5834Sgw25295 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <errno.h> 32fa9e4066Sahrens #include <libdevinfo.h> 33fa9e4066Sahrens #include <libintl.h> 34fa9e4066Sahrens #include <math.h> 35fa9e4066Sahrens #include <stdio.h> 36fa9e4066Sahrens #include <stdlib.h> 37fa9e4066Sahrens #include <strings.h> 38fa9e4066Sahrens #include <unistd.h> 39fa9e4066Sahrens #include <zone.h> 4099653d4eSeschrock #include <fcntl.h> 41fa9e4066Sahrens #include <sys/mntent.h> 42fa9e4066Sahrens #include <sys/mnttab.h> 43b12a1c38Slling #include <sys/mount.h> 44fa9e4066Sahrens 45fa9e4066Sahrens #include <sys/spa.h> 46fa9e4066Sahrens #include <sys/zio.h> 47e9dbad6fSeschrock #include <sys/zap.h> 48fa9e4066Sahrens #include <libzfs.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include "zfs_namecheck.h" 51fa9e4066Sahrens #include "zfs_prop.h" 52fa9e4066Sahrens #include "libzfs_impl.h" 53fa9e4066Sahrens 54fa9e4066Sahrens /* 55fa9e4066Sahrens * Given a single type (not a mask of types), return the type in a human 56fa9e4066Sahrens * readable form. 57fa9e4066Sahrens */ 58fa9e4066Sahrens const char * 59fa9e4066Sahrens zfs_type_to_name(zfs_type_t type) 60fa9e4066Sahrens { 61fa9e4066Sahrens switch (type) { 62fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 63fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 64fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 65fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 66fa9e4066Sahrens case ZFS_TYPE_VOLUME: 67fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 68fa9e4066Sahrens } 69fa9e4066Sahrens 70fa9e4066Sahrens return (NULL); 71fa9e4066Sahrens } 72fa9e4066Sahrens 73fa9e4066Sahrens /* 74fa9e4066Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 75fa9e4066Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 76fa9e4066Sahrens * We guess what the type would have been based on the path and the mask of 77fa9e4066Sahrens * acceptable types. 78fa9e4066Sahrens */ 79fa9e4066Sahrens static const char * 80fa9e4066Sahrens path_to_str(const char *path, int types) 81fa9e4066Sahrens { 82fa9e4066Sahrens /* 83fa9e4066Sahrens * When given a single type, always report the exact type. 84fa9e4066Sahrens */ 85fa9e4066Sahrens if (types == ZFS_TYPE_SNAPSHOT) 86fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 87fa9e4066Sahrens if (types == ZFS_TYPE_FILESYSTEM) 88fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 89fa9e4066Sahrens if (types == ZFS_TYPE_VOLUME) 90fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 91fa9e4066Sahrens 92fa9e4066Sahrens /* 93fa9e4066Sahrens * The user is requesting more than one type of dataset. If this is the 94fa9e4066Sahrens * case, consult the path itself. If we're looking for a snapshot, and 95fa9e4066Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 96fa9e4066Sahrens * snapshot attribute and try again. 97fa9e4066Sahrens */ 98fa9e4066Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 99fa9e4066Sahrens if (strchr(path, '@') != NULL) 100fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 101fa9e4066Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 102fa9e4066Sahrens } 103fa9e4066Sahrens 104fa9e4066Sahrens 105fa9e4066Sahrens /* 106fa9e4066Sahrens * The user has requested either filesystems or volumes. 107fa9e4066Sahrens * We have no way of knowing a priori what type this would be, so always 108fa9e4066Sahrens * report it as "filesystem" or "volume", our two primitive types. 109fa9e4066Sahrens */ 110fa9e4066Sahrens if (types & ZFS_TYPE_FILESYSTEM) 111fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 112fa9e4066Sahrens 113fa9e4066Sahrens assert(types & ZFS_TYPE_VOLUME); 114fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 115fa9e4066Sahrens } 116fa9e4066Sahrens 117fa9e4066Sahrens /* 118fa9e4066Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 119fa9e4066Sahrens * provide a more meaningful error message. We place a more useful message in 120fa9e4066Sahrens * 'buf' detailing exactly why the name was not valid. 121fa9e4066Sahrens */ 122fa9e4066Sahrens static int 12399653d4eSeschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 124fa9e4066Sahrens { 125fa9e4066Sahrens namecheck_err_t why; 126fa9e4066Sahrens char what; 127fa9e4066Sahrens 128fa9e4066Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 12999653d4eSeschrock if (hdl != NULL) { 130fa9e4066Sahrens switch (why) { 131b81d61a6Slling case NAME_ERR_TOOLONG: 13299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13399653d4eSeschrock "name is too long")); 134b81d61a6Slling break; 135b81d61a6Slling 136fa9e4066Sahrens case NAME_ERR_LEADING_SLASH: 13799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13899653d4eSeschrock "leading slash in name")); 139fa9e4066Sahrens break; 140fa9e4066Sahrens 141fa9e4066Sahrens case NAME_ERR_EMPTY_COMPONENT: 14299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 14399653d4eSeschrock "empty component in name")); 144fa9e4066Sahrens break; 145fa9e4066Sahrens 146fa9e4066Sahrens case NAME_ERR_TRAILING_SLASH: 14799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 14899653d4eSeschrock "trailing slash in name")); 149fa9e4066Sahrens break; 150fa9e4066Sahrens 151fa9e4066Sahrens case NAME_ERR_INVALCHAR: 15299653d4eSeschrock zfs_error_aux(hdl, 153fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 15499653d4eSeschrock "'%c' in name"), what); 155fa9e4066Sahrens break; 156fa9e4066Sahrens 157fa9e4066Sahrens case NAME_ERR_MULTIPLE_AT: 15899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 15999653d4eSeschrock "multiple '@' delimiters in name")); 160fa9e4066Sahrens break; 1615ad82045Snd150628 1625ad82045Snd150628 case NAME_ERR_NOLETTER: 1635ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1645ad82045Snd150628 "pool doesn't begin with a letter")); 1655ad82045Snd150628 break; 1665ad82045Snd150628 1675ad82045Snd150628 case NAME_ERR_RESERVED: 1685ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1695ad82045Snd150628 "name is reserved")); 1705ad82045Snd150628 break; 1715ad82045Snd150628 1725ad82045Snd150628 case NAME_ERR_DISKLIKE: 1735ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1745ad82045Snd150628 "reserved disk name")); 1755ad82045Snd150628 break; 176fa9e4066Sahrens } 177fa9e4066Sahrens } 178fa9e4066Sahrens 179fa9e4066Sahrens return (0); 180fa9e4066Sahrens } 181fa9e4066Sahrens 182fa9e4066Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 18399653d4eSeschrock if (hdl != NULL) 18499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18599653d4eSeschrock "snapshot delimiter '@' in filesystem name")); 186fa9e4066Sahrens return (0); 187fa9e4066Sahrens } 188fa9e4066Sahrens 1891d452cf5Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1901d452cf5Sahrens if (hdl != NULL) 1911d452cf5Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 192d7d4af51Smmusante "missing '@' delimiter in snapshot name")); 1931d452cf5Sahrens return (0); 1941d452cf5Sahrens } 1951d452cf5Sahrens 19699653d4eSeschrock return (-1); 197fa9e4066Sahrens } 198fa9e4066Sahrens 199fa9e4066Sahrens int 200fa9e4066Sahrens zfs_name_valid(const char *name, zfs_type_t type) 201fa9e4066Sahrens { 20299653d4eSeschrock return (zfs_validate_name(NULL, name, type)); 203fa9e4066Sahrens } 204fa9e4066Sahrens 205fa9e4066Sahrens /* 206e9dbad6fSeschrock * This function takes the raw DSL properties, and filters out the user-defined 207e9dbad6fSeschrock * properties into a separate nvlist. 208e9dbad6fSeschrock */ 209e9dbad6fSeschrock static int 210e9dbad6fSeschrock process_user_props(zfs_handle_t *zhp) 211e9dbad6fSeschrock { 212e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 213e9dbad6fSeschrock nvpair_t *elem; 214e9dbad6fSeschrock nvlist_t *propval; 215e9dbad6fSeschrock 216e9dbad6fSeschrock nvlist_free(zhp->zfs_user_props); 217e9dbad6fSeschrock 218e9dbad6fSeschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 219e9dbad6fSeschrock return (no_memory(hdl)); 220e9dbad6fSeschrock 221e9dbad6fSeschrock elem = NULL; 222e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 223e9dbad6fSeschrock if (!zfs_prop_user(nvpair_name(elem))) 224e9dbad6fSeschrock continue; 225e9dbad6fSeschrock 226e9dbad6fSeschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 227e9dbad6fSeschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 228e9dbad6fSeschrock nvpair_name(elem), propval) != 0) 229e9dbad6fSeschrock return (no_memory(hdl)); 230e9dbad6fSeschrock } 231e9dbad6fSeschrock 232e9dbad6fSeschrock return (0); 233e9dbad6fSeschrock } 234e9dbad6fSeschrock 235e9dbad6fSeschrock /* 236fa9e4066Sahrens * Utility function to gather stats (objset and zpl) for the given object. 237fa9e4066Sahrens */ 238fa9e4066Sahrens static int 239fa9e4066Sahrens get_stats(zfs_handle_t *zhp) 240fa9e4066Sahrens { 241fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 242e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 243fa9e4066Sahrens 244fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 245fa9e4066Sahrens 246e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 24799653d4eSeschrock return (-1); 2487f7322feSeschrock 24999653d4eSeschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2507f7322feSeschrock if (errno == ENOMEM) { 251e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 252e9dbad6fSeschrock zcmd_free_nvlists(&zc); 25399653d4eSeschrock return (-1); 254e9dbad6fSeschrock } 2557f7322feSeschrock } else { 256e9dbad6fSeschrock zcmd_free_nvlists(&zc); 257fa9e4066Sahrens return (-1); 2587f7322feSeschrock } 2597f7322feSeschrock } 260fa9e4066Sahrens 261a2eea2e1Sahrens zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 262fa9e4066Sahrens 263e9dbad6fSeschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 264ea8dc4b6Seschrock 26599653d4eSeschrock if (zhp->zfs_props) { 26699653d4eSeschrock nvlist_free(zhp->zfs_props); 26799653d4eSeschrock zhp->zfs_props = NULL; 26899653d4eSeschrock } 26999653d4eSeschrock 270e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 271e9dbad6fSeschrock zcmd_free_nvlists(&zc); 27299653d4eSeschrock return (-1); 27399653d4eSeschrock } 274fa9e4066Sahrens 275e9dbad6fSeschrock zcmd_free_nvlists(&zc); 276fa9e4066Sahrens 277e9dbad6fSeschrock if (process_user_props(zhp) != 0) 278e9dbad6fSeschrock return (-1); 27999653d4eSeschrock 280fa9e4066Sahrens return (0); 281fa9e4066Sahrens } 282fa9e4066Sahrens 283fa9e4066Sahrens /* 284fa9e4066Sahrens * Refresh the properties currently stored in the handle. 285fa9e4066Sahrens */ 286fa9e4066Sahrens void 287fa9e4066Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 288fa9e4066Sahrens { 289fa9e4066Sahrens (void) get_stats(zhp); 290fa9e4066Sahrens } 291fa9e4066Sahrens 292fa9e4066Sahrens /* 293fa9e4066Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 294fa9e4066Sahrens * zfs_iter_* to create child handles on the fly. 295fa9e4066Sahrens */ 296fa9e4066Sahrens zfs_handle_t * 29799653d4eSeschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 298fa9e4066Sahrens { 29999653d4eSeschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 30099653d4eSeschrock 30199653d4eSeschrock if (zhp == NULL) 30299653d4eSeschrock return (NULL); 30399653d4eSeschrock 30499653d4eSeschrock zhp->zfs_hdl = hdl; 305fa9e4066Sahrens 30631fd60d3Sahrens top: 307fa9e4066Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 308fa9e4066Sahrens 309fa9e4066Sahrens if (get_stats(zhp) != 0) { 310fa9e4066Sahrens free(zhp); 311fa9e4066Sahrens return (NULL); 312fa9e4066Sahrens } 313fa9e4066Sahrens 31431fd60d3Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 31531fd60d3Sahrens zfs_cmd_t zc = { 0 }; 31631fd60d3Sahrens 31731fd60d3Sahrens /* 31831fd60d3Sahrens * If it is dds_inconsistent, then we've caught it in 31931fd60d3Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 32031fd60d3Sahrens * it is inconsistent from the ZPL's point of view, so 32131fd60d3Sahrens * can't be mounted. However, it could also be that we 32231fd60d3Sahrens * have crashed in the middle of one of those 32331fd60d3Sahrens * operations, in which case we need to get rid of the 32431fd60d3Sahrens * inconsistent state. We do that by either rolling 32531fd60d3Sahrens * back to the previous snapshot (which will fail if 32631fd60d3Sahrens * there is none), or destroying the filesystem. Note 32731fd60d3Sahrens * that if we are still in the middle of an active 32831fd60d3Sahrens * 'receive' or 'destroy', then the rollback and destroy 32931fd60d3Sahrens * will fail with EBUSY and we will drive on as usual. 33031fd60d3Sahrens */ 33131fd60d3Sahrens 33231fd60d3Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 33331fd60d3Sahrens 334a2eea2e1Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 33599653d4eSeschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 33631fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 33731fd60d3Sahrens } else { 33831fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZFS; 33931fd60d3Sahrens } 34031fd60d3Sahrens 34131fd60d3Sahrens /* If we can successfully roll it back, reget the stats */ 34299653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 34331fd60d3Sahrens goto top; 34431fd60d3Sahrens /* 34531fd60d3Sahrens * If we can sucessfully destroy it, pretend that it 34631fd60d3Sahrens * never existed. 34731fd60d3Sahrens */ 34899653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 34931fd60d3Sahrens free(zhp); 35031fd60d3Sahrens errno = ENOENT; 35131fd60d3Sahrens return (NULL); 35231fd60d3Sahrens } 35331fd60d3Sahrens } 35431fd60d3Sahrens 355fa9e4066Sahrens /* 356fa9e4066Sahrens * We've managed to open the dataset and gather statistics. Determine 357fa9e4066Sahrens * the high-level type. 358fa9e4066Sahrens */ 359a2eea2e1Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 360a2eea2e1Sahrens zhp->zfs_head_type = ZFS_TYPE_VOLUME; 361a2eea2e1Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 362a2eea2e1Sahrens zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 363a2eea2e1Sahrens else 364a2eea2e1Sahrens abort(); 365a2eea2e1Sahrens 366fa9e4066Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 367fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 368fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 369fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 370fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 371fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 372fa9e4066Sahrens else 37399653d4eSeschrock abort(); /* we should never see any other types */ 374fa9e4066Sahrens 375fa9e4066Sahrens return (zhp); 376fa9e4066Sahrens } 377fa9e4066Sahrens 378fa9e4066Sahrens /* 379fa9e4066Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 380fa9e4066Sahrens * argument is a mask of acceptable types. The function will print an 381fa9e4066Sahrens * appropriate error message and return NULL if it can't be opened. 382fa9e4066Sahrens */ 383fa9e4066Sahrens zfs_handle_t * 38499653d4eSeschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 385fa9e4066Sahrens { 386fa9e4066Sahrens zfs_handle_t *zhp; 38799653d4eSeschrock char errbuf[1024]; 38899653d4eSeschrock 38999653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 39099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 391fa9e4066Sahrens 392fa9e4066Sahrens /* 39399653d4eSeschrock * Validate the name before we even try to open it. 394fa9e4066Sahrens */ 39599653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 39699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 39799653d4eSeschrock "invalid dataset name")); 39899653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 399fa9e4066Sahrens return (NULL); 400fa9e4066Sahrens } 401fa9e4066Sahrens 402fa9e4066Sahrens /* 403fa9e4066Sahrens * Try to get stats for the dataset, which will tell us if it exists. 404fa9e4066Sahrens */ 405fa9e4066Sahrens errno = 0; 40699653d4eSeschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 407ece3d9b3Slling (void) zfs_standard_error(hdl, errno, errbuf); 408fa9e4066Sahrens return (NULL); 409fa9e4066Sahrens } 410fa9e4066Sahrens 411fa9e4066Sahrens if (!(types & zhp->zfs_type)) { 41299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 41394de1d4cSeschrock zfs_close(zhp); 414fa9e4066Sahrens return (NULL); 415fa9e4066Sahrens } 416fa9e4066Sahrens 417fa9e4066Sahrens return (zhp); 418fa9e4066Sahrens } 419fa9e4066Sahrens 420fa9e4066Sahrens /* 421fa9e4066Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 422fa9e4066Sahrens */ 423fa9e4066Sahrens void 424fa9e4066Sahrens zfs_close(zfs_handle_t *zhp) 425fa9e4066Sahrens { 426fa9e4066Sahrens if (zhp->zfs_mntopts) 427fa9e4066Sahrens free(zhp->zfs_mntopts); 42899653d4eSeschrock nvlist_free(zhp->zfs_props); 429e9dbad6fSeschrock nvlist_free(zhp->zfs_user_props); 430fa9e4066Sahrens free(zhp); 431fa9e4066Sahrens } 432fa9e4066Sahrens 433fa9e4066Sahrens /* 434fa9e4066Sahrens * Given a numeric suffix, convert the value into a number of bits that the 435fa9e4066Sahrens * resulting value must be shifted. 436fa9e4066Sahrens */ 437fa9e4066Sahrens static int 43899653d4eSeschrock str2shift(libzfs_handle_t *hdl, const char *buf) 439fa9e4066Sahrens { 440fa9e4066Sahrens const char *ends = "BKMGTPEZ"; 441fa9e4066Sahrens int i; 442fa9e4066Sahrens 443fa9e4066Sahrens if (buf[0] == '\0') 444fa9e4066Sahrens return (0); 445fa9e4066Sahrens for (i = 0; i < strlen(ends); i++) { 446fa9e4066Sahrens if (toupper(buf[0]) == ends[i]) 447fa9e4066Sahrens break; 448fa9e4066Sahrens } 449fa9e4066Sahrens if (i == strlen(ends)) { 45099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 45199653d4eSeschrock "invalid numeric suffix '%s'"), buf); 452fa9e4066Sahrens return (-1); 453fa9e4066Sahrens } 454fa9e4066Sahrens 455fa9e4066Sahrens /* 456fa9e4066Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 457fa9e4066Sahrens * allow 'BB' - that's just weird. 458fa9e4066Sahrens */ 459fa9e4066Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 46099653d4eSeschrock toupper(buf[0]) != 'B')) 461fa9e4066Sahrens return (10*i); 462fa9e4066Sahrens 46399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 46499653d4eSeschrock "invalid numeric suffix '%s'"), buf); 465fa9e4066Sahrens return (-1); 466fa9e4066Sahrens } 467fa9e4066Sahrens 468fa9e4066Sahrens /* 469fa9e4066Sahrens * Convert a string of the form '100G' into a real number. Used when setting 470fa9e4066Sahrens * properties or creating a volume. 'buf' is used to place an extended error 471fa9e4066Sahrens * message for the caller to use. 472fa9e4066Sahrens */ 473fa9e4066Sahrens static int 47499653d4eSeschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 475fa9e4066Sahrens { 476fa9e4066Sahrens char *end; 477fa9e4066Sahrens int shift; 478fa9e4066Sahrens 479fa9e4066Sahrens *num = 0; 480fa9e4066Sahrens 481fa9e4066Sahrens /* Check to see if this looks like a number. */ 482fa9e4066Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 48399653d4eSeschrock if (hdl) 48499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 48599653d4eSeschrock "bad numeric value '%s'"), value); 486fa9e4066Sahrens return (-1); 487fa9e4066Sahrens } 488fa9e4066Sahrens 489fa9e4066Sahrens /* Rely on stroll() to process the numeric portion. */ 490fa9e4066Sahrens errno = 0; 491fa9e4066Sahrens *num = strtoll(value, &end, 10); 492fa9e4066Sahrens 493fa9e4066Sahrens /* 494fa9e4066Sahrens * Check for ERANGE, which indicates that the value is too large to fit 495fa9e4066Sahrens * in a 64-bit value. 496fa9e4066Sahrens */ 497fa9e4066Sahrens if (errno == ERANGE) { 49899653d4eSeschrock if (hdl) 49999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50099653d4eSeschrock "numeric value is too large")); 501fa9e4066Sahrens return (-1); 502fa9e4066Sahrens } 503fa9e4066Sahrens 504fa9e4066Sahrens /* 505fa9e4066Sahrens * If we have a decimal value, then do the computation with floating 506fa9e4066Sahrens * point arithmetic. Otherwise, use standard arithmetic. 507fa9e4066Sahrens */ 508fa9e4066Sahrens if (*end == '.') { 509fa9e4066Sahrens double fval = strtod(value, &end); 510fa9e4066Sahrens 51199653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 512fa9e4066Sahrens return (-1); 513fa9e4066Sahrens 514fa9e4066Sahrens fval *= pow(2, shift); 515fa9e4066Sahrens 516fa9e4066Sahrens if (fval > UINT64_MAX) { 51799653d4eSeschrock if (hdl) 51899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 51999653d4eSeschrock "numeric value is too large")); 520fa9e4066Sahrens return (-1); 521fa9e4066Sahrens } 522fa9e4066Sahrens 523fa9e4066Sahrens *num = (uint64_t)fval; 524fa9e4066Sahrens } else { 52599653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 526fa9e4066Sahrens return (-1); 527fa9e4066Sahrens 528fa9e4066Sahrens /* Check for overflow */ 529fa9e4066Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 53099653d4eSeschrock if (hdl) 53199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 53299653d4eSeschrock "numeric value is too large")); 533fa9e4066Sahrens return (-1); 534fa9e4066Sahrens } 535fa9e4066Sahrens 536fa9e4066Sahrens *num <<= shift; 537fa9e4066Sahrens } 538fa9e4066Sahrens 539fa9e4066Sahrens return (0); 540fa9e4066Sahrens } 541fa9e4066Sahrens 542fa9e4066Sahrens int 543e9dbad6fSeschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 544fa9e4066Sahrens { 545e9dbad6fSeschrock return (nicestrtonum(hdl, str, val)); 546fa9e4066Sahrens } 547fa9e4066Sahrens 548fa9e4066Sahrens /* 549e9dbad6fSeschrock * The prop_parse_*() functions are designed to allow flexibility in callers 550e9dbad6fSeschrock * when setting properties. At the DSL layer, all properties are either 64-bit 551e9dbad6fSeschrock * numbers or strings. We want the user to be able to ignore this fact and 552e9dbad6fSeschrock * specify properties as native values (boolean, for example) or as strings (to 553e9dbad6fSeschrock * simplify command line utilities). This also handles converting index types 554e9dbad6fSeschrock * (compression, checksum, etc) from strings to their on-disk index. 555fa9e4066Sahrens */ 556e9dbad6fSeschrock 557e9dbad6fSeschrock static int 558e9dbad6fSeschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 559fa9e4066Sahrens { 560e9dbad6fSeschrock uint64_t ret; 561fa9e4066Sahrens 562e9dbad6fSeschrock switch (nvpair_type(elem)) { 563e9dbad6fSeschrock case DATA_TYPE_STRING: 564e9dbad6fSeschrock { 565e9dbad6fSeschrock char *value; 566798d5834Sgw25295 verify(nvpair_value_string(elem, &value) == 0); 56799653d4eSeschrock 568fa9e4066Sahrens if (strcmp(value, "on") == 0) { 569e9dbad6fSeschrock ret = 1; 570fa9e4066Sahrens } else if (strcmp(value, "off") == 0) { 571e9dbad6fSeschrock ret = 0; 572fa9e4066Sahrens } else { 57399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 574e9dbad6fSeschrock "property '%s' must be 'on' or 'off'"), 575e9dbad6fSeschrock nvpair_name(elem)); 576e9dbad6fSeschrock return (-1); 577fa9e4066Sahrens } 578fa9e4066Sahrens break; 579e9dbad6fSeschrock } 580fa9e4066Sahrens 581e9dbad6fSeschrock case DATA_TYPE_UINT64: 582e9dbad6fSeschrock { 583798d5834Sgw25295 verify(nvpair_value_uint64(elem, &ret) == 0); 584e9dbad6fSeschrock if (ret > 1) { 585e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 586e9dbad6fSeschrock "'%s' must be a boolean value"), 587e9dbad6fSeschrock nvpair_name(elem)); 588e9dbad6fSeschrock return (-1); 589e9dbad6fSeschrock } 590e9dbad6fSeschrock break; 591e9dbad6fSeschrock } 592e9dbad6fSeschrock 593e9dbad6fSeschrock case DATA_TYPE_BOOLEAN_VALUE: 594e9dbad6fSeschrock { 595e9dbad6fSeschrock boolean_t value; 596798d5834Sgw25295 verify(nvpair_value_boolean_value(elem, &value) == 0); 597e9dbad6fSeschrock ret = value; 598e9dbad6fSeschrock break; 599e9dbad6fSeschrock } 600e9dbad6fSeschrock 601e9dbad6fSeschrock default: 602e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 603e9dbad6fSeschrock "'%s' must be a boolean value"), 604e9dbad6fSeschrock nvpair_name(elem)); 605e9dbad6fSeschrock return (-1); 606e9dbad6fSeschrock } 607e9dbad6fSeschrock 608e9dbad6fSeschrock *val = ret; 609e9dbad6fSeschrock return (0); 610e9dbad6fSeschrock } 611e9dbad6fSeschrock 612e9dbad6fSeschrock static int 613e9dbad6fSeschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 614e9dbad6fSeschrock uint64_t *val) 615e9dbad6fSeschrock { 616e9dbad6fSeschrock uint64_t ret; 617e9dbad6fSeschrock boolean_t isnone = B_FALSE; 618e9dbad6fSeschrock 619e9dbad6fSeschrock switch (nvpair_type(elem)) { 620e9dbad6fSeschrock case DATA_TYPE_STRING: 621e9dbad6fSeschrock { 622e9dbad6fSeschrock char *value; 623e9dbad6fSeschrock (void) nvpair_value_string(elem, &value); 624fa9e4066Sahrens if (strcmp(value, "none") == 0) { 625e9dbad6fSeschrock isnone = B_TRUE; 626e9dbad6fSeschrock ret = 0; 627e9dbad6fSeschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 628e9dbad6fSeschrock return (-1); 629e9dbad6fSeschrock } 630fa9e4066Sahrens break; 631fa9e4066Sahrens } 632fa9e4066Sahrens 633e9dbad6fSeschrock case DATA_TYPE_UINT64: 634e9dbad6fSeschrock (void) nvpair_value_uint64(elem, &ret); 635fa9e4066Sahrens break; 636fa9e4066Sahrens 637e9dbad6fSeschrock default: 638e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 639e9dbad6fSeschrock "'%s' must be a number"), 640e9dbad6fSeschrock nvpair_name(elem)); 641e9dbad6fSeschrock return (-1); 642e9dbad6fSeschrock } 643e9dbad6fSeschrock 644fa9e4066Sahrens /* 645e9dbad6fSeschrock * Quota special: force 'none' and don't allow 0. 646fa9e4066Sahrens */ 647e9dbad6fSeschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 64899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 649e9dbad6fSeschrock "use 'none' to disable quota")); 650e9dbad6fSeschrock return (-1); 651fa9e4066Sahrens } 652fa9e4066Sahrens 653e9dbad6fSeschrock *val = ret; 654e9dbad6fSeschrock return (0); 655e9dbad6fSeschrock } 656e9dbad6fSeschrock 657e9dbad6fSeschrock static int 658e9dbad6fSeschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 659e9dbad6fSeschrock uint64_t *val) 660e9dbad6fSeschrock { 661e9dbad6fSeschrock char *propname = nvpair_name(elem); 662e9dbad6fSeschrock char *value; 663e9dbad6fSeschrock 664e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 66599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 666e9dbad6fSeschrock "'%s' must be a string"), propname); 667e9dbad6fSeschrock return (-1); 668fa9e4066Sahrens } 669fa9e4066Sahrens 670e9dbad6fSeschrock (void) nvpair_value_string(elem, &value); 671e9dbad6fSeschrock 672e9dbad6fSeschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 67399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 674e9dbad6fSeschrock "'%s' must be one of '%s'"), propname, 675e9dbad6fSeschrock zfs_prop_values(prop)); 676e9dbad6fSeschrock return (-1); 677fa9e4066Sahrens } 678fa9e4066Sahrens 679fa9e4066Sahrens return (0); 680fa9e4066Sahrens } 681fa9e4066Sahrens 682fa9e4066Sahrens /* 683e9dbad6fSeschrock * Given an nvlist of properties to set, validates that they are correct, and 684e9dbad6fSeschrock * parses any numeric properties (index, boolean, etc) if they are specified as 685e9dbad6fSeschrock * strings. 686fa9e4066Sahrens */ 687e9dbad6fSeschrock static nvlist_t * 688e9dbad6fSeschrock zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 689e9dbad6fSeschrock uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 690fa9e4066Sahrens { 691e9dbad6fSeschrock nvpair_t *elem; 692e9dbad6fSeschrock const char *propname; 693e9dbad6fSeschrock zfs_prop_t prop; 694e9dbad6fSeschrock uint64_t intval; 695e9dbad6fSeschrock char *strval; 696e9dbad6fSeschrock nvlist_t *ret; 697fa9e4066Sahrens 698e9dbad6fSeschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 699e9dbad6fSeschrock (void) no_memory(hdl); 700e9dbad6fSeschrock return (NULL); 701e9dbad6fSeschrock } 702fa9e4066Sahrens 703e9dbad6fSeschrock if (type == ZFS_TYPE_SNAPSHOT) { 704e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 705d7d4af51Smmusante "snapshot properties cannot be modified")); 706e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 707e9dbad6fSeschrock goto error; 708e9dbad6fSeschrock } 70999653d4eSeschrock 710e9dbad6fSeschrock elem = NULL; 711e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 712e9dbad6fSeschrock propname = nvpair_name(elem); 71399653d4eSeschrock 714fa9e4066Sahrens /* 715e9dbad6fSeschrock * Make sure this property is valid and applies to this type. 716fa9e4066Sahrens */ 717e9dbad6fSeschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 718e9dbad6fSeschrock if (!zfs_prop_user(propname)) { 719e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 720e9dbad6fSeschrock "invalid property '%s'"), 721e9dbad6fSeschrock propname); 722e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 723e9dbad6fSeschrock goto error; 724e9dbad6fSeschrock } else { 725e9dbad6fSeschrock /* 726e9dbad6fSeschrock * If this is a user property, make sure it's a 727e9dbad6fSeschrock * string, and that it's less than 728e9dbad6fSeschrock * ZAP_MAXNAMELEN. 729e9dbad6fSeschrock */ 730e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 731e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 732e9dbad6fSeschrock "'%s' must be a string"), 733e9dbad6fSeschrock propname); 734e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 735e9dbad6fSeschrock errbuf); 736e9dbad6fSeschrock goto error; 737e9dbad6fSeschrock } 738e9dbad6fSeschrock 739e9dbad6fSeschrock if (strlen(nvpair_name(elem)) >= 740e9dbad6fSeschrock ZAP_MAXNAMELEN) { 741e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 742e9dbad6fSeschrock "property name '%s' is too long"), 743e9dbad6fSeschrock propname); 744e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 745e9dbad6fSeschrock errbuf); 746e9dbad6fSeschrock goto error; 747e9dbad6fSeschrock } 748e9dbad6fSeschrock } 749e9dbad6fSeschrock 750e9dbad6fSeschrock (void) nvpair_value_string(elem, &strval); 751e9dbad6fSeschrock if (nvlist_add_string(ret, propname, strval) != 0) { 752e9dbad6fSeschrock (void) no_memory(hdl); 753e9dbad6fSeschrock goto error; 754e9dbad6fSeschrock } 755e9dbad6fSeschrock continue; 756e9dbad6fSeschrock } 757fa9e4066Sahrens 758fa9e4066Sahrens /* 759e9dbad6fSeschrock * Normalize the name, to get rid of shorthand abbrevations. 760e9dbad6fSeschrock */ 761e9dbad6fSeschrock propname = zfs_prop_to_name(prop); 762e9dbad6fSeschrock 763e9dbad6fSeschrock if (!zfs_prop_valid_for_type(prop, type)) { 764e9dbad6fSeschrock zfs_error_aux(hdl, 765e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "'%s' does not " 766e9dbad6fSeschrock "apply to datasets of this type"), propname); 767e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 768e9dbad6fSeschrock goto error; 769e9dbad6fSeschrock } 770e9dbad6fSeschrock 771e9dbad6fSeschrock if (zfs_prop_readonly(prop) && 772e9dbad6fSeschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 773e9dbad6fSeschrock zfs_error_aux(hdl, 774e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 775e9dbad6fSeschrock propname); 776e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 777e9dbad6fSeschrock goto error; 778e9dbad6fSeschrock } 779e9dbad6fSeschrock 780e9dbad6fSeschrock /* 781e9dbad6fSeschrock * Convert any properties to the internal DSL value types. 782e9dbad6fSeschrock */ 783e9dbad6fSeschrock strval = NULL; 784e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 785e9dbad6fSeschrock case prop_type_boolean: 786e9dbad6fSeschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 787e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 788e9dbad6fSeschrock goto error; 789e9dbad6fSeschrock } 790e9dbad6fSeschrock break; 791e9dbad6fSeschrock 792e9dbad6fSeschrock case prop_type_string: 793e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 794e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 795e9dbad6fSeschrock "'%s' must be a string"), 796e9dbad6fSeschrock propname); 797e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 798e9dbad6fSeschrock goto error; 799e9dbad6fSeschrock } 800e9dbad6fSeschrock (void) nvpair_value_string(elem, &strval); 801e9dbad6fSeschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 802e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 803e9dbad6fSeschrock "'%s' is too long"), propname); 804e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 805e9dbad6fSeschrock goto error; 806e9dbad6fSeschrock } 807e9dbad6fSeschrock break; 808e9dbad6fSeschrock 809e9dbad6fSeschrock case prop_type_number: 810e9dbad6fSeschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 811e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 812e9dbad6fSeschrock goto error; 813e9dbad6fSeschrock } 814e9dbad6fSeschrock break; 815e9dbad6fSeschrock 816e9dbad6fSeschrock case prop_type_index: 817e9dbad6fSeschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 818e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 819e9dbad6fSeschrock goto error; 820e9dbad6fSeschrock } 821e9dbad6fSeschrock break; 822e9dbad6fSeschrock 823e9dbad6fSeschrock default: 824e9dbad6fSeschrock abort(); 825e9dbad6fSeschrock } 826e9dbad6fSeschrock 827e9dbad6fSeschrock /* 828e9dbad6fSeschrock * Add the result to our return set of properties. 829e9dbad6fSeschrock */ 830e9dbad6fSeschrock if (strval) { 831e9dbad6fSeschrock if (nvlist_add_string(ret, propname, strval) != 0) { 832e9dbad6fSeschrock (void) no_memory(hdl); 833e9dbad6fSeschrock goto error; 834e9dbad6fSeschrock } 835e9dbad6fSeschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 836e9dbad6fSeschrock (void) no_memory(hdl); 837e9dbad6fSeschrock goto error; 838e9dbad6fSeschrock } 839e9dbad6fSeschrock 840e9dbad6fSeschrock /* 841e9dbad6fSeschrock * Perform some additional checks for specific properties. 842e9dbad6fSeschrock */ 843e9dbad6fSeschrock switch (prop) { 844e9dbad6fSeschrock case ZFS_PROP_RECORDSIZE: 845e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 846e9dbad6fSeschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 847e9dbad6fSeschrock if (intval < SPA_MINBLOCKSIZE || 848e9dbad6fSeschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 849e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 850e9dbad6fSeschrock "'%s' must be power of 2 from %u " 851e9dbad6fSeschrock "to %uk"), propname, 852e9dbad6fSeschrock (uint_t)SPA_MINBLOCKSIZE, 853e9dbad6fSeschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 854e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 855e9dbad6fSeschrock goto error; 856e9dbad6fSeschrock } 857e9dbad6fSeschrock break; 858e9dbad6fSeschrock 859f3861e1aSahl case ZFS_PROP_SHAREISCSI: 860f3861e1aSahl if (strcmp(strval, "off") != 0 && 861f3861e1aSahl strcmp(strval, "on") != 0 && 862f3861e1aSahl strcmp(strval, "type=disk") != 0) { 863f3861e1aSahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 864f3861e1aSahl "'%s' must be 'on', 'off', or 'type=disk'"), 865f3861e1aSahl propname); 866f3861e1aSahl (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 867f3861e1aSahl goto error; 868f3861e1aSahl } 869f3861e1aSahl 870f3861e1aSahl break; 871f3861e1aSahl 872e9dbad6fSeschrock case ZFS_PROP_MOUNTPOINT: 873e9dbad6fSeschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 874e9dbad6fSeschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 875e9dbad6fSeschrock break; 876e9dbad6fSeschrock 877e9dbad6fSeschrock if (strval[0] != '/') { 878e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 879e9dbad6fSeschrock "'%s' must be an absolute path, " 880e9dbad6fSeschrock "'none', or 'legacy'"), propname); 881e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 882e9dbad6fSeschrock goto error; 883e9dbad6fSeschrock } 884f3861e1aSahl /*FALLTHRU*/ 885e9dbad6fSeschrock 886f3861e1aSahl case ZFS_PROP_SHARENFS: 887e9dbad6fSeschrock /* 888f3861e1aSahl * For the mountpoint and sharenfs properties, check if 889f3861e1aSahl * it can be set in a global/non-global zone based on 890f3861e1aSahl * the zoned property value: 891fa9e4066Sahrens * 892fa9e4066Sahrens * global zone non-global zone 893f3861e1aSahl * -------------------------------------------------- 894fa9e4066Sahrens * zoned=on mountpoint (no) mountpoint (yes) 895fa9e4066Sahrens * sharenfs (no) sharenfs (no) 896fa9e4066Sahrens * 897fa9e4066Sahrens * zoned=off mountpoint (yes) N/A 898fa9e4066Sahrens * sharenfs (yes) 899fa9e4066Sahrens */ 900e9dbad6fSeschrock if (zoned) { 901fa9e4066Sahrens if (getzoneid() == GLOBAL_ZONEID) { 90299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 903e9dbad6fSeschrock "'%s' cannot be set on " 904e9dbad6fSeschrock "dataset in a non-global zone"), 905e9dbad6fSeschrock propname); 906e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, 907e9dbad6fSeschrock errbuf); 908e9dbad6fSeschrock goto error; 909fa9e4066Sahrens } else if (prop == ZFS_PROP_SHARENFS) { 91099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 911e9dbad6fSeschrock "'%s' cannot be set in " 912e9dbad6fSeschrock "a non-global zone"), propname); 913e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, 914e9dbad6fSeschrock errbuf); 915e9dbad6fSeschrock goto error; 916fa9e4066Sahrens } 917fa9e4066Sahrens } else if (getzoneid() != GLOBAL_ZONEID) { 918fa9e4066Sahrens /* 919fa9e4066Sahrens * If zoned property is 'off', this must be in 920fa9e4066Sahrens * a globle zone. If not, something is wrong. 921fa9e4066Sahrens */ 92299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 923e9dbad6fSeschrock "'%s' cannot be set while dataset " 924e9dbad6fSeschrock "'zoned' property is set"), propname); 925e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 926e9dbad6fSeschrock goto error; 927fa9e4066Sahrens } 928f3861e1aSahl 929f3861e1aSahl break; 930fa9e4066Sahrens } 931fa9e4066Sahrens 932e9dbad6fSeschrock /* 933e9dbad6fSeschrock * For changes to existing volumes, we have some additional 934e9dbad6fSeschrock * checks to enforce. 935e9dbad6fSeschrock */ 936e9dbad6fSeschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 937e9dbad6fSeschrock uint64_t volsize = zfs_prop_get_int(zhp, 938e9dbad6fSeschrock ZFS_PROP_VOLSIZE); 939e9dbad6fSeschrock uint64_t blocksize = zfs_prop_get_int(zhp, 940e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 941e9dbad6fSeschrock char buf[64]; 942e9dbad6fSeschrock 943e9dbad6fSeschrock switch (prop) { 944e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 945e9dbad6fSeschrock if (intval > volsize) { 946e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 947e9dbad6fSeschrock "'%s' is greater than current " 948e9dbad6fSeschrock "volume size"), propname); 949e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 950e9dbad6fSeschrock errbuf); 951e9dbad6fSeschrock goto error; 952e9dbad6fSeschrock } 953e9dbad6fSeschrock break; 954e9dbad6fSeschrock 955e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 956e9dbad6fSeschrock if (intval % blocksize != 0) { 957e9dbad6fSeschrock zfs_nicenum(blocksize, buf, 958e9dbad6fSeschrock sizeof (buf)); 959e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 960e9dbad6fSeschrock "'%s' must be a multiple of " 961e9dbad6fSeschrock "volume block size (%s)"), 962e9dbad6fSeschrock propname, buf); 963e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 964e9dbad6fSeschrock errbuf); 965e9dbad6fSeschrock goto error; 966e9dbad6fSeschrock } 967e9dbad6fSeschrock 968e9dbad6fSeschrock if (intval == 0) { 969e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 970e9dbad6fSeschrock "'%s' cannot be zero"), 971e9dbad6fSeschrock propname); 972e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 973e9dbad6fSeschrock errbuf); 974e9dbad6fSeschrock goto error; 975e9dbad6fSeschrock } 976f3861e1aSahl break; 977e9dbad6fSeschrock } 978e9dbad6fSeschrock } 979e9dbad6fSeschrock } 980e9dbad6fSeschrock 981e9dbad6fSeschrock /* 982e9dbad6fSeschrock * If this is an existing volume, and someone is setting the volsize, 983e9dbad6fSeschrock * make sure that it matches the reservation, or add it if necessary. 984e9dbad6fSeschrock */ 985e9dbad6fSeschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 986e9dbad6fSeschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 987e9dbad6fSeschrock &intval) == 0) { 988e9dbad6fSeschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 989e9dbad6fSeschrock ZFS_PROP_VOLSIZE); 990e9dbad6fSeschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 991e9dbad6fSeschrock ZFS_PROP_RESERVATION); 992e9dbad6fSeschrock uint64_t new_reservation; 993e9dbad6fSeschrock 994e9dbad6fSeschrock if (old_volsize == old_reservation && 995e9dbad6fSeschrock nvlist_lookup_uint64(ret, 996e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 997e9dbad6fSeschrock &new_reservation) != 0) { 998e9dbad6fSeschrock if (nvlist_add_uint64(ret, 999e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 1000e9dbad6fSeschrock intval) != 0) { 1001e9dbad6fSeschrock (void) no_memory(hdl); 1002e9dbad6fSeschrock goto error; 1003e9dbad6fSeschrock } 1004e9dbad6fSeschrock } 1005e9dbad6fSeschrock } 1006e9dbad6fSeschrock 1007e9dbad6fSeschrock return (ret); 1008e9dbad6fSeschrock 1009e9dbad6fSeschrock error: 1010e9dbad6fSeschrock nvlist_free(ret); 1011e9dbad6fSeschrock return (NULL); 1012e9dbad6fSeschrock } 1013e9dbad6fSeschrock 1014e9dbad6fSeschrock /* 1015e9dbad6fSeschrock * Given a property name and value, set the property for the given dataset. 1016e9dbad6fSeschrock */ 1017e9dbad6fSeschrock int 1018e9dbad6fSeschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1019e9dbad6fSeschrock { 1020e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 1021e9dbad6fSeschrock int ret = -1; 1022e9dbad6fSeschrock prop_changelist_t *cl = NULL; 1023e9dbad6fSeschrock char errbuf[1024]; 1024e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 1025e9dbad6fSeschrock nvlist_t *nvl = NULL, *realprops; 1026e9dbad6fSeschrock zfs_prop_t prop; 1027e9dbad6fSeschrock 1028e9dbad6fSeschrock (void) snprintf(errbuf, sizeof (errbuf), 1029e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1030e9dbad6fSeschrock zhp->zfs_name); 1031e9dbad6fSeschrock 1032e9dbad6fSeschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1033e9dbad6fSeschrock nvlist_add_string(nvl, propname, propval) != 0) { 1034e9dbad6fSeschrock (void) no_memory(hdl); 1035e9dbad6fSeschrock goto error; 1036e9dbad6fSeschrock } 1037e9dbad6fSeschrock 1038e9dbad6fSeschrock if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl, 1039e9dbad6fSeschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1040e9dbad6fSeschrock goto error; 1041e9dbad6fSeschrock nvlist_free(nvl); 1042e9dbad6fSeschrock nvl = realprops; 1043e9dbad6fSeschrock 1044e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 1045e9dbad6fSeschrock 1046fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1047e9dbad6fSeschrock goto error; 1048fa9e4066Sahrens 1049fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 105099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1051fa9e4066Sahrens "child dataset with inherited mountpoint is used " 105299653d4eSeschrock "in a non-global zone")); 105399653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1054fa9e4066Sahrens goto error; 1055fa9e4066Sahrens } 1056fa9e4066Sahrens 1057fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 1058fa9e4066Sahrens goto error; 1059fa9e4066Sahrens 1060fa9e4066Sahrens /* 1061fa9e4066Sahrens * Execute the corresponding ioctl() to set this property. 1062fa9e4066Sahrens */ 1063fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1064fa9e4066Sahrens 1065e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 1066e9dbad6fSeschrock goto error; 1067e9dbad6fSeschrock 1068e9dbad6fSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1069fa9e4066Sahrens 1070fa9e4066Sahrens if (ret != 0) { 1071fa9e4066Sahrens switch (errno) { 1072fa9e4066Sahrens 1073fa9e4066Sahrens case ENOSPC: 1074fa9e4066Sahrens /* 1075fa9e4066Sahrens * For quotas and reservations, ENOSPC indicates 1076fa9e4066Sahrens * something different; setting a quota or reservation 1077fa9e4066Sahrens * doesn't use any disk space. 1078fa9e4066Sahrens */ 1079fa9e4066Sahrens switch (prop) { 1080fa9e4066Sahrens case ZFS_PROP_QUOTA: 108199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 108299653d4eSeschrock "size is less than current used or " 108399653d4eSeschrock "reserved space")); 108499653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1085fa9e4066Sahrens break; 1086fa9e4066Sahrens 1087fa9e4066Sahrens case ZFS_PROP_RESERVATION: 108899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 108999653d4eSeschrock "size is greater than available space")); 109099653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1091fa9e4066Sahrens break; 1092fa9e4066Sahrens 1093fa9e4066Sahrens default: 109499653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 1095fa9e4066Sahrens break; 1096fa9e4066Sahrens } 1097fa9e4066Sahrens break; 1098fa9e4066Sahrens 1099fa9e4066Sahrens case EBUSY: 110099653d4eSeschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 110199653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 110299653d4eSeschrock else 1103e9dbad6fSeschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1104fa9e4066Sahrens break; 1105fa9e4066Sahrens 11062a79c5feSlling case EROFS: 110799653d4eSeschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 11082a79c5feSlling break; 11092a79c5feSlling 1110fa9e4066Sahrens case EOVERFLOW: 1111fa9e4066Sahrens /* 1112fa9e4066Sahrens * This platform can't address a volume this big. 1113fa9e4066Sahrens */ 1114fa9e4066Sahrens #ifdef _ILP32 1115fa9e4066Sahrens if (prop == ZFS_PROP_VOLSIZE) { 111699653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1117fa9e4066Sahrens break; 1118fa9e4066Sahrens } 1119fa9e4066Sahrens #endif 112099653d4eSeschrock /* FALLTHROUGH */ 1121fa9e4066Sahrens default: 112299653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 1123fa9e4066Sahrens } 1124fa9e4066Sahrens } else { 1125fa9e4066Sahrens /* 1126fa9e4066Sahrens * Refresh the statistics so the new property value 1127fa9e4066Sahrens * is reflected. 1128fa9e4066Sahrens */ 1129e9dbad6fSeschrock if ((ret = changelist_postfix(cl)) == 0) 1130fa9e4066Sahrens (void) get_stats(zhp); 1131fa9e4066Sahrens } 1132fa9e4066Sahrens 1133fa9e4066Sahrens error: 1134e9dbad6fSeschrock nvlist_free(nvl); 1135e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1136e9dbad6fSeschrock if (cl) 1137fa9e4066Sahrens changelist_free(cl); 1138fa9e4066Sahrens return (ret); 1139fa9e4066Sahrens } 1140fa9e4066Sahrens 1141fa9e4066Sahrens /* 1142fa9e4066Sahrens * Given a property, inherit the value from the parent dataset. 1143fa9e4066Sahrens */ 1144fa9e4066Sahrens int 1145e9dbad6fSeschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1146fa9e4066Sahrens { 1147fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1148fa9e4066Sahrens int ret; 1149fa9e4066Sahrens prop_changelist_t *cl; 115099653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 115199653d4eSeschrock char errbuf[1024]; 1152e9dbad6fSeschrock zfs_prop_t prop; 115399653d4eSeschrock 115499653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 115599653d4eSeschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1156fa9e4066Sahrens 1157e9dbad6fSeschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 1158e9dbad6fSeschrock /* 1159e9dbad6fSeschrock * For user properties, the amount of work we have to do is very 1160e9dbad6fSeschrock * small, so just do it here. 1161e9dbad6fSeschrock */ 1162e9dbad6fSeschrock if (!zfs_prop_user(propname)) { 1163e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1164e9dbad6fSeschrock "invalid property")); 1165e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1166e9dbad6fSeschrock } 1167e9dbad6fSeschrock 1168e9dbad6fSeschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1169e9dbad6fSeschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1170e9dbad6fSeschrock 1171e9dbad6fSeschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 1172e9dbad6fSeschrock ZFS_IOC_SET_PROP, &zc) != 0) 1173e9dbad6fSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1174e9dbad6fSeschrock 1175e9dbad6fSeschrock return (0); 1176e9dbad6fSeschrock } 1177e9dbad6fSeschrock 1178fa9e4066Sahrens /* 1179fa9e4066Sahrens * Verify that this property is inheritable. 1180fa9e4066Sahrens */ 118199653d4eSeschrock if (zfs_prop_readonly(prop)) 118299653d4eSeschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1183fa9e4066Sahrens 118499653d4eSeschrock if (!zfs_prop_inheritable(prop)) 118599653d4eSeschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1186fa9e4066Sahrens 1187fa9e4066Sahrens /* 1188fa9e4066Sahrens * Check to see if the value applies to this type 1189fa9e4066Sahrens */ 119099653d4eSeschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 119199653d4eSeschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1192fa9e4066Sahrens 1193bf7c2d40Srm160521 /* 1194bf7c2d40Srm160521 * Normalize the name, to get rid of shorthand abbrevations. 1195bf7c2d40Srm160521 */ 1196bf7c2d40Srm160521 propname = zfs_prop_to_name(prop); 1197fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1198e9dbad6fSeschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1199fa9e4066Sahrens 1200fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1201fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 120299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 120399653d4eSeschrock "dataset is used in a non-global zone")); 120499653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1205fa9e4066Sahrens } 1206fa9e4066Sahrens 1207fa9e4066Sahrens /* 1208fa9e4066Sahrens * Determine datasets which will be affected by this change, if any. 1209fa9e4066Sahrens */ 1210fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1211fa9e4066Sahrens return (-1); 1212fa9e4066Sahrens 1213fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 121499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 121599653d4eSeschrock "child dataset with inherited mountpoint is used " 121699653d4eSeschrock "in a non-global zone")); 121799653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1218fa9e4066Sahrens goto error; 1219fa9e4066Sahrens } 1220fa9e4066Sahrens 1221fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 1222fa9e4066Sahrens goto error; 1223fa9e4066Sahrens 122499653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 122599653d4eSeschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 122699653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1227fa9e4066Sahrens } else { 1228fa9e4066Sahrens 1229efc555ebSnd150628 if ((ret = changelist_postfix(cl)) != 0) 1230fa9e4066Sahrens goto error; 1231fa9e4066Sahrens 1232fa9e4066Sahrens /* 1233fa9e4066Sahrens * Refresh the statistics so the new property is reflected. 1234fa9e4066Sahrens */ 1235fa9e4066Sahrens (void) get_stats(zhp); 1236fa9e4066Sahrens } 1237fa9e4066Sahrens 1238fa9e4066Sahrens error: 1239fa9e4066Sahrens changelist_free(cl); 1240fa9e4066Sahrens return (ret); 1241fa9e4066Sahrens } 1242fa9e4066Sahrens 1243fa9e4066Sahrens static void 1244fa9e4066Sahrens nicebool(int value, char *buf, size_t buflen) 1245fa9e4066Sahrens { 1246fa9e4066Sahrens if (value) 1247fa9e4066Sahrens (void) strlcpy(buf, "on", buflen); 1248fa9e4066Sahrens else 1249fa9e4066Sahrens (void) strlcpy(buf, "off", buflen); 1250fa9e4066Sahrens } 1251fa9e4066Sahrens 1252fa9e4066Sahrens /* 12537f7322feSeschrock * True DSL properties are stored in an nvlist. The following two functions 12547f7322feSeschrock * extract them appropriately. 12557f7322feSeschrock */ 12567f7322feSeschrock static uint64_t 12577f7322feSeschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12587f7322feSeschrock { 12597f7322feSeschrock nvlist_t *nv; 12607f7322feSeschrock uint64_t value; 12617f7322feSeschrock 1262a2eea2e1Sahrens *source = NULL; 12637f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12647f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 12657f7322feSeschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 1266a2eea2e1Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12677f7322feSeschrock } else { 12687f7322feSeschrock value = zfs_prop_default_numeric(prop); 12697f7322feSeschrock *source = ""; 12707f7322feSeschrock } 12717f7322feSeschrock 12727f7322feSeschrock return (value); 12737f7322feSeschrock } 12747f7322feSeschrock 12757f7322feSeschrock static char * 12767f7322feSeschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12777f7322feSeschrock { 12787f7322feSeschrock nvlist_t *nv; 12797f7322feSeschrock char *value; 12807f7322feSeschrock 1281a2eea2e1Sahrens *source = NULL; 12827f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12837f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 12847f7322feSeschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 1285a2eea2e1Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 12867f7322feSeschrock } else { 12877f7322feSeschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 12887f7322feSeschrock value = ""; 12897f7322feSeschrock *source = ""; 12907f7322feSeschrock } 12917f7322feSeschrock 12927f7322feSeschrock return (value); 12937f7322feSeschrock } 12947f7322feSeschrock 12957f7322feSeschrock /* 1296fa9e4066Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1297fa9e4066Sahrens * zfs_prop_get_int() are built using this interface. 1298fa9e4066Sahrens * 1299fa9e4066Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1300fa9e4066Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1301fa9e4066Sahrens * If they differ from the on-disk values, report the current values and mark 1302fa9e4066Sahrens * the source "temporary". 1303fa9e4066Sahrens */ 130499653d4eSeschrock static int 1305fa9e4066Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 130699653d4eSeschrock char **source, uint64_t *val) 1307fa9e4066Sahrens { 1308fa9e4066Sahrens struct mnttab mnt; 13093ccfa83cSahrens char *mntopt_on = NULL; 13103ccfa83cSahrens char *mntopt_off = NULL; 1311fa9e4066Sahrens 1312fa9e4066Sahrens *source = NULL; 1313fa9e4066Sahrens 13143ccfa83cSahrens switch (prop) { 13153ccfa83cSahrens case ZFS_PROP_ATIME: 13163ccfa83cSahrens mntopt_on = MNTOPT_ATIME; 13173ccfa83cSahrens mntopt_off = MNTOPT_NOATIME; 13183ccfa83cSahrens break; 13193ccfa83cSahrens 13203ccfa83cSahrens case ZFS_PROP_DEVICES: 13213ccfa83cSahrens mntopt_on = MNTOPT_DEVICES; 13223ccfa83cSahrens mntopt_off = MNTOPT_NODEVICES; 13233ccfa83cSahrens break; 13243ccfa83cSahrens 13253ccfa83cSahrens case ZFS_PROP_EXEC: 13263ccfa83cSahrens mntopt_on = MNTOPT_EXEC; 13273ccfa83cSahrens mntopt_off = MNTOPT_NOEXEC; 13283ccfa83cSahrens break; 13293ccfa83cSahrens 13303ccfa83cSahrens case ZFS_PROP_READONLY: 13313ccfa83cSahrens mntopt_on = MNTOPT_RO; 13323ccfa83cSahrens mntopt_off = MNTOPT_RW; 13333ccfa83cSahrens break; 13343ccfa83cSahrens 13353ccfa83cSahrens case ZFS_PROP_SETUID: 13363ccfa83cSahrens mntopt_on = MNTOPT_SETUID; 13373ccfa83cSahrens mntopt_off = MNTOPT_NOSETUID; 13383ccfa83cSahrens break; 13393ccfa83cSahrens 13403ccfa83cSahrens case ZFS_PROP_XATTR: 13413ccfa83cSahrens mntopt_on = MNTOPT_XATTR; 13423ccfa83cSahrens mntopt_off = MNTOPT_NOXATTR; 13433ccfa83cSahrens break; 13443ccfa83cSahrens } 13453ccfa83cSahrens 13463bb79becSeschrock /* 13473bb79becSeschrock * Because looking up the mount options is potentially expensive 13483bb79becSeschrock * (iterating over all of /etc/mnttab), we defer its calculation until 13493bb79becSeschrock * we're looking up a property which requires its presence. 13503bb79becSeschrock */ 13513bb79becSeschrock if (!zhp->zfs_mntcheck && 13523ccfa83cSahrens (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 13533ccfa83cSahrens struct mnttab entry, search = { 0 }; 13543ccfa83cSahrens FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 13553bb79becSeschrock 13563bb79becSeschrock search.mnt_special = (char *)zhp->zfs_name; 13573bb79becSeschrock search.mnt_fstype = MNTTYPE_ZFS; 13583ccfa83cSahrens rewind(mnttab); 13593bb79becSeschrock 13603ccfa83cSahrens if (getmntany(mnttab, &entry, &search) == 0) { 13613ccfa83cSahrens zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 13623ccfa83cSahrens entry.mnt_mntopts); 13633ccfa83cSahrens if (zhp->zfs_mntopts == NULL) 13643bb79becSeschrock return (-1); 13653ccfa83cSahrens } 13663bb79becSeschrock 13673bb79becSeschrock zhp->zfs_mntcheck = B_TRUE; 13683bb79becSeschrock } 13693bb79becSeschrock 1370fa9e4066Sahrens if (zhp->zfs_mntopts == NULL) 1371fa9e4066Sahrens mnt.mnt_mntopts = ""; 1372fa9e4066Sahrens else 1373fa9e4066Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1374fa9e4066Sahrens 1375fa9e4066Sahrens switch (prop) { 1376fa9e4066Sahrens case ZFS_PROP_ATIME: 1377fa9e4066Sahrens case ZFS_PROP_DEVICES: 1378fa9e4066Sahrens case ZFS_PROP_EXEC: 13793ccfa83cSahrens case ZFS_PROP_READONLY: 13803ccfa83cSahrens case ZFS_PROP_SETUID: 13813ccfa83cSahrens case ZFS_PROP_XATTR: 138299653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1383fa9e4066Sahrens 13843ccfa83cSahrens if (hasmntopt(&mnt, mntopt_on) && !*val) { 138599653d4eSeschrock *val = B_TRUE; 1386fa9e4066Sahrens if (src) 1387fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 13883ccfa83cSahrens } else if (hasmntopt(&mnt, mntopt_off) && *val) { 138999653d4eSeschrock *val = B_FALSE; 1390fa9e4066Sahrens if (src) 1391fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1392fa9e4066Sahrens } 139399653d4eSeschrock break; 1394fa9e4066Sahrens 1395fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1396fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 13977f7322feSeschrock case ZFS_PROP_ZONED: 1398a2eea2e1Sahrens case ZFS_PROP_CREATION: 1399a2eea2e1Sahrens case ZFS_PROP_COMPRESSRATIO: 1400a2eea2e1Sahrens case ZFS_PROP_REFERENCED: 1401a2eea2e1Sahrens case ZFS_PROP_USED: 1402a2eea2e1Sahrens case ZFS_PROP_CREATETXG: 1403a2eea2e1Sahrens case ZFS_PROP_AVAILABLE: 1404a2eea2e1Sahrens case ZFS_PROP_VOLSIZE: 1405a2eea2e1Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1406fda77a98Srm160521 *val = getprop_uint64(zhp, prop, source); 1407fda77a98Srm160521 break; 1408fda77a98Srm160521 14093ccfa83cSahrens case ZFS_PROP_CANMOUNT: 141099653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1411fda77a98Srm160521 if (*val == 0) 1412fda77a98Srm160521 *source = zhp->zfs_name; 1413fda77a98Srm160521 else 1414fda77a98Srm160521 *source = ""; /* default */ 141599653d4eSeschrock break; 1416fa9e4066Sahrens 1417fa9e4066Sahrens case ZFS_PROP_QUOTA: 1418fa9e4066Sahrens case ZFS_PROP_RESERVATION: 1419a2eea2e1Sahrens *val = getprop_uint64(zhp, prop, source); 1420a2eea2e1Sahrens if (*val == 0) 1421fa9e4066Sahrens *source = ""; /* default */ 1422fa9e4066Sahrens else 1423fa9e4066Sahrens *source = zhp->zfs_name; 142499653d4eSeschrock break; 1425fa9e4066Sahrens 1426fa9e4066Sahrens case ZFS_PROP_MOUNTED: 142799653d4eSeschrock *val = (zhp->zfs_mntopts != NULL); 142899653d4eSeschrock break; 1429fa9e4066Sahrens 143039c23413Seschrock case ZFS_PROP_NUMCLONES: 143139c23413Seschrock *val = zhp->zfs_dmustats.dds_num_clones; 143239c23413Seschrock break; 143339c23413Seschrock 1434fa9e4066Sahrens default: 143599653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 143699653d4eSeschrock "cannot get non-numeric property")); 143799653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 143899653d4eSeschrock dgettext(TEXT_DOMAIN, "internal error"))); 1439fa9e4066Sahrens } 1440fa9e4066Sahrens 1441fa9e4066Sahrens return (0); 1442fa9e4066Sahrens } 1443fa9e4066Sahrens 1444fa9e4066Sahrens /* 1445fa9e4066Sahrens * Calculate the source type, given the raw source string. 1446fa9e4066Sahrens */ 1447fa9e4066Sahrens static void 1448fa9e4066Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1449fa9e4066Sahrens char *statbuf, size_t statlen) 1450fa9e4066Sahrens { 1451fa9e4066Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1452fa9e4066Sahrens return; 1453fa9e4066Sahrens 1454fa9e4066Sahrens if (source == NULL) { 1455fa9e4066Sahrens *srctype = ZFS_SRC_NONE; 1456fa9e4066Sahrens } else if (source[0] == '\0') { 1457fa9e4066Sahrens *srctype = ZFS_SRC_DEFAULT; 1458fa9e4066Sahrens } else { 1459fa9e4066Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1460fa9e4066Sahrens *srctype = ZFS_SRC_LOCAL; 1461fa9e4066Sahrens } else { 1462fa9e4066Sahrens (void) strlcpy(statbuf, source, statlen); 1463fa9e4066Sahrens *srctype = ZFS_SRC_INHERITED; 1464fa9e4066Sahrens } 1465fa9e4066Sahrens } 1466fa9e4066Sahrens 1467fa9e4066Sahrens } 1468fa9e4066Sahrens 1469fa9e4066Sahrens /* 1470fa9e4066Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1471fa9e4066Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1472fa9e4066Sahrens * human-readable form. 1473fa9e4066Sahrens * 1474fa9e4066Sahrens * Returns 0 on success, or -1 on error. 1475fa9e4066Sahrens */ 1476fa9e4066Sahrens int 1477fa9e4066Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 147899653d4eSeschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1479fa9e4066Sahrens { 1480fa9e4066Sahrens char *source = NULL; 1481fa9e4066Sahrens uint64_t val; 1482fa9e4066Sahrens char *str; 1483fa9e4066Sahrens const char *root; 1484e9dbad6fSeschrock const char *strval; 1485fa9e4066Sahrens 1486fa9e4066Sahrens /* 1487fa9e4066Sahrens * Check to see if this property applies to our object 1488fa9e4066Sahrens */ 1489fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1490fa9e4066Sahrens return (-1); 1491fa9e4066Sahrens 1492fa9e4066Sahrens if (src) 1493fa9e4066Sahrens *src = ZFS_SRC_NONE; 1494fa9e4066Sahrens 1495fa9e4066Sahrens switch (prop) { 1496fa9e4066Sahrens case ZFS_PROP_ATIME: 1497fa9e4066Sahrens case ZFS_PROP_READONLY: 1498fa9e4066Sahrens case ZFS_PROP_SETUID: 1499fa9e4066Sahrens case ZFS_PROP_ZONED: 1500fa9e4066Sahrens case ZFS_PROP_DEVICES: 1501fa9e4066Sahrens case ZFS_PROP_EXEC: 1502e9dbad6fSeschrock case ZFS_PROP_CANMOUNT: 15037b55fa8eSck153898 case ZFS_PROP_XATTR: 1504fa9e4066Sahrens /* 1505fa9e4066Sahrens * Basic boolean values are built on top of 1506fa9e4066Sahrens * get_numeric_property(). 1507fa9e4066Sahrens */ 150899653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 150999653d4eSeschrock return (-1); 151099653d4eSeschrock nicebool(val, propbuf, proplen); 1511fa9e4066Sahrens 1512fa9e4066Sahrens break; 1513fa9e4066Sahrens 1514fa9e4066Sahrens case ZFS_PROP_AVAILABLE: 1515fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1516fa9e4066Sahrens case ZFS_PROP_CREATETXG: 1517fa9e4066Sahrens case ZFS_PROP_REFERENCED: 1518fa9e4066Sahrens case ZFS_PROP_USED: 1519fa9e4066Sahrens case ZFS_PROP_VOLSIZE: 1520fa9e4066Sahrens case ZFS_PROP_VOLBLOCKSIZE: 152139c23413Seschrock case ZFS_PROP_NUMCLONES: 1522fa9e4066Sahrens /* 1523fa9e4066Sahrens * Basic numeric values are built on top of 1524fa9e4066Sahrens * get_numeric_property(). 1525fa9e4066Sahrens */ 152699653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 152799653d4eSeschrock return (-1); 1528fa9e4066Sahrens if (literal) 15295ad82045Snd150628 (void) snprintf(propbuf, proplen, "%llu", 15305ad82045Snd150628 (u_longlong_t)val); 1531fa9e4066Sahrens else 1532fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1533fa9e4066Sahrens break; 1534fa9e4066Sahrens 1535fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 1536fa9e4066Sahrens case ZFS_PROP_CHECKSUM: 1537fa9e4066Sahrens case ZFS_PROP_SNAPDIR: 1538fa9e4066Sahrens case ZFS_PROP_ACLMODE: 1539fa9e4066Sahrens case ZFS_PROP_ACLINHERIT: 15407f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1541e9dbad6fSeschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 1542e9dbad6fSeschrock (void) strlcpy(propbuf, strval, proplen); 1543fa9e4066Sahrens break; 1544fa9e4066Sahrens 1545fa9e4066Sahrens case ZFS_PROP_CREATION: 1546fa9e4066Sahrens /* 1547fa9e4066Sahrens * 'creation' is a time_t stored in the statistics. We convert 1548fa9e4066Sahrens * this into a string unless 'literal' is specified. 1549fa9e4066Sahrens */ 1550fa9e4066Sahrens { 1551a2eea2e1Sahrens val = getprop_uint64(zhp, prop, &source); 1552a2eea2e1Sahrens time_t time = (time_t)val; 1553fa9e4066Sahrens struct tm t; 1554fa9e4066Sahrens 1555fa9e4066Sahrens if (literal || 1556fa9e4066Sahrens localtime_r(&time, &t) == NULL || 1557fa9e4066Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1558fa9e4066Sahrens &t) == 0) 1559a2eea2e1Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1560fa9e4066Sahrens } 1561fa9e4066Sahrens break; 1562fa9e4066Sahrens 1563fa9e4066Sahrens case ZFS_PROP_MOUNTPOINT: 1564fa9e4066Sahrens /* 1565fa9e4066Sahrens * Getting the precise mountpoint can be tricky. 1566fa9e4066Sahrens * 1567fa9e4066Sahrens * - for 'none' or 'legacy', return those values. 1568fa9e4066Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1569fa9e4066Sahrens * - for inherited mountpoints, we want to take everything 1570fa9e4066Sahrens * after our ancestor and append it to the inherited value. 1571fa9e4066Sahrens * 1572fa9e4066Sahrens * If the pool has an alternate root, we want to prepend that 1573fa9e4066Sahrens * root to any values we return. 1574fa9e4066Sahrens */ 1575ea8dc4b6Seschrock root = zhp->zfs_root; 15767f7322feSeschrock str = getprop_string(zhp, prop, &source); 1577fa9e4066Sahrens 15787f7322feSeschrock if (str[0] == '\0') { 1579fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1580fa9e4066Sahrens root, zhp->zfs_name); 15817f7322feSeschrock } else if (str[0] == '/') { 15827f7322feSeschrock const char *relpath = zhp->zfs_name + strlen(source); 1583fa9e4066Sahrens 1584fa9e4066Sahrens if (relpath[0] == '/') 1585fa9e4066Sahrens relpath++; 15867f7322feSeschrock if (str[1] == '\0') 15877f7322feSeschrock str++; 1588fa9e4066Sahrens 1589fa9e4066Sahrens if (relpath[0] == '\0') 1590fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s", 15917f7322feSeschrock root, str); 1592fa9e4066Sahrens else 1593fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 15947f7322feSeschrock root, str, relpath[0] == '@' ? "" : "/", 1595fa9e4066Sahrens relpath); 1596fa9e4066Sahrens } else { 1597fa9e4066Sahrens /* 'legacy' or 'none' */ 15987f7322feSeschrock (void) strlcpy(propbuf, str, proplen); 1599fa9e4066Sahrens } 1600fa9e4066Sahrens 1601fa9e4066Sahrens break; 1602fa9e4066Sahrens 1603fa9e4066Sahrens case ZFS_PROP_SHARENFS: 1604f3861e1aSahl case ZFS_PROP_SHAREISCSI: 1605f3861e1aSahl case ZFS_PROP_ISCSIOPTIONS: 16067f7322feSeschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16077f7322feSeschrock proplen); 1608fa9e4066Sahrens break; 1609fa9e4066Sahrens 1610fa9e4066Sahrens case ZFS_PROP_ORIGIN: 1611a2eea2e1Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1612fa9e4066Sahrens proplen); 1613fa9e4066Sahrens /* 1614fa9e4066Sahrens * If there is no parent at all, return failure to indicate that 1615fa9e4066Sahrens * it doesn't apply to this dataset. 1616fa9e4066Sahrens */ 1617fa9e4066Sahrens if (propbuf[0] == '\0') 1618fa9e4066Sahrens return (-1); 1619fa9e4066Sahrens break; 1620fa9e4066Sahrens 1621fa9e4066Sahrens case ZFS_PROP_QUOTA: 1622fa9e4066Sahrens case ZFS_PROP_RESERVATION: 162399653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 162499653d4eSeschrock return (-1); 1625fa9e4066Sahrens 1626fa9e4066Sahrens /* 1627fa9e4066Sahrens * If quota or reservation is 0, we translate this into 'none' 1628fa9e4066Sahrens * (unless literal is set), and indicate that it's the default 1629fa9e4066Sahrens * value. Otherwise, we print the number nicely and indicate 1630fa9e4066Sahrens * that its set locally. 1631fa9e4066Sahrens */ 1632fa9e4066Sahrens if (val == 0) { 1633fa9e4066Sahrens if (literal) 1634fa9e4066Sahrens (void) strlcpy(propbuf, "0", proplen); 1635fa9e4066Sahrens else 1636fa9e4066Sahrens (void) strlcpy(propbuf, "none", proplen); 1637fa9e4066Sahrens } else { 1638fa9e4066Sahrens if (literal) 16395ad82045Snd150628 (void) snprintf(propbuf, proplen, "%llu", 16405ad82045Snd150628 (u_longlong_t)val); 1641fa9e4066Sahrens else 1642fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1643fa9e4066Sahrens } 1644fa9e4066Sahrens break; 1645fa9e4066Sahrens 1646fa9e4066Sahrens case ZFS_PROP_COMPRESSRATIO: 164799653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 164899653d4eSeschrock return (-1); 16495ad82045Snd150628 (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 16505ad82045Snd150628 val / 100, (longlong_t)val % 100); 1651fa9e4066Sahrens break; 1652fa9e4066Sahrens 1653fa9e4066Sahrens case ZFS_PROP_TYPE: 1654fa9e4066Sahrens switch (zhp->zfs_type) { 1655fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 1656fa9e4066Sahrens str = "filesystem"; 1657fa9e4066Sahrens break; 1658fa9e4066Sahrens case ZFS_TYPE_VOLUME: 1659fa9e4066Sahrens str = "volume"; 1660fa9e4066Sahrens break; 1661fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 1662fa9e4066Sahrens str = "snapshot"; 1663fa9e4066Sahrens break; 1664fa9e4066Sahrens default: 166599653d4eSeschrock abort(); 1666fa9e4066Sahrens } 1667fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1668fa9e4066Sahrens break; 1669fa9e4066Sahrens 1670fa9e4066Sahrens case ZFS_PROP_MOUNTED: 1671fa9e4066Sahrens /* 1672fa9e4066Sahrens * The 'mounted' property is a pseudo-property that described 1673fa9e4066Sahrens * whether the filesystem is currently mounted. Even though 1674fa9e4066Sahrens * it's a boolean value, the typical values of "on" and "off" 1675fa9e4066Sahrens * don't make sense, so we translate to "yes" and "no". 1676fa9e4066Sahrens */ 167799653d4eSeschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 167899653d4eSeschrock src, &source, &val) != 0) 167999653d4eSeschrock return (-1); 168099653d4eSeschrock if (val) 1681fa9e4066Sahrens (void) strlcpy(propbuf, "yes", proplen); 1682fa9e4066Sahrens else 1683fa9e4066Sahrens (void) strlcpy(propbuf, "no", proplen); 1684fa9e4066Sahrens break; 1685fa9e4066Sahrens 1686fa9e4066Sahrens case ZFS_PROP_NAME: 1687fa9e4066Sahrens /* 1688fa9e4066Sahrens * The 'name' property is a pseudo-property derived from the 1689fa9e4066Sahrens * dataset name. It is presented as a real property to simplify 1690fa9e4066Sahrens * consumers. 1691fa9e4066Sahrens */ 1692fa9e4066Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1693fa9e4066Sahrens break; 1694fa9e4066Sahrens 1695fa9e4066Sahrens default: 169699653d4eSeschrock abort(); 1697fa9e4066Sahrens } 1698fa9e4066Sahrens 1699fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1700fa9e4066Sahrens 1701fa9e4066Sahrens return (0); 1702fa9e4066Sahrens } 1703fa9e4066Sahrens 1704fa9e4066Sahrens /* 1705fa9e4066Sahrens * Utility function to get the given numeric property. Does no validation that 1706fa9e4066Sahrens * the given property is the appropriate type; should only be used with 1707fa9e4066Sahrens * hard-coded property types. 1708fa9e4066Sahrens */ 1709fa9e4066Sahrens uint64_t 1710fa9e4066Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1711fa9e4066Sahrens { 1712fa9e4066Sahrens char *source; 1713fa9e4066Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 171499653d4eSeschrock uint64_t val; 1715fa9e4066Sahrens 171699653d4eSeschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 171799653d4eSeschrock 171899653d4eSeschrock return (val); 1719fa9e4066Sahrens } 1720fa9e4066Sahrens 1721fa9e4066Sahrens /* 1722fa9e4066Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1723fa9e4066Sahrens */ 1724fa9e4066Sahrens int 1725fa9e4066Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1726fa9e4066Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1727fa9e4066Sahrens { 1728fa9e4066Sahrens char *source; 1729fa9e4066Sahrens 1730fa9e4066Sahrens /* 1731fa9e4066Sahrens * Check to see if this property applies to our object 1732fa9e4066Sahrens */ 1733fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1734ece3d9b3Slling return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 173599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 173699653d4eSeschrock zfs_prop_to_name(prop))); 1737fa9e4066Sahrens 1738fa9e4066Sahrens if (src) 1739fa9e4066Sahrens *src = ZFS_SRC_NONE; 1740fa9e4066Sahrens 174199653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 174299653d4eSeschrock return (-1); 1743fa9e4066Sahrens 1744fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1745fa9e4066Sahrens 1746fa9e4066Sahrens return (0); 1747fa9e4066Sahrens } 1748fa9e4066Sahrens 1749fa9e4066Sahrens /* 1750fa9e4066Sahrens * Returns the name of the given zfs handle. 1751fa9e4066Sahrens */ 1752fa9e4066Sahrens const char * 1753fa9e4066Sahrens zfs_get_name(const zfs_handle_t *zhp) 1754fa9e4066Sahrens { 1755fa9e4066Sahrens return (zhp->zfs_name); 1756fa9e4066Sahrens } 1757fa9e4066Sahrens 1758fa9e4066Sahrens /* 1759fa9e4066Sahrens * Returns the type of the given zfs handle. 1760fa9e4066Sahrens */ 1761fa9e4066Sahrens zfs_type_t 1762fa9e4066Sahrens zfs_get_type(const zfs_handle_t *zhp) 1763fa9e4066Sahrens { 1764fa9e4066Sahrens return (zhp->zfs_type); 1765fa9e4066Sahrens } 1766fa9e4066Sahrens 1767fa9e4066Sahrens /* 17687f7322feSeschrock * Iterate over all child filesystems 1769fa9e4066Sahrens */ 1770fa9e4066Sahrens int 17717f7322feSeschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1772fa9e4066Sahrens { 1773fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1774fa9e4066Sahrens zfs_handle_t *nzhp; 1775fa9e4066Sahrens int ret; 1776fa9e4066Sahrens 1777fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 177899653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1779fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1780fa9e4066Sahrens /* 1781fa9e4066Sahrens * Ignore private dataset names. 1782fa9e4066Sahrens */ 1783fa9e4066Sahrens if (dataset_name_hidden(zc.zc_name)) 1784fa9e4066Sahrens continue; 1785fa9e4066Sahrens 1786fa9e4066Sahrens /* 1787fa9e4066Sahrens * Silently ignore errors, as the only plausible explanation is 1788fa9e4066Sahrens * that the pool has since been removed. 1789fa9e4066Sahrens */ 179099653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 179199653d4eSeschrock zc.zc_name)) == NULL) 1792fa9e4066Sahrens continue; 1793fa9e4066Sahrens 1794fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1795fa9e4066Sahrens return (ret); 1796fa9e4066Sahrens } 1797fa9e4066Sahrens 1798fa9e4066Sahrens /* 1799fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1800fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1801fa9e4066Sahrens * obtained the handle. 1802fa9e4066Sahrens */ 1803fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 180499653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 180599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1806fa9e4066Sahrens 18077f7322feSeschrock return (0); 18087f7322feSeschrock } 18097f7322feSeschrock 18107f7322feSeschrock /* 18117f7322feSeschrock * Iterate over all snapshots 18127f7322feSeschrock */ 18137f7322feSeschrock int 18147f7322feSeschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18157f7322feSeschrock { 18167f7322feSeschrock zfs_cmd_t zc = { 0 }; 18177f7322feSeschrock zfs_handle_t *nzhp; 18187f7322feSeschrock int ret; 1819fa9e4066Sahrens 1820fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 182199653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 182299653d4eSeschrock &zc) == 0; 1823fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1824fa9e4066Sahrens 182599653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 182699653d4eSeschrock zc.zc_name)) == NULL) 1827fa9e4066Sahrens continue; 1828fa9e4066Sahrens 1829fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1830fa9e4066Sahrens return (ret); 1831fa9e4066Sahrens } 1832fa9e4066Sahrens 1833fa9e4066Sahrens /* 1834fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1835fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1836fa9e4066Sahrens * obtained the handle. Silently ignore this case, and return success. 1837fa9e4066Sahrens */ 1838fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 183999653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 184099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1841fa9e4066Sahrens 1842fa9e4066Sahrens return (0); 1843fa9e4066Sahrens } 1844fa9e4066Sahrens 1845fa9e4066Sahrens /* 18467f7322feSeschrock * Iterate over all children, snapshots and filesystems 18477f7322feSeschrock */ 18487f7322feSeschrock int 18497f7322feSeschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18507f7322feSeschrock { 18517f7322feSeschrock int ret; 18527f7322feSeschrock 18537f7322feSeschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 18547f7322feSeschrock return (ret); 18557f7322feSeschrock 18567f7322feSeschrock return (zfs_iter_snapshots(zhp, func, data)); 18577f7322feSeschrock } 18587f7322feSeschrock 18597f7322feSeschrock /* 1860fa9e4066Sahrens * Given a complete name, return just the portion that refers to the parent. 1861fa9e4066Sahrens * Can return NULL if this is a pool. 1862fa9e4066Sahrens */ 1863fa9e4066Sahrens static int 1864fa9e4066Sahrens parent_name(const char *path, char *buf, size_t buflen) 1865fa9e4066Sahrens { 1866fa9e4066Sahrens char *loc; 1867fa9e4066Sahrens 1868fa9e4066Sahrens if ((loc = strrchr(path, '/')) == NULL) 1869fa9e4066Sahrens return (-1); 1870fa9e4066Sahrens 1871fa9e4066Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1872fa9e4066Sahrens buf[loc - path] = '\0'; 1873fa9e4066Sahrens 1874fa9e4066Sahrens return (0); 1875fa9e4066Sahrens } 1876fa9e4066Sahrens 1877fa9e4066Sahrens /* 1878e9dbad6fSeschrock * Checks to make sure that the given path has a parent, and that it exists. We 1879e9dbad6fSeschrock * also fetch the 'zoned' property, which is used to validate property settings 1880e9dbad6fSeschrock * when creating new datasets. 1881fa9e4066Sahrens */ 1882fa9e4066Sahrens static int 1883e9dbad6fSeschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1884fa9e4066Sahrens { 1885fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1886fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 1887fa9e4066Sahrens char *slash; 18887f7322feSeschrock zfs_handle_t *zhp; 188999653d4eSeschrock char errbuf[1024]; 189099653d4eSeschrock 189199653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 189299653d4eSeschrock path); 1893fa9e4066Sahrens 1894fa9e4066Sahrens /* get parent, and check to see if this is just a pool */ 1895fa9e4066Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 189699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 189799653d4eSeschrock "missing dataset name")); 189899653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1899fa9e4066Sahrens } 1900fa9e4066Sahrens 1901fa9e4066Sahrens /* check to see if the pool exists */ 1902fa9e4066Sahrens if ((slash = strchr(parent, '/')) == NULL) 1903fa9e4066Sahrens slash = parent + strlen(parent); 1904fa9e4066Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1905fa9e4066Sahrens zc.zc_name[slash - parent] = '\0'; 190699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1907fa9e4066Sahrens errno == ENOENT) { 190899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 190999653d4eSeschrock "no such pool '%s'"), zc.zc_name); 191099653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1911fa9e4066Sahrens } 1912fa9e4066Sahrens 1913fa9e4066Sahrens /* check to see if the parent dataset exists */ 191499653d4eSeschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1915fa9e4066Sahrens switch (errno) { 1916fa9e4066Sahrens case ENOENT: 191799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 191899653d4eSeschrock "parent does not exist")); 191999653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1920fa9e4066Sahrens 1921fa9e4066Sahrens default: 192299653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1923fa9e4066Sahrens } 1924fa9e4066Sahrens } 1925fa9e4066Sahrens 1926e9dbad6fSeschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1927fa9e4066Sahrens /* we are in a non-global zone, but parent is in the global zone */ 1928e9dbad6fSeschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 192999653d4eSeschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19307f7322feSeschrock zfs_close(zhp); 1931fa9e4066Sahrens return (-1); 1932fa9e4066Sahrens } 1933fa9e4066Sahrens 1934fa9e4066Sahrens /* make sure parent is a filesystem */ 19357f7322feSeschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 193699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 193799653d4eSeschrock "parent is not a filesystem")); 193899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19397f7322feSeschrock zfs_close(zhp); 1940fa9e4066Sahrens return (-1); 1941fa9e4066Sahrens } 1942fa9e4066Sahrens 19437f7322feSeschrock zfs_close(zhp); 1944fa9e4066Sahrens return (0); 1945fa9e4066Sahrens } 1946fa9e4066Sahrens 1947fa9e4066Sahrens /* 1948e9dbad6fSeschrock * Create a new filesystem or volume. 1949fa9e4066Sahrens */ 1950fa9e4066Sahrens int 195199653d4eSeschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 1952e9dbad6fSeschrock nvlist_t *props) 1953fa9e4066Sahrens { 1954fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1955fa9e4066Sahrens int ret; 1956fa9e4066Sahrens uint64_t size = 0; 1957fa9e4066Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 195899653d4eSeschrock char errbuf[1024]; 1959e9dbad6fSeschrock uint64_t zoned; 196099653d4eSeschrock 196199653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 196299653d4eSeschrock "cannot create '%s'"), path); 1963fa9e4066Sahrens 1964fa9e4066Sahrens /* validate the path, taking care to note the extended error message */ 196599653d4eSeschrock if (!zfs_validate_name(hdl, path, type)) 196699653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1967fa9e4066Sahrens 1968fa9e4066Sahrens /* validate parents exist */ 1969e9dbad6fSeschrock if (check_parents(hdl, path, &zoned) != 0) 1970fa9e4066Sahrens return (-1); 1971fa9e4066Sahrens 1972fa9e4066Sahrens /* 1973fa9e4066Sahrens * The failure modes when creating a dataset of a different type over 1974fa9e4066Sahrens * one that already exists is a little strange. In particular, if you 1975fa9e4066Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1976fa9e4066Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1977fa9e4066Sahrens * first try to see if the dataset exists. 1978fa9e4066Sahrens */ 1979fa9e4066Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 198099653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 198199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 198299653d4eSeschrock "dataset already exists")); 198399653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1984fa9e4066Sahrens } 1985fa9e4066Sahrens 1986fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) 1987fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1988fa9e4066Sahrens else 1989fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1990fa9e4066Sahrens 1991e9dbad6fSeschrock if (props && (props = zfs_validate_properties(hdl, type, props, zoned, 1992e9dbad6fSeschrock NULL, errbuf)) == 0) 1993e9dbad6fSeschrock return (-1); 1994e9dbad6fSeschrock 1995fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) { 19965c5460e9Seschrock /* 19975c5460e9Seschrock * If we are creating a volume, the size and block size must 19985c5460e9Seschrock * satisfy a few restraints. First, the blocksize must be a 19995c5460e9Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20005c5460e9Seschrock * volsize must be a multiple of the block size, and cannot be 20015c5460e9Seschrock * zero. 20025c5460e9Seschrock */ 2003e9dbad6fSeschrock if (props == NULL || nvlist_lookup_uint64(props, 2004e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2005e9dbad6fSeschrock nvlist_free(props); 200699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2007e9dbad6fSeschrock "missing volume size")); 2008e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2009fa9e4066Sahrens } 2010fa9e4066Sahrens 2011e9dbad6fSeschrock if ((ret = nvlist_lookup_uint64(props, 2012e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2013e9dbad6fSeschrock &blocksize)) != 0) { 2014e9dbad6fSeschrock if (ret == ENOENT) { 2015e9dbad6fSeschrock blocksize = zfs_prop_default_numeric( 2016e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2017e9dbad6fSeschrock } else { 2018e9dbad6fSeschrock nvlist_free(props); 201999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2020e9dbad6fSeschrock "missing volume block size")); 2021e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2022e9dbad6fSeschrock } 2023e9dbad6fSeschrock } 2024e9dbad6fSeschrock 2025e9dbad6fSeschrock if (size == 0) { 2026e9dbad6fSeschrock nvlist_free(props); 2027e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2028e9dbad6fSeschrock "volume size cannot be zero")); 2029e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20305c5460e9Seschrock } 20315c5460e9Seschrock 20325c5460e9Seschrock if (size % blocksize != 0) { 2033e9dbad6fSeschrock nvlist_free(props); 203499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2035e9dbad6fSeschrock "volume size must be a multiple of volume block " 2036e9dbad6fSeschrock "size")); 2037e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2038e9dbad6fSeschrock } 20395c5460e9Seschrock } 20405c5460e9Seschrock 2041e9dbad6fSeschrock if (props && 2042e9dbad6fSeschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 2043e9dbad6fSeschrock return (-1); 2044e9dbad6fSeschrock nvlist_free(props); 2045fa9e4066Sahrens 2046fa9e4066Sahrens /* create the dataset */ 204799653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2048fa9e4066Sahrens 2049fa9e4066Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 205099653d4eSeschrock ret = zvol_create_link(hdl, path); 2051fa9e4066Sahrens 2052e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2053e9dbad6fSeschrock 2054fa9e4066Sahrens /* check for failure */ 2055fa9e4066Sahrens if (ret != 0) { 2056fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 2057fa9e4066Sahrens (void) parent_name(path, parent, sizeof (parent)); 2058fa9e4066Sahrens 2059fa9e4066Sahrens switch (errno) { 2060fa9e4066Sahrens case ENOENT: 206199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 206299653d4eSeschrock "no such parent '%s'"), parent); 206399653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2064fa9e4066Sahrens 2065fa9e4066Sahrens case EINVAL: 206699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2067d7d4af51Smmusante "parent '%s' is not a filesystem"), parent); 206899653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2069fa9e4066Sahrens 2070fa9e4066Sahrens case EDOM: 207199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2072e9dbad6fSeschrock "volume block size must be power of 2 from " 2073e9dbad6fSeschrock "%u to %uk"), 2074fa9e4066Sahrens (uint_t)SPA_MINBLOCKSIZE, 2075fa9e4066Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 207699653d4eSeschrock 2077e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 207899653d4eSeschrock 2079fa9e4066Sahrens #ifdef _ILP32 2080fa9e4066Sahrens case EOVERFLOW: 2081fa9e4066Sahrens /* 2082fa9e4066Sahrens * This platform can't address a volume this big. 2083fa9e4066Sahrens */ 208499653d4eSeschrock if (type == ZFS_TYPE_VOLUME) 208599653d4eSeschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 208699653d4eSeschrock errbuf)); 2087fa9e4066Sahrens #endif 208899653d4eSeschrock /* FALLTHROUGH */ 2089fa9e4066Sahrens default: 209099653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2091fa9e4066Sahrens } 2092fa9e4066Sahrens } 2093fa9e4066Sahrens 2094fa9e4066Sahrens return (0); 2095fa9e4066Sahrens } 2096fa9e4066Sahrens 2097fa9e4066Sahrens /* 2098fa9e4066Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2099fa9e4066Sahrens * isn't mounted, and that there are no active dependents. 2100fa9e4066Sahrens */ 2101fa9e4066Sahrens int 2102fa9e4066Sahrens zfs_destroy(zfs_handle_t *zhp) 2103fa9e4066Sahrens { 2104fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2105fa9e4066Sahrens 2106fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2107fa9e4066Sahrens 2108e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) { 2109f3861e1aSahl /* 2110f3861e1aSahl * Unconditionally unshare this zvol ignoring failure as it 2111f3861e1aSahl * indicates only that the volume wasn't shared initially. 2112f3861e1aSahl */ 2113f3861e1aSahl (void) zfs_unshare_iscsi(zhp); 2114f3861e1aSahl 211599653d4eSeschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2116fa9e4066Sahrens return (-1); 2117fa9e4066Sahrens 2118fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2119fa9e4066Sahrens } else { 2120fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2121fa9e4066Sahrens } 2122fa9e4066Sahrens 2123f3861e1aSahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 2124ece3d9b3Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 212599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 212699653d4eSeschrock zhp->zfs_name)); 21271d452cf5Sahrens } 2128fa9e4066Sahrens 2129fa9e4066Sahrens remove_mountpoint(zhp); 2130fa9e4066Sahrens 2131fa9e4066Sahrens return (0); 2132fa9e4066Sahrens } 2133fa9e4066Sahrens 21341d452cf5Sahrens struct destroydata { 21351d452cf5Sahrens char *snapname; 21361d452cf5Sahrens boolean_t gotone; 21373ccfa83cSahrens boolean_t closezhp; 21381d452cf5Sahrens }; 21391d452cf5Sahrens 21401d452cf5Sahrens static int 21411d452cf5Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 21421d452cf5Sahrens { 21431d452cf5Sahrens struct destroydata *dd = arg; 21441d452cf5Sahrens zfs_handle_t *szhp; 21451d452cf5Sahrens char name[ZFS_MAXNAMELEN]; 21463ccfa83cSahrens boolean_t closezhp = dd->closezhp; 21473ccfa83cSahrens int rv; 21481d452cf5Sahrens 2149e9dbad6fSeschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2150e9dbad6fSeschrock (void) strlcat(name, "@", sizeof (name)); 2151e9dbad6fSeschrock (void) strlcat(name, dd->snapname, sizeof (name)); 21521d452cf5Sahrens 21531d452cf5Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 21541d452cf5Sahrens if (szhp) { 21551d452cf5Sahrens dd->gotone = B_TRUE; 21561d452cf5Sahrens zfs_close(szhp); 21571d452cf5Sahrens } 21581d452cf5Sahrens 21591d452cf5Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 21601d452cf5Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 21611d452cf5Sahrens /* 21621d452cf5Sahrens * NB: this is simply a best-effort. We don't want to 21631d452cf5Sahrens * return an error, because then we wouldn't visit all 21641d452cf5Sahrens * the volumes. 21651d452cf5Sahrens */ 21661d452cf5Sahrens } 21671d452cf5Sahrens 21683ccfa83cSahrens dd->closezhp = B_TRUE; 21693ccfa83cSahrens rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 21703ccfa83cSahrens if (closezhp) 21713ccfa83cSahrens zfs_close(zhp); 21723ccfa83cSahrens return (rv); 21731d452cf5Sahrens } 21741d452cf5Sahrens 21751d452cf5Sahrens /* 21761d452cf5Sahrens * Destroys all snapshots with the given name in zhp & descendants. 21771d452cf5Sahrens */ 21781d452cf5Sahrens int 21791d452cf5Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 21801d452cf5Sahrens { 21811d452cf5Sahrens zfs_cmd_t zc = { 0 }; 21821d452cf5Sahrens int ret; 21831d452cf5Sahrens struct destroydata dd = { 0 }; 21841d452cf5Sahrens 21851d452cf5Sahrens dd.snapname = snapname; 21861d452cf5Sahrens (void) zfs_remove_link_cb(zhp, &dd); 21871d452cf5Sahrens 21881d452cf5Sahrens if (!dd.gotone) { 2189ece3d9b3Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 21901d452cf5Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 21911d452cf5Sahrens zhp->zfs_name, snapname)); 21921d452cf5Sahrens } 21931d452cf5Sahrens 21941d452cf5Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2195e9dbad6fSeschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 21961d452cf5Sahrens 21971d452cf5Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 21981d452cf5Sahrens if (ret != 0) { 21991d452cf5Sahrens char errbuf[1024]; 22001d452cf5Sahrens 22011d452cf5Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22021d452cf5Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22031d452cf5Sahrens 22041d452cf5Sahrens switch (errno) { 22051d452cf5Sahrens case EEXIST: 22061d452cf5Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22071d452cf5Sahrens "snapshot is cloned")); 22081d452cf5Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22091d452cf5Sahrens 22101d452cf5Sahrens default: 22111d452cf5Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22121d452cf5Sahrens errbuf)); 22131d452cf5Sahrens } 22141d452cf5Sahrens } 22151d452cf5Sahrens 22161d452cf5Sahrens return (0); 22171d452cf5Sahrens } 22181d452cf5Sahrens 2219fa9e4066Sahrens /* 2220fa9e4066Sahrens * Clones the given dataset. The target must be of the same type as the source. 2221fa9e4066Sahrens */ 2222fa9e4066Sahrens int 2223e9dbad6fSeschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2224fa9e4066Sahrens { 2225fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2226fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 2227fa9e4066Sahrens int ret; 222899653d4eSeschrock char errbuf[1024]; 222999653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2230e9dbad6fSeschrock zfs_type_t type; 2231e9dbad6fSeschrock uint64_t zoned; 2232fa9e4066Sahrens 2233fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2234fa9e4066Sahrens 223599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 223699653d4eSeschrock "cannot create '%s'"), target); 223799653d4eSeschrock 2238fa9e4066Sahrens /* validate the target name */ 223999653d4eSeschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 224099653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2241fa9e4066Sahrens 2242fa9e4066Sahrens /* validate parents exist */ 2243e9dbad6fSeschrock if (check_parents(hdl, target, &zoned) != 0) 2244fa9e4066Sahrens return (-1); 2245fa9e4066Sahrens 2246fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 2247fa9e4066Sahrens 2248fa9e4066Sahrens /* do the clone */ 2249e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) { 2250fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 22515f8e1617Snn35248 type = ZFS_TYPE_VOLUME; 2252e9dbad6fSeschrock } else { 2253fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 22545f8e1617Snn35248 type = ZFS_TYPE_FILESYSTEM; 2255e9dbad6fSeschrock } 2256e9dbad6fSeschrock 2257e9dbad6fSeschrock if (props) { 2258e9dbad6fSeschrock if ((props = zfs_validate_properties(hdl, type, props, zoned, 2259e9dbad6fSeschrock zhp, errbuf)) == NULL) 2260e9dbad6fSeschrock return (-1); 2261e9dbad6fSeschrock 2262e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 2263e9dbad6fSeschrock nvlist_free(props); 2264e9dbad6fSeschrock return (-1); 2265e9dbad6fSeschrock } 2266e9dbad6fSeschrock 2267e9dbad6fSeschrock nvlist_free(props); 2268e9dbad6fSeschrock } 2269fa9e4066Sahrens 2270fa9e4066Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2271e9dbad6fSeschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 227299653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2273fa9e4066Sahrens 2274e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2275e9dbad6fSeschrock 2276fa9e4066Sahrens if (ret != 0) { 2277fa9e4066Sahrens switch (errno) { 2278fa9e4066Sahrens 2279fa9e4066Sahrens case ENOENT: 2280fa9e4066Sahrens /* 2281fa9e4066Sahrens * The parent doesn't exist. We should have caught this 2282fa9e4066Sahrens * above, but there may a race condition that has since 2283fa9e4066Sahrens * destroyed the parent. 2284fa9e4066Sahrens * 2285fa9e4066Sahrens * At this point, we don't know whether it's the source 2286fa9e4066Sahrens * that doesn't exist anymore, or whether the target 2287fa9e4066Sahrens * dataset doesn't exist. 2288fa9e4066Sahrens */ 228999653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 229099653d4eSeschrock "no such parent '%s'"), parent); 229199653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 2292fa9e4066Sahrens 229399653d4eSeschrock case EXDEV: 229499653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 229599653d4eSeschrock "source and target pools differ")); 229699653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 229799653d4eSeschrock errbuf)); 229899653d4eSeschrock 229999653d4eSeschrock default: 230099653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 230199653d4eSeschrock errbuf)); 230299653d4eSeschrock } 2303e9dbad6fSeschrock } else if (ZFS_IS_VOLUME(zhp)) { 230499653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, target); 230599653d4eSeschrock } 230699653d4eSeschrock 230799653d4eSeschrock return (ret); 230899653d4eSeschrock } 230999653d4eSeschrock 231099653d4eSeschrock typedef struct promote_data { 231199653d4eSeschrock char cb_mountpoint[MAXPATHLEN]; 231299653d4eSeschrock const char *cb_target; 231399653d4eSeschrock const char *cb_errbuf; 231499653d4eSeschrock uint64_t cb_pivot_txg; 231599653d4eSeschrock } promote_data_t; 231699653d4eSeschrock 231799653d4eSeschrock static int 231899653d4eSeschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 231999653d4eSeschrock { 232099653d4eSeschrock promote_data_t *pd = data; 232199653d4eSeschrock zfs_handle_t *szhp; 232299653d4eSeschrock char snapname[MAXPATHLEN]; 23233ccfa83cSahrens int rv = 0; 232499653d4eSeschrock 232599653d4eSeschrock /* We don't care about snapshots after the pivot point */ 23263ccfa83cSahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 23273ccfa83cSahrens zfs_close(zhp); 232899653d4eSeschrock return (0); 23293ccfa83cSahrens } 233099653d4eSeschrock 23310b69c2f0Sahrens /* Remove the device link if it's a zvol. */ 2332e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 23330b69c2f0Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 233499653d4eSeschrock 233599653d4eSeschrock /* Check for conflicting names */ 2336e9dbad6fSeschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 2337e9dbad6fSeschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 233899653d4eSeschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 233999653d4eSeschrock if (szhp != NULL) { 234099653d4eSeschrock zfs_close(szhp); 234199653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 234299653d4eSeschrock "snapshot name '%s' from origin \n" 234399653d4eSeschrock "conflicts with '%s' from target"), 234499653d4eSeschrock zhp->zfs_name, snapname); 23453ccfa83cSahrens rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 234699653d4eSeschrock } 23473ccfa83cSahrens zfs_close(zhp); 23483ccfa83cSahrens return (rv); 234999653d4eSeschrock } 235099653d4eSeschrock 23510b69c2f0Sahrens static int 23520b69c2f0Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 23530b69c2f0Sahrens { 23540b69c2f0Sahrens promote_data_t *pd = data; 23550b69c2f0Sahrens 23560b69c2f0Sahrens /* We don't care about snapshots after the pivot point */ 23573ccfa83cSahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 23580b69c2f0Sahrens /* Create the device link if it's a zvol. */ 2359e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 23600b69c2f0Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 23613ccfa83cSahrens } 23620b69c2f0Sahrens 23633ccfa83cSahrens zfs_close(zhp); 23640b69c2f0Sahrens return (0); 23650b69c2f0Sahrens } 23660b69c2f0Sahrens 236799653d4eSeschrock /* 236899653d4eSeschrock * Promotes the given clone fs to be the clone parent. 236999653d4eSeschrock */ 237099653d4eSeschrock int 237199653d4eSeschrock zfs_promote(zfs_handle_t *zhp) 237299653d4eSeschrock { 237399653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 237499653d4eSeschrock zfs_cmd_t zc = { 0 }; 237599653d4eSeschrock char parent[MAXPATHLEN]; 237699653d4eSeschrock char *cp; 237799653d4eSeschrock int ret; 237899653d4eSeschrock zfs_handle_t *pzhp; 237999653d4eSeschrock promote_data_t pd; 238099653d4eSeschrock char errbuf[1024]; 238199653d4eSeschrock 238299653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 238399653d4eSeschrock "cannot promote '%s'"), zhp->zfs_name); 238499653d4eSeschrock 238599653d4eSeschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 238699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 238799653d4eSeschrock "snapshots can not be promoted")); 238899653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 238999653d4eSeschrock } 239099653d4eSeschrock 2391e9dbad6fSeschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 239299653d4eSeschrock if (parent[0] == '\0') { 239399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 239499653d4eSeschrock "not a cloned filesystem")); 239599653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 239699653d4eSeschrock } 239799653d4eSeschrock cp = strchr(parent, '@'); 239899653d4eSeschrock *cp = '\0'; 239999653d4eSeschrock 240099653d4eSeschrock /* Walk the snapshots we will be moving */ 240199653d4eSeschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 240299653d4eSeschrock if (pzhp == NULL) 240399653d4eSeschrock return (-1); 240499653d4eSeschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 240599653d4eSeschrock zfs_close(pzhp); 240699653d4eSeschrock pd.cb_target = zhp->zfs_name; 240799653d4eSeschrock pd.cb_errbuf = errbuf; 240899653d4eSeschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 240999653d4eSeschrock if (pzhp == NULL) 241099653d4eSeschrock return (-1); 241199653d4eSeschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 241299653d4eSeschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 241399653d4eSeschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24140b69c2f0Sahrens if (ret != 0) { 24150b69c2f0Sahrens zfs_close(pzhp); 241699653d4eSeschrock return (-1); 24170b69c2f0Sahrens } 241899653d4eSeschrock 241999653d4eSeschrock /* issue the ioctl */ 2420e9dbad6fSeschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 2421e9dbad6fSeschrock sizeof (zc.zc_value)); 242299653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 242399653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 242499653d4eSeschrock 242599653d4eSeschrock if (ret != 0) { 24260b69c2f0Sahrens int save_errno = errno; 2427fa9e4066Sahrens 24280b69c2f0Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24290b69c2f0Sahrens zfs_close(pzhp); 24300b69c2f0Sahrens 24310b69c2f0Sahrens switch (save_errno) { 2432fa9e4066Sahrens case EEXIST: 2433fa9e4066Sahrens /* 243499653d4eSeschrock * There is a conflicting snapshot name. We 243599653d4eSeschrock * should have caught this above, but they could 243699653d4eSeschrock * have renamed something in the mean time. 2437fa9e4066Sahrens */ 243899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 243999653d4eSeschrock "conflicting snapshot name from parent '%s'"), 244099653d4eSeschrock parent); 244199653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2442fa9e4066Sahrens 2443fa9e4066Sahrens default: 24440b69c2f0Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2445fa9e4066Sahrens } 24460b69c2f0Sahrens } else { 24470b69c2f0Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2448fa9e4066Sahrens } 2449fa9e4066Sahrens 24500b69c2f0Sahrens zfs_close(pzhp); 2451fa9e4066Sahrens return (ret); 2452fa9e4066Sahrens } 2453fa9e4066Sahrens 24541d452cf5Sahrens static int 24551d452cf5Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 24561d452cf5Sahrens { 24571d452cf5Sahrens char *snapname = arg; 2458e9dbad6fSeschrock int ret; 24591d452cf5Sahrens 24601d452cf5Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 24611d452cf5Sahrens char name[MAXPATHLEN]; 24621d452cf5Sahrens 2463e9dbad6fSeschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2464e9dbad6fSeschrock (void) strlcat(name, "@", sizeof (name)); 2465e9dbad6fSeschrock (void) strlcat(name, snapname, sizeof (name)); 24661d452cf5Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 24671d452cf5Sahrens /* 24681d452cf5Sahrens * NB: this is simply a best-effort. We don't want to 24691d452cf5Sahrens * return an error, because then we wouldn't visit all 24701d452cf5Sahrens * the volumes. 24711d452cf5Sahrens */ 24721d452cf5Sahrens } 2473e9dbad6fSeschrock 2474e9dbad6fSeschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 2475e9dbad6fSeschrock 2476e9dbad6fSeschrock zfs_close(zhp); 2477e9dbad6fSeschrock 2478e9dbad6fSeschrock return (ret); 24791d452cf5Sahrens } 24801d452cf5Sahrens 2481fa9e4066Sahrens /* 2482*72bdce51Sahl * Takes a snapshot of the given dataset. 2483fa9e4066Sahrens */ 2484fa9e4066Sahrens int 24851d452cf5Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2486fa9e4066Sahrens { 2487fa9e4066Sahrens const char *delim; 2488fa9e4066Sahrens char *parent; 2489fa9e4066Sahrens zfs_handle_t *zhp; 2490fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2491fa9e4066Sahrens int ret; 249299653d4eSeschrock char errbuf[1024]; 2493fa9e4066Sahrens 249499653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 249599653d4eSeschrock "cannot snapshot '%s'"), path); 249699653d4eSeschrock 249799653d4eSeschrock /* validate the target name */ 249899653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 249999653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2500fa9e4066Sahrens 2501fa9e4066Sahrens /* make sure the parent exists and is of the appropriate type */ 25021d452cf5Sahrens delim = strchr(path, '@'); 250399653d4eSeschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 250499653d4eSeschrock return (-1); 2505fa9e4066Sahrens (void) strncpy(parent, path, delim - path); 2506fa9e4066Sahrens parent[delim - path] = '\0'; 2507fa9e4066Sahrens 250899653d4eSeschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2509fa9e4066Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2510fa9e4066Sahrens free(parent); 2511fa9e4066Sahrens return (-1); 2512fa9e4066Sahrens } 2513fa9e4066Sahrens 25141d452cf5Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2515e9dbad6fSeschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25161d452cf5Sahrens zc.zc_cookie = recursive; 25171d452cf5Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 2518fa9e4066Sahrens 25191d452cf5Sahrens /* 25201d452cf5Sahrens * if it was recursive, the one that actually failed will be in 25211d452cf5Sahrens * zc.zc_name. 25221d452cf5Sahrens */ 25231d452cf5Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2524e9dbad6fSeschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25251d452cf5Sahrens if (ret == 0 && recursive) { 25261d452cf5Sahrens (void) zfs_iter_filesystems(zhp, 25271d452cf5Sahrens zfs_create_link_cb, (char *)delim+1); 25281d452cf5Sahrens } 2529fa9e4066Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 253099653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25311d452cf5Sahrens if (ret != 0) { 253299653d4eSeschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 253399653d4eSeschrock &zc); 2534fa9e4066Sahrens } 25351d452cf5Sahrens } 2536fa9e4066Sahrens 253799653d4eSeschrock if (ret != 0) 253899653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2539fa9e4066Sahrens 2540fa9e4066Sahrens free(parent); 2541fa9e4066Sahrens zfs_close(zhp); 2542fa9e4066Sahrens 2543fa9e4066Sahrens return (ret); 2544fa9e4066Sahrens } 2545fa9e4066Sahrens 2546fa9e4066Sahrens /* 2547*72bdce51Sahl * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 2548*72bdce51Sahl * NULL) to the file descriptor specified by outfd. 2549fa9e4066Sahrens */ 2550fa9e4066Sahrens int 2551*72bdce51Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2552fa9e4066Sahrens { 2553fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 255499653d4eSeschrock char errbuf[1024]; 2555a2eea2e1Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 255699653d4eSeschrock 2557*72bdce51Sahl assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2558fa9e4066Sahrens 2559a2eea2e1Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2560a2eea2e1Sahrens if (fromsnap) 2561a2eea2e1Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 2562*72bdce51Sahl zc.zc_cookie = outfd; 2563fa9e4066Sahrens 2564*72bdce51Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 2565*72bdce51Sahl (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2566*72bdce51Sahl "cannot send '%s'"), zhp->zfs_name); 2567*72bdce51Sahl 2568fa9e4066Sahrens switch (errno) { 2569fa9e4066Sahrens 2570fa9e4066Sahrens case EXDEV: 257199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2572d7d4af51Smmusante "not an earlier snapshot from the same fs")); 257399653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2574fa9e4066Sahrens 2575fa9e4066Sahrens case EDQUOT: 2576fa9e4066Sahrens case EFBIG: 2577fa9e4066Sahrens case EIO: 2578fa9e4066Sahrens case ENOLINK: 2579fa9e4066Sahrens case ENOSPC: 2580fa9e4066Sahrens case ENOSTR: 2581fa9e4066Sahrens case ENXIO: 2582fa9e4066Sahrens case EPIPE: 2583fa9e4066Sahrens case ERANGE: 2584fa9e4066Sahrens case EFAULT: 2585fa9e4066Sahrens case EROFS: 258699653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 258799653d4eSeschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2588fa9e4066Sahrens 2589fa9e4066Sahrens default: 259099653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2591fa9e4066Sahrens } 2592fa9e4066Sahrens } 2593fa9e4066Sahrens 2594*72bdce51Sahl return (0); 2595fa9e4066Sahrens } 2596fa9e4066Sahrens 2597fa9e4066Sahrens /* 2598a2eea2e1Sahrens * Create ancestors of 'target', but not target itself, and not 2599a2eea2e1Sahrens * ancestors whose names are shorter than prefixlen. Die if 2600a2eea2e1Sahrens * prefixlen-ancestor does not exist. 2601a2eea2e1Sahrens */ 2602a2eea2e1Sahrens static int 2603a2eea2e1Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2604a2eea2e1Sahrens { 2605a2eea2e1Sahrens zfs_handle_t *h; 2606a2eea2e1Sahrens char *cp; 2607a2eea2e1Sahrens 2608a2eea2e1Sahrens /* make sure prefix exists */ 2609a2eea2e1Sahrens cp = strchr(target + prefixlen, '/'); 2610a2eea2e1Sahrens *cp = '\0'; 2611a2eea2e1Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2612a2eea2e1Sahrens *cp = '/'; 2613a2eea2e1Sahrens if (h == NULL) 2614a2eea2e1Sahrens return (-1); 2615a2eea2e1Sahrens zfs_close(h); 2616a2eea2e1Sahrens 2617a2eea2e1Sahrens /* 2618a2eea2e1Sahrens * Attempt to create, mount, and share any ancestor filesystems, 2619a2eea2e1Sahrens * up to the prefixlen-long one. 2620a2eea2e1Sahrens */ 2621a2eea2e1Sahrens for (cp = target + prefixlen + 1; 2622a2eea2e1Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 2623a2eea2e1Sahrens const char *opname; 2624a2eea2e1Sahrens 2625a2eea2e1Sahrens *cp = '\0'; 2626a2eea2e1Sahrens 2627a2eea2e1Sahrens h = make_dataset_handle(hdl, target); 2628a2eea2e1Sahrens if (h) { 2629a2eea2e1Sahrens /* it already exists, nothing to do here */ 2630a2eea2e1Sahrens zfs_close(h); 2631a2eea2e1Sahrens continue; 2632a2eea2e1Sahrens } 2633a2eea2e1Sahrens 2634a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 2635a2eea2e1Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2636a2eea2e1Sahrens NULL) != 0) 2637a2eea2e1Sahrens goto ancestorerr; 2638a2eea2e1Sahrens 2639a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 2640a2eea2e1Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2641a2eea2e1Sahrens if (h == NULL) 2642a2eea2e1Sahrens goto ancestorerr; 2643a2eea2e1Sahrens 2644a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 2645a2eea2e1Sahrens if (zfs_mount(h, NULL, 0) != 0) 2646a2eea2e1Sahrens goto ancestorerr; 2647a2eea2e1Sahrens 2648a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 2649a2eea2e1Sahrens if (zfs_share(h) != 0) 2650a2eea2e1Sahrens goto ancestorerr; 2651a2eea2e1Sahrens 2652a2eea2e1Sahrens zfs_close(h); 2653a2eea2e1Sahrens 2654a2eea2e1Sahrens continue; 2655a2eea2e1Sahrens ancestorerr: 2656a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2657a2eea2e1Sahrens "failed to %s ancestor '%s'"), opname, target); 2658a2eea2e1Sahrens return (-1); 2659a2eea2e1Sahrens } 2660a2eea2e1Sahrens 2661a2eea2e1Sahrens return (0); 2662a2eea2e1Sahrens } 2663a2eea2e1Sahrens 2664a2eea2e1Sahrens /* 2665*72bdce51Sahl * Restores a backup of tosnap from the file descriptor specified by infd. 2666fa9e4066Sahrens */ 2667fa9e4066Sahrens int 266899653d4eSeschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 2669*72bdce51Sahl int verbose, int dryrun, boolean_t force, int infd) 2670fa9e4066Sahrens { 2671fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2672fa9e4066Sahrens time_t begin_time; 2673a2eea2e1Sahrens int ioctl_err, err, bytes, size, choplen; 2674fa9e4066Sahrens char *cp; 2675fa9e4066Sahrens dmu_replay_record_t drr; 2676fa9e4066Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 267799653d4eSeschrock char errbuf[1024]; 267898579b20Snd150628 prop_changelist_t *clp; 2679a2eea2e1Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2680fa9e4066Sahrens 2681fa9e4066Sahrens begin_time = time(NULL); 2682fa9e4066Sahrens 268399653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 268499653d4eSeschrock "cannot receive")); 268599653d4eSeschrock 2686fa9e4066Sahrens /* read in the BEGIN record */ 2687fa9e4066Sahrens cp = (char *)&drr; 2688fa9e4066Sahrens bytes = 0; 2689fa9e4066Sahrens do { 2690*72bdce51Sahl size = read(infd, cp, sizeof (drr) - bytes); 26919b4f025eSahrens cp += size; 26929b4f025eSahrens bytes += size; 26939b4f025eSahrens } while (size > 0); 2694fa9e4066Sahrens 26959b4f025eSahrens if (size < 0 || bytes != sizeof (drr)) { 269699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 269799653d4eSeschrock "stream (failed to read first record)")); 269899653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2699fa9e4066Sahrens } 2700fa9e4066Sahrens 2701fa9e4066Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2702fa9e4066Sahrens 2703fa9e4066Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2704fa9e4066Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 270599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 270699653d4eSeschrock "stream (bad magic number)")); 270799653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2708fa9e4066Sahrens } 2709fa9e4066Sahrens 2710fa9e4066Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2711fa9e4066Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 271299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 271399653d4eSeschrock "0x%llx is supported (stream is version 0x%llx)"), 2714fa9e4066Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 271599653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2716fa9e4066Sahrens } 2717fa9e4066Sahrens 2718a2eea2e1Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 2719a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2720a2eea2e1Sahrens "stream (bad snapshot name)")); 2721a2eea2e1Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2722fa9e4066Sahrens } 2723a2eea2e1Sahrens /* 2724a2eea2e1Sahrens * Determine how much of the snapshot name stored in the stream 2725a2eea2e1Sahrens * we are going to tack on to the name they specified on the 2726a2eea2e1Sahrens * command line, and how much we are going to chop off. 2727a2eea2e1Sahrens * 2728a2eea2e1Sahrens * If they specified a snapshot, chop the entire name stored in 2729a2eea2e1Sahrens * the stream. 2730a2eea2e1Sahrens */ 2731a2eea2e1Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2732a2eea2e1Sahrens if (isprefix) { 2733a2eea2e1Sahrens /* 2734a2eea2e1Sahrens * They specified a fs with -d, we want to tack on 2735a2eea2e1Sahrens * everything but the pool name stored in the stream 2736a2eea2e1Sahrens */ 2737a2eea2e1Sahrens if (strchr(tosnap, '@')) { 2738a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2739a2eea2e1Sahrens "argument - snapshot not allowed with -d")); 2740a2eea2e1Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2741a2eea2e1Sahrens } 2742a2eea2e1Sahrens cp = strchr(chopprefix, '/'); 2743fa9e4066Sahrens if (cp == NULL) 2744a2eea2e1Sahrens cp = strchr(chopprefix, '@'); 2745a2eea2e1Sahrens *cp = '\0'; 2746fa9e4066Sahrens } else if (strchr(tosnap, '@') == NULL) { 2747fa9e4066Sahrens /* 2748a2eea2e1Sahrens * If they specified a filesystem without -d, we want to 2749a2eea2e1Sahrens * tack on everything after the fs specified in the 2750a2eea2e1Sahrens * first name from the stream. 2751fa9e4066Sahrens */ 2752a2eea2e1Sahrens cp = strchr(chopprefix, '@'); 2753fa9e4066Sahrens *cp = '\0'; 2754a2eea2e1Sahrens } 2755a2eea2e1Sahrens choplen = strlen(chopprefix); 2756a2eea2e1Sahrens 2757a2eea2e1Sahrens /* 2758a2eea2e1Sahrens * Determine name of destination snapshot, store in zc_value. 2759a2eea2e1Sahrens */ 2760a2eea2e1Sahrens (void) strcpy(zc.zc_value, tosnap); 2761a2eea2e1Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 2762a2eea2e1Sahrens sizeof (zc.zc_value)); 27633ccfa83cSahrens if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 27643ccfa83cSahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2765a2eea2e1Sahrens 2766a2eea2e1Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2767a2eea2e1Sahrens if (drrb->drr_fromguid) { 2768a2eea2e1Sahrens /* incremental backup stream */ 2769a2eea2e1Sahrens zfs_handle_t *h; 2770a2eea2e1Sahrens 2771a2eea2e1Sahrens /* do the recvbackup ioctl to the containing fs */ 2772a2eea2e1Sahrens *strchr(zc.zc_name, '@') = '\0'; 2773fa9e4066Sahrens 2774fa9e4066Sahrens /* make sure destination fs exists */ 277599653d4eSeschrock h = zfs_open(hdl, zc.zc_name, 277699653d4eSeschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 277799653d4eSeschrock if (h == NULL) 2778fa9e4066Sahrens return (-1); 27799b4f025eSahrens if (!dryrun) { 278098579b20Snd150628 /* 278198579b20Snd150628 * We need to unmount all the dependents of the dataset 278298579b20Snd150628 * and the dataset itself. If it's a volume 278398579b20Snd150628 * then remove device link. 278498579b20Snd150628 */ 27859b4f025eSahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 278698579b20Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 278798579b20Snd150628 if (clp == NULL) 278898579b20Snd150628 return (-1); 278998579b20Snd150628 if (changelist_prefix(clp) != 0) { 279098579b20Snd150628 changelist_free(clp); 279198579b20Snd150628 return (-1); 279298579b20Snd150628 } 27939b4f025eSahrens } else { 279499653d4eSeschrock (void) zvol_remove_link(hdl, h->zfs_name); 27959b4f025eSahrens } 27969b4f025eSahrens } 2797fa9e4066Sahrens zfs_close(h); 2798fa9e4066Sahrens } else { 2799fa9e4066Sahrens /* full backup stream */ 2800fa9e4066Sahrens 28019b4f025eSahrens /* Make sure destination fs does not exist */ 2802a2eea2e1Sahrens *strchr(zc.zc_name, '@') = '\0'; 280399653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 280499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 280599653d4eSeschrock "destination '%s' exists"), zc.zc_name); 280699653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 28079b4f025eSahrens } 28089b4f025eSahrens 2809a2eea2e1Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2810a2eea2e1Sahrens /* 2811a2eea2e1Sahrens * they're trying to do a recv into a 2812a2eea2e1Sahrens * nonexistant topmost filesystem. 2813a2eea2e1Sahrens */ 2814a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2815a2eea2e1Sahrens "destination does not exist"), zc.zc_name); 2816a2eea2e1Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2817a2eea2e1Sahrens } 2818a2eea2e1Sahrens 28199b4f025eSahrens /* Do the recvbackup ioctl to the fs's parent. */ 2820a2eea2e1Sahrens *strrchr(zc.zc_name, '/') = '\0'; 2821a2eea2e1Sahrens 2822a2eea2e1Sahrens if (isprefix && (err = create_parents(hdl, 2823a2eea2e1Sahrens zc.zc_value, strlen(tosnap))) != 0) { 2824a2eea2e1Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 2825a2eea2e1Sahrens } 2826a2eea2e1Sahrens 2827fa9e4066Sahrens } 2828fa9e4066Sahrens 2829*72bdce51Sahl zc.zc_cookie = infd; 2830e9dbad6fSeschrock zc.zc_guid = force; 2831fa9e4066Sahrens if (verbose) { 2832f2a3c691Sahrens (void) printf("%s %s stream of %s into %s\n", 2833f2a3c691Sahrens dryrun ? "would receive" : "receiving", 2834fa9e4066Sahrens drrb->drr_fromguid ? "incremental" : "full", 2835fa9e4066Sahrens drr.drr_u.drr_begin.drr_toname, 2836e9dbad6fSeschrock zc.zc_value); 2837fa9e4066Sahrens (void) fflush(stdout); 2838fa9e4066Sahrens } 2839fa9e4066Sahrens if (dryrun) 2840fa9e4066Sahrens return (0); 284199653d4eSeschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 28429b4f025eSahrens if (ioctl_err != 0) { 2843fa9e4066Sahrens switch (errno) { 2844fa9e4066Sahrens case ENODEV: 284599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 284699653d4eSeschrock "most recent snapshot does not match incremental " 284799653d4eSeschrock "source")); 284899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2849fa9e4066Sahrens break; 2850fa9e4066Sahrens case ETXTBSY: 285199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 285299653d4eSeschrock "destination has been modified since most recent " 285399653d4eSeschrock "snapshot")); 285499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2855fa9e4066Sahrens break; 2856fa9e4066Sahrens case EEXIST: 2857fa9e4066Sahrens if (drrb->drr_fromguid == 0) { 2858fa9e4066Sahrens /* it's the containing fs that exists */ 2859e9dbad6fSeschrock cp = strchr(zc.zc_value, '@'); 2860fa9e4066Sahrens *cp = '\0'; 2861fa9e4066Sahrens } 286299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 286399653d4eSeschrock "destination already exists")); 2864ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_EXISTS, 2865ece3d9b3Slling dgettext(TEXT_DOMAIN, "cannot restore to %s"), 2866ece3d9b3Slling zc.zc_value); 2867fa9e4066Sahrens break; 2868fa9e4066Sahrens case EINVAL: 286999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 28709b4f025eSahrens break; 2871ea8dc4b6Seschrock case ECKSUM: 287299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 287399653d4eSeschrock "invalid stream (checksum mismatch)")); 287499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2875fa9e4066Sahrens break; 2876fa9e4066Sahrens default: 287799653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2878fa9e4066Sahrens } 2879fa9e4066Sahrens } 2880fa9e4066Sahrens 2881fa9e4066Sahrens /* 28829b4f025eSahrens * Mount or recreate the /dev links for the target filesystem 28839b4f025eSahrens * (if created, or if we tore them down to do an incremental 28849b4f025eSahrens * restore), and the /dev links for the new snapshot (if 288598579b20Snd150628 * created). Also mount any children of the target filesystem 288698579b20Snd150628 * if we did an incremental receive. 2887fa9e4066Sahrens */ 2888e9dbad6fSeschrock cp = strchr(zc.zc_value, '@'); 28899b4f025eSahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2890fa9e4066Sahrens zfs_handle_t *h; 2891fa9e4066Sahrens 2892fa9e4066Sahrens *cp = '\0'; 2893e9dbad6fSeschrock h = zfs_open(hdl, zc.zc_value, 2894fa9e4066Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2895fa9e4066Sahrens *cp = '@'; 2896fa9e4066Sahrens if (h) { 289798579b20Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 289899653d4eSeschrock err = zvol_create_link(hdl, h->zfs_name); 2899ea8dc4b6Seschrock if (err == 0 && ioctl_err == 0) 290099653d4eSeschrock err = zvol_create_link(hdl, 2901e9dbad6fSeschrock zc.zc_value); 290298579b20Snd150628 } else { 290398579b20Snd150628 if (drrb->drr_fromguid) { 290498579b20Snd150628 err = changelist_postfix(clp); 290598579b20Snd150628 changelist_free(clp); 290698579b20Snd150628 } else { 290798579b20Snd150628 err = zfs_mount(h, NULL, 0); 290898579b20Snd150628 } 29099b4f025eSahrens } 2910fa9e4066Sahrens zfs_close(h); 2911fa9e4066Sahrens } 2912fa9e4066Sahrens } 2913fa9e4066Sahrens 29149b4f025eSahrens if (err || ioctl_err) 29159b4f025eSahrens return (-1); 2916fa9e4066Sahrens 2917fa9e4066Sahrens if (verbose) { 2918fa9e4066Sahrens char buf1[64]; 2919fa9e4066Sahrens char buf2[64]; 2920fa9e4066Sahrens uint64_t bytes = zc.zc_cookie; 2921fa9e4066Sahrens time_t delta = time(NULL) - begin_time; 2922fa9e4066Sahrens if (delta == 0) 2923fa9e4066Sahrens delta = 1; 2924fa9e4066Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2925fa9e4066Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2926fa9e4066Sahrens 2927f2a3c691Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2928fa9e4066Sahrens buf1, delta, buf2); 2929fa9e4066Sahrens } 293098579b20Snd150628 2931fa9e4066Sahrens return (0); 2932fa9e4066Sahrens } 2933fa9e4066Sahrens 2934fa9e4066Sahrens /* 2935b12a1c38Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 2936b12a1c38Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 2937b12a1c38Slling * is a dependent and we should just destroy it without checking the transaction 2938b12a1c38Slling * group. 2939fa9e4066Sahrens */ 2940b12a1c38Slling typedef struct rollback_data { 2941b12a1c38Slling const char *cb_target; /* the snapshot */ 2942b12a1c38Slling uint64_t cb_create; /* creation time reference */ 2943b12a1c38Slling prop_changelist_t *cb_clp; /* changelist pointer */ 2944b12a1c38Slling int cb_error; 294599653d4eSeschrock boolean_t cb_dependent; 2946b12a1c38Slling } rollback_data_t; 2947b12a1c38Slling 2948b12a1c38Slling static int 2949b12a1c38Slling rollback_destroy(zfs_handle_t *zhp, void *data) 2950b12a1c38Slling { 2951b12a1c38Slling rollback_data_t *cbp = data; 2952b12a1c38Slling 2953b12a1c38Slling if (!cbp->cb_dependent) { 2954b12a1c38Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 2955b12a1c38Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 2956b12a1c38Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 2957b12a1c38Slling cbp->cb_create) { 2958b12a1c38Slling 295999653d4eSeschrock cbp->cb_dependent = B_TRUE; 29603bb79becSeschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 29613bb79becSeschrock cbp) != 0) 29623bb79becSeschrock cbp->cb_error = 1; 296399653d4eSeschrock cbp->cb_dependent = B_FALSE; 2964b12a1c38Slling 2965b12a1c38Slling if (zfs_destroy(zhp) != 0) 2966b12a1c38Slling cbp->cb_error = 1; 2967b12a1c38Slling else 2968b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 2969b12a1c38Slling } 2970b12a1c38Slling } else { 2971b12a1c38Slling if (zfs_destroy(zhp) != 0) 2972b12a1c38Slling cbp->cb_error = 1; 2973b12a1c38Slling else 2974b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 2975b12a1c38Slling } 2976b12a1c38Slling 2977b12a1c38Slling zfs_close(zhp); 2978b12a1c38Slling return (0); 2979b12a1c38Slling } 2980b12a1c38Slling 2981b12a1c38Slling /* 2982b12a1c38Slling * Rollback the dataset to its latest snapshot. 2983b12a1c38Slling */ 2984b12a1c38Slling static int 2985b12a1c38Slling do_rollback(zfs_handle_t *zhp) 2986fa9e4066Sahrens { 2987fa9e4066Sahrens int ret; 2988fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2989fa9e4066Sahrens 2990fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2991fa9e4066Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2992fa9e4066Sahrens 2993fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 299499653d4eSeschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2995fa9e4066Sahrens return (-1); 2996fa9e4066Sahrens 2997fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2998fa9e4066Sahrens 2999e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 3000fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3001fa9e4066Sahrens else 3002fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3003fa9e4066Sahrens 3004fa9e4066Sahrens /* 3005fa9e4066Sahrens * We rely on the consumer to verify that there are no newer snapshots 3006fa9e4066Sahrens * for the given dataset. Given these constraints, we can simply pass 3007fa9e4066Sahrens * the name on to the ioctl() call. There is still an unlikely race 3008fa9e4066Sahrens * condition where the user has taken a snapshot since we verified that 3009fa9e4066Sahrens * this was the most recent. 3010fa9e4066Sahrens */ 301199653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 301299653d4eSeschrock &zc)) != 0) { 3013ece3d9b3Slling (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 301499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 301599653d4eSeschrock zhp->zfs_name); 3016fa9e4066Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 301799653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3018fa9e4066Sahrens } 3019fa9e4066Sahrens 3020fa9e4066Sahrens return (ret); 3021fa9e4066Sahrens } 3022fa9e4066Sahrens 3023fa9e4066Sahrens /* 3024b12a1c38Slling * Given a dataset, rollback to a specific snapshot, discarding any 3025b12a1c38Slling * data changes since then and making it the active dataset. 3026b12a1c38Slling * 3027b12a1c38Slling * Any snapshots more recent than the target are destroyed, along with 3028b12a1c38Slling * their dependents. 3029b12a1c38Slling */ 3030b12a1c38Slling int 3031b12a1c38Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 3032b12a1c38Slling { 3033b12a1c38Slling int ret; 3034b12a1c38Slling rollback_data_t cb = { 0 }; 3035b12a1c38Slling prop_changelist_t *clp; 3036b12a1c38Slling 3037b12a1c38Slling /* 3038b12a1c38Slling * Unmount all dependendents of the dataset and the dataset itself. 3039b12a1c38Slling * The list we need to gather is the same as for doing rename 3040b12a1c38Slling */ 3041b12a1c38Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 3042b12a1c38Slling if (clp == NULL) 3043b12a1c38Slling return (-1); 3044b12a1c38Slling 3045b12a1c38Slling if ((ret = changelist_prefix(clp)) != 0) 3046b12a1c38Slling goto out; 3047b12a1c38Slling 3048b12a1c38Slling /* 3049b12a1c38Slling * Destroy all recent snapshots and its dependends. 3050b12a1c38Slling */ 3051b12a1c38Slling cb.cb_target = snap->zfs_name; 3052b12a1c38Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3053b12a1c38Slling cb.cb_clp = clp; 3054b12a1c38Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3055b12a1c38Slling 3056b12a1c38Slling if ((ret = cb.cb_error) != 0) { 3057b12a1c38Slling (void) changelist_postfix(clp); 3058b12a1c38Slling goto out; 3059b12a1c38Slling } 3060b12a1c38Slling 3061b12a1c38Slling /* 3062b12a1c38Slling * Now that we have verified that the snapshot is the latest, 3063b12a1c38Slling * rollback to the given snapshot. 3064b12a1c38Slling */ 3065b12a1c38Slling ret = do_rollback(zhp); 3066b12a1c38Slling 3067b12a1c38Slling if (ret != 0) { 3068b12a1c38Slling (void) changelist_postfix(clp); 3069b12a1c38Slling goto out; 3070b12a1c38Slling } 3071b12a1c38Slling 3072b12a1c38Slling /* 3073b12a1c38Slling * We only want to re-mount the filesystem if it was mounted in the 3074b12a1c38Slling * first place. 3075b12a1c38Slling */ 3076b12a1c38Slling ret = changelist_postfix(clp); 3077b12a1c38Slling 3078b12a1c38Slling out: 3079b12a1c38Slling changelist_free(clp); 3080b12a1c38Slling return (ret); 3081b12a1c38Slling } 3082b12a1c38Slling 3083b12a1c38Slling /* 3084fa9e4066Sahrens * Iterate over all dependents for a given dataset. This includes both 3085fa9e4066Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3086fa9e4066Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3087fa9e4066Sahrens * libzfs_graph.c. 3088fa9e4066Sahrens */ 3089fa9e4066Sahrens int 30903bb79becSeschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 30913bb79becSeschrock zfs_iter_f func, void *data) 3092fa9e4066Sahrens { 3093fa9e4066Sahrens char **dependents; 3094fa9e4066Sahrens size_t count; 3095fa9e4066Sahrens int i; 3096fa9e4066Sahrens zfs_handle_t *child; 3097fa9e4066Sahrens int ret = 0; 3098fa9e4066Sahrens 30993bb79becSeschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 31003bb79becSeschrock &dependents, &count) != 0) 31013bb79becSeschrock return (-1); 31023bb79becSeschrock 3103fa9e4066Sahrens for (i = 0; i < count; i++) { 310499653d4eSeschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 310599653d4eSeschrock dependents[i])) == NULL) 3106fa9e4066Sahrens continue; 3107fa9e4066Sahrens 3108fa9e4066Sahrens if ((ret = func(child, data)) != 0) 3109fa9e4066Sahrens break; 3110fa9e4066Sahrens } 3111fa9e4066Sahrens 3112fa9e4066Sahrens for (i = 0; i < count; i++) 3113fa9e4066Sahrens free(dependents[i]); 3114fa9e4066Sahrens free(dependents); 3115fa9e4066Sahrens 3116fa9e4066Sahrens return (ret); 3117fa9e4066Sahrens } 3118fa9e4066Sahrens 3119fa9e4066Sahrens /* 3120fa9e4066Sahrens * Renames the given dataset. 3121fa9e4066Sahrens */ 3122fa9e4066Sahrens int 3123fa9e4066Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3124fa9e4066Sahrens { 3125fa9e4066Sahrens int ret; 3126fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3127fa9e4066Sahrens char *delim; 3128fa9e4066Sahrens prop_changelist_t *cl; 3129fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 313099653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 313199653d4eSeschrock char errbuf[1024]; 3132fa9e4066Sahrens 3133fa9e4066Sahrens /* if we have the same exact name, just return success */ 3134fa9e4066Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3135fa9e4066Sahrens return (0); 3136fa9e4066Sahrens 313799653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 313899653d4eSeschrock "cannot rename to '%s'"), target); 313999653d4eSeschrock 3140fa9e4066Sahrens /* 3141fa9e4066Sahrens * Make sure the target name is valid 3142fa9e4066Sahrens */ 3143fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 314498579b20Snd150628 if ((strchr(target, '@') == NULL) || 314598579b20Snd150628 *target == '@') { 314698579b20Snd150628 /* 314798579b20Snd150628 * Snapshot target name is abbreviated, 314898579b20Snd150628 * reconstruct full dataset name 314998579b20Snd150628 */ 315098579b20Snd150628 (void) strlcpy(parent, zhp->zfs_name, 315198579b20Snd150628 sizeof (parent)); 315298579b20Snd150628 delim = strchr(parent, '@'); 315398579b20Snd150628 if (strchr(target, '@') == NULL) 315498579b20Snd150628 *(++delim) = '\0'; 315598579b20Snd150628 else 315698579b20Snd150628 *delim = '\0'; 315798579b20Snd150628 (void) strlcat(parent, target, sizeof (parent)); 315898579b20Snd150628 target = parent; 315998579b20Snd150628 } else { 3160fa9e4066Sahrens /* 3161fa9e4066Sahrens * Make sure we're renaming within the same dataset. 3162fa9e4066Sahrens */ 316398579b20Snd150628 delim = strchr(target, '@'); 316498579b20Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 316598579b20Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 316699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 316798579b20Snd150628 "snapshots must be part of same " 316898579b20Snd150628 "dataset")); 316998579b20Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 317098579b20Snd150628 errbuf)); 3171fa9e4066Sahrens } 317298579b20Snd150628 } 317398579b20Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 317498579b20Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3175fa9e4066Sahrens } else { 317698579b20Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 317798579b20Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3178e9dbad6fSeschrock uint64_t unused; 3179e9dbad6fSeschrock 3180fa9e4066Sahrens /* validate parents */ 3181e9dbad6fSeschrock if (check_parents(hdl, target, &unused) != 0) 3182fa9e4066Sahrens return (-1); 3183fa9e4066Sahrens 3184fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 3185fa9e4066Sahrens 3186fa9e4066Sahrens /* make sure we're in the same pool */ 3187fa9e4066Sahrens verify((delim = strchr(target, '/')) != NULL); 3188fa9e4066Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3189fa9e4066Sahrens zhp->zfs_name[delim - target] != '/') { 319099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 319199653d4eSeschrock "datasets must be within same pool")); 319299653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3193fa9e4066Sahrens } 3194f2fdf992Snd150628 3195f2fdf992Snd150628 /* new name cannot be a child of the current dataset name */ 3196f2fdf992Snd150628 if (strncmp(parent, zhp->zfs_name, 3197f2fdf992Snd150628 strlen(zhp->zfs_name)) == 0) { 3198f2fdf992Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3199f2fdf992Snd150628 "New dataset name cannot be a descendent of " 3200f2fdf992Snd150628 "current dataset name")); 3201f2fdf992Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3202f2fdf992Snd150628 } 3203fa9e4066Sahrens } 3204fa9e4066Sahrens 320599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 320699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 320799653d4eSeschrock 3208fa9e4066Sahrens if (getzoneid() == GLOBAL_ZONEID && 3209fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 321099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 321199653d4eSeschrock "dataset is used in a non-global zone")); 321299653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3213fa9e4066Sahrens } 3214fa9e4066Sahrens 3215fa9e4066Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 321699653d4eSeschrock return (-1); 3217fa9e4066Sahrens 3218fa9e4066Sahrens if (changelist_haszonedchild(cl)) { 321999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 322099653d4eSeschrock "child dataset with inherited mountpoint is used " 322199653d4eSeschrock "in a non-global zone")); 3222e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3223fa9e4066Sahrens goto error; 3224fa9e4066Sahrens } 3225fa9e4066Sahrens 3226fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 3227fa9e4066Sahrens goto error; 3228fa9e4066Sahrens 3229e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 3230fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3231fa9e4066Sahrens else 3232fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3233fa9e4066Sahrens 323498579b20Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3235e9dbad6fSeschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 323698579b20Snd150628 323799653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 323899653d4eSeschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3239fa9e4066Sahrens 3240fa9e4066Sahrens /* 3241fa9e4066Sahrens * On failure, we still want to remount any filesystems that 3242fa9e4066Sahrens * were previously mounted, so we don't alter the system state. 3243fa9e4066Sahrens */ 3244fa9e4066Sahrens (void) changelist_postfix(cl); 3245fa9e4066Sahrens } else { 3246fa9e4066Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3247fa9e4066Sahrens 3248fa9e4066Sahrens ret = changelist_postfix(cl); 3249fa9e4066Sahrens } 3250fa9e4066Sahrens 3251fa9e4066Sahrens error: 3252fa9e4066Sahrens changelist_free(cl); 3253fa9e4066Sahrens return (ret); 3254fa9e4066Sahrens } 3255fa9e4066Sahrens 3256fa9e4066Sahrens /* 3257fa9e4066Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3258fa9e4066Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3259fa9e4066Sahrens */ 3260fa9e4066Sahrens int 326199653d4eSeschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3262fa9e4066Sahrens { 3263fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 326499653d4eSeschrock di_devlink_handle_t dhdl; 3265fa9e4066Sahrens 3266fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3267fa9e4066Sahrens 3268fa9e4066Sahrens /* 3269fa9e4066Sahrens * Issue the appropriate ioctl. 3270fa9e4066Sahrens */ 327199653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3272fa9e4066Sahrens switch (errno) { 3273fa9e4066Sahrens case EEXIST: 3274fa9e4066Sahrens /* 3275fa9e4066Sahrens * Silently ignore the case where the link already 3276fa9e4066Sahrens * exists. This allows 'zfs volinit' to be run multiple 3277fa9e4066Sahrens * times without errors. 3278fa9e4066Sahrens */ 3279fa9e4066Sahrens return (0); 3280fa9e4066Sahrens 3281fa9e4066Sahrens default: 3282ece3d9b3Slling return (zfs_standard_error_fmt(hdl, errno, 328399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 328499653d4eSeschrock "for '%s'"), dataset)); 3285fa9e4066Sahrens } 3286fa9e4066Sahrens } 3287fa9e4066Sahrens 3288fa9e4066Sahrens /* 3289fa9e4066Sahrens * Call devfsadm and wait for the links to magically appear. 3290fa9e4066Sahrens */ 329199653d4eSeschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 329299653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 3293ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 329499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 329599653d4eSeschrock "for '%s'"), dataset); 329699653d4eSeschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3297fa9e4066Sahrens return (-1); 3298fa9e4066Sahrens } else { 329999653d4eSeschrock (void) di_devlink_fini(&dhdl); 3300fa9e4066Sahrens } 3301fa9e4066Sahrens 3302fa9e4066Sahrens return (0); 3303fa9e4066Sahrens } 3304fa9e4066Sahrens 3305fa9e4066Sahrens /* 3306fa9e4066Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3307fa9e4066Sahrens */ 3308fa9e4066Sahrens int 330999653d4eSeschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3310fa9e4066Sahrens { 3311fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3312fa9e4066Sahrens 3313fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3314fa9e4066Sahrens 331599653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3316fa9e4066Sahrens switch (errno) { 3317fa9e4066Sahrens case ENXIO: 3318fa9e4066Sahrens /* 3319fa9e4066Sahrens * Silently ignore the case where the link no longer 3320fa9e4066Sahrens * exists, so that 'zfs volfini' can be run multiple 3321fa9e4066Sahrens * times without errors. 3322fa9e4066Sahrens */ 3323fa9e4066Sahrens return (0); 3324fa9e4066Sahrens 3325fa9e4066Sahrens default: 3326ece3d9b3Slling return (zfs_standard_error_fmt(hdl, errno, 332799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove device " 332899653d4eSeschrock "links for '%s'"), dataset)); 3329fa9e4066Sahrens } 3330fa9e4066Sahrens } 3331fa9e4066Sahrens 3332fa9e4066Sahrens return (0); 3333fa9e4066Sahrens } 3334e9dbad6fSeschrock 3335e9dbad6fSeschrock nvlist_t * 3336e9dbad6fSeschrock zfs_get_user_props(zfs_handle_t *zhp) 3337e9dbad6fSeschrock { 3338e9dbad6fSeschrock return (zhp->zfs_user_props); 3339e9dbad6fSeschrock } 3340e9dbad6fSeschrock 3341e9dbad6fSeschrock /* 3342e9dbad6fSeschrock * Given a comma-separated list of properties, contruct a property list 3343e9dbad6fSeschrock * containing both user-defined and native properties. This function will 3344e9dbad6fSeschrock * return a NULL list if 'all' is specified, which can later be expanded on a 3345e9dbad6fSeschrock * per-dataset basis by zfs_expand_proplist(). 3346e9dbad6fSeschrock */ 3347e9dbad6fSeschrock int 3348e9dbad6fSeschrock zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 3349e9dbad6fSeschrock { 3350e9dbad6fSeschrock int i; 3351e9dbad6fSeschrock size_t len; 3352e9dbad6fSeschrock char *s, *p; 3353e9dbad6fSeschrock char c; 3354e9dbad6fSeschrock zfs_prop_t prop; 3355e9dbad6fSeschrock zfs_proplist_t *entry; 3356e9dbad6fSeschrock zfs_proplist_t **last; 3357e9dbad6fSeschrock 3358e9dbad6fSeschrock *listp = NULL; 3359e9dbad6fSeschrock last = listp; 3360e9dbad6fSeschrock 3361e9dbad6fSeschrock /* 3362e9dbad6fSeschrock * If 'all' is specified, return a NULL list. 3363e9dbad6fSeschrock */ 3364e9dbad6fSeschrock if (strcmp(fields, "all") == 0) 3365e9dbad6fSeschrock return (0); 3366e9dbad6fSeschrock 3367e9dbad6fSeschrock /* 3368e9dbad6fSeschrock * If no fields were specified, return an error. 3369e9dbad6fSeschrock */ 3370e9dbad6fSeschrock if (fields[0] == '\0') { 3371e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3372e9dbad6fSeschrock "no properties specified")); 3373e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 3374e9dbad6fSeschrock "bad property list"))); 3375e9dbad6fSeschrock } 3376e9dbad6fSeschrock 3377e9dbad6fSeschrock /* 3378e9dbad6fSeschrock * It would be nice to use getsubopt() here, but the inclusion of column 3379e9dbad6fSeschrock * aliases makes this more effort than it's worth. 3380e9dbad6fSeschrock */ 3381e9dbad6fSeschrock s = fields; 3382e9dbad6fSeschrock while (*s != '\0') { 3383e9dbad6fSeschrock if ((p = strchr(s, ',')) == NULL) { 3384e9dbad6fSeschrock len = strlen(s); 3385e9dbad6fSeschrock p = s + len; 3386e9dbad6fSeschrock } else { 3387e9dbad6fSeschrock len = p - s; 3388e9dbad6fSeschrock } 3389e9dbad6fSeschrock 3390e9dbad6fSeschrock /* 3391e9dbad6fSeschrock * Check for empty options. 3392e9dbad6fSeschrock */ 3393e9dbad6fSeschrock if (len == 0) { 3394e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3395e9dbad6fSeschrock "empty property name")); 3396e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, 3397e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "bad property list"))); 3398e9dbad6fSeschrock } 3399e9dbad6fSeschrock 3400e9dbad6fSeschrock /* 3401e9dbad6fSeschrock * Check all regular property names. 3402e9dbad6fSeschrock */ 3403e9dbad6fSeschrock c = s[len]; 3404e9dbad6fSeschrock s[len] = '\0'; 3405e9dbad6fSeschrock for (i = 0; i < ZFS_NPROP_ALL; i++) { 3406e9dbad6fSeschrock if ((prop = zfs_name_to_prop(s)) != ZFS_PROP_INVAL) 3407e9dbad6fSeschrock break; 3408e9dbad6fSeschrock } 3409e9dbad6fSeschrock 3410e9dbad6fSeschrock /* 3411e9dbad6fSeschrock * If no column is specified, and this isn't a user property, 3412e9dbad6fSeschrock * return failure. 3413e9dbad6fSeschrock */ 3414e9dbad6fSeschrock if (i == ZFS_NPROP_ALL && !zfs_prop_user(s)) { 3415e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3416e9dbad6fSeschrock "invalid property '%s'"), s); 3417e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, 3418e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "bad property list"))); 3419e9dbad6fSeschrock } 3420e9dbad6fSeschrock 3421e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 3422e9dbad6fSeschrock return (-1); 3423e9dbad6fSeschrock 3424e9dbad6fSeschrock entry->pl_prop = prop; 3425e9dbad6fSeschrock if (prop == ZFS_PROP_INVAL) { 3426e9dbad6fSeschrock if ((entry->pl_user_prop = 3427e9dbad6fSeschrock zfs_strdup(hdl, s)) == NULL) { 3428e9dbad6fSeschrock free(entry); 3429e9dbad6fSeschrock return (-1); 3430e9dbad6fSeschrock } 3431e9dbad6fSeschrock entry->pl_width = strlen(s); 3432e9dbad6fSeschrock } else { 3433e9dbad6fSeschrock entry->pl_width = zfs_prop_width(prop, 3434e9dbad6fSeschrock &entry->pl_fixed); 3435e9dbad6fSeschrock } 3436e9dbad6fSeschrock 3437e9dbad6fSeschrock *last = entry; 3438e9dbad6fSeschrock last = &entry->pl_next; 3439e9dbad6fSeschrock 3440e9dbad6fSeschrock s = p; 3441e9dbad6fSeschrock if (c == ',') 3442e9dbad6fSeschrock s++; 3443e9dbad6fSeschrock } 3444e9dbad6fSeschrock 3445e9dbad6fSeschrock return (0); 3446e9dbad6fSeschrock } 3447e9dbad6fSeschrock 3448e9dbad6fSeschrock void 3449e9dbad6fSeschrock zfs_free_proplist(zfs_proplist_t *pl) 3450e9dbad6fSeschrock { 3451e9dbad6fSeschrock zfs_proplist_t *next; 3452e9dbad6fSeschrock 3453e9dbad6fSeschrock while (pl != NULL) { 3454e9dbad6fSeschrock next = pl->pl_next; 3455e9dbad6fSeschrock free(pl->pl_user_prop); 3456e9dbad6fSeschrock free(pl); 3457e9dbad6fSeschrock pl = next; 3458e9dbad6fSeschrock } 3459e9dbad6fSeschrock } 3460e9dbad6fSeschrock 3461e9dbad6fSeschrock /* 3462e9dbad6fSeschrock * This function is used by 'zfs list' to determine the exact set of columns to 3463e9dbad6fSeschrock * display, and their maximum widths. This does two main things: 3464e9dbad6fSeschrock * 3465e9dbad6fSeschrock * - If this is a list of all properties, then expand the list to include 3466e9dbad6fSeschrock * all native properties, and set a flag so that for each dataset we look 3467e9dbad6fSeschrock * for new unique user properties and add them to the list. 3468e9dbad6fSeschrock * 3469e9dbad6fSeschrock * - For non fixed-width properties, keep track of the maximum width seen 3470e9dbad6fSeschrock * so that we can size the column appropriately. 3471e9dbad6fSeschrock */ 3472e9dbad6fSeschrock int 3473e9dbad6fSeschrock zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 3474e9dbad6fSeschrock { 3475e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 3476e9dbad6fSeschrock zfs_prop_t prop; 3477e9dbad6fSeschrock zfs_proplist_t *entry; 3478e9dbad6fSeschrock zfs_proplist_t **last, **start; 3479e9dbad6fSeschrock nvlist_t *userprops, *propval; 3480e9dbad6fSeschrock nvpair_t *elem; 3481e9dbad6fSeschrock char *strval; 3482e9dbad6fSeschrock char buf[ZFS_MAXPROPLEN]; 3483e9dbad6fSeschrock 3484e9dbad6fSeschrock if (*plp == NULL) { 3485e9dbad6fSeschrock /* 3486e9dbad6fSeschrock * If this is the very first time we've been called for an 'all' 3487e9dbad6fSeschrock * specification, expand the list to include all native 3488e9dbad6fSeschrock * properties. 3489e9dbad6fSeschrock */ 3490e9dbad6fSeschrock last = plp; 3491e9dbad6fSeschrock for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) { 3492e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, 3493e9dbad6fSeschrock sizeof (zfs_proplist_t))) == NULL) 3494e9dbad6fSeschrock return (-1); 3495e9dbad6fSeschrock 3496e9dbad6fSeschrock entry->pl_prop = prop; 3497e9dbad6fSeschrock entry->pl_width = zfs_prop_width(prop, 3498e9dbad6fSeschrock &entry->pl_fixed); 3499e9dbad6fSeschrock entry->pl_all = B_TRUE; 3500e9dbad6fSeschrock 3501e9dbad6fSeschrock *last = entry; 3502e9dbad6fSeschrock last = &entry->pl_next; 3503e9dbad6fSeschrock } 3504e9dbad6fSeschrock 3505e9dbad6fSeschrock /* 3506e9dbad6fSeschrock * Add 'name' to the beginning of the list, which is handled 3507e9dbad6fSeschrock * specially. 3508e9dbad6fSeschrock */ 3509e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, 3510e9dbad6fSeschrock sizeof (zfs_proplist_t))) == NULL) 3511e9dbad6fSeschrock return (-1); 3512e9dbad6fSeschrock 3513e9dbad6fSeschrock entry->pl_prop = ZFS_PROP_NAME; 3514e9dbad6fSeschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 3515e9dbad6fSeschrock &entry->pl_fixed); 3516e9dbad6fSeschrock entry->pl_all = B_TRUE; 3517e9dbad6fSeschrock entry->pl_next = *plp; 3518e9dbad6fSeschrock *plp = entry; 3519e9dbad6fSeschrock } 3520e9dbad6fSeschrock 3521e9dbad6fSeschrock userprops = zfs_get_user_props(zhp); 3522e9dbad6fSeschrock 3523e9dbad6fSeschrock entry = *plp; 3524e9dbad6fSeschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3525e9dbad6fSeschrock /* 3526e9dbad6fSeschrock * Go through and add any user properties as necessary. We 3527e9dbad6fSeschrock * start by incrementing our list pointer to the first 3528e9dbad6fSeschrock * non-native property. 3529e9dbad6fSeschrock */ 3530e9dbad6fSeschrock start = plp; 3531e9dbad6fSeschrock while (*start != NULL) { 3532e9dbad6fSeschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 3533e9dbad6fSeschrock break; 3534e9dbad6fSeschrock start = &(*start)->pl_next; 3535e9dbad6fSeschrock } 3536e9dbad6fSeschrock 3537e9dbad6fSeschrock elem = NULL; 3538e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3539e9dbad6fSeschrock /* 3540e9dbad6fSeschrock * See if we've already found this property in our list. 3541e9dbad6fSeschrock */ 3542e9dbad6fSeschrock for (last = start; *last != NULL; 3543e9dbad6fSeschrock last = &(*last)->pl_next) { 3544e9dbad6fSeschrock if (strcmp((*last)->pl_user_prop, 3545e9dbad6fSeschrock nvpair_name(elem)) == 0) 3546e9dbad6fSeschrock break; 3547e9dbad6fSeschrock } 3548e9dbad6fSeschrock 3549e9dbad6fSeschrock if (*last == NULL) { 3550e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, 3551e9dbad6fSeschrock sizeof (zfs_proplist_t))) == NULL || 3552e9dbad6fSeschrock ((entry->pl_user_prop = zfs_strdup(hdl, 3553e9dbad6fSeschrock nvpair_name(elem)))) == NULL) { 3554e9dbad6fSeschrock free(entry); 3555e9dbad6fSeschrock return (-1); 3556e9dbad6fSeschrock } 3557e9dbad6fSeschrock 3558e9dbad6fSeschrock entry->pl_prop = ZFS_PROP_INVAL; 3559e9dbad6fSeschrock entry->pl_width = strlen(nvpair_name(elem)); 3560e9dbad6fSeschrock entry->pl_all = B_TRUE; 3561e9dbad6fSeschrock *last = entry; 3562e9dbad6fSeschrock } 3563e9dbad6fSeschrock } 3564e9dbad6fSeschrock } 3565e9dbad6fSeschrock 3566e9dbad6fSeschrock /* 3567e9dbad6fSeschrock * Now go through and check the width of any non-fixed columns 3568e9dbad6fSeschrock */ 3569e9dbad6fSeschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3570e9dbad6fSeschrock if (entry->pl_fixed) 3571e9dbad6fSeschrock continue; 3572e9dbad6fSeschrock 3573e9dbad6fSeschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 3574e9dbad6fSeschrock if (zfs_prop_get(zhp, entry->pl_prop, 3575e9dbad6fSeschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3576e9dbad6fSeschrock if (strlen(buf) > entry->pl_width) 3577e9dbad6fSeschrock entry->pl_width = strlen(buf); 3578e9dbad6fSeschrock } 3579e9dbad6fSeschrock } else if (nvlist_lookup_nvlist(userprops, 3580e9dbad6fSeschrock entry->pl_user_prop, &propval) == 0) { 3581e9dbad6fSeschrock verify(nvlist_lookup_string(propval, 3582e9dbad6fSeschrock ZFS_PROP_VALUE, &strval) == 0); 3583e9dbad6fSeschrock if (strlen(strval) > entry->pl_width) 3584e9dbad6fSeschrock entry->pl_width = strlen(strval); 3585e9dbad6fSeschrock } 3586e9dbad6fSeschrock } 3587e9dbad6fSeschrock 3588e9dbad6fSeschrock return (0); 3589e9dbad6fSeschrock } 3590