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 /* 23798d5834Sgw * 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 54*cdf5b4caSmmusante static int zvol_create_link_common(libzfs_handle_t *, const char *, int); 55*cdf5b4caSmmusante 56fa9e4066Sahrens /* 57fa9e4066Sahrens * Given a single type (not a mask of types), return the type in a human 58fa9e4066Sahrens * readable form. 59fa9e4066Sahrens */ 60fa9e4066Sahrens const char * 61fa9e4066Sahrens zfs_type_to_name(zfs_type_t type) 62fa9e4066Sahrens { 63fa9e4066Sahrens switch (type) { 64fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 65fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 66fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 67fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 68fa9e4066Sahrens case ZFS_TYPE_VOLUME: 69fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 70fa9e4066Sahrens } 71fa9e4066Sahrens 72fa9e4066Sahrens return (NULL); 73fa9e4066Sahrens } 74fa9e4066Sahrens 75fa9e4066Sahrens /* 76fa9e4066Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 77fa9e4066Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 78fa9e4066Sahrens * We guess what the type would have been based on the path and the mask of 79fa9e4066Sahrens * acceptable types. 80fa9e4066Sahrens */ 81fa9e4066Sahrens static const char * 82fa9e4066Sahrens path_to_str(const char *path, int types) 83fa9e4066Sahrens { 84fa9e4066Sahrens /* 85fa9e4066Sahrens * When given a single type, always report the exact type. 86fa9e4066Sahrens */ 87fa9e4066Sahrens if (types == ZFS_TYPE_SNAPSHOT) 88fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 89fa9e4066Sahrens if (types == ZFS_TYPE_FILESYSTEM) 90fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 91fa9e4066Sahrens if (types == ZFS_TYPE_VOLUME) 92fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 93fa9e4066Sahrens 94fa9e4066Sahrens /* 95fa9e4066Sahrens * The user is requesting more than one type of dataset. If this is the 96fa9e4066Sahrens * case, consult the path itself. If we're looking for a snapshot, and 97fa9e4066Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 98fa9e4066Sahrens * snapshot attribute and try again. 99fa9e4066Sahrens */ 100fa9e4066Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 101fa9e4066Sahrens if (strchr(path, '@') != NULL) 102fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 103fa9e4066Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 104fa9e4066Sahrens } 105fa9e4066Sahrens 106fa9e4066Sahrens 107fa9e4066Sahrens /* 108fa9e4066Sahrens * The user has requested either filesystems or volumes. 109fa9e4066Sahrens * We have no way of knowing a priori what type this would be, so always 110fa9e4066Sahrens * report it as "filesystem" or "volume", our two primitive types. 111fa9e4066Sahrens */ 112fa9e4066Sahrens if (types & ZFS_TYPE_FILESYSTEM) 113fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 114fa9e4066Sahrens 115fa9e4066Sahrens assert(types & ZFS_TYPE_VOLUME); 116fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 117fa9e4066Sahrens } 118fa9e4066Sahrens 119fa9e4066Sahrens /* 120fa9e4066Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 121fa9e4066Sahrens * provide a more meaningful error message. We place a more useful message in 122fa9e4066Sahrens * 'buf' detailing exactly why the name was not valid. 123fa9e4066Sahrens */ 124fa9e4066Sahrens static int 12599653d4eSeschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 126fa9e4066Sahrens { 127fa9e4066Sahrens namecheck_err_t why; 128fa9e4066Sahrens char what; 129fa9e4066Sahrens 130fa9e4066Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 13199653d4eSeschrock if (hdl != NULL) { 132fa9e4066Sahrens switch (why) { 133b81d61a6Slling case NAME_ERR_TOOLONG: 13499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13599653d4eSeschrock "name is too long")); 136b81d61a6Slling break; 137b81d61a6Slling 138fa9e4066Sahrens case NAME_ERR_LEADING_SLASH: 13999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 14099653d4eSeschrock "leading slash in name")); 141fa9e4066Sahrens break; 142fa9e4066Sahrens 143fa9e4066Sahrens case NAME_ERR_EMPTY_COMPONENT: 14499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 14599653d4eSeschrock "empty component in name")); 146fa9e4066Sahrens break; 147fa9e4066Sahrens 148fa9e4066Sahrens case NAME_ERR_TRAILING_SLASH: 14999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 15099653d4eSeschrock "trailing slash in name")); 151fa9e4066Sahrens break; 152fa9e4066Sahrens 153fa9e4066Sahrens case NAME_ERR_INVALCHAR: 15499653d4eSeschrock zfs_error_aux(hdl, 155fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 15699653d4eSeschrock "'%c' in name"), what); 157fa9e4066Sahrens break; 158fa9e4066Sahrens 159fa9e4066Sahrens case NAME_ERR_MULTIPLE_AT: 16099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 16199653d4eSeschrock "multiple '@' delimiters in name")); 162fa9e4066Sahrens break; 1635ad82045Snd 1645ad82045Snd case NAME_ERR_NOLETTER: 1655ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1665ad82045Snd "pool doesn't begin with a letter")); 1675ad82045Snd break; 1685ad82045Snd 1695ad82045Snd case NAME_ERR_RESERVED: 1705ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1715ad82045Snd "name is reserved")); 1725ad82045Snd break; 1735ad82045Snd 1745ad82045Snd case NAME_ERR_DISKLIKE: 1755ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1765ad82045Snd "reserved disk name")); 1775ad82045Snd break; 178fa9e4066Sahrens } 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens return (0); 182fa9e4066Sahrens } 183fa9e4066Sahrens 184fa9e4066Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 18599653d4eSeschrock if (hdl != NULL) 18699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18799653d4eSeschrock "snapshot delimiter '@' in filesystem name")); 188fa9e4066Sahrens return (0); 189fa9e4066Sahrens } 190fa9e4066Sahrens 1911d452cf5Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1921d452cf5Sahrens if (hdl != NULL) 1931d452cf5Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 194d7d4af51Smmusante "missing '@' delimiter in snapshot name")); 1951d452cf5Sahrens return (0); 1961d452cf5Sahrens } 1971d452cf5Sahrens 19899653d4eSeschrock return (-1); 199fa9e4066Sahrens } 200fa9e4066Sahrens 201fa9e4066Sahrens int 202fa9e4066Sahrens zfs_name_valid(const char *name, zfs_type_t type) 203fa9e4066Sahrens { 20499653d4eSeschrock return (zfs_validate_name(NULL, name, type)); 205fa9e4066Sahrens } 206fa9e4066Sahrens 207e9dbad6fSeschrock /* 208e9dbad6fSeschrock * This function takes the raw DSL properties, and filters out the user-defined 209e9dbad6fSeschrock * properties into a separate nvlist. 210e9dbad6fSeschrock */ 211e9dbad6fSeschrock static int 212e9dbad6fSeschrock process_user_props(zfs_handle_t *zhp) 213e9dbad6fSeschrock { 214e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 215e9dbad6fSeschrock nvpair_t *elem; 216e9dbad6fSeschrock nvlist_t *propval; 217e9dbad6fSeschrock 218e9dbad6fSeschrock nvlist_free(zhp->zfs_user_props); 219e9dbad6fSeschrock 220e9dbad6fSeschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 221e9dbad6fSeschrock return (no_memory(hdl)); 222e9dbad6fSeschrock 223e9dbad6fSeschrock elem = NULL; 224e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 225e9dbad6fSeschrock if (!zfs_prop_user(nvpair_name(elem))) 226e9dbad6fSeschrock continue; 227e9dbad6fSeschrock 228e9dbad6fSeschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 229e9dbad6fSeschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 230e9dbad6fSeschrock nvpair_name(elem), propval) != 0) 231e9dbad6fSeschrock return (no_memory(hdl)); 232e9dbad6fSeschrock } 233e9dbad6fSeschrock 234e9dbad6fSeschrock return (0); 235e9dbad6fSeschrock } 236e9dbad6fSeschrock 237fa9e4066Sahrens /* 238fa9e4066Sahrens * Utility function to gather stats (objset and zpl) for the given object. 239fa9e4066Sahrens */ 240fa9e4066Sahrens static int 241fa9e4066Sahrens get_stats(zfs_handle_t *zhp) 242fa9e4066Sahrens { 243fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 244e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 245fa9e4066Sahrens 246fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 247fa9e4066Sahrens 248e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 24999653d4eSeschrock return (-1); 2507f7322feSeschrock 25199653d4eSeschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2527f7322feSeschrock if (errno == ENOMEM) { 253e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 254e9dbad6fSeschrock zcmd_free_nvlists(&zc); 25599653d4eSeschrock return (-1); 256e9dbad6fSeschrock } 2577f7322feSeschrock } else { 258e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2597f7322feSeschrock return (-1); 2607f7322feSeschrock } 2617f7322feSeschrock } 262fa9e4066Sahrens 263a2eea2e1Sahrens zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 264fa9e4066Sahrens 265e9dbad6fSeschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 266ea8dc4b6Seschrock 26799653d4eSeschrock if (zhp->zfs_props) { 26899653d4eSeschrock nvlist_free(zhp->zfs_props); 26999653d4eSeschrock zhp->zfs_props = NULL; 27099653d4eSeschrock } 27199653d4eSeschrock 272e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 273e9dbad6fSeschrock zcmd_free_nvlists(&zc); 27499653d4eSeschrock return (-1); 27599653d4eSeschrock } 276fa9e4066Sahrens 277e9dbad6fSeschrock zcmd_free_nvlists(&zc); 278fa9e4066Sahrens 279e9dbad6fSeschrock if (process_user_props(zhp) != 0) 280e9dbad6fSeschrock return (-1); 28199653d4eSeschrock 282fa9e4066Sahrens return (0); 283fa9e4066Sahrens } 284fa9e4066Sahrens 285fa9e4066Sahrens /* 286fa9e4066Sahrens * Refresh the properties currently stored in the handle. 287fa9e4066Sahrens */ 288fa9e4066Sahrens void 289fa9e4066Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 290fa9e4066Sahrens { 291fa9e4066Sahrens (void) get_stats(zhp); 292fa9e4066Sahrens } 293fa9e4066Sahrens 294fa9e4066Sahrens /* 295fa9e4066Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 296fa9e4066Sahrens * zfs_iter_* to create child handles on the fly. 297fa9e4066Sahrens */ 298fa9e4066Sahrens zfs_handle_t * 29999653d4eSeschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 300fa9e4066Sahrens { 30199653d4eSeschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 30299653d4eSeschrock 30399653d4eSeschrock if (zhp == NULL) 30499653d4eSeschrock return (NULL); 30599653d4eSeschrock 30699653d4eSeschrock zhp->zfs_hdl = hdl; 307fa9e4066Sahrens 30831fd60d3Sahrens top: 309fa9e4066Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 310fa9e4066Sahrens 311fa9e4066Sahrens if (get_stats(zhp) != 0) { 312fa9e4066Sahrens free(zhp); 313fa9e4066Sahrens return (NULL); 314fa9e4066Sahrens } 315fa9e4066Sahrens 31631fd60d3Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 31731fd60d3Sahrens zfs_cmd_t zc = { 0 }; 31831fd60d3Sahrens 31931fd60d3Sahrens /* 32031fd60d3Sahrens * If it is dds_inconsistent, then we've caught it in 32131fd60d3Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 32231fd60d3Sahrens * it is inconsistent from the ZPL's point of view, so 32331fd60d3Sahrens * can't be mounted. However, it could also be that we 32431fd60d3Sahrens * have crashed in the middle of one of those 32531fd60d3Sahrens * operations, in which case we need to get rid of the 32631fd60d3Sahrens * inconsistent state. We do that by either rolling 32731fd60d3Sahrens * back to the previous snapshot (which will fail if 32831fd60d3Sahrens * there is none), or destroying the filesystem. Note 32931fd60d3Sahrens * that if we are still in the middle of an active 33031fd60d3Sahrens * 'receive' or 'destroy', then the rollback and destroy 33131fd60d3Sahrens * will fail with EBUSY and we will drive on as usual. 33231fd60d3Sahrens */ 33331fd60d3Sahrens 33431fd60d3Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 33531fd60d3Sahrens 336a2eea2e1Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 33799653d4eSeschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 33831fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 33931fd60d3Sahrens } else { 34031fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZFS; 34131fd60d3Sahrens } 34231fd60d3Sahrens 34331fd60d3Sahrens /* If we can successfully roll it back, reget the stats */ 34499653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 34531fd60d3Sahrens goto top; 34631fd60d3Sahrens /* 34731fd60d3Sahrens * If we can sucessfully destroy it, pretend that it 34831fd60d3Sahrens * never existed. 34931fd60d3Sahrens */ 35099653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 35131fd60d3Sahrens free(zhp); 35231fd60d3Sahrens errno = ENOENT; 35331fd60d3Sahrens return (NULL); 35431fd60d3Sahrens } 35531fd60d3Sahrens } 35631fd60d3Sahrens 357fa9e4066Sahrens /* 358fa9e4066Sahrens * We've managed to open the dataset and gather statistics. Determine 359fa9e4066Sahrens * the high-level type. 360fa9e4066Sahrens */ 361a2eea2e1Sahrens if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 362a2eea2e1Sahrens zhp->zfs_head_type = ZFS_TYPE_VOLUME; 363a2eea2e1Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 364a2eea2e1Sahrens zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; 365a2eea2e1Sahrens else 366a2eea2e1Sahrens abort(); 367a2eea2e1Sahrens 368fa9e4066Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 369fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 370fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 371fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 372fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 373fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 374fa9e4066Sahrens else 37599653d4eSeschrock abort(); /* we should never see any other types */ 376fa9e4066Sahrens 377fa9e4066Sahrens return (zhp); 378fa9e4066Sahrens } 379fa9e4066Sahrens 380fa9e4066Sahrens /* 381fa9e4066Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 382fa9e4066Sahrens * argument is a mask of acceptable types. The function will print an 383fa9e4066Sahrens * appropriate error message and return NULL if it can't be opened. 384fa9e4066Sahrens */ 385fa9e4066Sahrens zfs_handle_t * 38699653d4eSeschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 387fa9e4066Sahrens { 388fa9e4066Sahrens zfs_handle_t *zhp; 38999653d4eSeschrock char errbuf[1024]; 39099653d4eSeschrock 39199653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 39299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 393fa9e4066Sahrens 394fa9e4066Sahrens /* 39599653d4eSeschrock * Validate the name before we even try to open it. 396fa9e4066Sahrens */ 39799653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 39899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 39999653d4eSeschrock "invalid dataset name")); 40099653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 401fa9e4066Sahrens return (NULL); 402fa9e4066Sahrens } 403fa9e4066Sahrens 404fa9e4066Sahrens /* 405fa9e4066Sahrens * Try to get stats for the dataset, which will tell us if it exists. 406fa9e4066Sahrens */ 407fa9e4066Sahrens errno = 0; 40899653d4eSeschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 409ece3d9b3Slling (void) zfs_standard_error(hdl, errno, errbuf); 410fa9e4066Sahrens return (NULL); 411fa9e4066Sahrens } 412fa9e4066Sahrens 413fa9e4066Sahrens if (!(types & zhp->zfs_type)) { 41499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 41594de1d4cSeschrock zfs_close(zhp); 416fa9e4066Sahrens return (NULL); 417fa9e4066Sahrens } 418fa9e4066Sahrens 419fa9e4066Sahrens return (zhp); 420fa9e4066Sahrens } 421fa9e4066Sahrens 422fa9e4066Sahrens /* 423fa9e4066Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 424fa9e4066Sahrens */ 425fa9e4066Sahrens void 426fa9e4066Sahrens zfs_close(zfs_handle_t *zhp) 427fa9e4066Sahrens { 428fa9e4066Sahrens if (zhp->zfs_mntopts) 429fa9e4066Sahrens free(zhp->zfs_mntopts); 430e9dbad6fSeschrock nvlist_free(zhp->zfs_props); 431e9dbad6fSeschrock nvlist_free(zhp->zfs_user_props); 432fa9e4066Sahrens free(zhp); 433fa9e4066Sahrens } 434fa9e4066Sahrens 435fa9e4066Sahrens /* 436fa9e4066Sahrens * Given a numeric suffix, convert the value into a number of bits that the 437fa9e4066Sahrens * resulting value must be shifted. 438fa9e4066Sahrens */ 439fa9e4066Sahrens static int 44099653d4eSeschrock str2shift(libzfs_handle_t *hdl, const char *buf) 441fa9e4066Sahrens { 442fa9e4066Sahrens const char *ends = "BKMGTPEZ"; 443fa9e4066Sahrens int i; 444fa9e4066Sahrens 445fa9e4066Sahrens if (buf[0] == '\0') 446fa9e4066Sahrens return (0); 447fa9e4066Sahrens for (i = 0; i < strlen(ends); i++) { 448fa9e4066Sahrens if (toupper(buf[0]) == ends[i]) 449fa9e4066Sahrens break; 450fa9e4066Sahrens } 451fa9e4066Sahrens if (i == strlen(ends)) { 45299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 45399653d4eSeschrock "invalid numeric suffix '%s'"), buf); 454fa9e4066Sahrens return (-1); 455fa9e4066Sahrens } 456fa9e4066Sahrens 457fa9e4066Sahrens /* 458fa9e4066Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 459fa9e4066Sahrens * allow 'BB' - that's just weird. 460fa9e4066Sahrens */ 461fa9e4066Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 46299653d4eSeschrock toupper(buf[0]) != 'B')) 463fa9e4066Sahrens return (10*i); 464fa9e4066Sahrens 46599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 46699653d4eSeschrock "invalid numeric suffix '%s'"), buf); 467fa9e4066Sahrens return (-1); 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens /* 471fa9e4066Sahrens * Convert a string of the form '100G' into a real number. Used when setting 472fa9e4066Sahrens * properties or creating a volume. 'buf' is used to place an extended error 473fa9e4066Sahrens * message for the caller to use. 474fa9e4066Sahrens */ 475fa9e4066Sahrens static int 47699653d4eSeschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 477fa9e4066Sahrens { 478fa9e4066Sahrens char *end; 479fa9e4066Sahrens int shift; 480fa9e4066Sahrens 481fa9e4066Sahrens *num = 0; 482fa9e4066Sahrens 483fa9e4066Sahrens /* Check to see if this looks like a number. */ 484fa9e4066Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 48599653d4eSeschrock if (hdl) 48699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 48799653d4eSeschrock "bad numeric value '%s'"), value); 488fa9e4066Sahrens return (-1); 489fa9e4066Sahrens } 490fa9e4066Sahrens 491fa9e4066Sahrens /* Rely on stroll() to process the numeric portion. */ 492fa9e4066Sahrens errno = 0; 493fa9e4066Sahrens *num = strtoll(value, &end, 10); 494fa9e4066Sahrens 495fa9e4066Sahrens /* 496fa9e4066Sahrens * Check for ERANGE, which indicates that the value is too large to fit 497fa9e4066Sahrens * in a 64-bit value. 498fa9e4066Sahrens */ 499fa9e4066Sahrens if (errno == ERANGE) { 50099653d4eSeschrock if (hdl) 50199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50299653d4eSeschrock "numeric value is too large")); 503fa9e4066Sahrens return (-1); 504fa9e4066Sahrens } 505fa9e4066Sahrens 506fa9e4066Sahrens /* 507fa9e4066Sahrens * If we have a decimal value, then do the computation with floating 508fa9e4066Sahrens * point arithmetic. Otherwise, use standard arithmetic. 509fa9e4066Sahrens */ 510fa9e4066Sahrens if (*end == '.') { 511fa9e4066Sahrens double fval = strtod(value, &end); 512fa9e4066Sahrens 51399653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 514fa9e4066Sahrens return (-1); 515fa9e4066Sahrens 516fa9e4066Sahrens fval *= pow(2, shift); 517fa9e4066Sahrens 518fa9e4066Sahrens if (fval > UINT64_MAX) { 51999653d4eSeschrock if (hdl) 52099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 52199653d4eSeschrock "numeric value is too large")); 522fa9e4066Sahrens return (-1); 523fa9e4066Sahrens } 524fa9e4066Sahrens 525fa9e4066Sahrens *num = (uint64_t)fval; 526fa9e4066Sahrens } else { 52799653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 528fa9e4066Sahrens return (-1); 529fa9e4066Sahrens 530fa9e4066Sahrens /* Check for overflow */ 531fa9e4066Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 53299653d4eSeschrock if (hdl) 53399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 53499653d4eSeschrock "numeric value is too large")); 535fa9e4066Sahrens return (-1); 536fa9e4066Sahrens } 537fa9e4066Sahrens 538fa9e4066Sahrens *num <<= shift; 539fa9e4066Sahrens } 540fa9e4066Sahrens 541fa9e4066Sahrens return (0); 542fa9e4066Sahrens } 543fa9e4066Sahrens 544fa9e4066Sahrens int 545e9dbad6fSeschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 546fa9e4066Sahrens { 547e9dbad6fSeschrock return (nicestrtonum(hdl, str, val)); 548fa9e4066Sahrens } 549fa9e4066Sahrens 550fa9e4066Sahrens /* 551e9dbad6fSeschrock * The prop_parse_*() functions are designed to allow flexibility in callers 552e9dbad6fSeschrock * when setting properties. At the DSL layer, all properties are either 64-bit 553e9dbad6fSeschrock * numbers or strings. We want the user to be able to ignore this fact and 554e9dbad6fSeschrock * specify properties as native values (boolean, for example) or as strings (to 555e9dbad6fSeschrock * simplify command line utilities). This also handles converting index types 556e9dbad6fSeschrock * (compression, checksum, etc) from strings to their on-disk index. 557fa9e4066Sahrens */ 558fa9e4066Sahrens 559e9dbad6fSeschrock static int 560e9dbad6fSeschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 561e9dbad6fSeschrock { 562e9dbad6fSeschrock uint64_t ret; 56399653d4eSeschrock 564e9dbad6fSeschrock switch (nvpair_type(elem)) { 565e9dbad6fSeschrock case DATA_TYPE_STRING: 566e9dbad6fSeschrock { 567e9dbad6fSeschrock char *value; 568798d5834Sgw verify(nvpair_value_string(elem, &value) == 0); 569fa9e4066Sahrens 570e9dbad6fSeschrock if (strcmp(value, "on") == 0) { 571e9dbad6fSeschrock ret = 1; 572e9dbad6fSeschrock } else if (strcmp(value, "off") == 0) { 573e9dbad6fSeschrock ret = 0; 574e9dbad6fSeschrock } else { 575e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 576e9dbad6fSeschrock "property '%s' must be 'on' or 'off'"), 577e9dbad6fSeschrock nvpair_name(elem)); 578e9dbad6fSeschrock return (-1); 579e9dbad6fSeschrock } 580e9dbad6fSeschrock break; 581e9dbad6fSeschrock } 582fa9e4066Sahrens 583e9dbad6fSeschrock case DATA_TYPE_UINT64: 584e9dbad6fSeschrock { 585798d5834Sgw verify(nvpair_value_uint64(elem, &ret) == 0); 586e9dbad6fSeschrock if (ret > 1) { 587e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 588e9dbad6fSeschrock "'%s' must be a boolean value"), 589e9dbad6fSeschrock nvpair_name(elem)); 590e9dbad6fSeschrock return (-1); 591e9dbad6fSeschrock } 592e9dbad6fSeschrock break; 593fa9e4066Sahrens } 594fa9e4066Sahrens 595e9dbad6fSeschrock case DATA_TYPE_BOOLEAN_VALUE: 596e9dbad6fSeschrock { 597e9dbad6fSeschrock boolean_t value; 598798d5834Sgw verify(nvpair_value_boolean_value(elem, &value) == 0); 599e9dbad6fSeschrock ret = value; 600fa9e4066Sahrens break; 601fa9e4066Sahrens } 602fa9e4066Sahrens 603e9dbad6fSeschrock default: 604e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 605e9dbad6fSeschrock "'%s' must be a boolean value"), 606e9dbad6fSeschrock nvpair_name(elem)); 607e9dbad6fSeschrock return (-1); 608e9dbad6fSeschrock } 609fa9e4066Sahrens 610e9dbad6fSeschrock *val = ret; 611e9dbad6fSeschrock return (0); 612e9dbad6fSeschrock } 613fa9e4066Sahrens 614e9dbad6fSeschrock static int 615e9dbad6fSeschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 616e9dbad6fSeschrock uint64_t *val) 617e9dbad6fSeschrock { 618e9dbad6fSeschrock uint64_t ret; 619e9dbad6fSeschrock boolean_t isnone = B_FALSE; 620e9dbad6fSeschrock 621e9dbad6fSeschrock switch (nvpair_type(elem)) { 622e9dbad6fSeschrock case DATA_TYPE_STRING: 623e9dbad6fSeschrock { 624e9dbad6fSeschrock char *value; 625e9dbad6fSeschrock (void) nvpair_value_string(elem, &value); 626e9dbad6fSeschrock if (strcmp(value, "none") == 0) { 627e9dbad6fSeschrock isnone = B_TRUE; 628e9dbad6fSeschrock ret = 0; 629e9dbad6fSeschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 630e9dbad6fSeschrock return (-1); 631fa9e4066Sahrens } 632e9dbad6fSeschrock break; 633fa9e4066Sahrens } 634fa9e4066Sahrens 635e9dbad6fSeschrock case DATA_TYPE_UINT64: 636e9dbad6fSeschrock (void) nvpair_value_uint64(elem, &ret); 637fa9e4066Sahrens break; 638fa9e4066Sahrens 639e9dbad6fSeschrock default: 640e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 641e9dbad6fSeschrock "'%s' must be a number"), 642e9dbad6fSeschrock nvpair_name(elem)); 643e9dbad6fSeschrock return (-1); 644e9dbad6fSeschrock } 645e9dbad6fSeschrock 646e9dbad6fSeschrock /* 647e9dbad6fSeschrock * Quota special: force 'none' and don't allow 0. 648e9dbad6fSeschrock */ 649e9dbad6fSeschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 650e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 651e9dbad6fSeschrock "use 'none' to disable quota")); 652e9dbad6fSeschrock return (-1); 653e9dbad6fSeschrock } 654e9dbad6fSeschrock 655e9dbad6fSeschrock *val = ret; 656e9dbad6fSeschrock return (0); 657e9dbad6fSeschrock } 658e9dbad6fSeschrock 659e9dbad6fSeschrock static int 660e9dbad6fSeschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 661e9dbad6fSeschrock uint64_t *val) 662e9dbad6fSeschrock { 663e9dbad6fSeschrock char *propname = nvpair_name(elem); 664e9dbad6fSeschrock char *value; 665e9dbad6fSeschrock 666e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 667e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 668e9dbad6fSeschrock "'%s' must be a string"), propname); 669e9dbad6fSeschrock return (-1); 670e9dbad6fSeschrock } 671e9dbad6fSeschrock 672e9dbad6fSeschrock (void) nvpair_value_string(elem, &value); 673e9dbad6fSeschrock 674e9dbad6fSeschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 675e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 676e9dbad6fSeschrock "'%s' must be one of '%s'"), propname, 677e9dbad6fSeschrock zfs_prop_values(prop)); 678e9dbad6fSeschrock return (-1); 679e9dbad6fSeschrock } 680e9dbad6fSeschrock 681e9dbad6fSeschrock return (0); 682e9dbad6fSeschrock } 683e9dbad6fSeschrock 684b1b8ab34Slling /* 685b1b8ab34Slling * Check if the bootfs name has the same pool name as it is set to. 686b1b8ab34Slling * Assuming bootfs is a valid dataset name. 687b1b8ab34Slling */ 688b1b8ab34Slling static boolean_t 689b1b8ab34Slling bootfs_poolname_valid(char *pool, char *bootfs) 690b1b8ab34Slling { 691b1b8ab34Slling char ch, *pname; 692b1b8ab34Slling 693b1b8ab34Slling /* get the pool name from the bootfs name */ 694b1b8ab34Slling pname = bootfs; 695b1b8ab34Slling while (*bootfs && !isspace(*bootfs) && *bootfs != '/') 696b1b8ab34Slling bootfs++; 697b1b8ab34Slling 698b1b8ab34Slling ch = *bootfs; 699b1b8ab34Slling *bootfs = 0; 700b1b8ab34Slling 701b1b8ab34Slling if (strcmp(pool, pname) == 0) { 702b1b8ab34Slling *bootfs = ch; 703b1b8ab34Slling return (B_TRUE); 704b1b8ab34Slling } 705b1b8ab34Slling 706b1b8ab34Slling *bootfs = ch; 707b1b8ab34Slling return (B_FALSE); 708b1b8ab34Slling } 709b1b8ab34Slling 710e9dbad6fSeschrock /* 711e9dbad6fSeschrock * Given an nvlist of properties to set, validates that they are correct, and 712e9dbad6fSeschrock * parses any numeric properties (index, boolean, etc) if they are specified as 713e9dbad6fSeschrock * strings. 714e9dbad6fSeschrock */ 715b1b8ab34Slling nvlist_t * 716b1b8ab34Slling zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, 717b1b8ab34Slling nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 718e9dbad6fSeschrock { 719e9dbad6fSeschrock nvpair_t *elem; 720e9dbad6fSeschrock const char *propname; 721e9dbad6fSeschrock zfs_prop_t prop; 722e9dbad6fSeschrock uint64_t intval; 723e9dbad6fSeschrock char *strval; 724e9dbad6fSeschrock nvlist_t *ret; 725b1b8ab34Slling int isuser; 726e9dbad6fSeschrock 727e9dbad6fSeschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 728e9dbad6fSeschrock (void) no_memory(hdl); 729e9dbad6fSeschrock return (NULL); 730e9dbad6fSeschrock } 731e9dbad6fSeschrock 732e9dbad6fSeschrock if (type == ZFS_TYPE_SNAPSHOT) { 733e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 734d7d4af51Smmusante "snapshot properties cannot be modified")); 735e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 736e9dbad6fSeschrock goto error; 737e9dbad6fSeschrock } 738e9dbad6fSeschrock 739e9dbad6fSeschrock elem = NULL; 740e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 741e9dbad6fSeschrock propname = nvpair_name(elem); 742e9dbad6fSeschrock 743fa9e4066Sahrens /* 744e9dbad6fSeschrock * Make sure this property is valid and applies to this type. 745fa9e4066Sahrens */ 746b1b8ab34Slling if ((prop = zfs_name_to_prop_common(propname, type)) 747b1b8ab34Slling == ZFS_PROP_INVAL) { 748b1b8ab34Slling isuser = zfs_prop_user(propname); 749b1b8ab34Slling if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) { 75099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 751e9dbad6fSeschrock "invalid property '%s'"), 752e9dbad6fSeschrock propname); 753e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 754e9dbad6fSeschrock goto error; 755e9dbad6fSeschrock } else { 756e9dbad6fSeschrock /* 757e9dbad6fSeschrock * If this is a user property, make sure it's a 758e9dbad6fSeschrock * string, and that it's less than 759e9dbad6fSeschrock * ZAP_MAXNAMELEN. 760e9dbad6fSeschrock */ 761e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 762e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 763e9dbad6fSeschrock "'%s' must be a string"), 764e9dbad6fSeschrock propname); 765e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 766e9dbad6fSeschrock errbuf); 767e9dbad6fSeschrock goto error; 768e9dbad6fSeschrock } 769fa9e4066Sahrens 770e9dbad6fSeschrock if (strlen(nvpair_name(elem)) >= 771e9dbad6fSeschrock ZAP_MAXNAMELEN) { 772e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 773e9dbad6fSeschrock "property name '%s' is too long"), 774e9dbad6fSeschrock propname); 775e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 776e9dbad6fSeschrock errbuf); 777e9dbad6fSeschrock goto error; 778fa9e4066Sahrens } 779fa9e4066Sahrens } 780fa9e4066Sahrens 781e9dbad6fSeschrock (void) nvpair_value_string(elem, &strval); 782e9dbad6fSeschrock if (nvlist_add_string(ret, propname, strval) != 0) { 783e9dbad6fSeschrock (void) no_memory(hdl); 784e9dbad6fSeschrock goto error; 785e9dbad6fSeschrock } 786e9dbad6fSeschrock continue; 787e9dbad6fSeschrock } 788e9dbad6fSeschrock 789e9dbad6fSeschrock /* 790e9dbad6fSeschrock * Normalize the name, to get rid of shorthand abbrevations. 791e9dbad6fSeschrock */ 792e9dbad6fSeschrock propname = zfs_prop_to_name(prop); 793e9dbad6fSeschrock 794e9dbad6fSeschrock if (!zfs_prop_valid_for_type(prop, type)) { 795e9dbad6fSeschrock zfs_error_aux(hdl, 796e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "'%s' does not " 797e9dbad6fSeschrock "apply to datasets of this type"), propname); 798e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 799e9dbad6fSeschrock goto error; 800e9dbad6fSeschrock } 801e9dbad6fSeschrock 802e9dbad6fSeschrock if (zfs_prop_readonly(prop) && 803e9dbad6fSeschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 804e9dbad6fSeschrock zfs_error_aux(hdl, 805e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 806e9dbad6fSeschrock propname); 807e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 808e9dbad6fSeschrock goto error; 809e9dbad6fSeschrock } 810e9dbad6fSeschrock 811e9dbad6fSeschrock /* 812e9dbad6fSeschrock * Convert any properties to the internal DSL value types. 813e9dbad6fSeschrock */ 814e9dbad6fSeschrock strval = NULL; 815e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 816e9dbad6fSeschrock case prop_type_boolean: 817e9dbad6fSeschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 818e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 819e9dbad6fSeschrock goto error; 820e9dbad6fSeschrock } 821e9dbad6fSeschrock break; 822e9dbad6fSeschrock 823e9dbad6fSeschrock case prop_type_string: 824e9dbad6fSeschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 82599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 826e9dbad6fSeschrock "'%s' must be a string"), 827e9dbad6fSeschrock propname); 828e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 829e9dbad6fSeschrock goto error; 830e9dbad6fSeschrock } 831e9dbad6fSeschrock (void) nvpair_value_string(elem, &strval); 832e9dbad6fSeschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 833e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 834e9dbad6fSeschrock "'%s' is too long"), propname); 835e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 836e9dbad6fSeschrock goto error; 837fa9e4066Sahrens } 838fa9e4066Sahrens break; 839fa9e4066Sahrens 840e9dbad6fSeschrock case prop_type_number: 841e9dbad6fSeschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 842e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 843e9dbad6fSeschrock goto error; 844fa9e4066Sahrens } 845e9dbad6fSeschrock break; 846fa9e4066Sahrens 847e9dbad6fSeschrock case prop_type_index: 848e9dbad6fSeschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 849e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 850e9dbad6fSeschrock goto error; 851fa9e4066Sahrens } 852fa9e4066Sahrens break; 853fa9e4066Sahrens 854e9dbad6fSeschrock default: 855e9dbad6fSeschrock abort(); 856e9dbad6fSeschrock } 857e9dbad6fSeschrock 858e9dbad6fSeschrock /* 859e9dbad6fSeschrock * Add the result to our return set of properties. 860e9dbad6fSeschrock */ 861e9dbad6fSeschrock if (strval) { 862e9dbad6fSeschrock if (nvlist_add_string(ret, propname, strval) != 0) { 863e9dbad6fSeschrock (void) no_memory(hdl); 864e9dbad6fSeschrock goto error; 865fa9e4066Sahrens } 866e9dbad6fSeschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 867e9dbad6fSeschrock (void) no_memory(hdl); 868e9dbad6fSeschrock goto error; 869e9dbad6fSeschrock } 870fa9e4066Sahrens 871e9dbad6fSeschrock /* 872e9dbad6fSeschrock * Perform some additional checks for specific properties. 873e9dbad6fSeschrock */ 874e9dbad6fSeschrock switch (prop) { 875e9dbad6fSeschrock case ZFS_PROP_RECORDSIZE: 876e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 877e9dbad6fSeschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 878e9dbad6fSeschrock if (intval < SPA_MINBLOCKSIZE || 879e9dbad6fSeschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 88099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 881e9dbad6fSeschrock "'%s' must be power of 2 from %u " 882e9dbad6fSeschrock "to %uk"), propname, 883e9dbad6fSeschrock (uint_t)SPA_MINBLOCKSIZE, 884e9dbad6fSeschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 885e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 886e9dbad6fSeschrock goto error; 887fa9e4066Sahrens } 888fa9e4066Sahrens break; 889fa9e4066Sahrens 890f3861e1aSahl case ZFS_PROP_SHAREISCSI: 891f3861e1aSahl if (strcmp(strval, "off") != 0 && 892f3861e1aSahl strcmp(strval, "on") != 0 && 893f3861e1aSahl strcmp(strval, "type=disk") != 0) { 894f3861e1aSahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 895f3861e1aSahl "'%s' must be 'on', 'off', or 'type=disk'"), 896f3861e1aSahl propname); 897f3861e1aSahl (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 898f3861e1aSahl goto error; 899f3861e1aSahl } 900f3861e1aSahl 901f3861e1aSahl break; 902f3861e1aSahl 903e9dbad6fSeschrock case ZFS_PROP_MOUNTPOINT: 904e9dbad6fSeschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 905e9dbad6fSeschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 906e9dbad6fSeschrock break; 907fa9e4066Sahrens 908e9dbad6fSeschrock if (strval[0] != '/') { 90999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 910e9dbad6fSeschrock "'%s' must be an absolute path, " 911e9dbad6fSeschrock "'none', or 'legacy'"), propname); 912e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 913e9dbad6fSeschrock goto error; 914fa9e4066Sahrens } 915f3861e1aSahl /*FALLTHRU*/ 916fa9e4066Sahrens 917f3861e1aSahl case ZFS_PROP_SHARENFS: 918f3861e1aSahl /* 919f3861e1aSahl * For the mountpoint and sharenfs properties, check if 920f3861e1aSahl * it can be set in a global/non-global zone based on 921f3861e1aSahl * the zoned property value: 922f3861e1aSahl * 923f3861e1aSahl * global zone non-global zone 924f3861e1aSahl * -------------------------------------------------- 925f3861e1aSahl * zoned=on mountpoint (no) mountpoint (yes) 926f3861e1aSahl * sharenfs (no) sharenfs (no) 927f3861e1aSahl * 928f3861e1aSahl * zoned=off mountpoint (yes) N/A 929f3861e1aSahl * sharenfs (yes) 930f3861e1aSahl */ 931e9dbad6fSeschrock if (zoned) { 932e9dbad6fSeschrock if (getzoneid() == GLOBAL_ZONEID) { 933e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 934e9dbad6fSeschrock "'%s' cannot be set on " 935e9dbad6fSeschrock "dataset in a non-global zone"), 936e9dbad6fSeschrock propname); 937e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, 938e9dbad6fSeschrock errbuf); 939e9dbad6fSeschrock goto error; 940e9dbad6fSeschrock } else if (prop == ZFS_PROP_SHARENFS) { 941e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 942e9dbad6fSeschrock "'%s' cannot be set in " 943e9dbad6fSeschrock "a non-global zone"), propname); 944e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, 945e9dbad6fSeschrock errbuf); 946e9dbad6fSeschrock goto error; 947fa9e4066Sahrens } 948e9dbad6fSeschrock } else if (getzoneid() != GLOBAL_ZONEID) { 949e9dbad6fSeschrock /* 950e9dbad6fSeschrock * If zoned property is 'off', this must be in 951e9dbad6fSeschrock * a globle zone. If not, something is wrong. 952e9dbad6fSeschrock */ 953e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 954e9dbad6fSeschrock "'%s' cannot be set while dataset " 955e9dbad6fSeschrock "'zoned' property is set"), propname); 956e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 957e9dbad6fSeschrock goto error; 958fa9e4066Sahrens } 959f3861e1aSahl 960f3861e1aSahl break; 961b1b8ab34Slling 962b1b8ab34Slling case ZFS_PROP_BOOTFS: 963b1b8ab34Slling /* 964b1b8ab34Slling * bootfs property value has to be a dataset name and 965b1b8ab34Slling * the dataset has to be in the same pool as it sets to. 966b1b8ab34Slling */ 967b1b8ab34Slling if (strval[0] != '\0' && (!zfs_name_valid(strval, 968b1b8ab34Slling ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid( 969b1b8ab34Slling pool_name, strval))) { 970b1b8ab34Slling 971b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 972b1b8ab34Slling "is an invalid name"), strval); 973b1b8ab34Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 974b1b8ab34Slling goto error; 975b1b8ab34Slling } 976b1b8ab34Slling break; 977e9dbad6fSeschrock } 978fa9e4066Sahrens 979e9dbad6fSeschrock /* 980e9dbad6fSeschrock * For changes to existing volumes, we have some additional 981e9dbad6fSeschrock * checks to enforce. 982e9dbad6fSeschrock */ 983e9dbad6fSeschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 984e9dbad6fSeschrock uint64_t volsize = zfs_prop_get_int(zhp, 985e9dbad6fSeschrock ZFS_PROP_VOLSIZE); 986e9dbad6fSeschrock uint64_t blocksize = zfs_prop_get_int(zhp, 987e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 988e9dbad6fSeschrock char buf[64]; 989e9dbad6fSeschrock 990e9dbad6fSeschrock switch (prop) { 991e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 992e9dbad6fSeschrock if (intval > volsize) { 993e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 994e9dbad6fSeschrock "'%s' is greater than current " 995e9dbad6fSeschrock "volume size"), propname); 996e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 997e9dbad6fSeschrock errbuf); 998e9dbad6fSeschrock goto error; 999e9dbad6fSeschrock } 1000e9dbad6fSeschrock break; 1001e9dbad6fSeschrock 1002e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1003e9dbad6fSeschrock if (intval % blocksize != 0) { 1004e9dbad6fSeschrock zfs_nicenum(blocksize, buf, 1005e9dbad6fSeschrock sizeof (buf)); 1006e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1007e9dbad6fSeschrock "'%s' must be a multiple of " 1008e9dbad6fSeschrock "volume block size (%s)"), 1009e9dbad6fSeschrock propname, buf); 1010e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 1011e9dbad6fSeschrock errbuf); 1012e9dbad6fSeschrock goto error; 1013e9dbad6fSeschrock } 1014e9dbad6fSeschrock 1015e9dbad6fSeschrock if (intval == 0) { 1016e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1017e9dbad6fSeschrock "'%s' cannot be zero"), 1018e9dbad6fSeschrock propname); 1019e9dbad6fSeschrock (void) zfs_error(hdl, EZFS_BADPROP, 1020e9dbad6fSeschrock errbuf); 1021e9dbad6fSeschrock goto error; 1022e9dbad6fSeschrock } 1023f3861e1aSahl break; 1024fa9e4066Sahrens } 1025e9dbad6fSeschrock } 1026e9dbad6fSeschrock } 1027fa9e4066Sahrens 1028e9dbad6fSeschrock /* 1029e9dbad6fSeschrock * If this is an existing volume, and someone is setting the volsize, 1030e9dbad6fSeschrock * make sure that it matches the reservation, or add it if necessary. 1031e9dbad6fSeschrock */ 1032e9dbad6fSeschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 1033e9dbad6fSeschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1034e9dbad6fSeschrock &intval) == 0) { 1035e9dbad6fSeschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 1036e9dbad6fSeschrock ZFS_PROP_VOLSIZE); 1037e9dbad6fSeschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 1038e9dbad6fSeschrock ZFS_PROP_RESERVATION); 1039e9dbad6fSeschrock uint64_t new_reservation; 1040e9dbad6fSeschrock 1041e9dbad6fSeschrock if (old_volsize == old_reservation && 1042e9dbad6fSeschrock nvlist_lookup_uint64(ret, 1043e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 1044e9dbad6fSeschrock &new_reservation) != 0) { 1045e9dbad6fSeschrock if (nvlist_add_uint64(ret, 1046e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 1047e9dbad6fSeschrock intval) != 0) { 1048e9dbad6fSeschrock (void) no_memory(hdl); 1049e9dbad6fSeschrock goto error; 1050e9dbad6fSeschrock } 1051fa9e4066Sahrens } 1052fa9e4066Sahrens } 1053fa9e4066Sahrens 1054e9dbad6fSeschrock return (ret); 1055fa9e4066Sahrens 1056e9dbad6fSeschrock error: 1057e9dbad6fSeschrock nvlist_free(ret); 1058e9dbad6fSeschrock return (NULL); 1059fa9e4066Sahrens } 1060fa9e4066Sahrens 1061fa9e4066Sahrens /* 1062fa9e4066Sahrens * Given a property name and value, set the property for the given dataset. 1063fa9e4066Sahrens */ 1064fa9e4066Sahrens int 1065e9dbad6fSeschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1066fa9e4066Sahrens { 1067fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1068e9dbad6fSeschrock int ret = -1; 1069e9dbad6fSeschrock prop_changelist_t *cl = NULL; 107099653d4eSeschrock char errbuf[1024]; 107199653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 1072e9dbad6fSeschrock nvlist_t *nvl = NULL, *realprops; 1073e9dbad6fSeschrock zfs_prop_t prop; 107499653d4eSeschrock 107599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 1076e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 107799653d4eSeschrock zhp->zfs_name); 107899653d4eSeschrock 1079e9dbad6fSeschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1080e9dbad6fSeschrock nvlist_add_string(nvl, propname, propval) != 0) { 1081e9dbad6fSeschrock (void) no_memory(hdl); 1082e9dbad6fSeschrock goto error; 1083fa9e4066Sahrens } 1084fa9e4066Sahrens 1085b1b8ab34Slling if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl, 1086e9dbad6fSeschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1087e9dbad6fSeschrock goto error; 1088e9dbad6fSeschrock nvlist_free(nvl); 1089e9dbad6fSeschrock nvl = realprops; 1090e9dbad6fSeschrock 1091e9dbad6fSeschrock prop = zfs_name_to_prop(propname); 1092e9dbad6fSeschrock 1093fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1094e9dbad6fSeschrock goto error; 1095fa9e4066Sahrens 1096fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 109799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 109899653d4eSeschrock "child dataset with inherited mountpoint is used " 109999653d4eSeschrock "in a non-global zone")); 110099653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1101fa9e4066Sahrens goto error; 1102fa9e4066Sahrens } 1103fa9e4066Sahrens 1104fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 1105fa9e4066Sahrens goto error; 1106fa9e4066Sahrens 1107fa9e4066Sahrens /* 1108fa9e4066Sahrens * Execute the corresponding ioctl() to set this property. 1109fa9e4066Sahrens */ 1110fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1111fa9e4066Sahrens 1112e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 1113e9dbad6fSeschrock goto error; 1114e9dbad6fSeschrock 1115e9dbad6fSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1116fa9e4066Sahrens 1117fa9e4066Sahrens if (ret != 0) { 1118fa9e4066Sahrens switch (errno) { 1119fa9e4066Sahrens 1120fa9e4066Sahrens case ENOSPC: 1121fa9e4066Sahrens /* 1122fa9e4066Sahrens * For quotas and reservations, ENOSPC indicates 1123fa9e4066Sahrens * something different; setting a quota or reservation 1124fa9e4066Sahrens * doesn't use any disk space. 1125fa9e4066Sahrens */ 1126fa9e4066Sahrens switch (prop) { 1127fa9e4066Sahrens case ZFS_PROP_QUOTA: 112899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 112999653d4eSeschrock "size is less than current used or " 113099653d4eSeschrock "reserved space")); 113199653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1132fa9e4066Sahrens break; 1133fa9e4066Sahrens 1134fa9e4066Sahrens case ZFS_PROP_RESERVATION: 113599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 113699653d4eSeschrock "size is greater than available space")); 113799653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1138fa9e4066Sahrens break; 1139fa9e4066Sahrens 1140fa9e4066Sahrens default: 114199653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 1142fa9e4066Sahrens break; 1143fa9e4066Sahrens } 1144fa9e4066Sahrens break; 1145fa9e4066Sahrens 1146fa9e4066Sahrens case EBUSY: 114799653d4eSeschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 114899653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 114999653d4eSeschrock else 1150e9dbad6fSeschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1151fa9e4066Sahrens break; 1152fa9e4066Sahrens 11532a79c5feSlling case EROFS: 115499653d4eSeschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 11552a79c5feSlling break; 11562a79c5feSlling 1157c9431fa1Sahl case ENOTSUP: 1158c9431fa1Sahl zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1159c9431fa1Sahl "pool must be upgraded to allow gzip compression")); 1160c9431fa1Sahl (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1161c9431fa1Sahl break; 1162c9431fa1Sahl 1163fa9e4066Sahrens case EOVERFLOW: 1164fa9e4066Sahrens /* 1165fa9e4066Sahrens * This platform can't address a volume this big. 1166fa9e4066Sahrens */ 1167fa9e4066Sahrens #ifdef _ILP32 1168fa9e4066Sahrens if (prop == ZFS_PROP_VOLSIZE) { 116999653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1170fa9e4066Sahrens break; 1171fa9e4066Sahrens } 1172fa9e4066Sahrens #endif 117399653d4eSeschrock /* FALLTHROUGH */ 1174fa9e4066Sahrens default: 117599653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 1176fa9e4066Sahrens } 1177fa9e4066Sahrens } else { 1178fa9e4066Sahrens /* 1179fa9e4066Sahrens * Refresh the statistics so the new property value 1180fa9e4066Sahrens * is reflected. 1181fa9e4066Sahrens */ 1182e9dbad6fSeschrock if ((ret = changelist_postfix(cl)) == 0) 1183e9dbad6fSeschrock (void) get_stats(zhp); 1184fa9e4066Sahrens } 1185fa9e4066Sahrens 1186fa9e4066Sahrens error: 1187e9dbad6fSeschrock nvlist_free(nvl); 1188e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1189e9dbad6fSeschrock if (cl) 1190e9dbad6fSeschrock changelist_free(cl); 1191fa9e4066Sahrens return (ret); 1192fa9e4066Sahrens } 1193fa9e4066Sahrens 1194fa9e4066Sahrens /* 1195fa9e4066Sahrens * Given a property, inherit the value from the parent dataset. 1196fa9e4066Sahrens */ 1197fa9e4066Sahrens int 1198e9dbad6fSeschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1199fa9e4066Sahrens { 1200fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1201fa9e4066Sahrens int ret; 1202fa9e4066Sahrens prop_changelist_t *cl; 120399653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 120499653d4eSeschrock char errbuf[1024]; 1205e9dbad6fSeschrock zfs_prop_t prop; 120699653d4eSeschrock 120799653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 120899653d4eSeschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1209fa9e4066Sahrens 1210e9dbad6fSeschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 1211e9dbad6fSeschrock /* 1212e9dbad6fSeschrock * For user properties, the amount of work we have to do is very 1213e9dbad6fSeschrock * small, so just do it here. 1214e9dbad6fSeschrock */ 1215e9dbad6fSeschrock if (!zfs_prop_user(propname)) { 1216e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1217e9dbad6fSeschrock "invalid property")); 1218e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1219e9dbad6fSeschrock } 1220e9dbad6fSeschrock 1221e9dbad6fSeschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1222e9dbad6fSeschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1223e9dbad6fSeschrock 1224e9dbad6fSeschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 1225e9dbad6fSeschrock ZFS_IOC_SET_PROP, &zc) != 0) 1226e9dbad6fSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1227e9dbad6fSeschrock 1228e9dbad6fSeschrock return (0); 1229e9dbad6fSeschrock } 1230e9dbad6fSeschrock 1231fa9e4066Sahrens /* 1232fa9e4066Sahrens * Verify that this property is inheritable. 1233fa9e4066Sahrens */ 123499653d4eSeschrock if (zfs_prop_readonly(prop)) 123599653d4eSeschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 1236fa9e4066Sahrens 123799653d4eSeschrock if (!zfs_prop_inheritable(prop)) 123899653d4eSeschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1239fa9e4066Sahrens 1240fa9e4066Sahrens /* 1241fa9e4066Sahrens * Check to see if the value applies to this type 1242fa9e4066Sahrens */ 124399653d4eSeschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 124499653d4eSeschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1245fa9e4066Sahrens 1246bf7c2d40Srm /* 1247bf7c2d40Srm * Normalize the name, to get rid of shorthand abbrevations. 1248bf7c2d40Srm */ 1249bf7c2d40Srm propname = zfs_prop_to_name(prop); 1250fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1251e9dbad6fSeschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1252fa9e4066Sahrens 1253fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1254fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 125599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 125699653d4eSeschrock "dataset is used in a non-global zone")); 125799653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1258fa9e4066Sahrens } 1259fa9e4066Sahrens 1260fa9e4066Sahrens /* 1261fa9e4066Sahrens * Determine datasets which will be affected by this change, if any. 1262fa9e4066Sahrens */ 1263fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1264fa9e4066Sahrens return (-1); 1265fa9e4066Sahrens 1266fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 126799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 126899653d4eSeschrock "child dataset with inherited mountpoint is used " 126999653d4eSeschrock "in a non-global zone")); 127099653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1271fa9e4066Sahrens goto error; 1272fa9e4066Sahrens } 1273fa9e4066Sahrens 1274fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 1275fa9e4066Sahrens goto error; 1276fa9e4066Sahrens 127799653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 127899653d4eSeschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 127999653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1280fa9e4066Sahrens } else { 1281fa9e4066Sahrens 1282efc555ebSnd if ((ret = changelist_postfix(cl)) != 0) 1283fa9e4066Sahrens goto error; 1284fa9e4066Sahrens 1285fa9e4066Sahrens /* 1286fa9e4066Sahrens * Refresh the statistics so the new property is reflected. 1287fa9e4066Sahrens */ 1288fa9e4066Sahrens (void) get_stats(zhp); 1289fa9e4066Sahrens } 1290fa9e4066Sahrens 1291fa9e4066Sahrens error: 1292fa9e4066Sahrens changelist_free(cl); 1293fa9e4066Sahrens return (ret); 1294fa9e4066Sahrens } 1295fa9e4066Sahrens 1296b1b8ab34Slling void 1297fa9e4066Sahrens nicebool(int value, char *buf, size_t buflen) 1298fa9e4066Sahrens { 1299fa9e4066Sahrens if (value) 1300fa9e4066Sahrens (void) strlcpy(buf, "on", buflen); 1301fa9e4066Sahrens else 1302fa9e4066Sahrens (void) strlcpy(buf, "off", buflen); 1303fa9e4066Sahrens } 1304fa9e4066Sahrens 13057f7322feSeschrock /* 13067f7322feSeschrock * True DSL properties are stored in an nvlist. The following two functions 13077f7322feSeschrock * extract them appropriately. 13087f7322feSeschrock */ 13097f7322feSeschrock static uint64_t 13107f7322feSeschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13117f7322feSeschrock { 13127f7322feSeschrock nvlist_t *nv; 13137f7322feSeschrock uint64_t value; 13147f7322feSeschrock 1315a2eea2e1Sahrens *source = NULL; 13167f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13177f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 13187f7322feSeschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 1319a2eea2e1Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13207f7322feSeschrock } else { 13217f7322feSeschrock value = zfs_prop_default_numeric(prop); 13227f7322feSeschrock *source = ""; 13237f7322feSeschrock } 13247f7322feSeschrock 13257f7322feSeschrock return (value); 13267f7322feSeschrock } 13277f7322feSeschrock 13287f7322feSeschrock static char * 13297f7322feSeschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 13307f7322feSeschrock { 13317f7322feSeschrock nvlist_t *nv; 13327f7322feSeschrock char *value; 13337f7322feSeschrock 1334a2eea2e1Sahrens *source = NULL; 13357f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 13367f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 13377f7322feSeschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 1338a2eea2e1Sahrens (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); 13397f7322feSeschrock } else { 13407f7322feSeschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 13417f7322feSeschrock value = ""; 13427f7322feSeschrock *source = ""; 13437f7322feSeschrock } 13447f7322feSeschrock 13457f7322feSeschrock return (value); 13467f7322feSeschrock } 13477f7322feSeschrock 1348fa9e4066Sahrens /* 1349fa9e4066Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1350fa9e4066Sahrens * zfs_prop_get_int() are built using this interface. 1351fa9e4066Sahrens * 1352fa9e4066Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1353fa9e4066Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1354fa9e4066Sahrens * If they differ from the on-disk values, report the current values and mark 1355fa9e4066Sahrens * the source "temporary". 1356fa9e4066Sahrens */ 135799653d4eSeschrock static int 1358fa9e4066Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 135999653d4eSeschrock char **source, uint64_t *val) 1360fa9e4066Sahrens { 1361fa9e4066Sahrens struct mnttab mnt; 13623ccfa83cSahrens char *mntopt_on = NULL; 13633ccfa83cSahrens char *mntopt_off = NULL; 1364fa9e4066Sahrens 1365fa9e4066Sahrens *source = NULL; 1366fa9e4066Sahrens 13673ccfa83cSahrens switch (prop) { 13683ccfa83cSahrens case ZFS_PROP_ATIME: 13693ccfa83cSahrens mntopt_on = MNTOPT_ATIME; 13703ccfa83cSahrens mntopt_off = MNTOPT_NOATIME; 13713ccfa83cSahrens break; 13723ccfa83cSahrens 13733ccfa83cSahrens case ZFS_PROP_DEVICES: 13743ccfa83cSahrens mntopt_on = MNTOPT_DEVICES; 13753ccfa83cSahrens mntopt_off = MNTOPT_NODEVICES; 13763ccfa83cSahrens break; 13773ccfa83cSahrens 13783ccfa83cSahrens case ZFS_PROP_EXEC: 13793ccfa83cSahrens mntopt_on = MNTOPT_EXEC; 13803ccfa83cSahrens mntopt_off = MNTOPT_NOEXEC; 13813ccfa83cSahrens break; 13823ccfa83cSahrens 13833ccfa83cSahrens case ZFS_PROP_READONLY: 13843ccfa83cSahrens mntopt_on = MNTOPT_RO; 13853ccfa83cSahrens mntopt_off = MNTOPT_RW; 13863ccfa83cSahrens break; 13873ccfa83cSahrens 13883ccfa83cSahrens case ZFS_PROP_SETUID: 13893ccfa83cSahrens mntopt_on = MNTOPT_SETUID; 13903ccfa83cSahrens mntopt_off = MNTOPT_NOSETUID; 13913ccfa83cSahrens break; 13923ccfa83cSahrens 13933ccfa83cSahrens case ZFS_PROP_XATTR: 13943ccfa83cSahrens mntopt_on = MNTOPT_XATTR; 13953ccfa83cSahrens mntopt_off = MNTOPT_NOXATTR; 13963ccfa83cSahrens break; 13973ccfa83cSahrens } 13983ccfa83cSahrens 13993bb79becSeschrock /* 14003bb79becSeschrock * Because looking up the mount options is potentially expensive 14013bb79becSeschrock * (iterating over all of /etc/mnttab), we defer its calculation until 14023bb79becSeschrock * we're looking up a property which requires its presence. 14033bb79becSeschrock */ 14043bb79becSeschrock if (!zhp->zfs_mntcheck && 14053ccfa83cSahrens (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { 14063ccfa83cSahrens struct mnttab entry, search = { 0 }; 14073ccfa83cSahrens FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab; 14083bb79becSeschrock 14093bb79becSeschrock search.mnt_special = (char *)zhp->zfs_name; 14103bb79becSeschrock search.mnt_fstype = MNTTYPE_ZFS; 14113ccfa83cSahrens rewind(mnttab); 14123bb79becSeschrock 14133ccfa83cSahrens if (getmntany(mnttab, &entry, &search) == 0) { 14143ccfa83cSahrens zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl, 14153ccfa83cSahrens entry.mnt_mntopts); 14163ccfa83cSahrens if (zhp->zfs_mntopts == NULL) 14173ccfa83cSahrens return (-1); 14183ccfa83cSahrens } 14193bb79becSeschrock 14203bb79becSeschrock zhp->zfs_mntcheck = B_TRUE; 14213bb79becSeschrock } 14223bb79becSeschrock 1423fa9e4066Sahrens if (zhp->zfs_mntopts == NULL) 1424fa9e4066Sahrens mnt.mnt_mntopts = ""; 1425fa9e4066Sahrens else 1426fa9e4066Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1427fa9e4066Sahrens 1428fa9e4066Sahrens switch (prop) { 1429fa9e4066Sahrens case ZFS_PROP_ATIME: 1430fa9e4066Sahrens case ZFS_PROP_DEVICES: 1431fa9e4066Sahrens case ZFS_PROP_EXEC: 14323ccfa83cSahrens case ZFS_PROP_READONLY: 14333ccfa83cSahrens case ZFS_PROP_SETUID: 14343ccfa83cSahrens case ZFS_PROP_XATTR: 143599653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1436fa9e4066Sahrens 14373ccfa83cSahrens if (hasmntopt(&mnt, mntopt_on) && !*val) { 143899653d4eSeschrock *val = B_TRUE; 1439fa9e4066Sahrens if (src) 1440fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 14413ccfa83cSahrens } else if (hasmntopt(&mnt, mntopt_off) && *val) { 144299653d4eSeschrock *val = B_FALSE; 1443fa9e4066Sahrens if (src) 1444fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1445fa9e4066Sahrens } 144699653d4eSeschrock break; 1447fa9e4066Sahrens 1448fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1449fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 14507f7322feSeschrock case ZFS_PROP_ZONED: 1451a2eea2e1Sahrens case ZFS_PROP_CREATION: 1452a2eea2e1Sahrens case ZFS_PROP_COMPRESSRATIO: 1453a2eea2e1Sahrens case ZFS_PROP_REFERENCED: 1454a2eea2e1Sahrens case ZFS_PROP_USED: 1455a2eea2e1Sahrens case ZFS_PROP_CREATETXG: 1456a2eea2e1Sahrens case ZFS_PROP_AVAILABLE: 1457a2eea2e1Sahrens case ZFS_PROP_VOLSIZE: 1458a2eea2e1Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1459fda77a98Srm *val = getprop_uint64(zhp, prop, source); 1460fda77a98Srm break; 1461fda77a98Srm 14623ccfa83cSahrens case ZFS_PROP_CANMOUNT: 146399653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1464fda77a98Srm if (*val == 0) 1465fda77a98Srm *source = zhp->zfs_name; 1466fda77a98Srm else 1467fda77a98Srm *source = ""; /* default */ 146899653d4eSeschrock break; 1469fa9e4066Sahrens 1470fa9e4066Sahrens case ZFS_PROP_QUOTA: 1471fa9e4066Sahrens case ZFS_PROP_RESERVATION: 1472a2eea2e1Sahrens *val = getprop_uint64(zhp, prop, source); 1473a2eea2e1Sahrens if (*val == 0) 1474fa9e4066Sahrens *source = ""; /* default */ 1475fa9e4066Sahrens else 1476fa9e4066Sahrens *source = zhp->zfs_name; 147799653d4eSeschrock break; 1478fa9e4066Sahrens 1479fa9e4066Sahrens case ZFS_PROP_MOUNTED: 148099653d4eSeschrock *val = (zhp->zfs_mntopts != NULL); 148199653d4eSeschrock break; 1482fa9e4066Sahrens 148339c23413Seschrock case ZFS_PROP_NUMCLONES: 148439c23413Seschrock *val = zhp->zfs_dmustats.dds_num_clones; 148539c23413Seschrock break; 148639c23413Seschrock 1487fa9e4066Sahrens default: 148899653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 148999653d4eSeschrock "cannot get non-numeric property")); 149099653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 149199653d4eSeschrock dgettext(TEXT_DOMAIN, "internal error"))); 1492fa9e4066Sahrens } 1493fa9e4066Sahrens 1494fa9e4066Sahrens return (0); 1495fa9e4066Sahrens } 1496fa9e4066Sahrens 1497fa9e4066Sahrens /* 1498fa9e4066Sahrens * Calculate the source type, given the raw source string. 1499fa9e4066Sahrens */ 1500fa9e4066Sahrens static void 1501fa9e4066Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1502fa9e4066Sahrens char *statbuf, size_t statlen) 1503fa9e4066Sahrens { 1504fa9e4066Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1505fa9e4066Sahrens return; 1506fa9e4066Sahrens 1507fa9e4066Sahrens if (source == NULL) { 1508fa9e4066Sahrens *srctype = ZFS_SRC_NONE; 1509fa9e4066Sahrens } else if (source[0] == '\0') { 1510fa9e4066Sahrens *srctype = ZFS_SRC_DEFAULT; 1511fa9e4066Sahrens } else { 1512fa9e4066Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1513fa9e4066Sahrens *srctype = ZFS_SRC_LOCAL; 1514fa9e4066Sahrens } else { 1515fa9e4066Sahrens (void) strlcpy(statbuf, source, statlen); 1516fa9e4066Sahrens *srctype = ZFS_SRC_INHERITED; 1517fa9e4066Sahrens } 1518fa9e4066Sahrens } 1519fa9e4066Sahrens 1520fa9e4066Sahrens } 1521fa9e4066Sahrens 1522fa9e4066Sahrens /* 1523fa9e4066Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1524fa9e4066Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1525fa9e4066Sahrens * human-readable form. 1526fa9e4066Sahrens * 1527fa9e4066Sahrens * Returns 0 on success, or -1 on error. 1528fa9e4066Sahrens */ 1529fa9e4066Sahrens int 1530fa9e4066Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 153199653d4eSeschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1532fa9e4066Sahrens { 1533fa9e4066Sahrens char *source = NULL; 1534fa9e4066Sahrens uint64_t val; 1535fa9e4066Sahrens char *str; 1536fa9e4066Sahrens const char *root; 1537e9dbad6fSeschrock const char *strval; 1538fa9e4066Sahrens 1539fa9e4066Sahrens /* 1540fa9e4066Sahrens * Check to see if this property applies to our object 1541fa9e4066Sahrens */ 1542fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1543fa9e4066Sahrens return (-1); 1544fa9e4066Sahrens 1545fa9e4066Sahrens if (src) 1546fa9e4066Sahrens *src = ZFS_SRC_NONE; 1547fa9e4066Sahrens 1548fa9e4066Sahrens switch (prop) { 1549fa9e4066Sahrens case ZFS_PROP_ATIME: 1550fa9e4066Sahrens case ZFS_PROP_READONLY: 1551fa9e4066Sahrens case ZFS_PROP_SETUID: 1552fa9e4066Sahrens case ZFS_PROP_ZONED: 1553fa9e4066Sahrens case ZFS_PROP_DEVICES: 1554fa9e4066Sahrens case ZFS_PROP_EXEC: 1555e9dbad6fSeschrock case ZFS_PROP_CANMOUNT: 15567b55fa8eSck case ZFS_PROP_XATTR: 1557fa9e4066Sahrens /* 1558fa9e4066Sahrens * Basic boolean values are built on top of 1559fa9e4066Sahrens * get_numeric_property(). 1560fa9e4066Sahrens */ 156199653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 156299653d4eSeschrock return (-1); 156399653d4eSeschrock nicebool(val, propbuf, proplen); 1564fa9e4066Sahrens 1565fa9e4066Sahrens break; 1566fa9e4066Sahrens 1567fa9e4066Sahrens case ZFS_PROP_AVAILABLE: 1568fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1569fa9e4066Sahrens case ZFS_PROP_CREATETXG: 1570fa9e4066Sahrens case ZFS_PROP_REFERENCED: 1571fa9e4066Sahrens case ZFS_PROP_USED: 1572fa9e4066Sahrens case ZFS_PROP_VOLSIZE: 1573fa9e4066Sahrens case ZFS_PROP_VOLBLOCKSIZE: 157439c23413Seschrock case ZFS_PROP_NUMCLONES: 1575fa9e4066Sahrens /* 1576fa9e4066Sahrens * Basic numeric values are built on top of 1577fa9e4066Sahrens * get_numeric_property(). 1578fa9e4066Sahrens */ 157999653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 158099653d4eSeschrock return (-1); 1581fa9e4066Sahrens if (literal) 15825ad82045Snd (void) snprintf(propbuf, proplen, "%llu", 1583b1b8ab34Slling (u_longlong_t)val); 1584fa9e4066Sahrens else 1585fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1586fa9e4066Sahrens break; 1587fa9e4066Sahrens 1588fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 1589fa9e4066Sahrens case ZFS_PROP_CHECKSUM: 1590fa9e4066Sahrens case ZFS_PROP_SNAPDIR: 1591fa9e4066Sahrens case ZFS_PROP_ACLMODE: 1592fa9e4066Sahrens case ZFS_PROP_ACLINHERIT: 1593d0ad202dSahrens case ZFS_PROP_COPIES: 15947f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1595e9dbad6fSeschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 1596e9dbad6fSeschrock (void) strlcpy(propbuf, strval, proplen); 1597fa9e4066Sahrens break; 1598fa9e4066Sahrens 1599fa9e4066Sahrens case ZFS_PROP_CREATION: 1600fa9e4066Sahrens /* 1601fa9e4066Sahrens * 'creation' is a time_t stored in the statistics. We convert 1602fa9e4066Sahrens * this into a string unless 'literal' is specified. 1603fa9e4066Sahrens */ 1604fa9e4066Sahrens { 1605a2eea2e1Sahrens val = getprop_uint64(zhp, prop, &source); 1606a2eea2e1Sahrens time_t time = (time_t)val; 1607fa9e4066Sahrens struct tm t; 1608fa9e4066Sahrens 1609fa9e4066Sahrens if (literal || 1610fa9e4066Sahrens localtime_r(&time, &t) == NULL || 1611fa9e4066Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1612fa9e4066Sahrens &t) == 0) 1613a2eea2e1Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1614fa9e4066Sahrens } 1615fa9e4066Sahrens break; 1616fa9e4066Sahrens 1617fa9e4066Sahrens case ZFS_PROP_MOUNTPOINT: 1618fa9e4066Sahrens /* 1619fa9e4066Sahrens * Getting the precise mountpoint can be tricky. 1620fa9e4066Sahrens * 1621fa9e4066Sahrens * - for 'none' or 'legacy', return those values. 1622fa9e4066Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1623fa9e4066Sahrens * - for inherited mountpoints, we want to take everything 1624fa9e4066Sahrens * after our ancestor and append it to the inherited value. 1625fa9e4066Sahrens * 1626fa9e4066Sahrens * If the pool has an alternate root, we want to prepend that 1627fa9e4066Sahrens * root to any values we return. 1628fa9e4066Sahrens */ 1629ea8dc4b6Seschrock root = zhp->zfs_root; 16307f7322feSeschrock str = getprop_string(zhp, prop, &source); 1631fa9e4066Sahrens 16327f7322feSeschrock if (str[0] == '\0') { 1633fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1634fa9e4066Sahrens root, zhp->zfs_name); 16357f7322feSeschrock } else if (str[0] == '/') { 16367f7322feSeschrock const char *relpath = zhp->zfs_name + strlen(source); 1637fa9e4066Sahrens 1638fa9e4066Sahrens if (relpath[0] == '/') 1639fa9e4066Sahrens relpath++; 16407f7322feSeschrock if (str[1] == '\0') 16417f7322feSeschrock str++; 1642fa9e4066Sahrens 1643fa9e4066Sahrens if (relpath[0] == '\0') 1644fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s", 16457f7322feSeschrock root, str); 1646fa9e4066Sahrens else 1647fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16487f7322feSeschrock root, str, relpath[0] == '@' ? "" : "/", 1649fa9e4066Sahrens relpath); 1650fa9e4066Sahrens } else { 1651fa9e4066Sahrens /* 'legacy' or 'none' */ 16527f7322feSeschrock (void) strlcpy(propbuf, str, proplen); 1653fa9e4066Sahrens } 1654fa9e4066Sahrens 1655fa9e4066Sahrens break; 1656fa9e4066Sahrens 1657fa9e4066Sahrens case ZFS_PROP_SHARENFS: 1658f3861e1aSahl case ZFS_PROP_SHAREISCSI: 1659f3861e1aSahl case ZFS_PROP_ISCSIOPTIONS: 16607f7322feSeschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16617f7322feSeschrock proplen); 1662fa9e4066Sahrens break; 1663fa9e4066Sahrens 1664fa9e4066Sahrens case ZFS_PROP_ORIGIN: 1665a2eea2e1Sahrens (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1666fa9e4066Sahrens proplen); 1667fa9e4066Sahrens /* 1668fa9e4066Sahrens * If there is no parent at all, return failure to indicate that 1669fa9e4066Sahrens * it doesn't apply to this dataset. 1670fa9e4066Sahrens */ 1671fa9e4066Sahrens if (propbuf[0] == '\0') 1672fa9e4066Sahrens return (-1); 1673fa9e4066Sahrens break; 1674fa9e4066Sahrens 1675fa9e4066Sahrens case ZFS_PROP_QUOTA: 1676fa9e4066Sahrens case ZFS_PROP_RESERVATION: 167799653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 167899653d4eSeschrock return (-1); 1679fa9e4066Sahrens 1680fa9e4066Sahrens /* 1681fa9e4066Sahrens * If quota or reservation is 0, we translate this into 'none' 1682fa9e4066Sahrens * (unless literal is set), and indicate that it's the default 1683fa9e4066Sahrens * value. Otherwise, we print the number nicely and indicate 1684fa9e4066Sahrens * that its set locally. 1685fa9e4066Sahrens */ 1686fa9e4066Sahrens if (val == 0) { 1687fa9e4066Sahrens if (literal) 1688fa9e4066Sahrens (void) strlcpy(propbuf, "0", proplen); 1689fa9e4066Sahrens else 1690fa9e4066Sahrens (void) strlcpy(propbuf, "none", proplen); 1691fa9e4066Sahrens } else { 1692fa9e4066Sahrens if (literal) 16935ad82045Snd (void) snprintf(propbuf, proplen, "%llu", 1694b1b8ab34Slling (u_longlong_t)val); 1695fa9e4066Sahrens else 1696fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1697fa9e4066Sahrens } 1698fa9e4066Sahrens break; 1699fa9e4066Sahrens 1700fa9e4066Sahrens case ZFS_PROP_COMPRESSRATIO: 170199653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 170299653d4eSeschrock return (-1); 17035ad82045Snd (void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t) 17045ad82045Snd val / 100, (longlong_t)val % 100); 1705fa9e4066Sahrens break; 1706fa9e4066Sahrens 1707fa9e4066Sahrens case ZFS_PROP_TYPE: 1708fa9e4066Sahrens switch (zhp->zfs_type) { 1709fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 1710fa9e4066Sahrens str = "filesystem"; 1711fa9e4066Sahrens break; 1712fa9e4066Sahrens case ZFS_TYPE_VOLUME: 1713fa9e4066Sahrens str = "volume"; 1714fa9e4066Sahrens break; 1715fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 1716fa9e4066Sahrens str = "snapshot"; 1717fa9e4066Sahrens break; 1718fa9e4066Sahrens default: 171999653d4eSeschrock abort(); 1720fa9e4066Sahrens } 1721fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1722fa9e4066Sahrens break; 1723fa9e4066Sahrens 1724fa9e4066Sahrens case ZFS_PROP_MOUNTED: 1725fa9e4066Sahrens /* 1726fa9e4066Sahrens * The 'mounted' property is a pseudo-property that described 1727fa9e4066Sahrens * whether the filesystem is currently mounted. Even though 1728fa9e4066Sahrens * it's a boolean value, the typical values of "on" and "off" 1729fa9e4066Sahrens * don't make sense, so we translate to "yes" and "no". 1730fa9e4066Sahrens */ 173199653d4eSeschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 173299653d4eSeschrock src, &source, &val) != 0) 173399653d4eSeschrock return (-1); 173499653d4eSeschrock if (val) 1735fa9e4066Sahrens (void) strlcpy(propbuf, "yes", proplen); 1736fa9e4066Sahrens else 1737fa9e4066Sahrens (void) strlcpy(propbuf, "no", proplen); 1738fa9e4066Sahrens break; 1739fa9e4066Sahrens 1740fa9e4066Sahrens case ZFS_PROP_NAME: 1741fa9e4066Sahrens /* 1742fa9e4066Sahrens * The 'name' property is a pseudo-property derived from the 1743fa9e4066Sahrens * dataset name. It is presented as a real property to simplify 1744fa9e4066Sahrens * consumers. 1745fa9e4066Sahrens */ 1746fa9e4066Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1747fa9e4066Sahrens break; 1748fa9e4066Sahrens 1749fa9e4066Sahrens default: 175099653d4eSeschrock abort(); 1751fa9e4066Sahrens } 1752fa9e4066Sahrens 1753fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1754fa9e4066Sahrens 1755fa9e4066Sahrens return (0); 1756fa9e4066Sahrens } 1757fa9e4066Sahrens 1758fa9e4066Sahrens /* 1759fa9e4066Sahrens * Utility function to get the given numeric property. Does no validation that 1760fa9e4066Sahrens * the given property is the appropriate type; should only be used with 1761fa9e4066Sahrens * hard-coded property types. 1762fa9e4066Sahrens */ 1763fa9e4066Sahrens uint64_t 1764fa9e4066Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1765fa9e4066Sahrens { 1766fa9e4066Sahrens char *source; 1767fa9e4066Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 176899653d4eSeschrock uint64_t val; 176999653d4eSeschrock 177099653d4eSeschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 1771fa9e4066Sahrens 177299653d4eSeschrock return (val); 1773fa9e4066Sahrens } 1774fa9e4066Sahrens 1775fa9e4066Sahrens /* 1776fa9e4066Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1777fa9e4066Sahrens */ 1778fa9e4066Sahrens int 1779fa9e4066Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1780fa9e4066Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1781fa9e4066Sahrens { 1782fa9e4066Sahrens char *source; 1783fa9e4066Sahrens 1784fa9e4066Sahrens /* 1785fa9e4066Sahrens * Check to see if this property applies to our object 1786fa9e4066Sahrens */ 1787fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1788ece3d9b3Slling return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 178999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 179099653d4eSeschrock zfs_prop_to_name(prop))); 1791fa9e4066Sahrens 1792fa9e4066Sahrens if (src) 1793fa9e4066Sahrens *src = ZFS_SRC_NONE; 1794fa9e4066Sahrens 179599653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 179699653d4eSeschrock return (-1); 1797fa9e4066Sahrens 1798fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1799fa9e4066Sahrens 1800fa9e4066Sahrens return (0); 1801fa9e4066Sahrens } 1802fa9e4066Sahrens 1803fa9e4066Sahrens /* 1804fa9e4066Sahrens * Returns the name of the given zfs handle. 1805fa9e4066Sahrens */ 1806fa9e4066Sahrens const char * 1807fa9e4066Sahrens zfs_get_name(const zfs_handle_t *zhp) 1808fa9e4066Sahrens { 1809fa9e4066Sahrens return (zhp->zfs_name); 1810fa9e4066Sahrens } 1811fa9e4066Sahrens 1812fa9e4066Sahrens /* 1813fa9e4066Sahrens * Returns the type of the given zfs handle. 1814fa9e4066Sahrens */ 1815fa9e4066Sahrens zfs_type_t 1816fa9e4066Sahrens zfs_get_type(const zfs_handle_t *zhp) 1817fa9e4066Sahrens { 1818fa9e4066Sahrens return (zhp->zfs_type); 1819fa9e4066Sahrens } 1820fa9e4066Sahrens 1821fa9e4066Sahrens /* 18227f7322feSeschrock * Iterate over all child filesystems 1823fa9e4066Sahrens */ 1824fa9e4066Sahrens int 18257f7322feSeschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1826fa9e4066Sahrens { 1827fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1828fa9e4066Sahrens zfs_handle_t *nzhp; 1829fa9e4066Sahrens int ret; 1830fa9e4066Sahrens 1831fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 183299653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1833fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1834fa9e4066Sahrens /* 1835fa9e4066Sahrens * Ignore private dataset names. 1836fa9e4066Sahrens */ 1837fa9e4066Sahrens if (dataset_name_hidden(zc.zc_name)) 1838fa9e4066Sahrens continue; 1839fa9e4066Sahrens 1840fa9e4066Sahrens /* 1841fa9e4066Sahrens * Silently ignore errors, as the only plausible explanation is 1842fa9e4066Sahrens * that the pool has since been removed. 1843fa9e4066Sahrens */ 184499653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 184599653d4eSeschrock zc.zc_name)) == NULL) 1846fa9e4066Sahrens continue; 1847fa9e4066Sahrens 1848fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1849fa9e4066Sahrens return (ret); 1850fa9e4066Sahrens } 1851fa9e4066Sahrens 1852fa9e4066Sahrens /* 1853fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1854fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1855fa9e4066Sahrens * obtained the handle. 1856fa9e4066Sahrens */ 1857fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 185899653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 185999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1860fa9e4066Sahrens 18617f7322feSeschrock return (0); 18627f7322feSeschrock } 18637f7322feSeschrock 18647f7322feSeschrock /* 18657f7322feSeschrock * Iterate over all snapshots 18667f7322feSeschrock */ 18677f7322feSeschrock int 18687f7322feSeschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18697f7322feSeschrock { 18707f7322feSeschrock zfs_cmd_t zc = { 0 }; 18717f7322feSeschrock zfs_handle_t *nzhp; 18727f7322feSeschrock int ret; 1873fa9e4066Sahrens 1874fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 187599653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 187699653d4eSeschrock &zc) == 0; 1877fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1878fa9e4066Sahrens 187999653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 188099653d4eSeschrock zc.zc_name)) == NULL) 1881fa9e4066Sahrens continue; 1882fa9e4066Sahrens 1883fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1884fa9e4066Sahrens return (ret); 1885fa9e4066Sahrens } 1886fa9e4066Sahrens 1887fa9e4066Sahrens /* 1888fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1889fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1890fa9e4066Sahrens * obtained the handle. Silently ignore this case, and return success. 1891fa9e4066Sahrens */ 1892fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 189399653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 189499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1895fa9e4066Sahrens 1896fa9e4066Sahrens return (0); 1897fa9e4066Sahrens } 1898fa9e4066Sahrens 18997f7322feSeschrock /* 19007f7322feSeschrock * Iterate over all children, snapshots and filesystems 19017f7322feSeschrock */ 19027f7322feSeschrock int 19037f7322feSeschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 19047f7322feSeschrock { 19057f7322feSeschrock int ret; 19067f7322feSeschrock 19077f7322feSeschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 19087f7322feSeschrock return (ret); 19097f7322feSeschrock 19107f7322feSeschrock return (zfs_iter_snapshots(zhp, func, data)); 19117f7322feSeschrock } 19127f7322feSeschrock 1913fa9e4066Sahrens /* 1914fa9e4066Sahrens * Given a complete name, return just the portion that refers to the parent. 1915fa9e4066Sahrens * Can return NULL if this is a pool. 1916fa9e4066Sahrens */ 1917fa9e4066Sahrens static int 1918fa9e4066Sahrens parent_name(const char *path, char *buf, size_t buflen) 1919fa9e4066Sahrens { 1920fa9e4066Sahrens char *loc; 1921fa9e4066Sahrens 1922fa9e4066Sahrens if ((loc = strrchr(path, '/')) == NULL) 1923fa9e4066Sahrens return (-1); 1924fa9e4066Sahrens 1925fa9e4066Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1926fa9e4066Sahrens buf[loc - path] = '\0'; 1927fa9e4066Sahrens 1928fa9e4066Sahrens return (0); 1929fa9e4066Sahrens } 1930fa9e4066Sahrens 1931fa9e4066Sahrens /* 1932e9dbad6fSeschrock * Checks to make sure that the given path has a parent, and that it exists. We 1933e9dbad6fSeschrock * also fetch the 'zoned' property, which is used to validate property settings 1934e9dbad6fSeschrock * when creating new datasets. 1935fa9e4066Sahrens */ 1936fa9e4066Sahrens static int 1937e9dbad6fSeschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1938fa9e4066Sahrens { 1939fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1940fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 1941fa9e4066Sahrens char *slash; 19427f7322feSeschrock zfs_handle_t *zhp; 194399653d4eSeschrock char errbuf[1024]; 194499653d4eSeschrock 194599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 194699653d4eSeschrock path); 1947fa9e4066Sahrens 1948fa9e4066Sahrens /* get parent, and check to see if this is just a pool */ 1949fa9e4066Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 195099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 195199653d4eSeschrock "missing dataset name")); 195299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1953fa9e4066Sahrens } 1954fa9e4066Sahrens 1955fa9e4066Sahrens /* check to see if the pool exists */ 1956fa9e4066Sahrens if ((slash = strchr(parent, '/')) == NULL) 1957fa9e4066Sahrens slash = parent + strlen(parent); 1958fa9e4066Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1959fa9e4066Sahrens zc.zc_name[slash - parent] = '\0'; 196099653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1961fa9e4066Sahrens errno == ENOENT) { 196299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 196399653d4eSeschrock "no such pool '%s'"), zc.zc_name); 196499653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1965fa9e4066Sahrens } 1966fa9e4066Sahrens 1967fa9e4066Sahrens /* check to see if the parent dataset exists */ 196899653d4eSeschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1969fa9e4066Sahrens switch (errno) { 1970fa9e4066Sahrens case ENOENT: 197199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 197299653d4eSeschrock "parent does not exist")); 197399653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1974fa9e4066Sahrens 1975fa9e4066Sahrens default: 197699653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1977fa9e4066Sahrens } 1978fa9e4066Sahrens } 1979fa9e4066Sahrens 1980e9dbad6fSeschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1981fa9e4066Sahrens /* we are in a non-global zone, but parent is in the global zone */ 1982e9dbad6fSeschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 198399653d4eSeschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19847f7322feSeschrock zfs_close(zhp); 1985fa9e4066Sahrens return (-1); 1986fa9e4066Sahrens } 1987fa9e4066Sahrens 1988fa9e4066Sahrens /* make sure parent is a filesystem */ 19897f7322feSeschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 199099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 199199653d4eSeschrock "parent is not a filesystem")); 199299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19937f7322feSeschrock zfs_close(zhp); 1994fa9e4066Sahrens return (-1); 1995fa9e4066Sahrens } 1996fa9e4066Sahrens 19977f7322feSeschrock zfs_close(zhp); 1998fa9e4066Sahrens return (0); 1999fa9e4066Sahrens } 2000fa9e4066Sahrens 2001fa9e4066Sahrens /* 2002e9dbad6fSeschrock * Create a new filesystem or volume. 2003fa9e4066Sahrens */ 2004fa9e4066Sahrens int 200599653d4eSeschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2006e9dbad6fSeschrock nvlist_t *props) 2007fa9e4066Sahrens { 2008fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2009fa9e4066Sahrens int ret; 2010fa9e4066Sahrens uint64_t size = 0; 2011fa9e4066Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 201299653d4eSeschrock char errbuf[1024]; 2013e9dbad6fSeschrock uint64_t zoned; 201499653d4eSeschrock 201599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 201699653d4eSeschrock "cannot create '%s'"), path); 2017fa9e4066Sahrens 2018fa9e4066Sahrens /* validate the path, taking care to note the extended error message */ 201999653d4eSeschrock if (!zfs_validate_name(hdl, path, type)) 202099653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2021fa9e4066Sahrens 2022fa9e4066Sahrens /* validate parents exist */ 2023e9dbad6fSeschrock if (check_parents(hdl, path, &zoned) != 0) 2024fa9e4066Sahrens return (-1); 2025fa9e4066Sahrens 2026fa9e4066Sahrens /* 2027fa9e4066Sahrens * The failure modes when creating a dataset of a different type over 2028fa9e4066Sahrens * one that already exists is a little strange. In particular, if you 2029fa9e4066Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 2030fa9e4066Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 2031fa9e4066Sahrens * first try to see if the dataset exists. 2032fa9e4066Sahrens */ 2033fa9e4066Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 203499653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 203599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 203699653d4eSeschrock "dataset already exists")); 203799653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2038fa9e4066Sahrens } 2039fa9e4066Sahrens 2040fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) 2041fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2042fa9e4066Sahrens else 2043fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2044fa9e4066Sahrens 2045b1b8ab34Slling if (props && (props = zfs_validate_properties(hdl, type, NULL, props, 2046b1b8ab34Slling zoned, NULL, errbuf)) == 0) 2047e9dbad6fSeschrock return (-1); 2048e9dbad6fSeschrock 2049fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) { 20505c5460e9Seschrock /* 20515c5460e9Seschrock * If we are creating a volume, the size and block size must 20525c5460e9Seschrock * satisfy a few restraints. First, the blocksize must be a 20535c5460e9Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20545c5460e9Seschrock * volsize must be a multiple of the block size, and cannot be 20555c5460e9Seschrock * zero. 20565c5460e9Seschrock */ 2057e9dbad6fSeschrock if (props == NULL || nvlist_lookup_uint64(props, 2058e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 2059e9dbad6fSeschrock nvlist_free(props); 206099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2061e9dbad6fSeschrock "missing volume size")); 2062e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2063e9dbad6fSeschrock } 2064e9dbad6fSeschrock 2065e9dbad6fSeschrock if ((ret = nvlist_lookup_uint64(props, 2066e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2067e9dbad6fSeschrock &blocksize)) != 0) { 2068e9dbad6fSeschrock if (ret == ENOENT) { 2069e9dbad6fSeschrock blocksize = zfs_prop_default_numeric( 2070e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2071e9dbad6fSeschrock } else { 2072e9dbad6fSeschrock nvlist_free(props); 2073e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2074e9dbad6fSeschrock "missing volume block size")); 2075e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2076e9dbad6fSeschrock } 2077fa9e4066Sahrens } 2078fa9e4066Sahrens 2079e9dbad6fSeschrock if (size == 0) { 2080e9dbad6fSeschrock nvlist_free(props); 208199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2082e9dbad6fSeschrock "volume size cannot be zero")); 2083e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20845c5460e9Seschrock } 20855c5460e9Seschrock 20865c5460e9Seschrock if (size % blocksize != 0) { 2087e9dbad6fSeschrock nvlist_free(props); 208899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2089e9dbad6fSeschrock "volume size must be a multiple of volume block " 2090e9dbad6fSeschrock "size")); 2091e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20925c5460e9Seschrock } 2093fa9e4066Sahrens } 2094fa9e4066Sahrens 2095e9dbad6fSeschrock if (props && 2096e9dbad6fSeschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 2097e9dbad6fSeschrock return (-1); 2098e9dbad6fSeschrock nvlist_free(props); 2099e9dbad6fSeschrock 2100fa9e4066Sahrens /* create the dataset */ 210199653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2102fa9e4066Sahrens 2103b1b8ab34Slling if (ret == 0 && type == ZFS_TYPE_VOLUME) { 210499653d4eSeschrock ret = zvol_create_link(hdl, path); 2105b1b8ab34Slling if (ret) { 2106b1b8ab34Slling (void) zfs_standard_error(hdl, errno, 2107b1b8ab34Slling dgettext(TEXT_DOMAIN, 2108b1b8ab34Slling "Volume successfully created, but device links " 2109b1b8ab34Slling "were not created")); 2110b1b8ab34Slling zcmd_free_nvlists(&zc); 2111b1b8ab34Slling return (-1); 2112b1b8ab34Slling } 2113b1b8ab34Slling } 2114fa9e4066Sahrens 2115e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2116e9dbad6fSeschrock 2117fa9e4066Sahrens /* check for failure */ 2118fa9e4066Sahrens if (ret != 0) { 2119fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 2120fa9e4066Sahrens (void) parent_name(path, parent, sizeof (parent)); 2121fa9e4066Sahrens 2122fa9e4066Sahrens switch (errno) { 2123fa9e4066Sahrens case ENOENT: 212499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 212599653d4eSeschrock "no such parent '%s'"), parent); 212699653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2127fa9e4066Sahrens 2128fa9e4066Sahrens case EINVAL: 212999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2130d7d4af51Smmusante "parent '%s' is not a filesystem"), parent); 213199653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2132fa9e4066Sahrens 2133fa9e4066Sahrens case EDOM: 213499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2135e9dbad6fSeschrock "volume block size must be power of 2 from " 2136e9dbad6fSeschrock "%u to %uk"), 2137fa9e4066Sahrens (uint_t)SPA_MINBLOCKSIZE, 2138fa9e4066Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 213999653d4eSeschrock 2140e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 214199653d4eSeschrock 2142fa9e4066Sahrens #ifdef _ILP32 2143fa9e4066Sahrens case EOVERFLOW: 2144fa9e4066Sahrens /* 2145fa9e4066Sahrens * This platform can't address a volume this big. 2146fa9e4066Sahrens */ 214799653d4eSeschrock if (type == ZFS_TYPE_VOLUME) 214899653d4eSeschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 214999653d4eSeschrock errbuf)); 2150fa9e4066Sahrens #endif 215199653d4eSeschrock /* FALLTHROUGH */ 2152fa9e4066Sahrens default: 215399653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2154fa9e4066Sahrens } 2155fa9e4066Sahrens } 2156fa9e4066Sahrens 2157fa9e4066Sahrens return (0); 2158fa9e4066Sahrens } 2159fa9e4066Sahrens 2160fa9e4066Sahrens /* 2161fa9e4066Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2162fa9e4066Sahrens * isn't mounted, and that there are no active dependents. 2163fa9e4066Sahrens */ 2164fa9e4066Sahrens int 2165fa9e4066Sahrens zfs_destroy(zfs_handle_t *zhp) 2166fa9e4066Sahrens { 2167fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2168fa9e4066Sahrens 2169fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2170fa9e4066Sahrens 2171e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) { 2172f3861e1aSahl /* 2173f3861e1aSahl * Unconditionally unshare this zvol ignoring failure as it 2174f3861e1aSahl * indicates only that the volume wasn't shared initially. 2175f3861e1aSahl */ 2176f3861e1aSahl (void) zfs_unshare_iscsi(zhp); 2177f3861e1aSahl 217899653d4eSeschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2179fa9e4066Sahrens return (-1); 2180fa9e4066Sahrens 2181fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2182fa9e4066Sahrens } else { 2183fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2184fa9e4066Sahrens } 2185fa9e4066Sahrens 2186f3861e1aSahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { 2187ece3d9b3Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 218899653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 218999653d4eSeschrock zhp->zfs_name)); 21901d452cf5Sahrens } 2191fa9e4066Sahrens 2192fa9e4066Sahrens remove_mountpoint(zhp); 2193fa9e4066Sahrens 2194fa9e4066Sahrens return (0); 2195fa9e4066Sahrens } 2196fa9e4066Sahrens 21971d452cf5Sahrens struct destroydata { 21981d452cf5Sahrens char *snapname; 21991d452cf5Sahrens boolean_t gotone; 22003ccfa83cSahrens boolean_t closezhp; 22011d452cf5Sahrens }; 22021d452cf5Sahrens 22031d452cf5Sahrens static int 22041d452cf5Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 22051d452cf5Sahrens { 22061d452cf5Sahrens struct destroydata *dd = arg; 22071d452cf5Sahrens zfs_handle_t *szhp; 22081d452cf5Sahrens char name[ZFS_MAXNAMELEN]; 22093ccfa83cSahrens boolean_t closezhp = dd->closezhp; 22103ccfa83cSahrens int rv; 22111d452cf5Sahrens 2212e9dbad6fSeschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2213e9dbad6fSeschrock (void) strlcat(name, "@", sizeof (name)); 2214e9dbad6fSeschrock (void) strlcat(name, dd->snapname, sizeof (name)); 22151d452cf5Sahrens 22161d452cf5Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 22171d452cf5Sahrens if (szhp) { 22181d452cf5Sahrens dd->gotone = B_TRUE; 22191d452cf5Sahrens zfs_close(szhp); 22201d452cf5Sahrens } 22211d452cf5Sahrens 22221d452cf5Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 22231d452cf5Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 22241d452cf5Sahrens /* 22251d452cf5Sahrens * NB: this is simply a best-effort. We don't want to 22261d452cf5Sahrens * return an error, because then we wouldn't visit all 22271d452cf5Sahrens * the volumes. 22281d452cf5Sahrens */ 22291d452cf5Sahrens } 22301d452cf5Sahrens 22313ccfa83cSahrens dd->closezhp = B_TRUE; 22323ccfa83cSahrens rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); 22333ccfa83cSahrens if (closezhp) 22343ccfa83cSahrens zfs_close(zhp); 22353ccfa83cSahrens return (rv); 22361d452cf5Sahrens } 22371d452cf5Sahrens 22381d452cf5Sahrens /* 22391d452cf5Sahrens * Destroys all snapshots with the given name in zhp & descendants. 22401d452cf5Sahrens */ 22411d452cf5Sahrens int 22421d452cf5Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 22431d452cf5Sahrens { 22441d452cf5Sahrens zfs_cmd_t zc = { 0 }; 22451d452cf5Sahrens int ret; 22461d452cf5Sahrens struct destroydata dd = { 0 }; 22471d452cf5Sahrens 22481d452cf5Sahrens dd.snapname = snapname; 22491d452cf5Sahrens (void) zfs_remove_link_cb(zhp, &dd); 22501d452cf5Sahrens 22511d452cf5Sahrens if (!dd.gotone) { 2252ece3d9b3Slling return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 22531d452cf5Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 22541d452cf5Sahrens zhp->zfs_name, snapname)); 22551d452cf5Sahrens } 22561d452cf5Sahrens 22571d452cf5Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2258e9dbad6fSeschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 22591d452cf5Sahrens 22601d452cf5Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 22611d452cf5Sahrens if (ret != 0) { 22621d452cf5Sahrens char errbuf[1024]; 22631d452cf5Sahrens 22641d452cf5Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22651d452cf5Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22661d452cf5Sahrens 22671d452cf5Sahrens switch (errno) { 22681d452cf5Sahrens case EEXIST: 22691d452cf5Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22701d452cf5Sahrens "snapshot is cloned")); 22711d452cf5Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22721d452cf5Sahrens 22731d452cf5Sahrens default: 22741d452cf5Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22751d452cf5Sahrens errbuf)); 22761d452cf5Sahrens } 22771d452cf5Sahrens } 22781d452cf5Sahrens 22791d452cf5Sahrens return (0); 22801d452cf5Sahrens } 22811d452cf5Sahrens 2282fa9e4066Sahrens /* 2283fa9e4066Sahrens * Clones the given dataset. The target must be of the same type as the source. 2284fa9e4066Sahrens */ 2285fa9e4066Sahrens int 2286e9dbad6fSeschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2287fa9e4066Sahrens { 2288fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2289fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 2290fa9e4066Sahrens int ret; 229199653d4eSeschrock char errbuf[1024]; 229299653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2293e9dbad6fSeschrock zfs_type_t type; 2294e9dbad6fSeschrock uint64_t zoned; 2295fa9e4066Sahrens 2296fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2297fa9e4066Sahrens 229899653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 229999653d4eSeschrock "cannot create '%s'"), target); 230099653d4eSeschrock 2301fa9e4066Sahrens /* validate the target name */ 230299653d4eSeschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 230399653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2304fa9e4066Sahrens 2305fa9e4066Sahrens /* validate parents exist */ 2306e9dbad6fSeschrock if (check_parents(hdl, target, &zoned) != 0) 2307fa9e4066Sahrens return (-1); 2308fa9e4066Sahrens 2309fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 2310fa9e4066Sahrens 2311fa9e4066Sahrens /* do the clone */ 2312e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) { 2313fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 23145f8e1617Snn type = ZFS_TYPE_VOLUME; 2315e9dbad6fSeschrock } else { 2316fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 23175f8e1617Snn type = ZFS_TYPE_FILESYSTEM; 2318e9dbad6fSeschrock } 2319e9dbad6fSeschrock 2320e9dbad6fSeschrock if (props) { 2321b1b8ab34Slling if ((props = zfs_validate_properties(hdl, type, NULL, props, 2322b1b8ab34Slling zoned, zhp, errbuf)) == NULL) 2323e9dbad6fSeschrock return (-1); 2324e9dbad6fSeschrock 2325e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 2326e9dbad6fSeschrock nvlist_free(props); 2327e9dbad6fSeschrock return (-1); 2328e9dbad6fSeschrock } 2329e9dbad6fSeschrock 2330e9dbad6fSeschrock nvlist_free(props); 2331e9dbad6fSeschrock } 2332fa9e4066Sahrens 2333fa9e4066Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2334e9dbad6fSeschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 233599653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2336fa9e4066Sahrens 2337e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2338e9dbad6fSeschrock 2339fa9e4066Sahrens if (ret != 0) { 2340fa9e4066Sahrens switch (errno) { 2341fa9e4066Sahrens 2342fa9e4066Sahrens case ENOENT: 2343fa9e4066Sahrens /* 2344fa9e4066Sahrens * The parent doesn't exist. We should have caught this 2345fa9e4066Sahrens * above, but there may a race condition that has since 2346fa9e4066Sahrens * destroyed the parent. 2347fa9e4066Sahrens * 2348fa9e4066Sahrens * At this point, we don't know whether it's the source 2349fa9e4066Sahrens * that doesn't exist anymore, or whether the target 2350fa9e4066Sahrens * dataset doesn't exist. 2351fa9e4066Sahrens */ 235299653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 235399653d4eSeschrock "no such parent '%s'"), parent); 235499653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 2355fa9e4066Sahrens 235699653d4eSeschrock case EXDEV: 235799653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 235899653d4eSeschrock "source and target pools differ")); 235999653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 236099653d4eSeschrock errbuf)); 2361fa9e4066Sahrens 236299653d4eSeschrock default: 236399653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 236499653d4eSeschrock errbuf)); 236599653d4eSeschrock } 2366e9dbad6fSeschrock } else if (ZFS_IS_VOLUME(zhp)) { 236799653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, target); 236899653d4eSeschrock } 2369fa9e4066Sahrens 237099653d4eSeschrock return (ret); 237199653d4eSeschrock } 237299653d4eSeschrock 237399653d4eSeschrock typedef struct promote_data { 237499653d4eSeschrock char cb_mountpoint[MAXPATHLEN]; 237599653d4eSeschrock const char *cb_target; 237699653d4eSeschrock const char *cb_errbuf; 237799653d4eSeschrock uint64_t cb_pivot_txg; 237899653d4eSeschrock } promote_data_t; 237999653d4eSeschrock 238099653d4eSeschrock static int 238199653d4eSeschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 238299653d4eSeschrock { 238399653d4eSeschrock promote_data_t *pd = data; 238499653d4eSeschrock zfs_handle_t *szhp; 238599653d4eSeschrock char snapname[MAXPATHLEN]; 23863ccfa83cSahrens int rv = 0; 238799653d4eSeschrock 238899653d4eSeschrock /* We don't care about snapshots after the pivot point */ 23893ccfa83cSahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { 23903ccfa83cSahrens zfs_close(zhp); 239199653d4eSeschrock return (0); 23923ccfa83cSahrens } 239399653d4eSeschrock 23940b69c2f0Sahrens /* Remove the device link if it's a zvol. */ 2395e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 23960b69c2f0Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 239799653d4eSeschrock 239899653d4eSeschrock /* Check for conflicting names */ 2399e9dbad6fSeschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 2400e9dbad6fSeschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 240199653d4eSeschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 240299653d4eSeschrock if (szhp != NULL) { 240399653d4eSeschrock zfs_close(szhp); 240499653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 240599653d4eSeschrock "snapshot name '%s' from origin \n" 240699653d4eSeschrock "conflicts with '%s' from target"), 240799653d4eSeschrock zhp->zfs_name, snapname); 24083ccfa83cSahrens rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); 240999653d4eSeschrock } 24103ccfa83cSahrens zfs_close(zhp); 24113ccfa83cSahrens return (rv); 241299653d4eSeschrock } 241399653d4eSeschrock 24140b69c2f0Sahrens static int 24150b69c2f0Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 24160b69c2f0Sahrens { 24170b69c2f0Sahrens promote_data_t *pd = data; 24180b69c2f0Sahrens 24190b69c2f0Sahrens /* We don't care about snapshots after the pivot point */ 24203ccfa83cSahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { 24213ccfa83cSahrens /* Create the device link if it's a zvol. */ 24223ccfa83cSahrens if (ZFS_IS_VOLUME(zhp)) 24233ccfa83cSahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 24243ccfa83cSahrens } 24250b69c2f0Sahrens 24263ccfa83cSahrens zfs_close(zhp); 24270b69c2f0Sahrens return (0); 24280b69c2f0Sahrens } 24290b69c2f0Sahrens 243099653d4eSeschrock /* 243199653d4eSeschrock * Promotes the given clone fs to be the clone parent. 243299653d4eSeschrock */ 243399653d4eSeschrock int 243499653d4eSeschrock zfs_promote(zfs_handle_t *zhp) 243599653d4eSeschrock { 243699653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 243799653d4eSeschrock zfs_cmd_t zc = { 0 }; 243899653d4eSeschrock char parent[MAXPATHLEN]; 243999653d4eSeschrock char *cp; 244099653d4eSeschrock int ret; 244199653d4eSeschrock zfs_handle_t *pzhp; 244299653d4eSeschrock promote_data_t pd; 244399653d4eSeschrock char errbuf[1024]; 244499653d4eSeschrock 244599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 244699653d4eSeschrock "cannot promote '%s'"), zhp->zfs_name); 244799653d4eSeschrock 244899653d4eSeschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 244999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 245099653d4eSeschrock "snapshots can not be promoted")); 245199653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 245299653d4eSeschrock } 245399653d4eSeschrock 2454e9dbad6fSeschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 245599653d4eSeschrock if (parent[0] == '\0') { 245699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 245799653d4eSeschrock "not a cloned filesystem")); 245899653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 245999653d4eSeschrock } 246099653d4eSeschrock cp = strchr(parent, '@'); 246199653d4eSeschrock *cp = '\0'; 246299653d4eSeschrock 246399653d4eSeschrock /* Walk the snapshots we will be moving */ 246499653d4eSeschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 246599653d4eSeschrock if (pzhp == NULL) 246699653d4eSeschrock return (-1); 246799653d4eSeschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 246899653d4eSeschrock zfs_close(pzhp); 246999653d4eSeschrock pd.cb_target = zhp->zfs_name; 247099653d4eSeschrock pd.cb_errbuf = errbuf; 247199653d4eSeschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 247299653d4eSeschrock if (pzhp == NULL) 247399653d4eSeschrock return (-1); 247499653d4eSeschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 247599653d4eSeschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 247699653d4eSeschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24770b69c2f0Sahrens if (ret != 0) { 24780b69c2f0Sahrens zfs_close(pzhp); 247999653d4eSeschrock return (-1); 24800b69c2f0Sahrens } 248199653d4eSeschrock 248299653d4eSeschrock /* issue the ioctl */ 2483e9dbad6fSeschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 2484e9dbad6fSeschrock sizeof (zc.zc_value)); 248599653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 248699653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 248799653d4eSeschrock 248899653d4eSeschrock if (ret != 0) { 24890b69c2f0Sahrens int save_errno = errno; 24900b69c2f0Sahrens 24910b69c2f0Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24920b69c2f0Sahrens zfs_close(pzhp); 249399653d4eSeschrock 24940b69c2f0Sahrens switch (save_errno) { 249599653d4eSeschrock case EEXIST: 2496fa9e4066Sahrens /* 249799653d4eSeschrock * There is a conflicting snapshot name. We 249899653d4eSeschrock * should have caught this above, but they could 249999653d4eSeschrock * have renamed something in the mean time. 2500fa9e4066Sahrens */ 250199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 250299653d4eSeschrock "conflicting snapshot name from parent '%s'"), 250399653d4eSeschrock parent); 250499653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2505fa9e4066Sahrens 2506fa9e4066Sahrens default: 25070b69c2f0Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2508fa9e4066Sahrens } 25090b69c2f0Sahrens } else { 25100b69c2f0Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2511fa9e4066Sahrens } 2512fa9e4066Sahrens 25130b69c2f0Sahrens zfs_close(pzhp); 2514fa9e4066Sahrens return (ret); 2515fa9e4066Sahrens } 2516fa9e4066Sahrens 2517*cdf5b4caSmmusante struct createdata { 2518*cdf5b4caSmmusante const char *cd_snapname; 2519*cdf5b4caSmmusante int cd_ifexists; 2520*cdf5b4caSmmusante }; 2521*cdf5b4caSmmusante 25221d452cf5Sahrens static int 25231d452cf5Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 25241d452cf5Sahrens { 2525*cdf5b4caSmmusante struct createdata *cd = arg; 2526e9dbad6fSeschrock int ret; 25271d452cf5Sahrens 25281d452cf5Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 25291d452cf5Sahrens char name[MAXPATHLEN]; 25301d452cf5Sahrens 2531e9dbad6fSeschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 2532e9dbad6fSeschrock (void) strlcat(name, "@", sizeof (name)); 2533*cdf5b4caSmmusante (void) strlcat(name, cd->cd_snapname, sizeof (name)); 2534*cdf5b4caSmmusante (void) zvol_create_link_common(zhp->zfs_hdl, name, 2535*cdf5b4caSmmusante cd->cd_ifexists); 25361d452cf5Sahrens /* 25371d452cf5Sahrens * NB: this is simply a best-effort. We don't want to 25381d452cf5Sahrens * return an error, because then we wouldn't visit all 25391d452cf5Sahrens * the volumes. 25401d452cf5Sahrens */ 25411d452cf5Sahrens } 2542e9dbad6fSeschrock 2543*cdf5b4caSmmusante ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd); 2544e9dbad6fSeschrock 2545e9dbad6fSeschrock zfs_close(zhp); 2546e9dbad6fSeschrock 2547e9dbad6fSeschrock return (ret); 25481d452cf5Sahrens } 25491d452cf5Sahrens 2550fa9e4066Sahrens /* 255172bdce51Sahl * Takes a snapshot of the given dataset. 2552fa9e4066Sahrens */ 2553fa9e4066Sahrens int 25541d452cf5Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2555fa9e4066Sahrens { 2556fa9e4066Sahrens const char *delim; 2557fa9e4066Sahrens char *parent; 2558fa9e4066Sahrens zfs_handle_t *zhp; 2559fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2560fa9e4066Sahrens int ret; 256199653d4eSeschrock char errbuf[1024]; 2562fa9e4066Sahrens 256399653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 256499653d4eSeschrock "cannot snapshot '%s'"), path); 256599653d4eSeschrock 256699653d4eSeschrock /* validate the target name */ 256799653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 256899653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2569fa9e4066Sahrens 2570fa9e4066Sahrens /* make sure the parent exists and is of the appropriate type */ 25711d452cf5Sahrens delim = strchr(path, '@'); 257299653d4eSeschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 257399653d4eSeschrock return (-1); 2574fa9e4066Sahrens (void) strncpy(parent, path, delim - path); 2575fa9e4066Sahrens parent[delim - path] = '\0'; 2576fa9e4066Sahrens 257799653d4eSeschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2578fa9e4066Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2579fa9e4066Sahrens free(parent); 2580fa9e4066Sahrens return (-1); 2581fa9e4066Sahrens } 2582fa9e4066Sahrens 25831d452cf5Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2584e9dbad6fSeschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25851d452cf5Sahrens zc.zc_cookie = recursive; 25861d452cf5Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 2587fa9e4066Sahrens 25881d452cf5Sahrens /* 25891d452cf5Sahrens * if it was recursive, the one that actually failed will be in 25901d452cf5Sahrens * zc.zc_name. 25911d452cf5Sahrens */ 25921d452cf5Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2593e9dbad6fSeschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25941d452cf5Sahrens if (ret == 0 && recursive) { 2595*cdf5b4caSmmusante struct createdata cd; 2596*cdf5b4caSmmusante 2597*cdf5b4caSmmusante cd.cd_snapname = delim + 1; 2598*cdf5b4caSmmusante cd.cd_ifexists = B_FALSE; 2599*cdf5b4caSmmusante (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 26001d452cf5Sahrens } 2601fa9e4066Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 260299653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, path); 26031d452cf5Sahrens if (ret != 0) { 260499653d4eSeschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 260599653d4eSeschrock &zc); 26061d452cf5Sahrens } 2607fa9e4066Sahrens } 2608fa9e4066Sahrens 260999653d4eSeschrock if (ret != 0) 261099653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2611fa9e4066Sahrens 2612fa9e4066Sahrens free(parent); 2613fa9e4066Sahrens zfs_close(zhp); 2614fa9e4066Sahrens 2615fa9e4066Sahrens return (ret); 2616fa9e4066Sahrens } 2617fa9e4066Sahrens 2618fa9e4066Sahrens /* 261972bdce51Sahl * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 262072bdce51Sahl * NULL) to the file descriptor specified by outfd. 2621fa9e4066Sahrens */ 2622fa9e4066Sahrens int 262372bdce51Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2624fa9e4066Sahrens { 2625fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 262699653d4eSeschrock char errbuf[1024]; 2627a2eea2e1Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 262899653d4eSeschrock 262972bdce51Sahl assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2630fa9e4066Sahrens 2631a2eea2e1Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2632a2eea2e1Sahrens if (fromsnap) 2633a2eea2e1Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 263472bdce51Sahl zc.zc_cookie = outfd; 263572bdce51Sahl 263672bdce51Sahl if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 263772bdce51Sahl (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 263872bdce51Sahl "cannot send '%s'"), zhp->zfs_name); 2639fa9e4066Sahrens 2640fa9e4066Sahrens switch (errno) { 2641fa9e4066Sahrens 2642fa9e4066Sahrens case EXDEV: 264399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2644d7d4af51Smmusante "not an earlier snapshot from the same fs")); 264599653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2646fa9e4066Sahrens 2647fa9e4066Sahrens case EDQUOT: 2648fa9e4066Sahrens case EFBIG: 2649fa9e4066Sahrens case EIO: 2650fa9e4066Sahrens case ENOLINK: 2651fa9e4066Sahrens case ENOSPC: 2652fa9e4066Sahrens case ENOSTR: 2653fa9e4066Sahrens case ENXIO: 2654fa9e4066Sahrens case EPIPE: 2655fa9e4066Sahrens case ERANGE: 2656fa9e4066Sahrens case EFAULT: 2657fa9e4066Sahrens case EROFS: 265899653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 265999653d4eSeschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2660fa9e4066Sahrens 2661fa9e4066Sahrens default: 266299653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2663fa9e4066Sahrens } 2664fa9e4066Sahrens } 2665fa9e4066Sahrens 266672bdce51Sahl return (0); 2667fa9e4066Sahrens } 2668fa9e4066Sahrens 2669a2eea2e1Sahrens /* 2670a2eea2e1Sahrens * Create ancestors of 'target', but not target itself, and not 2671a2eea2e1Sahrens * ancestors whose names are shorter than prefixlen. Die if 2672a2eea2e1Sahrens * prefixlen-ancestor does not exist. 2673a2eea2e1Sahrens */ 2674a2eea2e1Sahrens static int 2675a2eea2e1Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2676a2eea2e1Sahrens { 2677a2eea2e1Sahrens zfs_handle_t *h; 2678a2eea2e1Sahrens char *cp; 2679a2eea2e1Sahrens 2680a2eea2e1Sahrens /* make sure prefix exists */ 2681a2eea2e1Sahrens cp = strchr(target + prefixlen, '/'); 2682a2eea2e1Sahrens *cp = '\0'; 2683a2eea2e1Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2684a2eea2e1Sahrens *cp = '/'; 2685a2eea2e1Sahrens if (h == NULL) 2686a2eea2e1Sahrens return (-1); 2687a2eea2e1Sahrens zfs_close(h); 2688a2eea2e1Sahrens 2689a2eea2e1Sahrens /* 2690a2eea2e1Sahrens * Attempt to create, mount, and share any ancestor filesystems, 2691a2eea2e1Sahrens * up to the prefixlen-long one. 2692a2eea2e1Sahrens */ 2693a2eea2e1Sahrens for (cp = target + prefixlen + 1; 2694a2eea2e1Sahrens cp = strchr(cp, '/'); *cp = '/', cp++) { 2695a2eea2e1Sahrens const char *opname; 2696a2eea2e1Sahrens 2697a2eea2e1Sahrens *cp = '\0'; 2698a2eea2e1Sahrens 2699a2eea2e1Sahrens h = make_dataset_handle(hdl, target); 2700a2eea2e1Sahrens if (h) { 2701a2eea2e1Sahrens /* it already exists, nothing to do here */ 2702a2eea2e1Sahrens zfs_close(h); 2703a2eea2e1Sahrens continue; 2704a2eea2e1Sahrens } 2705a2eea2e1Sahrens 2706a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "create"); 2707a2eea2e1Sahrens if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2708a2eea2e1Sahrens NULL) != 0) 2709a2eea2e1Sahrens goto ancestorerr; 2710a2eea2e1Sahrens 2711a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "open"); 2712a2eea2e1Sahrens h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2713a2eea2e1Sahrens if (h == NULL) 2714a2eea2e1Sahrens goto ancestorerr; 2715a2eea2e1Sahrens 2716a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "mount"); 2717a2eea2e1Sahrens if (zfs_mount(h, NULL, 0) != 0) 2718a2eea2e1Sahrens goto ancestorerr; 2719a2eea2e1Sahrens 2720a2eea2e1Sahrens opname = dgettext(TEXT_DOMAIN, "share"); 2721a2eea2e1Sahrens if (zfs_share(h) != 0) 2722a2eea2e1Sahrens goto ancestorerr; 2723a2eea2e1Sahrens 2724a2eea2e1Sahrens zfs_close(h); 2725a2eea2e1Sahrens 2726a2eea2e1Sahrens continue; 2727a2eea2e1Sahrens ancestorerr: 2728a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2729a2eea2e1Sahrens "failed to %s ancestor '%s'"), opname, target); 2730a2eea2e1Sahrens return (-1); 2731a2eea2e1Sahrens } 2732a2eea2e1Sahrens 2733a2eea2e1Sahrens return (0); 2734a2eea2e1Sahrens } 2735a2eea2e1Sahrens 2736fa9e4066Sahrens /* 273772bdce51Sahl * Restores a backup of tosnap from the file descriptor specified by infd. 2738fa9e4066Sahrens */ 2739fa9e4066Sahrens int 274099653d4eSeschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 274172bdce51Sahl int verbose, int dryrun, boolean_t force, int infd) 2742fa9e4066Sahrens { 2743fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2744fa9e4066Sahrens time_t begin_time; 2745a2eea2e1Sahrens int ioctl_err, err, bytes, size, choplen; 2746fa9e4066Sahrens char *cp; 2747fa9e4066Sahrens dmu_replay_record_t drr; 2748fa9e4066Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 274999653d4eSeschrock char errbuf[1024]; 275098579b20Snd prop_changelist_t *clp; 2751a2eea2e1Sahrens char chopprefix[ZFS_MAXNAMELEN]; 2752fa9e4066Sahrens 2753fa9e4066Sahrens begin_time = time(NULL); 2754fa9e4066Sahrens 275599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 275699653d4eSeschrock "cannot receive")); 275799653d4eSeschrock 2758fa9e4066Sahrens /* read in the BEGIN record */ 2759fa9e4066Sahrens cp = (char *)&drr; 2760fa9e4066Sahrens bytes = 0; 2761fa9e4066Sahrens do { 276272bdce51Sahl size = read(infd, cp, sizeof (drr) - bytes); 27639b4f025eSahrens cp += size; 27649b4f025eSahrens bytes += size; 27659b4f025eSahrens } while (size > 0); 2766fa9e4066Sahrens 27679b4f025eSahrens if (size < 0 || bytes != sizeof (drr)) { 276899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 276999653d4eSeschrock "stream (failed to read first record)")); 277099653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2771fa9e4066Sahrens } 2772fa9e4066Sahrens 2773fa9e4066Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2774fa9e4066Sahrens 2775fa9e4066Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2776fa9e4066Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 277799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 277899653d4eSeschrock "stream (bad magic number)")); 277999653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2780fa9e4066Sahrens } 2781fa9e4066Sahrens 2782fa9e4066Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2783fa9e4066Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 278499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 278599653d4eSeschrock "0x%llx is supported (stream is version 0x%llx)"), 2786fa9e4066Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 278799653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2788fa9e4066Sahrens } 2789fa9e4066Sahrens 2790a2eea2e1Sahrens if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 2791a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2792b1b8ab34Slling "stream (bad snapshot name)")); 2793a2eea2e1Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2794a2eea2e1Sahrens } 2795fa9e4066Sahrens /* 2796a2eea2e1Sahrens * Determine how much of the snapshot name stored in the stream 2797a2eea2e1Sahrens * we are going to tack on to the name they specified on the 2798a2eea2e1Sahrens * command line, and how much we are going to chop off. 2799a2eea2e1Sahrens * 2800a2eea2e1Sahrens * If they specified a snapshot, chop the entire name stored in 2801a2eea2e1Sahrens * the stream. 2802fa9e4066Sahrens */ 2803a2eea2e1Sahrens (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2804fa9e4066Sahrens if (isprefix) { 2805a2eea2e1Sahrens /* 2806a2eea2e1Sahrens * They specified a fs with -d, we want to tack on 2807a2eea2e1Sahrens * everything but the pool name stored in the stream 2808a2eea2e1Sahrens */ 2809a2eea2e1Sahrens if (strchr(tosnap, '@')) { 2810a2eea2e1Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2811a2eea2e1Sahrens "argument - snapshot not allowed with -d")); 2812a2eea2e1Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2813fa9e4066Sahrens } 2814a2eea2e1Sahrens cp = strchr(chopprefix, '/'); 2815fa9e4066Sahrens if (cp == NULL) 2816a2eea2e1Sahrens cp = strchr(chopprefix, '@'); 2817a2eea2e1Sahrens *cp = '\0'; 2818fa9e4066Sahrens } else if (strchr(tosnap, '@') == NULL) { 2819fa9e4066Sahrens /* 2820a2eea2e1Sahrens * If they specified a filesystem without -d, we want to 2821a2eea2e1Sahrens * tack on everything after the fs specified in the 2822a2eea2e1Sahrens * first name from the stream. 2823fa9e4066Sahrens */ 2824a2eea2e1Sahrens cp = strchr(chopprefix, '@'); 2825a2eea2e1Sahrens *cp = '\0'; 2826fa9e4066Sahrens } 2827a2eea2e1Sahrens choplen = strlen(chopprefix); 2828a2eea2e1Sahrens 2829a2eea2e1Sahrens /* 2830a2eea2e1Sahrens * Determine name of destination snapshot, store in zc_value. 2831a2eea2e1Sahrens */ 2832a2eea2e1Sahrens (void) strcpy(zc.zc_value, tosnap); 2833a2eea2e1Sahrens (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 2834a2eea2e1Sahrens sizeof (zc.zc_value)); 28353ccfa83cSahrens if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 28363ccfa83cSahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2837fa9e4066Sahrens 2838a2eea2e1Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 2839fa9e4066Sahrens if (drrb->drr_fromguid) { 2840fa9e4066Sahrens /* incremental backup stream */ 2841a2eea2e1Sahrens zfs_handle_t *h; 2842fa9e4066Sahrens 2843a2eea2e1Sahrens /* do the recvbackup ioctl to the containing fs */ 2844a2eea2e1Sahrens *strchr(zc.zc_name, '@') = '\0'; 2845fa9e4066Sahrens 2846fa9e4066Sahrens /* make sure destination fs exists */ 284799653d4eSeschrock h = zfs_open(hdl, zc.zc_name, 284899653d4eSeschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 284999653d4eSeschrock if (h == NULL) 2850fa9e4066Sahrens return (-1); 28519b4f025eSahrens if (!dryrun) { 285298579b20Snd /* 285398579b20Snd * We need to unmount all the dependents of the dataset 285498579b20Snd * and the dataset itself. If it's a volume 285598579b20Snd * then remove device link. 285698579b20Snd */ 28579b4f025eSahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 285898579b20Snd clp = changelist_gather(h, ZFS_PROP_NAME, 0); 285998579b20Snd if (clp == NULL) 286098579b20Snd return (-1); 286198579b20Snd if (changelist_prefix(clp) != 0) { 286298579b20Snd changelist_free(clp); 286398579b20Snd return (-1); 286498579b20Snd } 28659b4f025eSahrens } else { 286699653d4eSeschrock (void) zvol_remove_link(hdl, h->zfs_name); 28679b4f025eSahrens } 28689b4f025eSahrens } 2869fa9e4066Sahrens zfs_close(h); 2870fa9e4066Sahrens } else { 2871fa9e4066Sahrens /* full backup stream */ 2872fa9e4066Sahrens 2873a2eea2e1Sahrens /* Make sure destination fs does not exist */ 2874a2eea2e1Sahrens *strchr(zc.zc_name, '@') = '\0'; 2875a2eea2e1Sahrens if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 287699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2877a2eea2e1Sahrens "destination '%s' exists"), zc.zc_name); 287899653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2879fa9e4066Sahrens } 2880fa9e4066Sahrens 2881a2eea2e1Sahrens if (strchr(zc.zc_name, '/') == NULL) { 28829b4f025eSahrens /* 2883a2eea2e1Sahrens * they're trying to do a recv into a 2884a2eea2e1Sahrens * nonexistant topmost filesystem. 28859b4f025eSahrens */ 288699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2887a2eea2e1Sahrens "destination does not exist"), zc.zc_name); 288899653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 28899b4f025eSahrens } 28909b4f025eSahrens 28919b4f025eSahrens /* Do the recvbackup ioctl to the fs's parent. */ 2892a2eea2e1Sahrens *strrchr(zc.zc_name, '/') = '\0'; 2893a2eea2e1Sahrens 2894a2eea2e1Sahrens if (isprefix && (err = create_parents(hdl, 2895a2eea2e1Sahrens zc.zc_value, strlen(tosnap))) != 0) { 2896a2eea2e1Sahrens return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 2897a2eea2e1Sahrens } 2898a2eea2e1Sahrens 2899fa9e4066Sahrens } 2900fa9e4066Sahrens 290172bdce51Sahl zc.zc_cookie = infd; 2902e9dbad6fSeschrock zc.zc_guid = force; 2903fa9e4066Sahrens if (verbose) { 2904f2a3c691Sahrens (void) printf("%s %s stream of %s into %s\n", 2905f2a3c691Sahrens dryrun ? "would receive" : "receiving", 2906fa9e4066Sahrens drrb->drr_fromguid ? "incremental" : "full", 2907fa9e4066Sahrens drr.drr_u.drr_begin.drr_toname, 2908e9dbad6fSeschrock zc.zc_value); 2909fa9e4066Sahrens (void) fflush(stdout); 2910fa9e4066Sahrens } 2911fa9e4066Sahrens if (dryrun) 2912fa9e4066Sahrens return (0); 291399653d4eSeschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 29149b4f025eSahrens if (ioctl_err != 0) { 2915fa9e4066Sahrens switch (errno) { 2916fa9e4066Sahrens case ENODEV: 291799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 291899653d4eSeschrock "most recent snapshot does not match incremental " 291999653d4eSeschrock "source")); 292099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2921fa9e4066Sahrens break; 2922fa9e4066Sahrens case ETXTBSY: 292399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 292499653d4eSeschrock "destination has been modified since most recent " 292599653d4eSeschrock "snapshot")); 292699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2927fa9e4066Sahrens break; 2928fa9e4066Sahrens case EEXIST: 2929fa9e4066Sahrens if (drrb->drr_fromguid == 0) { 2930fa9e4066Sahrens /* it's the containing fs that exists */ 2931e9dbad6fSeschrock cp = strchr(zc.zc_value, '@'); 2932fa9e4066Sahrens *cp = '\0'; 2933fa9e4066Sahrens } 293499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 293599653d4eSeschrock "destination already exists")); 2936ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_EXISTS, 2937ece3d9b3Slling dgettext(TEXT_DOMAIN, "cannot restore to %s"), 2938ece3d9b3Slling zc.zc_value); 2939fa9e4066Sahrens break; 2940fa9e4066Sahrens case EINVAL: 294199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 29429b4f025eSahrens break; 2943ea8dc4b6Seschrock case ECKSUM: 294499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 294599653d4eSeschrock "invalid stream (checksum mismatch)")); 294699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2947fa9e4066Sahrens break; 2948fa9e4066Sahrens default: 294999653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2950fa9e4066Sahrens } 2951fa9e4066Sahrens } 2952fa9e4066Sahrens 2953fa9e4066Sahrens /* 29549b4f025eSahrens * Mount or recreate the /dev links for the target filesystem 29559b4f025eSahrens * (if created, or if we tore them down to do an incremental 29569b4f025eSahrens * restore), and the /dev links for the new snapshot (if 295798579b20Snd * created). Also mount any children of the target filesystem 295898579b20Snd * if we did an incremental receive. 2959fa9e4066Sahrens */ 2960e9dbad6fSeschrock cp = strchr(zc.zc_value, '@'); 29619b4f025eSahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2962fa9e4066Sahrens zfs_handle_t *h; 2963fa9e4066Sahrens 2964fa9e4066Sahrens *cp = '\0'; 2965e9dbad6fSeschrock h = zfs_open(hdl, zc.zc_value, 2966fa9e4066Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 29679b4f025eSahrens *cp = '@'; 2968fa9e4066Sahrens if (h) { 296998579b20Snd if (h->zfs_type == ZFS_TYPE_VOLUME) { 297099653d4eSeschrock err = zvol_create_link(hdl, h->zfs_name); 2971ea8dc4b6Seschrock if (err == 0 && ioctl_err == 0) 297299653d4eSeschrock err = zvol_create_link(hdl, 2973e9dbad6fSeschrock zc.zc_value); 297498579b20Snd } else { 297598579b20Snd if (drrb->drr_fromguid) { 297698579b20Snd err = changelist_postfix(clp); 297798579b20Snd changelist_free(clp); 297898579b20Snd } else { 297998579b20Snd err = zfs_mount(h, NULL, 0); 298098579b20Snd } 29819b4f025eSahrens } 298298579b20Snd zfs_close(h); 2983fa9e4066Sahrens } 2984fa9e4066Sahrens } 2985fa9e4066Sahrens 29869b4f025eSahrens if (err || ioctl_err) 29879b4f025eSahrens return (-1); 2988fa9e4066Sahrens 2989fa9e4066Sahrens if (verbose) { 2990fa9e4066Sahrens char buf1[64]; 2991fa9e4066Sahrens char buf2[64]; 2992fa9e4066Sahrens uint64_t bytes = zc.zc_cookie; 2993fa9e4066Sahrens time_t delta = time(NULL) - begin_time; 2994fa9e4066Sahrens if (delta == 0) 2995fa9e4066Sahrens delta = 1; 2996fa9e4066Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2997fa9e4066Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2998fa9e4066Sahrens 2999f2a3c691Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 3000fa9e4066Sahrens buf1, delta, buf2); 3001fa9e4066Sahrens } 300298579b20Snd 3003fa9e4066Sahrens return (0); 3004fa9e4066Sahrens } 3005fa9e4066Sahrens 3006fa9e4066Sahrens /* 3007b12a1c38Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 3008b12a1c38Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3009b12a1c38Slling * is a dependent and we should just destroy it without checking the transaction 3010b12a1c38Slling * group. 3011fa9e4066Sahrens */ 3012b12a1c38Slling typedef struct rollback_data { 3013b12a1c38Slling const char *cb_target; /* the snapshot */ 3014b12a1c38Slling uint64_t cb_create; /* creation time reference */ 3015b12a1c38Slling prop_changelist_t *cb_clp; /* changelist pointer */ 3016b12a1c38Slling int cb_error; 301799653d4eSeschrock boolean_t cb_dependent; 3018b12a1c38Slling } rollback_data_t; 3019b12a1c38Slling 3020b12a1c38Slling static int 3021b12a1c38Slling rollback_destroy(zfs_handle_t *zhp, void *data) 3022b12a1c38Slling { 3023b12a1c38Slling rollback_data_t *cbp = data; 3024b12a1c38Slling 3025b12a1c38Slling if (!cbp->cb_dependent) { 3026b12a1c38Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3027b12a1c38Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3028b12a1c38Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3029b12a1c38Slling cbp->cb_create) { 3030b12a1c38Slling 303199653d4eSeschrock cbp->cb_dependent = B_TRUE; 30323bb79becSeschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 30333bb79becSeschrock cbp) != 0) 30343bb79becSeschrock cbp->cb_error = 1; 303599653d4eSeschrock cbp->cb_dependent = B_FALSE; 3036b12a1c38Slling 3037b12a1c38Slling if (zfs_destroy(zhp) != 0) 3038b12a1c38Slling cbp->cb_error = 1; 3039b12a1c38Slling else 3040b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 3041b12a1c38Slling } 3042b12a1c38Slling } else { 3043b12a1c38Slling if (zfs_destroy(zhp) != 0) 3044b12a1c38Slling cbp->cb_error = 1; 3045b12a1c38Slling else 3046b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 3047b12a1c38Slling } 3048b12a1c38Slling 3049b12a1c38Slling zfs_close(zhp); 3050b12a1c38Slling return (0); 3051b12a1c38Slling } 3052b12a1c38Slling 3053b12a1c38Slling /* 3054b12a1c38Slling * Rollback the dataset to its latest snapshot. 3055b12a1c38Slling */ 3056b12a1c38Slling static int 3057b12a1c38Slling do_rollback(zfs_handle_t *zhp) 3058fa9e4066Sahrens { 3059fa9e4066Sahrens int ret; 3060fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3061fa9e4066Sahrens 3062fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3063fa9e4066Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 3064fa9e4066Sahrens 3065fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 306699653d4eSeschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3067fa9e4066Sahrens return (-1); 3068fa9e4066Sahrens 3069fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3070fa9e4066Sahrens 3071e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 3072fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3073fa9e4066Sahrens else 3074fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3075fa9e4066Sahrens 3076fa9e4066Sahrens /* 3077fa9e4066Sahrens * We rely on the consumer to verify that there are no newer snapshots 3078fa9e4066Sahrens * for the given dataset. Given these constraints, we can simply pass 3079fa9e4066Sahrens * the name on to the ioctl() call. There is still an unlikely race 3080fa9e4066Sahrens * condition where the user has taken a snapshot since we verified that 3081fa9e4066Sahrens * this was the most recent. 3082fa9e4066Sahrens */ 308399653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 308499653d4eSeschrock &zc)) != 0) { 3085ece3d9b3Slling (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 308699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 308799653d4eSeschrock zhp->zfs_name); 3088fa9e4066Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 308999653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3090fa9e4066Sahrens } 3091fa9e4066Sahrens 3092fa9e4066Sahrens return (ret); 3093fa9e4066Sahrens } 3094fa9e4066Sahrens 3095b12a1c38Slling /* 3096b12a1c38Slling * Given a dataset, rollback to a specific snapshot, discarding any 3097b12a1c38Slling * data changes since then and making it the active dataset. 3098b12a1c38Slling * 3099b12a1c38Slling * Any snapshots more recent than the target are destroyed, along with 3100b12a1c38Slling * their dependents. 3101b12a1c38Slling */ 3102b12a1c38Slling int 3103b12a1c38Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 3104b12a1c38Slling { 3105b12a1c38Slling int ret; 3106b12a1c38Slling rollback_data_t cb = { 0 }; 3107b12a1c38Slling prop_changelist_t *clp; 3108b12a1c38Slling 3109b12a1c38Slling /* 3110b12a1c38Slling * Unmount all dependendents of the dataset and the dataset itself. 3111b12a1c38Slling * The list we need to gather is the same as for doing rename 3112b12a1c38Slling */ 3113b12a1c38Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 3114b12a1c38Slling if (clp == NULL) 3115b12a1c38Slling return (-1); 3116b12a1c38Slling 3117b12a1c38Slling if ((ret = changelist_prefix(clp)) != 0) 3118b12a1c38Slling goto out; 3119b12a1c38Slling 3120b12a1c38Slling /* 3121b12a1c38Slling * Destroy all recent snapshots and its dependends. 3122b12a1c38Slling */ 3123b12a1c38Slling cb.cb_target = snap->zfs_name; 3124b12a1c38Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3125b12a1c38Slling cb.cb_clp = clp; 3126b12a1c38Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3127b12a1c38Slling 3128b12a1c38Slling if ((ret = cb.cb_error) != 0) { 3129b12a1c38Slling (void) changelist_postfix(clp); 3130b12a1c38Slling goto out; 3131b12a1c38Slling } 3132b12a1c38Slling 3133b12a1c38Slling /* 3134b12a1c38Slling * Now that we have verified that the snapshot is the latest, 3135b12a1c38Slling * rollback to the given snapshot. 3136b12a1c38Slling */ 3137b12a1c38Slling ret = do_rollback(zhp); 3138b12a1c38Slling 3139b12a1c38Slling if (ret != 0) { 3140b12a1c38Slling (void) changelist_postfix(clp); 3141b12a1c38Slling goto out; 3142b12a1c38Slling } 3143b12a1c38Slling 3144b12a1c38Slling /* 3145b12a1c38Slling * We only want to re-mount the filesystem if it was mounted in the 3146b12a1c38Slling * first place. 3147b12a1c38Slling */ 3148b12a1c38Slling ret = changelist_postfix(clp); 3149b12a1c38Slling 3150b12a1c38Slling out: 3151b12a1c38Slling changelist_free(clp); 3152b12a1c38Slling return (ret); 3153b12a1c38Slling } 3154b12a1c38Slling 3155fa9e4066Sahrens /* 3156fa9e4066Sahrens * Iterate over all dependents for a given dataset. This includes both 3157fa9e4066Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3158fa9e4066Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3159fa9e4066Sahrens * libzfs_graph.c. 3160fa9e4066Sahrens */ 3161fa9e4066Sahrens int 31623bb79becSeschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 31633bb79becSeschrock zfs_iter_f func, void *data) 3164fa9e4066Sahrens { 3165fa9e4066Sahrens char **dependents; 3166fa9e4066Sahrens size_t count; 3167fa9e4066Sahrens int i; 3168fa9e4066Sahrens zfs_handle_t *child; 3169fa9e4066Sahrens int ret = 0; 3170fa9e4066Sahrens 31713bb79becSeschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 31723bb79becSeschrock &dependents, &count) != 0) 31733bb79becSeschrock return (-1); 31743bb79becSeschrock 3175fa9e4066Sahrens for (i = 0; i < count; i++) { 317699653d4eSeschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 317799653d4eSeschrock dependents[i])) == NULL) 3178fa9e4066Sahrens continue; 3179fa9e4066Sahrens 3180fa9e4066Sahrens if ((ret = func(child, data)) != 0) 3181fa9e4066Sahrens break; 3182fa9e4066Sahrens } 3183fa9e4066Sahrens 3184fa9e4066Sahrens for (i = 0; i < count; i++) 3185fa9e4066Sahrens free(dependents[i]); 3186fa9e4066Sahrens free(dependents); 3187fa9e4066Sahrens 3188fa9e4066Sahrens return (ret); 3189fa9e4066Sahrens } 3190fa9e4066Sahrens 3191fa9e4066Sahrens /* 3192fa9e4066Sahrens * Renames the given dataset. 3193fa9e4066Sahrens */ 3194fa9e4066Sahrens int 3195*cdf5b4caSmmusante zfs_rename(zfs_handle_t *zhp, const char *target, int recursive) 3196fa9e4066Sahrens { 3197fa9e4066Sahrens int ret; 3198fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3199fa9e4066Sahrens char *delim; 3200*cdf5b4caSmmusante prop_changelist_t *cl = NULL; 3201*cdf5b4caSmmusante zfs_handle_t *zhrp = NULL; 3202*cdf5b4caSmmusante char *parentname = NULL; 3203fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 320499653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 320599653d4eSeschrock char errbuf[1024]; 3206fa9e4066Sahrens 3207fa9e4066Sahrens /* if we have the same exact name, just return success */ 3208fa9e4066Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3209fa9e4066Sahrens return (0); 3210fa9e4066Sahrens 321199653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 321299653d4eSeschrock "cannot rename to '%s'"), target); 321399653d4eSeschrock 3214fa9e4066Sahrens /* 3215fa9e4066Sahrens * Make sure the target name is valid 3216fa9e4066Sahrens */ 3217fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 321898579b20Snd if ((strchr(target, '@') == NULL) || 321998579b20Snd *target == '@') { 322098579b20Snd /* 322198579b20Snd * Snapshot target name is abbreviated, 322298579b20Snd * reconstruct full dataset name 322398579b20Snd */ 322498579b20Snd (void) strlcpy(parent, zhp->zfs_name, 322598579b20Snd sizeof (parent)); 322698579b20Snd delim = strchr(parent, '@'); 322798579b20Snd if (strchr(target, '@') == NULL) 322898579b20Snd *(++delim) = '\0'; 322998579b20Snd else 323098579b20Snd *delim = '\0'; 323198579b20Snd (void) strlcat(parent, target, sizeof (parent)); 323298579b20Snd target = parent; 323398579b20Snd } else { 323498579b20Snd /* 323598579b20Snd * Make sure we're renaming within the same dataset. 323698579b20Snd */ 323798579b20Snd delim = strchr(target, '@'); 323898579b20Snd if (strncmp(zhp->zfs_name, target, delim - target) 323998579b20Snd != 0 || zhp->zfs_name[delim - target] != '@') { 324098579b20Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 324198579b20Snd "snapshots must be part of same " 324298579b20Snd "dataset")); 324398579b20Snd return (zfs_error(hdl, EZFS_CROSSTARGET, 3244b1b8ab34Slling errbuf)); 324598579b20Snd } 3246fa9e4066Sahrens } 324798579b20Snd if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 324898579b20Snd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3249fa9e4066Sahrens } else { 3250*cdf5b4caSmmusante if (recursive) { 3251*cdf5b4caSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3252*cdf5b4caSmmusante "recursive rename must be a snapshot")); 3253*cdf5b4caSmmusante return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3254*cdf5b4caSmmusante } 3255*cdf5b4caSmmusante 325698579b20Snd if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 325798579b20Snd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3258e9dbad6fSeschrock uint64_t unused; 3259e9dbad6fSeschrock 3260fa9e4066Sahrens /* validate parents */ 3261e9dbad6fSeschrock if (check_parents(hdl, target, &unused) != 0) 3262fa9e4066Sahrens return (-1); 3263fa9e4066Sahrens 3264fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 3265fa9e4066Sahrens 3266fa9e4066Sahrens /* make sure we're in the same pool */ 3267fa9e4066Sahrens verify((delim = strchr(target, '/')) != NULL); 3268fa9e4066Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3269fa9e4066Sahrens zhp->zfs_name[delim - target] != '/') { 327099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 327199653d4eSeschrock "datasets must be within same pool")); 327299653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3273fa9e4066Sahrens } 3274f2fdf992Snd 3275f2fdf992Snd /* new name cannot be a child of the current dataset name */ 3276f2fdf992Snd if (strncmp(parent, zhp->zfs_name, 3277b1b8ab34Slling strlen(zhp->zfs_name)) == 0) { 3278f2fdf992Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3279f2fdf992Snd "New dataset name cannot be a descendent of " 3280f2fdf992Snd "current dataset name")); 3281f2fdf992Snd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3282f2fdf992Snd } 3283fa9e4066Sahrens } 3284fa9e4066Sahrens 328599653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 328699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 328799653d4eSeschrock 3288fa9e4066Sahrens if (getzoneid() == GLOBAL_ZONEID && 3289fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 329099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 329199653d4eSeschrock "dataset is used in a non-global zone")); 329299653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3293fa9e4066Sahrens } 3294fa9e4066Sahrens 3295*cdf5b4caSmmusante if (recursive) { 3296*cdf5b4caSmmusante struct destroydata dd; 3297fa9e4066Sahrens 3298*cdf5b4caSmmusante parentname = strdup(zhp->zfs_name); 3299*cdf5b4caSmmusante delim = strchr(parentname, '@'); 3300*cdf5b4caSmmusante *delim = '\0'; 3301*cdf5b4caSmmusante zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY); 3302*cdf5b4caSmmusante if (zhrp == NULL) { 3303*cdf5b4caSmmusante return (-1); 3304*cdf5b4caSmmusante } 3305fa9e4066Sahrens 3306*cdf5b4caSmmusante dd.snapname = delim + 1; 3307*cdf5b4caSmmusante dd.gotone = B_FALSE; 3308*cdf5b4caSmmusante dd.closezhp = B_FALSE; 3309*cdf5b4caSmmusante 3310*cdf5b4caSmmusante /* We remove any zvol links prior to renaming them */ 3311*cdf5b4caSmmusante ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3312*cdf5b4caSmmusante if (ret) { 3313*cdf5b4caSmmusante goto error; 3314*cdf5b4caSmmusante } 3315*cdf5b4caSmmusante } else { 3316*cdf5b4caSmmusante if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 3317*cdf5b4caSmmusante return (-1); 3318*cdf5b4caSmmusante 3319*cdf5b4caSmmusante if (changelist_haszonedchild(cl)) { 3320*cdf5b4caSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3321*cdf5b4caSmmusante "child dataset with inherited mountpoint is used " 3322*cdf5b4caSmmusante "in a non-global zone")); 3323*cdf5b4caSmmusante (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3324*cdf5b4caSmmusante goto error; 3325*cdf5b4caSmmusante } 3326*cdf5b4caSmmusante 3327*cdf5b4caSmmusante if ((ret = changelist_prefix(cl)) != 0) 3328*cdf5b4caSmmusante goto error; 3329*cdf5b4caSmmusante } 3330fa9e4066Sahrens 3331e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) 3332fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3333fa9e4066Sahrens else 3334fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3335fa9e4066Sahrens 333698579b20Snd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3337e9dbad6fSeschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 333898579b20Snd 3339*cdf5b4caSmmusante zc.zc_cookie = recursive; 3340*cdf5b4caSmmusante 334199653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 3342*cdf5b4caSmmusante /* 3343*cdf5b4caSmmusante * if it was recursive, the one that actually failed will 3344*cdf5b4caSmmusante * be in zc.zc_name 3345*cdf5b4caSmmusante */ 3346*cdf5b4caSmmusante (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3347*cdf5b4caSmmusante "cannot rename to '%s'"), zc.zc_name); 3348*cdf5b4caSmmusante 3349*cdf5b4caSmmusante if (recursive && errno == EEXIST) { 3350*cdf5b4caSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3351*cdf5b4caSmmusante "a child dataset already has a snapshot " 3352*cdf5b4caSmmusante "with the new name")); 3353*cdf5b4caSmmusante (void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf); 3354*cdf5b4caSmmusante } else { 3355*cdf5b4caSmmusante (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3356*cdf5b4caSmmusante } 3357fa9e4066Sahrens 3358fa9e4066Sahrens /* 3359fa9e4066Sahrens * On failure, we still want to remount any filesystems that 3360fa9e4066Sahrens * were previously mounted, so we don't alter the system state. 3361fa9e4066Sahrens */ 3362*cdf5b4caSmmusante if (recursive) { 3363*cdf5b4caSmmusante struct createdata cd; 3364*cdf5b4caSmmusante 3365*cdf5b4caSmmusante /* only create links for datasets that had existed */ 3366*cdf5b4caSmmusante cd.cd_snapname = delim + 1; 3367*cdf5b4caSmmusante cd.cd_ifexists = B_TRUE; 3368*cdf5b4caSmmusante (void) zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3369*cdf5b4caSmmusante &cd); 3370*cdf5b4caSmmusante } else { 3371*cdf5b4caSmmusante (void) changelist_postfix(cl); 3372*cdf5b4caSmmusante } 3373fa9e4066Sahrens } else { 3374*cdf5b4caSmmusante if (recursive) { 3375*cdf5b4caSmmusante struct createdata cd; 3376*cdf5b4caSmmusante 3377*cdf5b4caSmmusante /* only create links for datasets that had existed */ 3378*cdf5b4caSmmusante cd.cd_snapname = strchr(target, '@') + 1; 3379*cdf5b4caSmmusante cd.cd_ifexists = B_TRUE; 3380*cdf5b4caSmmusante ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb, 3381*cdf5b4caSmmusante &cd); 3382*cdf5b4caSmmusante } else { 3383*cdf5b4caSmmusante changelist_rename(cl, zfs_get_name(zhp), target); 3384*cdf5b4caSmmusante ret = changelist_postfix(cl); 3385*cdf5b4caSmmusante } 3386fa9e4066Sahrens } 3387fa9e4066Sahrens 3388fa9e4066Sahrens error: 3389*cdf5b4caSmmusante if (parentname) { 3390*cdf5b4caSmmusante free(parentname); 3391*cdf5b4caSmmusante } 3392*cdf5b4caSmmusante if (zhrp) { 3393*cdf5b4caSmmusante zfs_close(zhrp); 3394*cdf5b4caSmmusante } 3395*cdf5b4caSmmusante if (cl) { 3396*cdf5b4caSmmusante changelist_free(cl); 3397*cdf5b4caSmmusante } 3398fa9e4066Sahrens return (ret); 3399fa9e4066Sahrens } 3400fa9e4066Sahrens 3401fa9e4066Sahrens /* 3402fa9e4066Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3403fa9e4066Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3404fa9e4066Sahrens */ 3405fa9e4066Sahrens int 340699653d4eSeschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3407*cdf5b4caSmmusante { 3408*cdf5b4caSmmusante return (zvol_create_link_common(hdl, dataset, B_FALSE)); 3409*cdf5b4caSmmusante } 3410*cdf5b4caSmmusante 3411*cdf5b4caSmmusante static int 3412*cdf5b4caSmmusante zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3413fa9e4066Sahrens { 3414fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 341599653d4eSeschrock di_devlink_handle_t dhdl; 3416fa9e4066Sahrens 3417fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3418fa9e4066Sahrens 3419fa9e4066Sahrens /* 3420fa9e4066Sahrens * Issue the appropriate ioctl. 3421fa9e4066Sahrens */ 342299653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3423fa9e4066Sahrens switch (errno) { 3424fa9e4066Sahrens case EEXIST: 3425fa9e4066Sahrens /* 3426fa9e4066Sahrens * Silently ignore the case where the link already 3427fa9e4066Sahrens * exists. This allows 'zfs volinit' to be run multiple 3428fa9e4066Sahrens * times without errors. 3429fa9e4066Sahrens */ 3430fa9e4066Sahrens return (0); 3431fa9e4066Sahrens 3432*cdf5b4caSmmusante case ENOENT: 3433*cdf5b4caSmmusante /* 3434*cdf5b4caSmmusante * Dataset does not exist in the kernel. If we 3435*cdf5b4caSmmusante * don't care (see zfs_rename), then ignore the 3436*cdf5b4caSmmusante * error quietly. 3437*cdf5b4caSmmusante */ 3438*cdf5b4caSmmusante if (ifexists) { 3439*cdf5b4caSmmusante return (0); 3440*cdf5b4caSmmusante } 3441*cdf5b4caSmmusante 3442*cdf5b4caSmmusante /* FALLTHROUGH */ 3443*cdf5b4caSmmusante 3444fa9e4066Sahrens default: 3445ece3d9b3Slling return (zfs_standard_error_fmt(hdl, errno, 344699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 344799653d4eSeschrock "for '%s'"), dataset)); 3448fa9e4066Sahrens } 3449fa9e4066Sahrens } 3450fa9e4066Sahrens 3451fa9e4066Sahrens /* 3452fa9e4066Sahrens * Call devfsadm and wait for the links to magically appear. 3453fa9e4066Sahrens */ 345499653d4eSeschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 345599653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 3456ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 345799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 345899653d4eSeschrock "for '%s'"), dataset); 345999653d4eSeschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3460fa9e4066Sahrens return (-1); 3461fa9e4066Sahrens } else { 346299653d4eSeschrock (void) di_devlink_fini(&dhdl); 3463fa9e4066Sahrens } 3464fa9e4066Sahrens 3465fa9e4066Sahrens return (0); 3466fa9e4066Sahrens } 3467fa9e4066Sahrens 3468fa9e4066Sahrens /* 3469fa9e4066Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3470fa9e4066Sahrens */ 3471fa9e4066Sahrens int 347299653d4eSeschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3473fa9e4066Sahrens { 3474fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3475fa9e4066Sahrens 3476fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3477fa9e4066Sahrens 347899653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3479fa9e4066Sahrens switch (errno) { 3480fa9e4066Sahrens case ENXIO: 3481fa9e4066Sahrens /* 3482fa9e4066Sahrens * Silently ignore the case where the link no longer 3483fa9e4066Sahrens * exists, so that 'zfs volfini' can be run multiple 3484fa9e4066Sahrens * times without errors. 3485fa9e4066Sahrens */ 3486fa9e4066Sahrens return (0); 3487fa9e4066Sahrens 3488fa9e4066Sahrens default: 3489ece3d9b3Slling return (zfs_standard_error_fmt(hdl, errno, 349099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove device " 349199653d4eSeschrock "links for '%s'"), dataset)); 3492fa9e4066Sahrens } 3493fa9e4066Sahrens } 3494fa9e4066Sahrens 3495fa9e4066Sahrens return (0); 3496fa9e4066Sahrens } 3497e9dbad6fSeschrock 3498e9dbad6fSeschrock nvlist_t * 3499e9dbad6fSeschrock zfs_get_user_props(zfs_handle_t *zhp) 3500e9dbad6fSeschrock { 3501e9dbad6fSeschrock return (zhp->zfs_user_props); 3502e9dbad6fSeschrock } 3503e9dbad6fSeschrock 3504e9dbad6fSeschrock /* 3505e9dbad6fSeschrock * Given a comma-separated list of properties, contruct a property list 3506e9dbad6fSeschrock * containing both user-defined and native properties. This function will 3507e9dbad6fSeschrock * return a NULL list if 'all' is specified, which can later be expanded on a 3508e9dbad6fSeschrock * per-dataset basis by zfs_expand_proplist(). 3509e9dbad6fSeschrock */ 3510e9dbad6fSeschrock int 3511b1b8ab34Slling zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields, 3512b1b8ab34Slling zfs_proplist_t **listp, zfs_type_t type) 3513e9dbad6fSeschrock { 3514e9dbad6fSeschrock size_t len; 3515e9dbad6fSeschrock char *s, *p; 3516e9dbad6fSeschrock char c; 3517e9dbad6fSeschrock zfs_prop_t prop; 3518e9dbad6fSeschrock zfs_proplist_t *entry; 3519e9dbad6fSeschrock zfs_proplist_t **last; 3520e9dbad6fSeschrock 3521e9dbad6fSeschrock *listp = NULL; 3522e9dbad6fSeschrock last = listp; 3523e9dbad6fSeschrock 3524e9dbad6fSeschrock /* 3525e9dbad6fSeschrock * If 'all' is specified, return a NULL list. 3526e9dbad6fSeschrock */ 3527e9dbad6fSeschrock if (strcmp(fields, "all") == 0) 3528e9dbad6fSeschrock return (0); 3529e9dbad6fSeschrock 3530e9dbad6fSeschrock /* 3531e9dbad6fSeschrock * If no fields were specified, return an error. 3532e9dbad6fSeschrock */ 3533e9dbad6fSeschrock if (fields[0] == '\0') { 3534e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3535e9dbad6fSeschrock "no properties specified")); 3536e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 3537e9dbad6fSeschrock "bad property list"))); 3538e9dbad6fSeschrock } 3539e9dbad6fSeschrock 3540e9dbad6fSeschrock /* 3541e9dbad6fSeschrock * It would be nice to use getsubopt() here, but the inclusion of column 3542e9dbad6fSeschrock * aliases makes this more effort than it's worth. 3543e9dbad6fSeschrock */ 3544e9dbad6fSeschrock s = fields; 3545e9dbad6fSeschrock while (*s != '\0') { 3546e9dbad6fSeschrock if ((p = strchr(s, ',')) == NULL) { 3547e9dbad6fSeschrock len = strlen(s); 3548e9dbad6fSeschrock p = s + len; 3549e9dbad6fSeschrock } else { 3550e9dbad6fSeschrock len = p - s; 3551e9dbad6fSeschrock } 3552e9dbad6fSeschrock 3553e9dbad6fSeschrock /* 3554e9dbad6fSeschrock * Check for empty options. 3555e9dbad6fSeschrock */ 3556e9dbad6fSeschrock if (len == 0) { 3557e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3558e9dbad6fSeschrock "empty property name")); 3559e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, 3560e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "bad property list"))); 3561e9dbad6fSeschrock } 3562e9dbad6fSeschrock 3563e9dbad6fSeschrock /* 3564e9dbad6fSeschrock * Check all regular property names. 3565e9dbad6fSeschrock */ 3566e9dbad6fSeschrock c = s[len]; 3567e9dbad6fSeschrock s[len] = '\0'; 3568b1b8ab34Slling prop = zfs_name_to_prop_common(s, type); 3569b1b8ab34Slling 3570b1b8ab34Slling if (prop != ZFS_PROP_INVAL && 3571b1b8ab34Slling !zfs_prop_valid_for_type(prop, type)) 3572b1b8ab34Slling prop = ZFS_PROP_INVAL; 3573e9dbad6fSeschrock 3574e9dbad6fSeschrock /* 3575b1b8ab34Slling * When no property table entry can be found, return failure if 3576b1b8ab34Slling * this is a pool property or if this isn't a user-defined 3577b1b8ab34Slling * dataset property, 3578e9dbad6fSeschrock */ 3579b1b8ab34Slling if (prop == ZFS_PROP_INVAL && 3580b1b8ab34Slling (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) { 3581e9dbad6fSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3582e9dbad6fSeschrock "invalid property '%s'"), s); 3583e9dbad6fSeschrock return (zfs_error(hdl, EZFS_BADPROP, 3584e9dbad6fSeschrock dgettext(TEXT_DOMAIN, "bad property list"))); 3585e9dbad6fSeschrock } 3586e9dbad6fSeschrock 3587e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 3588e9dbad6fSeschrock return (-1); 3589e9dbad6fSeschrock 3590e9dbad6fSeschrock entry->pl_prop = prop; 3591e9dbad6fSeschrock if (prop == ZFS_PROP_INVAL) { 3592e9dbad6fSeschrock if ((entry->pl_user_prop = 3593e9dbad6fSeschrock zfs_strdup(hdl, s)) == NULL) { 3594e9dbad6fSeschrock free(entry); 3595e9dbad6fSeschrock return (-1); 3596e9dbad6fSeschrock } 3597e9dbad6fSeschrock entry->pl_width = strlen(s); 3598e9dbad6fSeschrock } else { 3599e9dbad6fSeschrock entry->pl_width = zfs_prop_width(prop, 3600e9dbad6fSeschrock &entry->pl_fixed); 3601e9dbad6fSeschrock } 3602e9dbad6fSeschrock 3603e9dbad6fSeschrock *last = entry; 3604e9dbad6fSeschrock last = &entry->pl_next; 3605e9dbad6fSeschrock 3606e9dbad6fSeschrock s = p; 3607e9dbad6fSeschrock if (c == ',') 3608e9dbad6fSeschrock s++; 3609e9dbad6fSeschrock } 3610e9dbad6fSeschrock 3611e9dbad6fSeschrock return (0); 3612e9dbad6fSeschrock } 3613e9dbad6fSeschrock 3614b1b8ab34Slling int 3615b1b8ab34Slling zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 3616b1b8ab34Slling { 3617b1b8ab34Slling return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY)); 3618b1b8ab34Slling } 3619b1b8ab34Slling 3620e9dbad6fSeschrock void 3621e9dbad6fSeschrock zfs_free_proplist(zfs_proplist_t *pl) 3622e9dbad6fSeschrock { 3623e9dbad6fSeschrock zfs_proplist_t *next; 3624e9dbad6fSeschrock 3625e9dbad6fSeschrock while (pl != NULL) { 3626e9dbad6fSeschrock next = pl->pl_next; 3627e9dbad6fSeschrock free(pl->pl_user_prop); 3628e9dbad6fSeschrock free(pl); 3629e9dbad6fSeschrock pl = next; 3630e9dbad6fSeschrock } 3631e9dbad6fSeschrock } 3632e9dbad6fSeschrock 363366e2aaccSgw typedef struct expand_data { 363466e2aaccSgw zfs_proplist_t **last; 363566e2aaccSgw libzfs_handle_t *hdl; 363666e2aaccSgw } expand_data_t; 363766e2aaccSgw 363866e2aaccSgw static zfs_prop_t 363966e2aaccSgw zfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 364066e2aaccSgw { 364166e2aaccSgw zfs_proplist_t *entry; 364266e2aaccSgw expand_data_t *edp = cb; 364366e2aaccSgw 364466e2aaccSgw if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 364566e2aaccSgw return (ZFS_PROP_INVAL); 364666e2aaccSgw 364766e2aaccSgw entry->pl_prop = prop; 364866e2aaccSgw entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 364966e2aaccSgw entry->pl_all = B_TRUE; 365066e2aaccSgw 365166e2aaccSgw *(edp->last) = entry; 365266e2aaccSgw edp->last = &entry->pl_next; 365366e2aaccSgw 365466e2aaccSgw return (ZFS_PROP_CONT); 365566e2aaccSgw } 365666e2aaccSgw 3657e9dbad6fSeschrock int 3658b1b8ab34Slling zfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp, 3659b1b8ab34Slling zfs_type_t type) 3660e9dbad6fSeschrock { 3661e9dbad6fSeschrock zfs_proplist_t *entry; 3662b1b8ab34Slling zfs_proplist_t **last; 366366e2aaccSgw expand_data_t exp; 3664e9dbad6fSeschrock 3665e9dbad6fSeschrock if (*plp == NULL) { 3666e9dbad6fSeschrock /* 3667e9dbad6fSeschrock * If this is the very first time we've been called for an 'all' 3668e9dbad6fSeschrock * specification, expand the list to include all native 3669e9dbad6fSeschrock * properties. 3670e9dbad6fSeschrock */ 3671e9dbad6fSeschrock last = plp; 3672e9dbad6fSeschrock 367366e2aaccSgw exp.last = last; 367466e2aaccSgw exp.hdl = hdl; 3675e9dbad6fSeschrock 3676b1b8ab34Slling if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type, 367766e2aaccSgw B_FALSE) == ZFS_PROP_INVAL) 367866e2aaccSgw return (-1); 3679e9dbad6fSeschrock 3680e9dbad6fSeschrock /* 3681e9dbad6fSeschrock * Add 'name' to the beginning of the list, which is handled 3682e9dbad6fSeschrock * specially. 3683e9dbad6fSeschrock */ 3684e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, 3685e9dbad6fSeschrock sizeof (zfs_proplist_t))) == NULL) 3686e9dbad6fSeschrock return (-1); 3687e9dbad6fSeschrock 3688e9dbad6fSeschrock entry->pl_prop = ZFS_PROP_NAME; 3689e9dbad6fSeschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 3690e9dbad6fSeschrock &entry->pl_fixed); 3691e9dbad6fSeschrock entry->pl_all = B_TRUE; 3692e9dbad6fSeschrock entry->pl_next = *plp; 3693e9dbad6fSeschrock *plp = entry; 3694e9dbad6fSeschrock } 3695b1b8ab34Slling return (0); 3696b1b8ab34Slling } 3697b1b8ab34Slling 3698b1b8ab34Slling /* 3699b1b8ab34Slling * This function is used by 'zfs list' to determine the exact set of columns to 3700b1b8ab34Slling * display, and their maximum widths. This does two main things: 3701b1b8ab34Slling * 3702b1b8ab34Slling * - If this is a list of all properties, then expand the list to include 3703b1b8ab34Slling * all native properties, and set a flag so that for each dataset we look 3704b1b8ab34Slling * for new unique user properties and add them to the list. 3705b1b8ab34Slling * 3706b1b8ab34Slling * - For non fixed-width properties, keep track of the maximum width seen 3707b1b8ab34Slling * so that we can size the column appropriately. 3708b1b8ab34Slling */ 3709b1b8ab34Slling int 3710b1b8ab34Slling zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 3711b1b8ab34Slling { 3712b1b8ab34Slling libzfs_handle_t *hdl = zhp->zfs_hdl; 3713b1b8ab34Slling zfs_proplist_t *entry; 3714b1b8ab34Slling zfs_proplist_t **last, **start; 3715b1b8ab34Slling nvlist_t *userprops, *propval; 3716b1b8ab34Slling nvpair_t *elem; 3717b1b8ab34Slling char *strval; 3718b1b8ab34Slling char buf[ZFS_MAXPROPLEN]; 3719b1b8ab34Slling 3720b1b8ab34Slling if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0) 3721b1b8ab34Slling return (-1); 3722e9dbad6fSeschrock 3723e9dbad6fSeschrock userprops = zfs_get_user_props(zhp); 3724e9dbad6fSeschrock 3725e9dbad6fSeschrock entry = *plp; 3726e9dbad6fSeschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3727e9dbad6fSeschrock /* 3728e9dbad6fSeschrock * Go through and add any user properties as necessary. We 3729e9dbad6fSeschrock * start by incrementing our list pointer to the first 3730e9dbad6fSeschrock * non-native property. 3731e9dbad6fSeschrock */ 3732e9dbad6fSeschrock start = plp; 3733e9dbad6fSeschrock while (*start != NULL) { 3734e9dbad6fSeschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 3735e9dbad6fSeschrock break; 3736e9dbad6fSeschrock start = &(*start)->pl_next; 3737e9dbad6fSeschrock } 3738e9dbad6fSeschrock 3739e9dbad6fSeschrock elem = NULL; 3740e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3741e9dbad6fSeschrock /* 3742e9dbad6fSeschrock * See if we've already found this property in our list. 3743e9dbad6fSeschrock */ 3744e9dbad6fSeschrock for (last = start; *last != NULL; 3745e9dbad6fSeschrock last = &(*last)->pl_next) { 3746e9dbad6fSeschrock if (strcmp((*last)->pl_user_prop, 3747e9dbad6fSeschrock nvpair_name(elem)) == 0) 3748e9dbad6fSeschrock break; 3749e9dbad6fSeschrock } 3750e9dbad6fSeschrock 3751e9dbad6fSeschrock if (*last == NULL) { 3752e9dbad6fSeschrock if ((entry = zfs_alloc(hdl, 3753e9dbad6fSeschrock sizeof (zfs_proplist_t))) == NULL || 3754e9dbad6fSeschrock ((entry->pl_user_prop = zfs_strdup(hdl, 3755e9dbad6fSeschrock nvpair_name(elem)))) == NULL) { 3756e9dbad6fSeschrock free(entry); 3757e9dbad6fSeschrock return (-1); 3758e9dbad6fSeschrock } 3759e9dbad6fSeschrock 3760e9dbad6fSeschrock entry->pl_prop = ZFS_PROP_INVAL; 3761e9dbad6fSeschrock entry->pl_width = strlen(nvpair_name(elem)); 3762e9dbad6fSeschrock entry->pl_all = B_TRUE; 3763e9dbad6fSeschrock *last = entry; 3764e9dbad6fSeschrock } 3765e9dbad6fSeschrock } 3766e9dbad6fSeschrock } 3767e9dbad6fSeschrock 3768e9dbad6fSeschrock /* 3769e9dbad6fSeschrock * Now go through and check the width of any non-fixed columns 3770e9dbad6fSeschrock */ 3771e9dbad6fSeschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3772e9dbad6fSeschrock if (entry->pl_fixed) 3773e9dbad6fSeschrock continue; 3774e9dbad6fSeschrock 3775e9dbad6fSeschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 3776e9dbad6fSeschrock if (zfs_prop_get(zhp, entry->pl_prop, 3777e9dbad6fSeschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3778e9dbad6fSeschrock if (strlen(buf) > entry->pl_width) 3779e9dbad6fSeschrock entry->pl_width = strlen(buf); 3780e9dbad6fSeschrock } 3781e9dbad6fSeschrock } else if (nvlist_lookup_nvlist(userprops, 3782e9dbad6fSeschrock entry->pl_user_prop, &propval) == 0) { 3783e9dbad6fSeschrock verify(nvlist_lookup_string(propval, 3784e9dbad6fSeschrock ZFS_PROP_VALUE, &strval) == 0); 3785e9dbad6fSeschrock if (strlen(strval) > entry->pl_width) 3786e9dbad6fSeschrock entry->pl_width = strlen(strval); 3787e9dbad6fSeschrock } 3788e9dbad6fSeschrock } 3789e9dbad6fSeschrock 3790e9dbad6fSeschrock return (0); 3791e9dbad6fSeschrock } 3792