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 */ 21fa9e4066Sahrens /* 22b12a1c38Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <assert.h> 29fa9e4066Sahrens #include <ctype.h> 30fa9e4066Sahrens #include <errno.h> 31fa9e4066Sahrens #include <libdevinfo.h> 32fa9e4066Sahrens #include <libintl.h> 33fa9e4066Sahrens #include <math.h> 34fa9e4066Sahrens #include <stdio.h> 35fa9e4066Sahrens #include <stdlib.h> 36fa9e4066Sahrens #include <strings.h> 37fa9e4066Sahrens #include <unistd.h> 38fa9e4066Sahrens #include <zone.h> 39*99653d4eSeschrock #include <fcntl.h> 40fa9e4066Sahrens #include <sys/mntent.h> 41fa9e4066Sahrens #include <sys/mnttab.h> 42b12a1c38Slling #include <sys/mount.h> 43fa9e4066Sahrens 44fa9e4066Sahrens #include <sys/spa.h> 45fa9e4066Sahrens #include <sys/zio.h> 46fa9e4066Sahrens #include <libzfs.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include "zfs_namecheck.h" 49fa9e4066Sahrens #include "zfs_prop.h" 50fa9e4066Sahrens #include "libzfs_impl.h" 51fa9e4066Sahrens 52fa9e4066Sahrens /* 53fa9e4066Sahrens * Given a single type (not a mask of types), return the type in a human 54fa9e4066Sahrens * readable form. 55fa9e4066Sahrens */ 56fa9e4066Sahrens const char * 57fa9e4066Sahrens zfs_type_to_name(zfs_type_t type) 58fa9e4066Sahrens { 59fa9e4066Sahrens switch (type) { 60fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 61fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 62fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 63fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 64fa9e4066Sahrens case ZFS_TYPE_VOLUME: 65fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 66fa9e4066Sahrens } 67fa9e4066Sahrens 68fa9e4066Sahrens return (NULL); 69fa9e4066Sahrens } 70fa9e4066Sahrens 71fa9e4066Sahrens /* 72fa9e4066Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 73fa9e4066Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 74fa9e4066Sahrens * We guess what the type would have been based on the path and the mask of 75fa9e4066Sahrens * acceptable types. 76fa9e4066Sahrens */ 77fa9e4066Sahrens static const char * 78fa9e4066Sahrens path_to_str(const char *path, int types) 79fa9e4066Sahrens { 80fa9e4066Sahrens /* 81fa9e4066Sahrens * When given a single type, always report the exact type. 82fa9e4066Sahrens */ 83fa9e4066Sahrens if (types == ZFS_TYPE_SNAPSHOT) 84fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 85fa9e4066Sahrens if (types == ZFS_TYPE_FILESYSTEM) 86fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 87fa9e4066Sahrens if (types == ZFS_TYPE_VOLUME) 88fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 89fa9e4066Sahrens 90fa9e4066Sahrens /* 91fa9e4066Sahrens * The user is requesting more than one type of dataset. If this is the 92fa9e4066Sahrens * case, consult the path itself. If we're looking for a snapshot, and 93fa9e4066Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 94fa9e4066Sahrens * snapshot attribute and try again. 95fa9e4066Sahrens */ 96fa9e4066Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 97fa9e4066Sahrens if (strchr(path, '@') != NULL) 98fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 99fa9e4066Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 100fa9e4066Sahrens } 101fa9e4066Sahrens 102fa9e4066Sahrens 103fa9e4066Sahrens /* 104fa9e4066Sahrens * The user has requested either filesystems or volumes. 105fa9e4066Sahrens * We have no way of knowing a priori what type this would be, so always 106fa9e4066Sahrens * report it as "filesystem" or "volume", our two primitive types. 107fa9e4066Sahrens */ 108fa9e4066Sahrens if (types & ZFS_TYPE_FILESYSTEM) 109fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 110fa9e4066Sahrens 111fa9e4066Sahrens assert(types & ZFS_TYPE_VOLUME); 112fa9e4066Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 113fa9e4066Sahrens } 114fa9e4066Sahrens 115fa9e4066Sahrens /* 116fa9e4066Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 117fa9e4066Sahrens * provide a more meaningful error message. We place a more useful message in 118fa9e4066Sahrens * 'buf' detailing exactly why the name was not valid. 119fa9e4066Sahrens */ 120fa9e4066Sahrens static int 121*99653d4eSeschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 122fa9e4066Sahrens { 123fa9e4066Sahrens namecheck_err_t why; 124fa9e4066Sahrens char what; 125fa9e4066Sahrens 126fa9e4066Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 127*99653d4eSeschrock if (hdl != NULL) { 128fa9e4066Sahrens switch (why) { 129b81d61a6Slling case NAME_ERR_TOOLONG: 130*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 131*99653d4eSeschrock "name is too long")); 132b81d61a6Slling break; 133b81d61a6Slling 134fa9e4066Sahrens case NAME_ERR_LEADING_SLASH: 135*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 136*99653d4eSeschrock "leading slash in name")); 137fa9e4066Sahrens break; 138fa9e4066Sahrens 139fa9e4066Sahrens case NAME_ERR_EMPTY_COMPONENT: 140*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 141*99653d4eSeschrock "empty component in name")); 142fa9e4066Sahrens break; 143fa9e4066Sahrens 144fa9e4066Sahrens case NAME_ERR_TRAILING_SLASH: 145*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 146*99653d4eSeschrock "trailing slash in name")); 147fa9e4066Sahrens break; 148fa9e4066Sahrens 149fa9e4066Sahrens case NAME_ERR_INVALCHAR: 150*99653d4eSeschrock zfs_error_aux(hdl, 151fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 152*99653d4eSeschrock "'%c' in name"), what); 153fa9e4066Sahrens break; 154fa9e4066Sahrens 155fa9e4066Sahrens case NAME_ERR_MULTIPLE_AT: 156*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 157*99653d4eSeschrock "multiple '@' delimiters in name")); 158fa9e4066Sahrens break; 159fa9e4066Sahrens } 160fa9e4066Sahrens } 161fa9e4066Sahrens 162fa9e4066Sahrens return (0); 163fa9e4066Sahrens } 164fa9e4066Sahrens 165fa9e4066Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 166*99653d4eSeschrock if (hdl != NULL) 167*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 168*99653d4eSeschrock "snapshot delimiter '@' in filesystem name")); 169fa9e4066Sahrens return (0); 170fa9e4066Sahrens } 171fa9e4066Sahrens 172*99653d4eSeschrock return (-1); 173fa9e4066Sahrens } 174fa9e4066Sahrens 175fa9e4066Sahrens int 176fa9e4066Sahrens zfs_name_valid(const char *name, zfs_type_t type) 177fa9e4066Sahrens { 178*99653d4eSeschrock return (zfs_validate_name(NULL, name, type)); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens /* 182fa9e4066Sahrens * Utility function to gather stats (objset and zpl) for the given object. 183fa9e4066Sahrens */ 184fa9e4066Sahrens static int 185fa9e4066Sahrens get_stats(zfs_handle_t *zhp) 186fa9e4066Sahrens { 187fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 188fa9e4066Sahrens 189fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 190fa9e4066Sahrens 191*99653d4eSeschrock if ((zc.zc_config_src = (uint64_t)(uintptr_t)malloc(1024)) == NULL) 192*99653d4eSeschrock return (-1); 1937f7322feSeschrock zc.zc_config_src_size = 1024; 1947f7322feSeschrock 195*99653d4eSeschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 1967f7322feSeschrock if (errno == ENOMEM) { 197*99653d4eSeschrock free((void *)(uintptr_t)zc.zc_config_src); 198*99653d4eSeschrock if ((zc.zc_config_src = (uint64_t)(uintptr_t) 199*99653d4eSeschrock malloc(zc.zc_config_src_size)) == NULL) 200*99653d4eSeschrock return (-1); 2017f7322feSeschrock } else { 2027f7322feSeschrock free((void *)(uintptr_t)zc.zc_config_src); 2037f7322feSeschrock return (-1); 2047f7322feSeschrock } 2057f7322feSeschrock } 206fa9e4066Sahrens 207fa9e4066Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 208fa9e4066Sahrens sizeof (zc.zc_objset_stats)); 209fa9e4066Sahrens 210ea8dc4b6Seschrock (void) strcpy(zhp->zfs_root, zc.zc_root); 211ea8dc4b6Seschrock 212*99653d4eSeschrock if (zhp->zfs_props) { 213*99653d4eSeschrock nvlist_free(zhp->zfs_props); 214*99653d4eSeschrock zhp->zfs_props = NULL; 215*99653d4eSeschrock } 216*99653d4eSeschrock 217*99653d4eSeschrock if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_src, 218*99653d4eSeschrock zc.zc_config_src_size, &zhp->zfs_props, 0) != 0) { 219*99653d4eSeschrock free((void *)(uintptr_t)zc.zc_config_src); 220*99653d4eSeschrock return (-1); 221*99653d4eSeschrock } 222fa9e4066Sahrens 223fa9e4066Sahrens zhp->zfs_volsize = zc.zc_volsize; 224fa9e4066Sahrens zhp->zfs_volblocksize = zc.zc_volblocksize; 225fa9e4066Sahrens 226*99653d4eSeschrock free((void *)(uintptr_t)zc.zc_config_src); 227*99653d4eSeschrock 228fa9e4066Sahrens return (0); 229fa9e4066Sahrens } 230fa9e4066Sahrens 231fa9e4066Sahrens /* 232fa9e4066Sahrens * Refresh the properties currently stored in the handle. 233fa9e4066Sahrens */ 234fa9e4066Sahrens void 235fa9e4066Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 236fa9e4066Sahrens { 237fa9e4066Sahrens (void) get_stats(zhp); 238fa9e4066Sahrens } 239fa9e4066Sahrens 240fa9e4066Sahrens /* 241fa9e4066Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 242fa9e4066Sahrens * zfs_iter_* to create child handles on the fly. 243fa9e4066Sahrens */ 244fa9e4066Sahrens zfs_handle_t * 245*99653d4eSeschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 246fa9e4066Sahrens { 247*99653d4eSeschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 248*99653d4eSeschrock 249*99653d4eSeschrock if (zhp == NULL) 250*99653d4eSeschrock return (NULL); 251*99653d4eSeschrock 252*99653d4eSeschrock zhp->zfs_hdl = hdl; 253fa9e4066Sahrens 25431fd60d3Sahrens top: 255fa9e4066Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 256fa9e4066Sahrens 257fa9e4066Sahrens if (get_stats(zhp) != 0) { 258fa9e4066Sahrens free(zhp); 259fa9e4066Sahrens return (NULL); 260fa9e4066Sahrens } 261fa9e4066Sahrens 26231fd60d3Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 26331fd60d3Sahrens zfs_cmd_t zc = { 0 }; 26431fd60d3Sahrens 26531fd60d3Sahrens /* 26631fd60d3Sahrens * If it is dds_inconsistent, then we've caught it in 26731fd60d3Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 26831fd60d3Sahrens * it is inconsistent from the ZPL's point of view, so 26931fd60d3Sahrens * can't be mounted. However, it could also be that we 27031fd60d3Sahrens * have crashed in the middle of one of those 27131fd60d3Sahrens * operations, in which case we need to get rid of the 27231fd60d3Sahrens * inconsistent state. We do that by either rolling 27331fd60d3Sahrens * back to the previous snapshot (which will fail if 27431fd60d3Sahrens * there is none), or destroying the filesystem. Note 27531fd60d3Sahrens * that if we are still in the middle of an active 27631fd60d3Sahrens * 'receive' or 'destroy', then the rollback and destroy 27731fd60d3Sahrens * will fail with EBUSY and we will drive on as usual. 27831fd60d3Sahrens */ 27931fd60d3Sahrens 28031fd60d3Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 28131fd60d3Sahrens 28231fd60d3Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 283*99653d4eSeschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 28431fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 28531fd60d3Sahrens } else { 28631fd60d3Sahrens zc.zc_objset_type = DMU_OST_ZFS; 28731fd60d3Sahrens } 28831fd60d3Sahrens 28931fd60d3Sahrens /* If we can successfully roll it back, reget the stats */ 290*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 29131fd60d3Sahrens goto top; 29231fd60d3Sahrens /* 29331fd60d3Sahrens * If we can sucessfully destroy it, pretend that it 29431fd60d3Sahrens * never existed. 29531fd60d3Sahrens */ 296*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 29731fd60d3Sahrens free(zhp); 29831fd60d3Sahrens errno = ENOENT; 29931fd60d3Sahrens return (NULL); 30031fd60d3Sahrens } 30131fd60d3Sahrens } 30231fd60d3Sahrens 303fa9e4066Sahrens /* 304fa9e4066Sahrens * We've managed to open the dataset and gather statistics. Determine 305fa9e4066Sahrens * the high-level type. 306fa9e4066Sahrens */ 307fa9e4066Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 308fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 309fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 310fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 311fa9e4066Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 312fa9e4066Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 313fa9e4066Sahrens else 314*99653d4eSeschrock abort(); /* we should never see any other types */ 315fa9e4066Sahrens 316fa9e4066Sahrens return (zhp); 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens /* 320fa9e4066Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 321fa9e4066Sahrens * argument is a mask of acceptable types. The function will print an 322fa9e4066Sahrens * appropriate error message and return NULL if it can't be opened. 323fa9e4066Sahrens */ 324fa9e4066Sahrens zfs_handle_t * 325*99653d4eSeschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 326fa9e4066Sahrens { 327fa9e4066Sahrens zfs_handle_t *zhp; 328*99653d4eSeschrock char errbuf[1024]; 329*99653d4eSeschrock 330*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 331*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 332fa9e4066Sahrens 333fa9e4066Sahrens /* 334*99653d4eSeschrock * Validate the name before we even try to open it. 335fa9e4066Sahrens */ 336*99653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 337*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 338*99653d4eSeschrock "invalid dataset name")); 339*99653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 340fa9e4066Sahrens return (NULL); 341fa9e4066Sahrens } 342fa9e4066Sahrens 343fa9e4066Sahrens /* 344fa9e4066Sahrens * Try to get stats for the dataset, which will tell us if it exists. 345fa9e4066Sahrens */ 346fa9e4066Sahrens errno = 0; 347*99653d4eSeschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 348*99653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf, path); 349fa9e4066Sahrens return (NULL); 350fa9e4066Sahrens } 351fa9e4066Sahrens 352fa9e4066Sahrens if (!(types & zhp->zfs_type)) { 353*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 354fa9e4066Sahrens free(zhp); 355fa9e4066Sahrens return (NULL); 356fa9e4066Sahrens } 357fa9e4066Sahrens 358fa9e4066Sahrens return (zhp); 359fa9e4066Sahrens } 360fa9e4066Sahrens 361fa9e4066Sahrens /* 362fa9e4066Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 363fa9e4066Sahrens */ 364fa9e4066Sahrens void 365fa9e4066Sahrens zfs_close(zfs_handle_t *zhp) 366fa9e4066Sahrens { 367fa9e4066Sahrens if (zhp->zfs_mntopts) 368fa9e4066Sahrens free(zhp->zfs_mntopts); 369*99653d4eSeschrock if (zhp->zfs_props) 370*99653d4eSeschrock nvlist_free(zhp->zfs_props); 371fa9e4066Sahrens free(zhp); 372fa9e4066Sahrens } 373fa9e4066Sahrens 374fa9e4066Sahrens struct { 375fa9e4066Sahrens const char *name; 376fa9e4066Sahrens uint64_t value; 377fa9e4066Sahrens } checksum_table[] = { 378fa9e4066Sahrens { "on", ZIO_CHECKSUM_ON }, 379fa9e4066Sahrens { "off", ZIO_CHECKSUM_OFF }, 380fa9e4066Sahrens { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 }, 381fa9e4066Sahrens { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 }, 382fa9e4066Sahrens { "sha256", ZIO_CHECKSUM_SHA256 }, 383fa9e4066Sahrens { NULL } 384fa9e4066Sahrens }; 385fa9e4066Sahrens 386fa9e4066Sahrens struct { 387fa9e4066Sahrens const char *name; 388fa9e4066Sahrens uint64_t value; 389fa9e4066Sahrens } compress_table[] = { 390fa9e4066Sahrens { "on", ZIO_COMPRESS_ON }, 391fa9e4066Sahrens { "off", ZIO_COMPRESS_OFF }, 392fa9e4066Sahrens { "lzjb", ZIO_COMPRESS_LZJB }, 393fa9e4066Sahrens { NULL } 394fa9e4066Sahrens }; 395fa9e4066Sahrens 396fa9e4066Sahrens struct { 397fa9e4066Sahrens const char *name; 398fa9e4066Sahrens uint64_t value; 399fa9e4066Sahrens } snapdir_table[] = { 400a0965f35Sbonwick { "hidden", ZFS_SNAPDIR_HIDDEN }, 401a0965f35Sbonwick { "visible", ZFS_SNAPDIR_VISIBLE }, 402fa9e4066Sahrens { NULL } 403fa9e4066Sahrens }; 404fa9e4066Sahrens 405fa9e4066Sahrens struct { 406fa9e4066Sahrens const char *name; 407fa9e4066Sahrens uint64_t value; 408fa9e4066Sahrens } acl_mode_table[] = { 409fa9e4066Sahrens { "discard", DISCARD }, 410fa9e4066Sahrens { "groupmask", GROUPMASK }, 411fa9e4066Sahrens { "passthrough", PASSTHROUGH }, 412fa9e4066Sahrens { NULL } 413fa9e4066Sahrens }; 414fa9e4066Sahrens 415fa9e4066Sahrens struct { 416fa9e4066Sahrens const char *name; 417fa9e4066Sahrens uint64_t value; 418fa9e4066Sahrens } acl_inherit_table[] = { 419fa9e4066Sahrens { "discard", DISCARD }, 420fa9e4066Sahrens { "noallow", NOALLOW }, 421fa9e4066Sahrens { "secure", SECURE }, 422fa9e4066Sahrens { "passthrough", PASSTHROUGH }, 423fa9e4066Sahrens { NULL } 424fa9e4066Sahrens }; 425fa9e4066Sahrens 426fa9e4066Sahrens 427fa9e4066Sahrens /* 428fa9e4066Sahrens * Given a numeric suffix, convert the value into a number of bits that the 429fa9e4066Sahrens * resulting value must be shifted. 430fa9e4066Sahrens */ 431fa9e4066Sahrens static int 432*99653d4eSeschrock str2shift(libzfs_handle_t *hdl, const char *buf) 433fa9e4066Sahrens { 434fa9e4066Sahrens const char *ends = "BKMGTPEZ"; 435fa9e4066Sahrens int i; 436fa9e4066Sahrens 437fa9e4066Sahrens if (buf[0] == '\0') 438fa9e4066Sahrens return (0); 439fa9e4066Sahrens for (i = 0; i < strlen(ends); i++) { 440fa9e4066Sahrens if (toupper(buf[0]) == ends[i]) 441fa9e4066Sahrens break; 442fa9e4066Sahrens } 443fa9e4066Sahrens if (i == strlen(ends)) { 444*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 445*99653d4eSeschrock "invalid numeric suffix '%s'"), buf); 446fa9e4066Sahrens return (-1); 447fa9e4066Sahrens } 448fa9e4066Sahrens 449fa9e4066Sahrens /* 450fa9e4066Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 451fa9e4066Sahrens * allow 'BB' - that's just weird. 452fa9e4066Sahrens */ 453fa9e4066Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 454*99653d4eSeschrock toupper(buf[0]) != 'B')) 455fa9e4066Sahrens return (10*i); 456fa9e4066Sahrens 457*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 458*99653d4eSeschrock "invalid numeric suffix '%s'"), buf); 459fa9e4066Sahrens return (-1); 460fa9e4066Sahrens } 461fa9e4066Sahrens 462fa9e4066Sahrens /* 463fa9e4066Sahrens * Convert a string of the form '100G' into a real number. Used when setting 464fa9e4066Sahrens * properties or creating a volume. 'buf' is used to place an extended error 465fa9e4066Sahrens * message for the caller to use. 466fa9e4066Sahrens */ 467fa9e4066Sahrens static int 468*99653d4eSeschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 469fa9e4066Sahrens { 470fa9e4066Sahrens char *end; 471fa9e4066Sahrens int shift; 472fa9e4066Sahrens 473fa9e4066Sahrens *num = 0; 474fa9e4066Sahrens 475fa9e4066Sahrens /* Check to see if this looks like a number. */ 476fa9e4066Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 477*99653d4eSeschrock if (hdl) 478*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 479*99653d4eSeschrock "bad numeric value '%s'"), value); 480fa9e4066Sahrens return (-1); 481fa9e4066Sahrens } 482fa9e4066Sahrens 483fa9e4066Sahrens /* Rely on stroll() to process the numeric portion. */ 484fa9e4066Sahrens errno = 0; 485fa9e4066Sahrens *num = strtoll(value, &end, 10); 486fa9e4066Sahrens 487fa9e4066Sahrens /* 488fa9e4066Sahrens * Check for ERANGE, which indicates that the value is too large to fit 489fa9e4066Sahrens * in a 64-bit value. 490fa9e4066Sahrens */ 491fa9e4066Sahrens if (errno == ERANGE) { 492*99653d4eSeschrock if (hdl) 493*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 494*99653d4eSeschrock "numeric value is too large")); 495fa9e4066Sahrens return (-1); 496fa9e4066Sahrens } 497fa9e4066Sahrens 498fa9e4066Sahrens /* 499fa9e4066Sahrens * If we have a decimal value, then do the computation with floating 500fa9e4066Sahrens * point arithmetic. Otherwise, use standard arithmetic. 501fa9e4066Sahrens */ 502fa9e4066Sahrens if (*end == '.') { 503fa9e4066Sahrens double fval = strtod(value, &end); 504fa9e4066Sahrens 505*99653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 506fa9e4066Sahrens return (-1); 507fa9e4066Sahrens 508fa9e4066Sahrens fval *= pow(2, shift); 509fa9e4066Sahrens 510fa9e4066Sahrens if (fval > UINT64_MAX) { 511*99653d4eSeschrock if (hdl) 512*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 513*99653d4eSeschrock "numeric value is too large")); 514fa9e4066Sahrens return (-1); 515fa9e4066Sahrens } 516fa9e4066Sahrens 517fa9e4066Sahrens *num = (uint64_t)fval; 518fa9e4066Sahrens } else { 519*99653d4eSeschrock if ((shift = str2shift(hdl, end)) == -1) 520fa9e4066Sahrens return (-1); 521fa9e4066Sahrens 522fa9e4066Sahrens /* Check for overflow */ 523fa9e4066Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 524*99653d4eSeschrock if (hdl) 525*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 526*99653d4eSeschrock "numeric value is too large")); 527fa9e4066Sahrens return (-1); 528fa9e4066Sahrens } 529fa9e4066Sahrens 530fa9e4066Sahrens *num <<= shift; 531fa9e4066Sahrens } 532fa9e4066Sahrens 533fa9e4066Sahrens return (0); 534fa9e4066Sahrens } 535fa9e4066Sahrens 536fa9e4066Sahrens int 537fa9e4066Sahrens zfs_nicestrtonum(const char *str, uint64_t *val) 538fa9e4066Sahrens { 539*99653d4eSeschrock return (nicestrtonum(NULL, str, val)); 540fa9e4066Sahrens } 541fa9e4066Sahrens 542fa9e4066Sahrens /* 543fa9e4066Sahrens * Given a property type and value, verify that the value is appropriate. Used 544fa9e4066Sahrens * by zfs_prop_set() and some libzfs consumers. 545fa9e4066Sahrens */ 546fa9e4066Sahrens int 547*99653d4eSeschrock zfs_prop_validate(libzfs_handle_t *hdl, zfs_prop_t prop, const char *value, 548*99653d4eSeschrock uint64_t *intval) 549fa9e4066Sahrens { 550fa9e4066Sahrens const char *propname = zfs_prop_to_name(prop); 551fa9e4066Sahrens uint64_t number; 552*99653d4eSeschrock char errbuf[1024]; 553fa9e4066Sahrens int i; 554fa9e4066Sahrens 555fa9e4066Sahrens /* 556fa9e4066Sahrens * Check to see if this a read-only property. 557fa9e4066Sahrens */ 558*99653d4eSeschrock if (zfs_prop_readonly(prop)) 559*99653d4eSeschrock return (zfs_error(hdl, EZFS_PROPREADONLY, 560*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot set %s property"), propname)); 561*99653d4eSeschrock 562*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 563*99653d4eSeschrock dgettext(TEXT_DOMAIN, "bad %s value '%s'"), propname, value); 564fa9e4066Sahrens 565fa9e4066Sahrens /* See if the property value is too long */ 566fa9e4066Sahrens if (strlen(value) >= ZFS_MAXPROPLEN) { 567*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "value is too long")); 568*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 569fa9e4066Sahrens } 570fa9e4066Sahrens 571fa9e4066Sahrens /* Perform basic checking based on property type */ 572fa9e4066Sahrens switch (zfs_prop_get_type(prop)) { 573fa9e4066Sahrens case prop_type_boolean: 574fa9e4066Sahrens if (strcmp(value, "on") == 0) { 575fa9e4066Sahrens number = 1; 576fa9e4066Sahrens } else if (strcmp(value, "off") == 0) { 577fa9e4066Sahrens number = 0; 578fa9e4066Sahrens } else { 579*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 580*99653d4eSeschrock "must be 'on' or 'off'")); 581*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 582fa9e4066Sahrens } 583fa9e4066Sahrens break; 584fa9e4066Sahrens 585fa9e4066Sahrens case prop_type_number: 586fa9e4066Sahrens /* treat 'none' as 0 */ 587fa9e4066Sahrens if (strcmp(value, "none") == 0) { 588fa9e4066Sahrens number = 0; 589fa9e4066Sahrens break; 590fa9e4066Sahrens } 591fa9e4066Sahrens 592*99653d4eSeschrock if (nicestrtonum(hdl, value, &number) != 0) 593*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 594fa9e4066Sahrens 595fa9e4066Sahrens /* don't allow 0 for quota, use 'none' instead */ 596fa9e4066Sahrens if (prop == ZFS_PROP_QUOTA && number == 0 && 597fa9e4066Sahrens strcmp(value, "none") != 0) { 598*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 599*99653d4eSeschrock "use 'quota=none' to disable")); 600*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 601fa9e4066Sahrens } 602fa9e4066Sahrens 603fa9e4066Sahrens /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 604fa9e4066Sahrens if (prop == ZFS_PROP_RECORDSIZE || 605fa9e4066Sahrens prop == ZFS_PROP_VOLBLOCKSIZE) { 606fa9e4066Sahrens if (number < SPA_MINBLOCKSIZE || 607fa9e4066Sahrens number > SPA_MAXBLOCKSIZE || !ISP2(number)) { 608*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 609fa9e4066Sahrens "must be power of 2 from %u to %uk"), 610fa9e4066Sahrens (uint_t)SPA_MINBLOCKSIZE, 611fa9e4066Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 612*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 613fa9e4066Sahrens } 614fa9e4066Sahrens } 615fa9e4066Sahrens 616fa9e4066Sahrens break; 617fa9e4066Sahrens 618fa9e4066Sahrens case prop_type_string: 619fa9e4066Sahrens case prop_type_index: 620fa9e4066Sahrens /* 621fa9e4066Sahrens * The two writable string values, 'mountpoint' and 622fa9e4066Sahrens * 'checksum' need special consideration. The 'index' types are 623fa9e4066Sahrens * specified as strings by the user, but passed to the kernel as 624fa9e4066Sahrens * integers. 625fa9e4066Sahrens */ 626fa9e4066Sahrens switch (prop) { 627fa9e4066Sahrens case ZFS_PROP_MOUNTPOINT: 628fa9e4066Sahrens if (strcmp(value, ZFS_MOUNTPOINT_NONE) == 0 || 629fa9e4066Sahrens strcmp(value, ZFS_MOUNTPOINT_LEGACY) == 0) 630fa9e4066Sahrens break; 631fa9e4066Sahrens 632fa9e4066Sahrens if (value[0] != '/') { 633*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 634*99653d4eSeschrock "must be an absolute path, 'none', or " 635*99653d4eSeschrock "'legacy'")); 636*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 637fa9e4066Sahrens } 638fa9e4066Sahrens break; 639fa9e4066Sahrens 640fa9e4066Sahrens case ZFS_PROP_CHECKSUM: 641fa9e4066Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 642fa9e4066Sahrens if (strcmp(value, checksum_table[i].name) 643fa9e4066Sahrens == 0) { 644fa9e4066Sahrens number = checksum_table[i].value; 645fa9e4066Sahrens break; 646fa9e4066Sahrens } 647fa9e4066Sahrens } 648fa9e4066Sahrens 649fa9e4066Sahrens if (checksum_table[i].name == NULL) { 650*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 651*99653d4eSeschrock "must be 'on', 'off', 'fletcher2', " 652*99653d4eSeschrock "'fletcher4', or 'sha256'")); 653*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 654fa9e4066Sahrens } 655fa9e4066Sahrens break; 656fa9e4066Sahrens 657fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 658fa9e4066Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 659fa9e4066Sahrens if (strcmp(value, compress_table[i].name) 660fa9e4066Sahrens == 0) { 661fa9e4066Sahrens number = compress_table[i].value; 662fa9e4066Sahrens break; 663fa9e4066Sahrens } 664fa9e4066Sahrens } 665fa9e4066Sahrens 666fa9e4066Sahrens if (compress_table[i].name == NULL) { 667*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 668*99653d4eSeschrock "must be 'on', 'off', or 'lzjb'")); 669*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 670fa9e4066Sahrens } 671fa9e4066Sahrens break; 672fa9e4066Sahrens 673fa9e4066Sahrens case ZFS_PROP_SNAPDIR: 674fa9e4066Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 675fa9e4066Sahrens if (strcmp(value, snapdir_table[i].name) == 0) { 676fa9e4066Sahrens number = snapdir_table[i].value; 677fa9e4066Sahrens break; 678fa9e4066Sahrens } 679fa9e4066Sahrens } 680fa9e4066Sahrens 681fa9e4066Sahrens if (snapdir_table[i].name == NULL) { 682*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 683*99653d4eSeschrock "must be 'hidden' or 'visible'")); 684*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 685fa9e4066Sahrens } 686fa9e4066Sahrens break; 687fa9e4066Sahrens 688fa9e4066Sahrens case ZFS_PROP_ACLMODE: 689fa9e4066Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 690fa9e4066Sahrens if (strcmp(value, acl_mode_table[i].name) 691fa9e4066Sahrens == 0) { 692fa9e4066Sahrens number = acl_mode_table[i].value; 693fa9e4066Sahrens break; 694fa9e4066Sahrens } 695fa9e4066Sahrens } 696fa9e4066Sahrens 697fa9e4066Sahrens if (acl_mode_table[i].name == NULL) { 698*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 699*99653d4eSeschrock "must be 'disacard', 'groupmask', or " 700*99653d4eSeschrock "'passthrough'")); 701*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 702fa9e4066Sahrens } 703fa9e4066Sahrens break; 704fa9e4066Sahrens 705fa9e4066Sahrens case ZFS_PROP_ACLINHERIT: 706fa9e4066Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 707fa9e4066Sahrens if (strcmp(value, acl_inherit_table[i].name) 708fa9e4066Sahrens == 0) { 709fa9e4066Sahrens number = acl_inherit_table[i].value; 710fa9e4066Sahrens break; 711fa9e4066Sahrens } 712fa9e4066Sahrens } 713fa9e4066Sahrens 714fa9e4066Sahrens if (acl_inherit_table[i].name == NULL) { 715*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 716*99653d4eSeschrock "must be 'discard, 'noallow', 'secure', " 717*99653d4eSeschrock "or 'passthrough'")); 718*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 719fa9e4066Sahrens } 720fa9e4066Sahrens break; 721fa9e4066Sahrens 722fa9e4066Sahrens case ZFS_PROP_SHARENFS: 723fa9e4066Sahrens /* 724fa9e4066Sahrens * Nothing to do for 'sharenfs', this gets passed on to 725fa9e4066Sahrens * share(1M) verbatim. 726fa9e4066Sahrens */ 727fa9e4066Sahrens break; 728fa9e4066Sahrens } 729fa9e4066Sahrens } 730fa9e4066Sahrens 731fa9e4066Sahrens if (intval != NULL) 732fa9e4066Sahrens *intval = number; 733fa9e4066Sahrens 734fa9e4066Sahrens return (0); 735fa9e4066Sahrens } 736fa9e4066Sahrens 737fa9e4066Sahrens /* 738fa9e4066Sahrens * Given a property name and value, set the property for the given dataset. 739fa9e4066Sahrens */ 740fa9e4066Sahrens int 741fa9e4066Sahrens zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval) 742fa9e4066Sahrens { 743fa9e4066Sahrens const char *propname = zfs_prop_to_name(prop); 744fa9e4066Sahrens uint64_t number; 745fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 746fa9e4066Sahrens int ret; 747fa9e4066Sahrens prop_changelist_t *cl; 748*99653d4eSeschrock char errbuf[1024]; 749*99653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 750fa9e4066Sahrens 751*99653d4eSeschrock if (zfs_prop_validate(zhp->zfs_hdl, prop, propval, &number) != 0) 752fa9e4066Sahrens return (-1); 753fa9e4066Sahrens 754*99653d4eSeschrock 755*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 756*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot set %s for '%s'"), propname, 757*99653d4eSeschrock zhp->zfs_name); 758*99653d4eSeschrock 759fa9e4066Sahrens /* 760fa9e4066Sahrens * Check to see if the value applies to this type 761fa9e4066Sahrens */ 762*99653d4eSeschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 763*99653d4eSeschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 764fa9e4066Sahrens 765fa9e4066Sahrens /* 766fa9e4066Sahrens * For the mountpoint and sharenfs properties, check if it can be set 767fa9e4066Sahrens * in a global/non-global zone based on the zoned property value: 768fa9e4066Sahrens * 769fa9e4066Sahrens * global zone non-global zone 770fa9e4066Sahrens * ----------------------------------------------------- 771fa9e4066Sahrens * zoned=on mountpoint (no) mountpoint (yes) 772fa9e4066Sahrens * sharenfs (no) sharenfs (no) 773fa9e4066Sahrens * 774fa9e4066Sahrens * zoned=off mountpoint (yes) N/A 775fa9e4066Sahrens * sharenfs (yes) 776fa9e4066Sahrens */ 777fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 778fa9e4066Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 779fa9e4066Sahrens if (getzoneid() == GLOBAL_ZONEID) { 780*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 781*99653d4eSeschrock "dataset is used in a non-global zone")); 782*99653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 783fa9e4066Sahrens } else if (prop == ZFS_PROP_SHARENFS) { 784*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 785*99653d4eSeschrock "filesystems cannot be shared in a " 786*99653d4eSeschrock "non-global zone")); 787*99653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 788fa9e4066Sahrens } 789fa9e4066Sahrens } else if (getzoneid() != GLOBAL_ZONEID) { 790fa9e4066Sahrens /* 791fa9e4066Sahrens * If zoned property is 'off', this must be in 792fa9e4066Sahrens * a globle zone. If not, something is wrong. 793fa9e4066Sahrens */ 794*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 795*99653d4eSeschrock "dataset is used in a non-global zone, but " 796*99653d4eSeschrock "'zoned' property is not set")); 797*99653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 798fa9e4066Sahrens } 799fa9e4066Sahrens } 800fa9e4066Sahrens 801fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 802fa9e4066Sahrens return (-1); 803fa9e4066Sahrens 804fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 805*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 806*99653d4eSeschrock "child dataset with inherited mountpoint is used " 807*99653d4eSeschrock "in a non-global zone")); 808*99653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 809fa9e4066Sahrens goto error; 810fa9e4066Sahrens } 811fa9e4066Sahrens 812fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 813fa9e4066Sahrens goto error; 814fa9e4066Sahrens 815fa9e4066Sahrens /* 816fa9e4066Sahrens * Execute the corresponding ioctl() to set this property. 817fa9e4066Sahrens */ 818fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 819fa9e4066Sahrens 820fa9e4066Sahrens switch (prop) { 821fa9e4066Sahrens case ZFS_PROP_QUOTA: 822fa9e4066Sahrens zc.zc_cookie = number; 823*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_QUOTA, &zc); 824fa9e4066Sahrens break; 825fa9e4066Sahrens case ZFS_PROP_RESERVATION: 826fa9e4066Sahrens zc.zc_cookie = number; 827*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_RESERVATION, 828*99653d4eSeschrock &zc); 829fa9e4066Sahrens break; 830fa9e4066Sahrens case ZFS_PROP_MOUNTPOINT: 831fa9e4066Sahrens case ZFS_PROP_SHARENFS: 832fa9e4066Sahrens /* 833fa9e4066Sahrens * These properties are passed down as real strings. 834fa9e4066Sahrens */ 835fa9e4066Sahrens (void) strlcpy(zc.zc_prop_name, propname, 836fa9e4066Sahrens sizeof (zc.zc_prop_name)); 837fa9e4066Sahrens (void) strlcpy(zc.zc_prop_value, propval, 838fa9e4066Sahrens sizeof (zc.zc_prop_value)); 839fa9e4066Sahrens zc.zc_intsz = 1; 840fa9e4066Sahrens zc.zc_numints = strlen(propval) + 1; 841*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 842fa9e4066Sahrens break; 843fa9e4066Sahrens case ZFS_PROP_VOLSIZE: 844fa9e4066Sahrens zc.zc_volsize = number; 845*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLSIZE, &zc); 846fa9e4066Sahrens break; 847fa9e4066Sahrens case ZFS_PROP_VOLBLOCKSIZE: 848fa9e4066Sahrens zc.zc_volblocksize = number; 849*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLBLOCKSIZE, 850*99653d4eSeschrock &zc); 851fa9e4066Sahrens break; 852fa9e4066Sahrens default: 853fa9e4066Sahrens (void) strlcpy(zc.zc_prop_name, propname, 854fa9e4066Sahrens sizeof (zc.zc_prop_name)); 855fa9e4066Sahrens /* LINTED - alignment */ 856fa9e4066Sahrens *(uint64_t *)zc.zc_prop_value = number; 857fa9e4066Sahrens zc.zc_intsz = 8; 858fa9e4066Sahrens zc.zc_numints = 1; 859*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 860fa9e4066Sahrens break; 861fa9e4066Sahrens } 862fa9e4066Sahrens 863fa9e4066Sahrens if (ret != 0) { 864fa9e4066Sahrens switch (errno) { 865fa9e4066Sahrens 866fa9e4066Sahrens case ENOSPC: 867fa9e4066Sahrens /* 868fa9e4066Sahrens * For quotas and reservations, ENOSPC indicates 869fa9e4066Sahrens * something different; setting a quota or reservation 870fa9e4066Sahrens * doesn't use any disk space. 871fa9e4066Sahrens */ 872fa9e4066Sahrens switch (prop) { 873fa9e4066Sahrens case ZFS_PROP_QUOTA: 874*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 875*99653d4eSeschrock "size is less than current used or " 876*99653d4eSeschrock "reserved space")); 877*99653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 878fa9e4066Sahrens break; 879fa9e4066Sahrens 880fa9e4066Sahrens case ZFS_PROP_RESERVATION: 881*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 882*99653d4eSeschrock "size is greater than available space")); 883*99653d4eSeschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 884fa9e4066Sahrens break; 885fa9e4066Sahrens 886fa9e4066Sahrens default: 887*99653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 888fa9e4066Sahrens break; 889fa9e4066Sahrens } 890fa9e4066Sahrens break; 891fa9e4066Sahrens 892fa9e4066Sahrens case EBUSY: 893*99653d4eSeschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 894*99653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 895*99653d4eSeschrock else 896*99653d4eSeschrock return (zfs_standard_error(hdl, EBUSY, errbuf)); 897fa9e4066Sahrens break; 898fa9e4066Sahrens 8992a79c5feSlling case EROFS: 900*99653d4eSeschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 9012a79c5feSlling break; 9022a79c5feSlling 903fa9e4066Sahrens case EOVERFLOW: 904fa9e4066Sahrens /* 905fa9e4066Sahrens * This platform can't address a volume this big. 906fa9e4066Sahrens */ 907fa9e4066Sahrens #ifdef _ILP32 908fa9e4066Sahrens if (prop == ZFS_PROP_VOLSIZE) { 909*99653d4eSeschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 910fa9e4066Sahrens break; 911fa9e4066Sahrens } 912fa9e4066Sahrens #endif 913*99653d4eSeschrock /* FALLTHROUGH */ 914fa9e4066Sahrens default: 915*99653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 916fa9e4066Sahrens } 917fa9e4066Sahrens } else { 918fa9e4066Sahrens /* 919fa9e4066Sahrens * Refresh the statistics so the new property value 920fa9e4066Sahrens * is reflected. 921fa9e4066Sahrens */ 922fa9e4066Sahrens if ((ret = changelist_postfix(cl)) != 0) 923fa9e4066Sahrens goto error; 924fa9e4066Sahrens 925fa9e4066Sahrens (void) get_stats(zhp); 926fa9e4066Sahrens } 927fa9e4066Sahrens 928fa9e4066Sahrens error: 929fa9e4066Sahrens changelist_free(cl); 930fa9e4066Sahrens return (ret); 931fa9e4066Sahrens } 932fa9e4066Sahrens 933fa9e4066Sahrens /* 934fa9e4066Sahrens * Given a property, inherit the value from the parent dataset. 935fa9e4066Sahrens */ 936fa9e4066Sahrens int 937fa9e4066Sahrens zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop) 938fa9e4066Sahrens { 939fa9e4066Sahrens const char *propname = zfs_prop_to_name(prop); 940fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 941fa9e4066Sahrens int ret; 942fa9e4066Sahrens prop_changelist_t *cl; 943*99653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 944*99653d4eSeschrock char errbuf[1024]; 945*99653d4eSeschrock 946*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 947*99653d4eSeschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 948fa9e4066Sahrens 949fa9e4066Sahrens /* 950fa9e4066Sahrens * Verify that this property is inheritable. 951fa9e4066Sahrens */ 952*99653d4eSeschrock if (zfs_prop_readonly(prop)) 953*99653d4eSeschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 954fa9e4066Sahrens 955*99653d4eSeschrock if (!zfs_prop_inheritable(prop)) 956*99653d4eSeschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 957fa9e4066Sahrens 958fa9e4066Sahrens /* 959fa9e4066Sahrens * Check to see if the value applies to this type 960fa9e4066Sahrens */ 961*99653d4eSeschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 962*99653d4eSeschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 963fa9e4066Sahrens 964fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 965fa9e4066Sahrens (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name)); 966fa9e4066Sahrens 967fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 968fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 969*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 970*99653d4eSeschrock "dataset is used in a non-global zone")); 971*99653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 972fa9e4066Sahrens } 973fa9e4066Sahrens 974fa9e4066Sahrens /* 975fa9e4066Sahrens * Determine datasets which will be affected by this change, if any. 976fa9e4066Sahrens */ 977fa9e4066Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 978fa9e4066Sahrens return (-1); 979fa9e4066Sahrens 980fa9e4066Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 981*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 982*99653d4eSeschrock "child dataset with inherited mountpoint is used " 983*99653d4eSeschrock "in a non-global zone")); 984*99653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 985fa9e4066Sahrens goto error; 986fa9e4066Sahrens } 987fa9e4066Sahrens 988fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 989fa9e4066Sahrens goto error; 990fa9e4066Sahrens 991fa9e4066Sahrens zc.zc_numints = 0; 992fa9e4066Sahrens 993*99653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 994*99653d4eSeschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 995*99653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 996fa9e4066Sahrens } else { 997fa9e4066Sahrens 998fa9e4066Sahrens if ((ret = changelist_postfix(cl)) != 0) 999fa9e4066Sahrens goto error; 1000fa9e4066Sahrens 1001fa9e4066Sahrens /* 1002fa9e4066Sahrens * Refresh the statistics so the new property is reflected. 1003fa9e4066Sahrens */ 1004fa9e4066Sahrens (void) get_stats(zhp); 1005fa9e4066Sahrens } 1006fa9e4066Sahrens 1007fa9e4066Sahrens 1008fa9e4066Sahrens error: 1009fa9e4066Sahrens changelist_free(cl); 1010fa9e4066Sahrens return (ret); 1011fa9e4066Sahrens } 1012fa9e4066Sahrens 1013fa9e4066Sahrens static void 1014fa9e4066Sahrens nicebool(int value, char *buf, size_t buflen) 1015fa9e4066Sahrens { 1016fa9e4066Sahrens if (value) 1017fa9e4066Sahrens (void) strlcpy(buf, "on", buflen); 1018fa9e4066Sahrens else 1019fa9e4066Sahrens (void) strlcpy(buf, "off", buflen); 1020fa9e4066Sahrens } 1021fa9e4066Sahrens 10227f7322feSeschrock /* 10237f7322feSeschrock * True DSL properties are stored in an nvlist. The following two functions 10247f7322feSeschrock * extract them appropriately. 10257f7322feSeschrock */ 10267f7322feSeschrock static uint64_t 10277f7322feSeschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10287f7322feSeschrock { 10297f7322feSeschrock nvlist_t *nv; 10307f7322feSeschrock uint64_t value; 10317f7322feSeschrock 10327f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10337f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 10347f7322feSeschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 10357f7322feSeschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10367f7322feSeschrock } else { 10377f7322feSeschrock value = zfs_prop_default_numeric(prop); 10387f7322feSeschrock *source = ""; 10397f7322feSeschrock } 10407f7322feSeschrock 10417f7322feSeschrock return (value); 10427f7322feSeschrock } 10437f7322feSeschrock 10447f7322feSeschrock static char * 10457f7322feSeschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 10467f7322feSeschrock { 10477f7322feSeschrock nvlist_t *nv; 10487f7322feSeschrock char *value; 10497f7322feSeschrock 10507f7322feSeschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 10517f7322feSeschrock zfs_prop_to_name(prop), &nv) == 0) { 10527f7322feSeschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 10537f7322feSeschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 10547f7322feSeschrock } else { 10557f7322feSeschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 10567f7322feSeschrock value = ""; 10577f7322feSeschrock *source = ""; 10587f7322feSeschrock } 10597f7322feSeschrock 10607f7322feSeschrock return (value); 10617f7322feSeschrock } 10627f7322feSeschrock 1063fa9e4066Sahrens /* 1064fa9e4066Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1065fa9e4066Sahrens * zfs_prop_get_int() are built using this interface. 1066fa9e4066Sahrens * 1067fa9e4066Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1068fa9e4066Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1069fa9e4066Sahrens * If they differ from the on-disk values, report the current values and mark 1070fa9e4066Sahrens * the source "temporary". 1071fa9e4066Sahrens */ 1072*99653d4eSeschrock static int 1073fa9e4066Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 1074*99653d4eSeschrock char **source, uint64_t *val) 1075fa9e4066Sahrens { 1076fa9e4066Sahrens struct mnttab mnt; 1077fa9e4066Sahrens 1078fa9e4066Sahrens *source = NULL; 1079fa9e4066Sahrens 1080fa9e4066Sahrens if (zhp->zfs_mntopts == NULL) 1081fa9e4066Sahrens mnt.mnt_mntopts = ""; 1082fa9e4066Sahrens else 1083fa9e4066Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1084fa9e4066Sahrens 1085fa9e4066Sahrens switch (prop) { 1086fa9e4066Sahrens case ZFS_PROP_ATIME: 1087*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1088fa9e4066Sahrens 1089*99653d4eSeschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 1090*99653d4eSeschrock *val = B_TRUE; 1091fa9e4066Sahrens if (src) 1092fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1093*99653d4eSeschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 1094*99653d4eSeschrock *val = B_FALSE; 1095fa9e4066Sahrens if (src) 1096fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1097fa9e4066Sahrens } 1098*99653d4eSeschrock break; 1099fa9e4066Sahrens 1100fa9e4066Sahrens case ZFS_PROP_AVAILABLE: 1101*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_available; 1102*99653d4eSeschrock break; 1103fa9e4066Sahrens 1104fa9e4066Sahrens case ZFS_PROP_DEVICES: 1105*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1106fa9e4066Sahrens 1107*99653d4eSeschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 1108*99653d4eSeschrock *val = B_TRUE; 1109fa9e4066Sahrens if (src) 1110fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1111*99653d4eSeschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 1112*99653d4eSeschrock *val = B_FALSE; 1113fa9e4066Sahrens if (src) 1114fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1115fa9e4066Sahrens } 1116*99653d4eSeschrock break; 1117fa9e4066Sahrens 1118fa9e4066Sahrens case ZFS_PROP_EXEC: 1119*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1120fa9e4066Sahrens 1121*99653d4eSeschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 1122*99653d4eSeschrock *val = B_TRUE; 1123fa9e4066Sahrens if (src) 1124fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1125*99653d4eSeschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 1126*99653d4eSeschrock *val = B_FALSE; 1127fa9e4066Sahrens if (src) 1128fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1129fa9e4066Sahrens } 1130*99653d4eSeschrock break; 1131fa9e4066Sahrens 1132fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1133fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 11347f7322feSeschrock case ZFS_PROP_ZONED: 1135*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1136*99653d4eSeschrock break; 1137fa9e4066Sahrens 1138fa9e4066Sahrens case ZFS_PROP_READONLY: 1139*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1140fa9e4066Sahrens 1141*99653d4eSeschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 1142*99653d4eSeschrock *val = B_TRUE; 1143fa9e4066Sahrens if (src) 1144fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1145*99653d4eSeschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 1146*99653d4eSeschrock *val = B_FALSE; 1147fa9e4066Sahrens if (src) 1148fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1149fa9e4066Sahrens } 1150*99653d4eSeschrock break; 1151fa9e4066Sahrens 1152ea8dc4b6Seschrock case ZFS_PROP_CREATION: 1153*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_creation_time; 1154*99653d4eSeschrock break; 1155ea8dc4b6Seschrock 1156fa9e4066Sahrens case ZFS_PROP_QUOTA: 1157fa9e4066Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1158fa9e4066Sahrens *source = ""; /* default */ 1159fa9e4066Sahrens else 1160fa9e4066Sahrens *source = zhp->zfs_name; 1161*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_quota; 1162*99653d4eSeschrock break; 1163fa9e4066Sahrens 1164fa9e4066Sahrens case ZFS_PROP_RESERVATION: 1165fa9e4066Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1166fa9e4066Sahrens *source = ""; /* default */ 1167fa9e4066Sahrens else 1168fa9e4066Sahrens *source = zhp->zfs_name; 1169*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_reserved; 1170*99653d4eSeschrock break; 1171fa9e4066Sahrens 1172fa9e4066Sahrens case ZFS_PROP_COMPRESSRATIO: 1173fa9e4066Sahrens /* 1174fa9e4066Sahrens * Using physical space and logical space, calculate the 1175fa9e4066Sahrens * compression ratio. We return the number as a multiple of 1176fa9e4066Sahrens * 100, so '2.5x' would be returned as 250. 1177fa9e4066Sahrens */ 1178fa9e4066Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 1179*99653d4eSeschrock *val = 100ULL; 1180fa9e4066Sahrens else 1181*99653d4eSeschrock *val = 1182*99653d4eSeschrock (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1183fa9e4066Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 1184*99653d4eSeschrock break; 1185fa9e4066Sahrens 1186fa9e4066Sahrens case ZFS_PROP_REFERENCED: 1187fa9e4066Sahrens /* 1188fa9e4066Sahrens * 'referenced' refers to the amount of physical space 1189fa9e4066Sahrens * referenced (possibly shared) by this object. 1190fa9e4066Sahrens */ 1191*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_space_refd; 1192*99653d4eSeschrock break; 1193fa9e4066Sahrens 1194fa9e4066Sahrens case ZFS_PROP_SETUID: 1195*99653d4eSeschrock *val = getprop_uint64(zhp, prop, source); 1196fa9e4066Sahrens 1197*99653d4eSeschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 1198*99653d4eSeschrock *val = B_TRUE; 1199fa9e4066Sahrens if (src) 1200fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1201*99653d4eSeschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 1202*99653d4eSeschrock *val = B_FALSE; 1203fa9e4066Sahrens if (src) 1204fa9e4066Sahrens *src = ZFS_SRC_TEMPORARY; 1205fa9e4066Sahrens } 1206*99653d4eSeschrock break; 1207fa9e4066Sahrens 1208fa9e4066Sahrens case ZFS_PROP_VOLSIZE: 1209*99653d4eSeschrock *val = zhp->zfs_volsize; 1210*99653d4eSeschrock break; 1211fa9e4066Sahrens 1212fa9e4066Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1213*99653d4eSeschrock *val = zhp->zfs_volblocksize; 1214*99653d4eSeschrock break; 1215fa9e4066Sahrens 1216fa9e4066Sahrens case ZFS_PROP_USED: 1217*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_space_used; 1218*99653d4eSeschrock break; 1219fa9e4066Sahrens 1220fa9e4066Sahrens case ZFS_PROP_CREATETXG: 1221*99653d4eSeschrock *val = zhp->zfs_dmustats.dds_creation_txg; 1222*99653d4eSeschrock break; 1223fa9e4066Sahrens 1224fa9e4066Sahrens case ZFS_PROP_MOUNTED: 1225fa9e4066Sahrens /* 1226fa9e4066Sahrens * Unlike other properties, we defer calculation of 'MOUNTED' 1227fa9e4066Sahrens * until actually requested. This is because the getmntany() 1228fa9e4066Sahrens * call can be extremely expensive on systems with a large 1229fa9e4066Sahrens * number of filesystems, and the property isn't needed in 1230fa9e4066Sahrens * normal use cases. 1231fa9e4066Sahrens */ 1232fa9e4066Sahrens if (zhp->zfs_mntopts == NULL) { 1233fa9e4066Sahrens struct mnttab search = { 0 }, entry; 1234fa9e4066Sahrens 1235fa9e4066Sahrens search.mnt_special = (char *)zhp->zfs_name; 123696dedd18Snd search.mnt_fstype = MNTTYPE_ZFS; 1237*99653d4eSeschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 1238fa9e4066Sahrens 1239*99653d4eSeschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 1240*99653d4eSeschrock &search) == 0 && (zhp->zfs_mntopts = 1241*99653d4eSeschrock zfs_strdup(zhp->zfs_hdl, 1242*99653d4eSeschrock entry.mnt_mntopts)) == NULL) 1243*99653d4eSeschrock return (-1); 1244fa9e4066Sahrens } 1245*99653d4eSeschrock *val = (zhp->zfs_mntopts != NULL); 1246*99653d4eSeschrock break; 1247fa9e4066Sahrens 1248fa9e4066Sahrens default: 1249*99653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1250*99653d4eSeschrock "cannot get non-numeric property")); 1251*99653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1252*99653d4eSeschrock dgettext(TEXT_DOMAIN, "internal error"))); 1253fa9e4066Sahrens } 1254fa9e4066Sahrens 1255fa9e4066Sahrens return (0); 1256fa9e4066Sahrens } 1257fa9e4066Sahrens 1258fa9e4066Sahrens /* 1259fa9e4066Sahrens * Calculate the source type, given the raw source string. 1260fa9e4066Sahrens */ 1261fa9e4066Sahrens static void 1262fa9e4066Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1263fa9e4066Sahrens char *statbuf, size_t statlen) 1264fa9e4066Sahrens { 1265fa9e4066Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1266fa9e4066Sahrens return; 1267fa9e4066Sahrens 1268fa9e4066Sahrens if (source == NULL) { 1269fa9e4066Sahrens *srctype = ZFS_SRC_NONE; 1270fa9e4066Sahrens } else if (source[0] == '\0') { 1271fa9e4066Sahrens *srctype = ZFS_SRC_DEFAULT; 1272fa9e4066Sahrens } else { 1273fa9e4066Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1274fa9e4066Sahrens *srctype = ZFS_SRC_LOCAL; 1275fa9e4066Sahrens } else { 1276fa9e4066Sahrens (void) strlcpy(statbuf, source, statlen); 1277fa9e4066Sahrens *srctype = ZFS_SRC_INHERITED; 1278fa9e4066Sahrens } 1279fa9e4066Sahrens } 1280fa9e4066Sahrens 1281fa9e4066Sahrens } 1282fa9e4066Sahrens 1283fa9e4066Sahrens /* 1284fa9e4066Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1285fa9e4066Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1286fa9e4066Sahrens * human-readable form. 1287fa9e4066Sahrens * 1288fa9e4066Sahrens * Returns 0 on success, or -1 on error. 1289fa9e4066Sahrens */ 1290fa9e4066Sahrens int 1291fa9e4066Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 1292*99653d4eSeschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1293fa9e4066Sahrens { 1294fa9e4066Sahrens char *source = NULL; 1295fa9e4066Sahrens uint64_t val; 1296fa9e4066Sahrens char *str; 1297fa9e4066Sahrens int i; 1298fa9e4066Sahrens const char *root; 1299fa9e4066Sahrens 1300fa9e4066Sahrens /* 1301fa9e4066Sahrens * Check to see if this property applies to our object 1302fa9e4066Sahrens */ 1303fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1304fa9e4066Sahrens return (-1); 1305fa9e4066Sahrens 1306fa9e4066Sahrens if (src) 1307fa9e4066Sahrens *src = ZFS_SRC_NONE; 1308fa9e4066Sahrens 1309fa9e4066Sahrens switch (prop) { 1310fa9e4066Sahrens case ZFS_PROP_ATIME: 1311fa9e4066Sahrens case ZFS_PROP_READONLY: 1312fa9e4066Sahrens case ZFS_PROP_SETUID: 1313fa9e4066Sahrens case ZFS_PROP_ZONED: 1314fa9e4066Sahrens case ZFS_PROP_DEVICES: 1315fa9e4066Sahrens case ZFS_PROP_EXEC: 1316fa9e4066Sahrens /* 1317fa9e4066Sahrens * Basic boolean values are built on top of 1318fa9e4066Sahrens * get_numeric_property(). 1319fa9e4066Sahrens */ 1320*99653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1321*99653d4eSeschrock return (-1); 1322*99653d4eSeschrock nicebool(val, propbuf, proplen); 1323fa9e4066Sahrens 1324fa9e4066Sahrens break; 1325fa9e4066Sahrens 1326fa9e4066Sahrens case ZFS_PROP_AVAILABLE: 1327fa9e4066Sahrens case ZFS_PROP_RECORDSIZE: 1328fa9e4066Sahrens case ZFS_PROP_CREATETXG: 1329fa9e4066Sahrens case ZFS_PROP_REFERENCED: 1330fa9e4066Sahrens case ZFS_PROP_USED: 1331fa9e4066Sahrens case ZFS_PROP_VOLSIZE: 1332fa9e4066Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1333fa9e4066Sahrens /* 1334fa9e4066Sahrens * Basic numeric values are built on top of 1335fa9e4066Sahrens * get_numeric_property(). 1336fa9e4066Sahrens */ 1337*99653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1338*99653d4eSeschrock return (-1); 1339fa9e4066Sahrens if (literal) 1340fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1341fa9e4066Sahrens else 1342fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1343fa9e4066Sahrens break; 1344fa9e4066Sahrens 1345fa9e4066Sahrens case ZFS_PROP_COMPRESSION: 13467f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1347fa9e4066Sahrens for (i = 0; compress_table[i].name != NULL; i++) { 13487f7322feSeschrock if (compress_table[i].value == val) 1349fa9e4066Sahrens break; 1350fa9e4066Sahrens } 1351fa9e4066Sahrens assert(compress_table[i].name != NULL); 1352fa9e4066Sahrens (void) strlcpy(propbuf, compress_table[i].name, proplen); 1353fa9e4066Sahrens break; 1354fa9e4066Sahrens 1355fa9e4066Sahrens case ZFS_PROP_CHECKSUM: 13567f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1357fa9e4066Sahrens for (i = 0; checksum_table[i].name != NULL; i++) { 13587f7322feSeschrock if (checksum_table[i].value == val) 1359fa9e4066Sahrens break; 1360fa9e4066Sahrens } 1361fa9e4066Sahrens assert(checksum_table[i].name != NULL); 1362fa9e4066Sahrens (void) strlcpy(propbuf, checksum_table[i].name, proplen); 1363fa9e4066Sahrens break; 1364fa9e4066Sahrens 1365fa9e4066Sahrens case ZFS_PROP_SNAPDIR: 13667f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1367fa9e4066Sahrens for (i = 0; snapdir_table[i].name != NULL; i++) { 13687f7322feSeschrock if (snapdir_table[i].value == val) 1369fa9e4066Sahrens break; 1370fa9e4066Sahrens } 1371fa9e4066Sahrens assert(snapdir_table[i].name != NULL); 1372fa9e4066Sahrens (void) strlcpy(propbuf, snapdir_table[i].name, proplen); 1373fa9e4066Sahrens break; 1374fa9e4066Sahrens 1375fa9e4066Sahrens case ZFS_PROP_ACLMODE: 13767f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1377fa9e4066Sahrens for (i = 0; acl_mode_table[i].name != NULL; i++) { 13787f7322feSeschrock if (acl_mode_table[i].value == val) 1379fa9e4066Sahrens break; 1380fa9e4066Sahrens } 1381fa9e4066Sahrens assert(acl_mode_table[i].name != NULL); 1382fa9e4066Sahrens (void) strlcpy(propbuf, acl_mode_table[i].name, proplen); 1383fa9e4066Sahrens break; 1384fa9e4066Sahrens 1385fa9e4066Sahrens case ZFS_PROP_ACLINHERIT: 13867f7322feSeschrock val = getprop_uint64(zhp, prop, &source); 1387fa9e4066Sahrens for (i = 0; acl_inherit_table[i].name != NULL; i++) { 13887f7322feSeschrock if (acl_inherit_table[i].value == val) 1389fa9e4066Sahrens break; 1390fa9e4066Sahrens } 1391fa9e4066Sahrens assert(acl_inherit_table[i].name != NULL); 1392fa9e4066Sahrens (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen); 1393fa9e4066Sahrens break; 1394fa9e4066Sahrens 1395fa9e4066Sahrens case ZFS_PROP_CREATION: 1396fa9e4066Sahrens /* 1397fa9e4066Sahrens * 'creation' is a time_t stored in the statistics. We convert 1398fa9e4066Sahrens * this into a string unless 'literal' is specified. 1399fa9e4066Sahrens */ 1400fa9e4066Sahrens { 1401fa9e4066Sahrens time_t time = (time_t) 1402fa9e4066Sahrens zhp->zfs_dmustats.dds_creation_time; 1403fa9e4066Sahrens struct tm t; 1404fa9e4066Sahrens 1405fa9e4066Sahrens if (literal || 1406fa9e4066Sahrens localtime_r(&time, &t) == NULL || 1407fa9e4066Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1408fa9e4066Sahrens &t) == 0) 1409fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%llu", 1410fa9e4066Sahrens zhp->zfs_dmustats.dds_creation_time); 1411fa9e4066Sahrens } 1412fa9e4066Sahrens break; 1413fa9e4066Sahrens 1414fa9e4066Sahrens case ZFS_PROP_MOUNTPOINT: 1415fa9e4066Sahrens /* 1416fa9e4066Sahrens * Getting the precise mountpoint can be tricky. 1417fa9e4066Sahrens * 1418fa9e4066Sahrens * - for 'none' or 'legacy', return those values. 1419fa9e4066Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1420fa9e4066Sahrens * - for inherited mountpoints, we want to take everything 1421fa9e4066Sahrens * after our ancestor and append it to the inherited value. 1422fa9e4066Sahrens * 1423fa9e4066Sahrens * If the pool has an alternate root, we want to prepend that 1424fa9e4066Sahrens * root to any values we return. 1425fa9e4066Sahrens */ 1426ea8dc4b6Seschrock root = zhp->zfs_root; 14277f7322feSeschrock str = getprop_string(zhp, prop, &source); 1428fa9e4066Sahrens 14297f7322feSeschrock if (str[0] == '\0') { 1430fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1431fa9e4066Sahrens root, zhp->zfs_name); 14327f7322feSeschrock } else if (str[0] == '/') { 14337f7322feSeschrock const char *relpath = zhp->zfs_name + strlen(source); 1434fa9e4066Sahrens 1435fa9e4066Sahrens if (relpath[0] == '/') 1436fa9e4066Sahrens relpath++; 14377f7322feSeschrock if (str[1] == '\0') 14387f7322feSeschrock str++; 1439fa9e4066Sahrens 1440fa9e4066Sahrens if (relpath[0] == '\0') 1441fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s", 14427f7322feSeschrock root, str); 1443fa9e4066Sahrens else 1444fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 14457f7322feSeschrock root, str, relpath[0] == '@' ? "" : "/", 1446fa9e4066Sahrens relpath); 1447fa9e4066Sahrens } else { 1448fa9e4066Sahrens /* 'legacy' or 'none' */ 14497f7322feSeschrock (void) strlcpy(propbuf, str, proplen); 1450fa9e4066Sahrens } 1451fa9e4066Sahrens 1452fa9e4066Sahrens break; 1453fa9e4066Sahrens 1454fa9e4066Sahrens case ZFS_PROP_SHARENFS: 14557f7322feSeschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 14567f7322feSeschrock proplen); 1457fa9e4066Sahrens break; 1458fa9e4066Sahrens 1459fa9e4066Sahrens case ZFS_PROP_ORIGIN: 1460ea8dc4b6Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1461fa9e4066Sahrens proplen); 1462fa9e4066Sahrens /* 1463fa9e4066Sahrens * If there is no parent at all, return failure to indicate that 1464fa9e4066Sahrens * it doesn't apply to this dataset. 1465fa9e4066Sahrens */ 1466fa9e4066Sahrens if (propbuf[0] == '\0') 1467fa9e4066Sahrens return (-1); 1468fa9e4066Sahrens break; 1469fa9e4066Sahrens 1470fa9e4066Sahrens case ZFS_PROP_QUOTA: 1471fa9e4066Sahrens case ZFS_PROP_RESERVATION: 1472*99653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1473*99653d4eSeschrock return (-1); 1474fa9e4066Sahrens 1475fa9e4066Sahrens /* 1476fa9e4066Sahrens * If quota or reservation is 0, we translate this into 'none' 1477fa9e4066Sahrens * (unless literal is set), and indicate that it's the default 1478fa9e4066Sahrens * value. Otherwise, we print the number nicely and indicate 1479fa9e4066Sahrens * that its set locally. 1480fa9e4066Sahrens */ 1481fa9e4066Sahrens if (val == 0) { 1482fa9e4066Sahrens if (literal) 1483fa9e4066Sahrens (void) strlcpy(propbuf, "0", proplen); 1484fa9e4066Sahrens else 1485fa9e4066Sahrens (void) strlcpy(propbuf, "none", proplen); 1486fa9e4066Sahrens } else { 1487fa9e4066Sahrens if (literal) 1488fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1489fa9e4066Sahrens else 1490fa9e4066Sahrens zfs_nicenum(val, propbuf, proplen); 1491fa9e4066Sahrens } 1492fa9e4066Sahrens break; 1493fa9e4066Sahrens 1494fa9e4066Sahrens case ZFS_PROP_COMPRESSRATIO: 1495*99653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1496*99653d4eSeschrock return (-1); 1497fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1498fa9e4066Sahrens val % 100); 1499fa9e4066Sahrens break; 1500fa9e4066Sahrens 1501fa9e4066Sahrens case ZFS_PROP_TYPE: 1502fa9e4066Sahrens switch (zhp->zfs_type) { 1503fa9e4066Sahrens case ZFS_TYPE_FILESYSTEM: 1504fa9e4066Sahrens str = "filesystem"; 1505fa9e4066Sahrens break; 1506fa9e4066Sahrens case ZFS_TYPE_VOLUME: 1507fa9e4066Sahrens str = "volume"; 1508fa9e4066Sahrens break; 1509fa9e4066Sahrens case ZFS_TYPE_SNAPSHOT: 1510fa9e4066Sahrens str = "snapshot"; 1511fa9e4066Sahrens break; 1512fa9e4066Sahrens default: 1513*99653d4eSeschrock abort(); 1514fa9e4066Sahrens } 1515fa9e4066Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1516fa9e4066Sahrens break; 1517fa9e4066Sahrens 1518fa9e4066Sahrens case ZFS_PROP_MOUNTED: 1519fa9e4066Sahrens /* 1520fa9e4066Sahrens * The 'mounted' property is a pseudo-property that described 1521fa9e4066Sahrens * whether the filesystem is currently mounted. Even though 1522fa9e4066Sahrens * it's a boolean value, the typical values of "on" and "off" 1523fa9e4066Sahrens * don't make sense, so we translate to "yes" and "no". 1524fa9e4066Sahrens */ 1525*99653d4eSeschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 1526*99653d4eSeschrock src, &source, &val) != 0) 1527*99653d4eSeschrock return (-1); 1528*99653d4eSeschrock if (val) 1529fa9e4066Sahrens (void) strlcpy(propbuf, "yes", proplen); 1530fa9e4066Sahrens else 1531fa9e4066Sahrens (void) strlcpy(propbuf, "no", proplen); 1532fa9e4066Sahrens break; 1533fa9e4066Sahrens 1534fa9e4066Sahrens case ZFS_PROP_NAME: 1535fa9e4066Sahrens /* 1536fa9e4066Sahrens * The 'name' property is a pseudo-property derived from the 1537fa9e4066Sahrens * dataset name. It is presented as a real property to simplify 1538fa9e4066Sahrens * consumers. 1539fa9e4066Sahrens */ 1540fa9e4066Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1541fa9e4066Sahrens break; 1542fa9e4066Sahrens 1543fa9e4066Sahrens default: 1544*99653d4eSeschrock abort(); 1545fa9e4066Sahrens } 1546fa9e4066Sahrens 1547fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1548fa9e4066Sahrens 1549fa9e4066Sahrens return (0); 1550fa9e4066Sahrens } 1551fa9e4066Sahrens 1552fa9e4066Sahrens /* 1553fa9e4066Sahrens * Utility function to get the given numeric property. Does no validation that 1554fa9e4066Sahrens * the given property is the appropriate type; should only be used with 1555fa9e4066Sahrens * hard-coded property types. 1556fa9e4066Sahrens */ 1557fa9e4066Sahrens uint64_t 1558fa9e4066Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1559fa9e4066Sahrens { 1560fa9e4066Sahrens char *source; 1561fa9e4066Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 1562*99653d4eSeschrock uint64_t val; 1563*99653d4eSeschrock 1564*99653d4eSeschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 1565fa9e4066Sahrens 1566*99653d4eSeschrock return (val); 1567fa9e4066Sahrens } 1568fa9e4066Sahrens 1569fa9e4066Sahrens /* 1570fa9e4066Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1571fa9e4066Sahrens */ 1572fa9e4066Sahrens int 1573fa9e4066Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1574fa9e4066Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1575fa9e4066Sahrens { 1576fa9e4066Sahrens char *source; 1577fa9e4066Sahrens 1578fa9e4066Sahrens /* 1579fa9e4066Sahrens * Check to see if this property applies to our object 1580fa9e4066Sahrens */ 1581fa9e4066Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1582*99653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 1583*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 1584*99653d4eSeschrock zfs_prop_to_name(prop))); 1585fa9e4066Sahrens 1586fa9e4066Sahrens if (src) 1587fa9e4066Sahrens *src = ZFS_SRC_NONE; 1588fa9e4066Sahrens 1589*99653d4eSeschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 1590*99653d4eSeschrock return (-1); 1591fa9e4066Sahrens 1592fa9e4066Sahrens get_source(zhp, src, source, statbuf, statlen); 1593fa9e4066Sahrens 1594fa9e4066Sahrens return (0); 1595fa9e4066Sahrens } 1596fa9e4066Sahrens 1597fa9e4066Sahrens /* 1598fa9e4066Sahrens * Returns the name of the given zfs handle. 1599fa9e4066Sahrens */ 1600fa9e4066Sahrens const char * 1601fa9e4066Sahrens zfs_get_name(const zfs_handle_t *zhp) 1602fa9e4066Sahrens { 1603fa9e4066Sahrens return (zhp->zfs_name); 1604fa9e4066Sahrens } 1605fa9e4066Sahrens 1606fa9e4066Sahrens /* 1607fa9e4066Sahrens * Returns the type of the given zfs handle. 1608fa9e4066Sahrens */ 1609fa9e4066Sahrens zfs_type_t 1610fa9e4066Sahrens zfs_get_type(const zfs_handle_t *zhp) 1611fa9e4066Sahrens { 1612fa9e4066Sahrens return (zhp->zfs_type); 1613fa9e4066Sahrens } 1614fa9e4066Sahrens 1615fa9e4066Sahrens /* 16167f7322feSeschrock * Iterate over all child filesystems 1617fa9e4066Sahrens */ 1618fa9e4066Sahrens int 16197f7322feSeschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1620fa9e4066Sahrens { 1621fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1622fa9e4066Sahrens zfs_handle_t *nzhp; 1623fa9e4066Sahrens int ret; 1624fa9e4066Sahrens 1625fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1626*99653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1627fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1628fa9e4066Sahrens /* 1629fa9e4066Sahrens * Ignore private dataset names. 1630fa9e4066Sahrens */ 1631fa9e4066Sahrens if (dataset_name_hidden(zc.zc_name)) 1632fa9e4066Sahrens continue; 1633fa9e4066Sahrens 1634fa9e4066Sahrens /* 1635fa9e4066Sahrens * Silently ignore errors, as the only plausible explanation is 1636fa9e4066Sahrens * that the pool has since been removed. 1637fa9e4066Sahrens */ 1638*99653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 1639*99653d4eSeschrock zc.zc_name)) == NULL) 1640fa9e4066Sahrens continue; 1641fa9e4066Sahrens 1642fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1643fa9e4066Sahrens return (ret); 1644fa9e4066Sahrens } 1645fa9e4066Sahrens 1646fa9e4066Sahrens /* 1647fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1648fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1649fa9e4066Sahrens * obtained the handle. 1650fa9e4066Sahrens */ 1651fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 1652*99653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 1653*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1654fa9e4066Sahrens 16557f7322feSeschrock return (0); 16567f7322feSeschrock } 16577f7322feSeschrock 16587f7322feSeschrock /* 16597f7322feSeschrock * Iterate over all snapshots 16607f7322feSeschrock */ 16617f7322feSeschrock int 16627f7322feSeschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 16637f7322feSeschrock { 16647f7322feSeschrock zfs_cmd_t zc = { 0 }; 16657f7322feSeschrock zfs_handle_t *nzhp; 16667f7322feSeschrock int ret; 1667fa9e4066Sahrens 1668fa9e4066Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1669*99653d4eSeschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 1670*99653d4eSeschrock &zc) == 0; 1671fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1672fa9e4066Sahrens 1673*99653d4eSeschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 1674*99653d4eSeschrock zc.zc_name)) == NULL) 1675fa9e4066Sahrens continue; 1676fa9e4066Sahrens 1677fa9e4066Sahrens if ((ret = func(nzhp, data)) != 0) 1678fa9e4066Sahrens return (ret); 1679fa9e4066Sahrens } 1680fa9e4066Sahrens 1681fa9e4066Sahrens /* 1682fa9e4066Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1683fa9e4066Sahrens * returned, then the underlying dataset has been removed since we 1684fa9e4066Sahrens * obtained the handle. Silently ignore this case, and return success. 1685fa9e4066Sahrens */ 1686fa9e4066Sahrens if (errno != ESRCH && errno != ENOENT) 1687*99653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 1688*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1689fa9e4066Sahrens 1690fa9e4066Sahrens return (0); 1691fa9e4066Sahrens } 1692fa9e4066Sahrens 16937f7322feSeschrock /* 16947f7322feSeschrock * Iterate over all children, snapshots and filesystems 16957f7322feSeschrock */ 16967f7322feSeschrock int 16977f7322feSeschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 16987f7322feSeschrock { 16997f7322feSeschrock int ret; 17007f7322feSeschrock 17017f7322feSeschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 17027f7322feSeschrock return (ret); 17037f7322feSeschrock 17047f7322feSeschrock return (zfs_iter_snapshots(zhp, func, data)); 17057f7322feSeschrock } 17067f7322feSeschrock 1707fa9e4066Sahrens /* 1708fa9e4066Sahrens * Given a complete name, return just the portion that refers to the parent. 1709fa9e4066Sahrens * Can return NULL if this is a pool. 1710fa9e4066Sahrens */ 1711fa9e4066Sahrens static int 1712fa9e4066Sahrens parent_name(const char *path, char *buf, size_t buflen) 1713fa9e4066Sahrens { 1714fa9e4066Sahrens char *loc; 1715fa9e4066Sahrens 1716fa9e4066Sahrens if ((loc = strrchr(path, '/')) == NULL) 1717fa9e4066Sahrens return (-1); 1718fa9e4066Sahrens 1719fa9e4066Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1720fa9e4066Sahrens buf[loc - path] = '\0'; 1721fa9e4066Sahrens 1722fa9e4066Sahrens return (0); 1723fa9e4066Sahrens } 1724fa9e4066Sahrens 1725fa9e4066Sahrens /* 1726fa9e4066Sahrens * Checks to make sure that the given path has a parent, and that it exists. 1727fa9e4066Sahrens */ 1728fa9e4066Sahrens static int 1729*99653d4eSeschrock check_parents(libzfs_handle_t *hdl, const char *path) 1730fa9e4066Sahrens { 1731fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1732fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 1733fa9e4066Sahrens char *slash; 17347f7322feSeschrock zfs_handle_t *zhp; 1735*99653d4eSeschrock char errbuf[1024]; 1736*99653d4eSeschrock 1737*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 1738*99653d4eSeschrock path); 1739fa9e4066Sahrens 1740fa9e4066Sahrens /* get parent, and check to see if this is just a pool */ 1741fa9e4066Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 1742*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1743*99653d4eSeschrock "missing dataset name")); 1744*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1745fa9e4066Sahrens } 1746fa9e4066Sahrens 1747fa9e4066Sahrens /* check to see if the pool exists */ 1748fa9e4066Sahrens if ((slash = strchr(parent, '/')) == NULL) 1749fa9e4066Sahrens slash = parent + strlen(parent); 1750fa9e4066Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1751fa9e4066Sahrens zc.zc_name[slash - parent] = '\0'; 1752*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1753fa9e4066Sahrens errno == ENOENT) { 1754*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1755*99653d4eSeschrock "no such pool '%s'"), zc.zc_name); 1756*99653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1757fa9e4066Sahrens } 1758fa9e4066Sahrens 1759fa9e4066Sahrens /* check to see if the parent dataset exists */ 1760*99653d4eSeschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1761fa9e4066Sahrens switch (errno) { 1762fa9e4066Sahrens case ENOENT: 1763*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1764*99653d4eSeschrock "parent does not exist")); 1765*99653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1766fa9e4066Sahrens 1767fa9e4066Sahrens default: 1768*99653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1769fa9e4066Sahrens } 1770fa9e4066Sahrens } 1771fa9e4066Sahrens 1772fa9e4066Sahrens /* we are in a non-global zone, but parent is in the global zone */ 17737f7322feSeschrock if (getzoneid() != GLOBAL_ZONEID && 177420c8013fSlling !zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 1775*99653d4eSeschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 17767f7322feSeschrock zfs_close(zhp); 1777fa9e4066Sahrens return (-1); 1778fa9e4066Sahrens } 1779fa9e4066Sahrens 1780fa9e4066Sahrens /* make sure parent is a filesystem */ 17817f7322feSeschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1782*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1783*99653d4eSeschrock "parent is not a filesystem")); 1784*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 17857f7322feSeschrock zfs_close(zhp); 1786fa9e4066Sahrens return (-1); 1787fa9e4066Sahrens } 1788fa9e4066Sahrens 17897f7322feSeschrock zfs_close(zhp); 1790fa9e4066Sahrens return (0); 1791fa9e4066Sahrens } 1792fa9e4066Sahrens 1793fa9e4066Sahrens /* 1794fa9e4066Sahrens * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used 1795fa9e4066Sahrens * only for volumes, and indicate the size and blocksize of the volume. 1796fa9e4066Sahrens */ 1797fa9e4066Sahrens int 1798*99653d4eSeschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 1799fa9e4066Sahrens const char *sizestr, const char *blocksizestr) 1800fa9e4066Sahrens { 1801fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1802fa9e4066Sahrens int ret; 1803fa9e4066Sahrens uint64_t size = 0; 1804fa9e4066Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 1805*99653d4eSeschrock char errbuf[1024]; 1806fa9e4066Sahrens 1807fa9e4066Sahrens /* convert sizestr into integer size */ 1808*99653d4eSeschrock if (sizestr != NULL && nicestrtonum(hdl, sizestr, &size) != 0) 1809*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 1810*99653d4eSeschrock "bad volume size '%s'"), sizestr)); 1811fa9e4066Sahrens 1812fa9e4066Sahrens /* convert blocksizestr into integer blocksize */ 1813*99653d4eSeschrock if (blocksizestr != NULL && nicestrtonum(hdl, blocksizestr, 1814*99653d4eSeschrock &blocksize) != 0) 1815*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 1816*99653d4eSeschrock "bad volume blocksize '%s'"), blocksizestr)); 1817*99653d4eSeschrock 1818*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1819*99653d4eSeschrock "cannot create '%s'"), path); 1820fa9e4066Sahrens 1821fa9e4066Sahrens /* validate the path, taking care to note the extended error message */ 1822*99653d4eSeschrock if (!zfs_validate_name(hdl, path, type)) 1823*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1824fa9e4066Sahrens 1825fa9e4066Sahrens /* validate parents exist */ 1826*99653d4eSeschrock if (check_parents(hdl, path) != 0) 1827fa9e4066Sahrens return (-1); 1828fa9e4066Sahrens 1829fa9e4066Sahrens /* 1830fa9e4066Sahrens * The failure modes when creating a dataset of a different type over 1831fa9e4066Sahrens * one that already exists is a little strange. In particular, if you 1832fa9e4066Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1833fa9e4066Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1834fa9e4066Sahrens * first try to see if the dataset exists. 1835fa9e4066Sahrens */ 1836fa9e4066Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 1837*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 1838*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1839*99653d4eSeschrock "dataset already exists")); 1840*99653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1841fa9e4066Sahrens } 1842fa9e4066Sahrens 1843fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) 1844fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1845fa9e4066Sahrens else 1846fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1847fa9e4066Sahrens 1848fa9e4066Sahrens if (type == ZFS_TYPE_VOLUME) { 18495c5460e9Seschrock /* 18505c5460e9Seschrock * If we are creating a volume, the size and block size must 18515c5460e9Seschrock * satisfy a few restraints. First, the blocksize must be a 18525c5460e9Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 18535c5460e9Seschrock * volsize must be a multiple of the block size, and cannot be 18545c5460e9Seschrock * zero. 18555c5460e9Seschrock */ 1856fa9e4066Sahrens if (size == 0) { 1857*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1858*99653d4eSeschrock "cannot be zero")); 1859*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, 1860*99653d4eSeschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 1861*99653d4eSeschrock sizestr)); 1862fa9e4066Sahrens } 1863fa9e4066Sahrens 18645c5460e9Seschrock if (blocksize < SPA_MINBLOCKSIZE || 18655c5460e9Seschrock blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) { 1866*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18675c5460e9Seschrock "must be power of 2 from %u to %uk"), 18685c5460e9Seschrock (uint_t)SPA_MINBLOCKSIZE, 18695c5460e9Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 1870*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, 1871*99653d4eSeschrock dgettext(TEXT_DOMAIN, 1872*99653d4eSeschrock "bad volume block size '%s'"), blocksizestr)); 18735c5460e9Seschrock } 18745c5460e9Seschrock 18755c5460e9Seschrock if (size % blocksize != 0) { 1876*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1877*99653d4eSeschrock "must be a multiple of volume block size")); 1878*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, 1879*99653d4eSeschrock dgettext(TEXT_DOMAIN, "bad volume size '%s'"), 1880*99653d4eSeschrock sizestr)); 18815c5460e9Seschrock } 18825c5460e9Seschrock 1883fa9e4066Sahrens zc.zc_volsize = size; 1884fa9e4066Sahrens zc.zc_volblocksize = blocksize; 1885fa9e4066Sahrens } 1886fa9e4066Sahrens 1887fa9e4066Sahrens /* create the dataset */ 1888*99653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 1889fa9e4066Sahrens 1890fa9e4066Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 1891*99653d4eSeschrock ret = zvol_create_link(hdl, path); 1892fa9e4066Sahrens 1893fa9e4066Sahrens /* check for failure */ 1894fa9e4066Sahrens if (ret != 0) { 1895fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 1896fa9e4066Sahrens (void) parent_name(path, parent, sizeof (parent)); 1897fa9e4066Sahrens 1898fa9e4066Sahrens switch (errno) { 1899fa9e4066Sahrens case ENOENT: 1900*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1901*99653d4eSeschrock "no such parent '%s'"), parent); 1902*99653d4eSeschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1903fa9e4066Sahrens 1904fa9e4066Sahrens case EINVAL: 1905*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1906*99653d4eSeschrock "parent '%s' is not a filesysem"), parent); 1907*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 1908fa9e4066Sahrens 1909fa9e4066Sahrens case EDOM: 1910*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1911fa9e4066Sahrens "must be power of 2 from %u to %uk"), 1912fa9e4066Sahrens (uint_t)SPA_MINBLOCKSIZE, 1913fa9e4066Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 1914*99653d4eSeschrock 1915*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADPROP, 1916*99653d4eSeschrock dgettext(TEXT_DOMAIN, "bad block size '%s'"), 1917*99653d4eSeschrock blocksizestr ? blocksizestr : "<unknown>")); 1918*99653d4eSeschrock 1919fa9e4066Sahrens #ifdef _ILP32 1920fa9e4066Sahrens case EOVERFLOW: 1921fa9e4066Sahrens /* 1922fa9e4066Sahrens * This platform can't address a volume this big. 1923fa9e4066Sahrens */ 1924*99653d4eSeschrock if (type == ZFS_TYPE_VOLUME) 1925*99653d4eSeschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 1926*99653d4eSeschrock errbuf)); 1927fa9e4066Sahrens #endif 1928*99653d4eSeschrock /* FALLTHROUGH */ 1929fa9e4066Sahrens default: 1930*99653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 1931fa9e4066Sahrens } 1932fa9e4066Sahrens } 1933fa9e4066Sahrens 1934fa9e4066Sahrens return (0); 1935fa9e4066Sahrens } 1936fa9e4066Sahrens 1937fa9e4066Sahrens /* 1938fa9e4066Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 1939fa9e4066Sahrens * isn't mounted, and that there are no active dependents. 1940fa9e4066Sahrens */ 1941fa9e4066Sahrens int 1942fa9e4066Sahrens zfs_destroy(zfs_handle_t *zhp) 1943fa9e4066Sahrens { 1944fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1945fa9e4066Sahrens int ret; 1946*99653d4eSeschrock char errbuf[1024]; 1947fa9e4066Sahrens 1948fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1949fa9e4066Sahrens 1950fa9e4066Sahrens /* 1951fa9e4066Sahrens * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME 1952fa9e4066Sahrens * so that we do the right thing for snapshots of volumes. 1953fa9e4066Sahrens */ 1954fa9e4066Sahrens if (zhp->zfs_volblocksize != 0) { 1955*99653d4eSeschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 1956fa9e4066Sahrens return (-1); 1957fa9e4066Sahrens 1958fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1959fa9e4066Sahrens } else { 1960fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 1961fa9e4066Sahrens } 1962fa9e4066Sahrens 1963*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 1964fa9e4066Sahrens 1965*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1966*99653d4eSeschrock "cannot destroy '%s'"), zhp->zfs_name); 1967fa9e4066Sahrens 1968*99653d4eSeschrock if (ret != 0) 1969*99653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 1970*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 1971*99653d4eSeschrock zhp->zfs_name)); 1972fa9e4066Sahrens 1973fa9e4066Sahrens remove_mountpoint(zhp); 1974fa9e4066Sahrens 1975fa9e4066Sahrens return (0); 1976fa9e4066Sahrens } 1977fa9e4066Sahrens 1978fa9e4066Sahrens /* 1979fa9e4066Sahrens * Clones the given dataset. The target must be of the same type as the source. 1980fa9e4066Sahrens */ 1981fa9e4066Sahrens int 1982fa9e4066Sahrens zfs_clone(zfs_handle_t *zhp, const char *target) 1983fa9e4066Sahrens { 1984fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1985fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 1986fa9e4066Sahrens int ret; 1987*99653d4eSeschrock char errbuf[1024]; 1988*99653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 1989fa9e4066Sahrens 1990fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 1991fa9e4066Sahrens 1992*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1993*99653d4eSeschrock "cannot create '%s'"), target); 1994*99653d4eSeschrock 1995fa9e4066Sahrens /* validate the target name */ 1996*99653d4eSeschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 1997*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1998fa9e4066Sahrens 1999fa9e4066Sahrens /* validate parents exist */ 2000*99653d4eSeschrock if (check_parents(zhp->zfs_hdl, target) != 0) 2001fa9e4066Sahrens return (-1); 2002fa9e4066Sahrens 2003fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 2004fa9e4066Sahrens 2005fa9e4066Sahrens /* do the clone */ 2006fa9e4066Sahrens if (zhp->zfs_volblocksize != 0) 2007fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2008fa9e4066Sahrens else 2009fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2010fa9e4066Sahrens 2011fa9e4066Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2012fa9e4066Sahrens (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename)); 2013*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2014fa9e4066Sahrens 2015fa9e4066Sahrens if (ret != 0) { 2016fa9e4066Sahrens switch (errno) { 2017fa9e4066Sahrens 2018fa9e4066Sahrens case ENOENT: 2019fa9e4066Sahrens /* 2020fa9e4066Sahrens * The parent doesn't exist. We should have caught this 2021fa9e4066Sahrens * above, but there may a race condition that has since 2022fa9e4066Sahrens * destroyed the parent. 2023fa9e4066Sahrens * 2024fa9e4066Sahrens * At this point, we don't know whether it's the source 2025fa9e4066Sahrens * that doesn't exist anymore, or whether the target 2026fa9e4066Sahrens * dataset doesn't exist. 2027fa9e4066Sahrens */ 2028*99653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2029*99653d4eSeschrock "no such parent '%s'"), parent); 2030*99653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 2031fa9e4066Sahrens 2032*99653d4eSeschrock case EXDEV: 2033*99653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2034*99653d4eSeschrock "source and target pools differ")); 2035*99653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 2036*99653d4eSeschrock errbuf)); 2037fa9e4066Sahrens 2038*99653d4eSeschrock default: 2039*99653d4eSeschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 2040*99653d4eSeschrock errbuf)); 2041*99653d4eSeschrock } 2042*99653d4eSeschrock } else if (zhp->zfs_volblocksize != 0) { 2043*99653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, target); 2044*99653d4eSeschrock } 2045fa9e4066Sahrens 2046*99653d4eSeschrock return (ret); 2047*99653d4eSeschrock } 2048*99653d4eSeschrock 2049*99653d4eSeschrock typedef struct promote_data { 2050*99653d4eSeschrock char cb_mountpoint[MAXPATHLEN]; 2051*99653d4eSeschrock const char *cb_target; 2052*99653d4eSeschrock const char *cb_errbuf; 2053*99653d4eSeschrock uint64_t cb_pivot_txg; 2054*99653d4eSeschrock } promote_data_t; 2055*99653d4eSeschrock 2056*99653d4eSeschrock static int 2057*99653d4eSeschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 2058*99653d4eSeschrock { 2059*99653d4eSeschrock promote_data_t *pd = data; 2060*99653d4eSeschrock zfs_handle_t *szhp; 2061*99653d4eSeschrock int err; 2062*99653d4eSeschrock char snapname[MAXPATHLEN]; 2063*99653d4eSeschrock char *cp; 2064*99653d4eSeschrock 2065*99653d4eSeschrock /* We don't care about snapshots after the pivot point */ 2066*99653d4eSeschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 2067*99653d4eSeschrock return (0); 2068*99653d4eSeschrock 2069*99653d4eSeschrock /* 2070*99653d4eSeschrock * Unmount it. We actually need to open it to provoke it to be 2071*99653d4eSeschrock * mounted first, because if it is not mounted, umount2 will 2072*99653d4eSeschrock * mount it! 2073*99653d4eSeschrock */ 2074*99653d4eSeschrock (void) strcpy(snapname, pd->cb_mountpoint); 2075*99653d4eSeschrock (void) strcat(snapname, "/.zfs/snapshot/"); 2076*99653d4eSeschrock cp = strchr(zhp->zfs_name, '@'); 2077*99653d4eSeschrock (void) strcat(snapname, cp+1); 2078*99653d4eSeschrock err = open(snapname, O_RDONLY); 2079*99653d4eSeschrock if (err != -1) 2080*99653d4eSeschrock (void) close(err); 2081*99653d4eSeschrock (void) umount2(snapname, MS_FORCE); 2082*99653d4eSeschrock 2083*99653d4eSeschrock /* Check for conflicting names */ 2084*99653d4eSeschrock (void) strcpy(snapname, pd->cb_target); 2085*99653d4eSeschrock (void) strcat(snapname, cp); 2086*99653d4eSeschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 2087*99653d4eSeschrock if (szhp != NULL) { 2088*99653d4eSeschrock zfs_close(szhp); 2089*99653d4eSeschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2090*99653d4eSeschrock "snapshot name '%s' from origin \n" 2091*99653d4eSeschrock "conflicts with '%s' from target"), 2092*99653d4eSeschrock zhp->zfs_name, snapname); 2093*99653d4eSeschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 2094*99653d4eSeschrock } 2095*99653d4eSeschrock return (0); 2096*99653d4eSeschrock } 2097*99653d4eSeschrock 2098*99653d4eSeschrock /* 2099*99653d4eSeschrock * Promotes the given clone fs to be the clone parent. 2100*99653d4eSeschrock */ 2101*99653d4eSeschrock int 2102*99653d4eSeschrock zfs_promote(zfs_handle_t *zhp) 2103*99653d4eSeschrock { 2104*99653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2105*99653d4eSeschrock zfs_cmd_t zc = { 0 }; 2106*99653d4eSeschrock char parent[MAXPATHLEN]; 2107*99653d4eSeschrock char *cp; 2108*99653d4eSeschrock int ret; 2109*99653d4eSeschrock zfs_handle_t *pzhp; 2110*99653d4eSeschrock promote_data_t pd; 2111*99653d4eSeschrock char errbuf[1024]; 2112*99653d4eSeschrock 2113*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2114*99653d4eSeschrock "cannot promote '%s'"), zhp->zfs_name); 2115*99653d4eSeschrock 2116*99653d4eSeschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2117*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2118*99653d4eSeschrock "snapshots can not be promoted")); 2119*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2120*99653d4eSeschrock } 2121*99653d4eSeschrock 2122*99653d4eSeschrock (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of); 2123*99653d4eSeschrock if (parent[0] == '\0') { 2124*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2125*99653d4eSeschrock "not a cloned filesystem")); 2126*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2127*99653d4eSeschrock } 2128*99653d4eSeschrock cp = strchr(parent, '@'); 2129*99653d4eSeschrock *cp = '\0'; 2130*99653d4eSeschrock 2131*99653d4eSeschrock /* Walk the snapshots we will be moving */ 2132*99653d4eSeschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 2133*99653d4eSeschrock if (pzhp == NULL) 2134*99653d4eSeschrock return (-1); 2135*99653d4eSeschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 2136*99653d4eSeschrock zfs_close(pzhp); 2137*99653d4eSeschrock pd.cb_target = zhp->zfs_name; 2138*99653d4eSeschrock pd.cb_errbuf = errbuf; 2139*99653d4eSeschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 2140*99653d4eSeschrock if (pzhp == NULL) 2141*99653d4eSeschrock return (-1); 2142*99653d4eSeschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 2143*99653d4eSeschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 2144*99653d4eSeschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 2145*99653d4eSeschrock if (ret != 0) 2146*99653d4eSeschrock return (-1); 2147*99653d4eSeschrock 2148*99653d4eSeschrock /* issue the ioctl */ 2149*99653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2150*99653d4eSeschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 2151*99653d4eSeschrock 2152*99653d4eSeschrock if (ret != 0) { 2153*99653d4eSeschrock switch (errno) { 2154*99653d4eSeschrock 2155*99653d4eSeschrock case EEXIST: 2156fa9e4066Sahrens /* 2157*99653d4eSeschrock * There is a conflicting snapshot name. We 2158*99653d4eSeschrock * should have caught this above, but they could 2159*99653d4eSeschrock * have renamed something in the mean time. 2160fa9e4066Sahrens */ 2161*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2162*99653d4eSeschrock "conflicting snapshot name from parent '%s'"), 2163*99653d4eSeschrock parent); 2164*99653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2165fa9e4066Sahrens 2166fa9e4066Sahrens default: 2167*99653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2168fa9e4066Sahrens } 2169fa9e4066Sahrens } 2170fa9e4066Sahrens 2171fa9e4066Sahrens return (ret); 2172fa9e4066Sahrens } 2173fa9e4066Sahrens 2174fa9e4066Sahrens /* 2175fa9e4066Sahrens * Takes a snapshot of the given dataset 2176fa9e4066Sahrens */ 2177fa9e4066Sahrens int 2178*99653d4eSeschrock zfs_snapshot(libzfs_handle_t *hdl, const char *path) 2179fa9e4066Sahrens { 2180fa9e4066Sahrens const char *delim; 2181fa9e4066Sahrens char *parent; 2182fa9e4066Sahrens zfs_handle_t *zhp; 2183fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2184fa9e4066Sahrens int ret; 2185*99653d4eSeschrock char errbuf[1024]; 2186fa9e4066Sahrens 2187*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2188*99653d4eSeschrock "cannot snapshot '%s'"), path); 2189*99653d4eSeschrock 2190*99653d4eSeschrock /* validate the target name */ 2191*99653d4eSeschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 2192*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2193fa9e4066Sahrens 2194fa9e4066Sahrens /* make sure we have a snapshot */ 2195fa9e4066Sahrens if ((delim = strchr(path, '@')) == NULL) { 2196*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2197*99653d4eSeschrock "missing '@' delimeter in snapshot name")); 2198*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2199fa9e4066Sahrens } 2200fa9e4066Sahrens 2201fa9e4066Sahrens /* make sure the parent exists and is of the appropriate type */ 2202*99653d4eSeschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 2203*99653d4eSeschrock return (-1); 2204fa9e4066Sahrens (void) strncpy(parent, path, delim - path); 2205fa9e4066Sahrens parent[delim - path] = '\0'; 2206fa9e4066Sahrens 2207*99653d4eSeschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2208fa9e4066Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2209fa9e4066Sahrens free(parent); 2210fa9e4066Sahrens return (-1); 2211fa9e4066Sahrens } 2212fa9e4066Sahrens 2213fa9e4066Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 2214fa9e4066Sahrens 2215fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) 2216fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2217fa9e4066Sahrens else 2218fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2219fa9e4066Sahrens 2220*99653d4eSeschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2221fa9e4066Sahrens 2222fa9e4066Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 2223*99653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, path); 2224fa9e4066Sahrens if (ret != 0) 2225*99653d4eSeschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 2226*99653d4eSeschrock &zc); 2227fa9e4066Sahrens } 2228fa9e4066Sahrens 2229*99653d4eSeschrock if (ret != 0) 2230*99653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2231fa9e4066Sahrens 2232fa9e4066Sahrens free(parent); 2233fa9e4066Sahrens zfs_close(zhp); 2234fa9e4066Sahrens 2235fa9e4066Sahrens return (ret); 2236fa9e4066Sahrens } 2237fa9e4066Sahrens 2238fa9e4066Sahrens /* 2239fa9e4066Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2240fa9e4066Sahrens */ 2241fa9e4066Sahrens int 2242f2a3c691Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2243fa9e4066Sahrens { 2244fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2245fa9e4066Sahrens int ret; 2246*99653d4eSeschrock char errbuf[1024]; 2247*99653d4eSeschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 2248*99653d4eSeschrock 2249*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2250*99653d4eSeschrock "cannot send '%s'"), zhp_to->zfs_name); 2251fa9e4066Sahrens 2252fa9e4066Sahrens /* do the ioctl() */ 2253fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2254fa9e4066Sahrens if (zhp_from) { 2255fa9e4066Sahrens (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name, 2256fa9e4066Sahrens sizeof (zc.zc_name)); 2257fa9e4066Sahrens } else { 2258fa9e4066Sahrens zc.zc_prop_value[0] = '\0'; 2259fa9e4066Sahrens } 2260fa9e4066Sahrens zc.zc_cookie = STDOUT_FILENO; 2261fa9e4066Sahrens 2262*99653d4eSeschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2263fa9e4066Sahrens if (ret != 0) { 2264fa9e4066Sahrens switch (errno) { 2265fa9e4066Sahrens 2266fa9e4066Sahrens case EXDEV: 2267*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2268*99653d4eSeschrock "not an ealier snapshot from the same fs")); 2269*99653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2270fa9e4066Sahrens 2271fa9e4066Sahrens case EDQUOT: 2272fa9e4066Sahrens case EFBIG: 2273fa9e4066Sahrens case EIO: 2274fa9e4066Sahrens case ENOLINK: 2275fa9e4066Sahrens case ENOSPC: 2276fa9e4066Sahrens case ENOSTR: 2277fa9e4066Sahrens case ENXIO: 2278fa9e4066Sahrens case EPIPE: 2279fa9e4066Sahrens case ERANGE: 2280fa9e4066Sahrens case EFAULT: 2281fa9e4066Sahrens case EROFS: 2282*99653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 2283*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2284fa9e4066Sahrens 2285fa9e4066Sahrens default: 2286*99653d4eSeschrock return (zfs_standard_error(hdl, errno, errbuf)); 2287fa9e4066Sahrens } 2288fa9e4066Sahrens } 2289fa9e4066Sahrens 2290fa9e4066Sahrens return (ret); 2291fa9e4066Sahrens } 2292fa9e4066Sahrens 2293fa9e4066Sahrens /* 2294fa9e4066Sahrens * Restores a backup of tosnap from stdin. 2295fa9e4066Sahrens */ 2296fa9e4066Sahrens int 2297*99653d4eSeschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 2298*99653d4eSeschrock int verbose, int dryrun) 2299fa9e4066Sahrens { 2300fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2301fa9e4066Sahrens time_t begin_time; 23029b4f025eSahrens int ioctl_err, err, bytes, size; 2303fa9e4066Sahrens char *cp; 2304fa9e4066Sahrens dmu_replay_record_t drr; 2305fa9e4066Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 2306*99653d4eSeschrock char errbuf[1024]; 2307fa9e4066Sahrens 2308fa9e4066Sahrens begin_time = time(NULL); 2309fa9e4066Sahrens 2310*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2311*99653d4eSeschrock "cannot receive")); 2312*99653d4eSeschrock 2313fa9e4066Sahrens /* trim off snapname, if any */ 2314fa9e4066Sahrens (void) strcpy(zc.zc_name, tosnap); 2315fa9e4066Sahrens cp = strchr(zc.zc_name, '@'); 2316fa9e4066Sahrens if (cp) 2317fa9e4066Sahrens *cp = '\0'; 2318fa9e4066Sahrens 2319fa9e4066Sahrens /* read in the BEGIN record */ 2320fa9e4066Sahrens cp = (char *)&drr; 2321fa9e4066Sahrens bytes = 0; 2322fa9e4066Sahrens do { 23239b4f025eSahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 23249b4f025eSahrens cp += size; 23259b4f025eSahrens bytes += size; 23269b4f025eSahrens } while (size > 0); 2327fa9e4066Sahrens 23289b4f025eSahrens if (size < 0 || bytes != sizeof (drr)) { 2329*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2330*99653d4eSeschrock "stream (failed to read first record)")); 2331*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2332fa9e4066Sahrens } 2333fa9e4066Sahrens 2334fa9e4066Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2335fa9e4066Sahrens 2336fa9e4066Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2337fa9e4066Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 2338*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2339*99653d4eSeschrock "stream (bad magic number)")); 2340*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2341fa9e4066Sahrens } 2342fa9e4066Sahrens 2343fa9e4066Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2344fa9e4066Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 2345*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 2346*99653d4eSeschrock "0x%llx is supported (stream is version 0x%llx)"), 2347fa9e4066Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 2348*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2349fa9e4066Sahrens } 2350fa9e4066Sahrens 2351fa9e4066Sahrens /* 2352fa9e4066Sahrens * Determine name of destination snapshot. 2353fa9e4066Sahrens */ 2354ea8dc4b6Seschrock (void) strcpy(zc.zc_filename, tosnap); 2355fa9e4066Sahrens if (isprefix) { 2356fa9e4066Sahrens if (strchr(tosnap, '@') != NULL) { 2357*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2358*99653d4eSeschrock "destination must be a filesystem")); 2359*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2360fa9e4066Sahrens } 2361fa9e4066Sahrens 2362fa9e4066Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2363fa9e4066Sahrens if (cp == NULL) 2364fa9e4066Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2365fa9e4066Sahrens else 2366fa9e4066Sahrens cp++; 2367fa9e4066Sahrens 2368ea8dc4b6Seschrock (void) strcat(zc.zc_filename, "/"); 2369ea8dc4b6Seschrock (void) strcat(zc.zc_filename, cp); 2370fa9e4066Sahrens } else if (strchr(tosnap, '@') == NULL) { 2371fa9e4066Sahrens /* 2372fa9e4066Sahrens * they specified just a filesystem; tack on the 2373fa9e4066Sahrens * snapname from the backup. 2374fa9e4066Sahrens */ 2375fa9e4066Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 2376*99653d4eSeschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 2377*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2378ea8dc4b6Seschrock (void) strcat(zc.zc_filename, cp); 2379fa9e4066Sahrens } 2380fa9e4066Sahrens 2381fa9e4066Sahrens if (drrb->drr_fromguid) { 2382fa9e4066Sahrens zfs_handle_t *h; 2383fa9e4066Sahrens /* incremental backup stream */ 2384fa9e4066Sahrens 2385fa9e4066Sahrens /* do the ioctl to the containing fs */ 2386ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 2387fa9e4066Sahrens cp = strchr(zc.zc_name, '@'); 2388fa9e4066Sahrens *cp = '\0'; 2389fa9e4066Sahrens 2390fa9e4066Sahrens /* make sure destination fs exists */ 2391*99653d4eSeschrock h = zfs_open(hdl, zc.zc_name, 2392*99653d4eSeschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2393*99653d4eSeschrock if (h == NULL) 2394fa9e4066Sahrens return (-1); 23959b4f025eSahrens if (!dryrun) { 23969b4f025eSahrens /* unmount destination fs or remove device link. */ 23979b4f025eSahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 23989b4f025eSahrens (void) zfs_unmount(h, NULL, 0); 23999b4f025eSahrens } else { 2400*99653d4eSeschrock (void) zvol_remove_link(hdl, h->zfs_name); 24019b4f025eSahrens } 24029b4f025eSahrens } 2403fa9e4066Sahrens zfs_close(h); 2404fa9e4066Sahrens } else { 2405fa9e4066Sahrens /* full backup stream */ 2406fa9e4066Sahrens 2407ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zc.zc_filename); 24089b4f025eSahrens 2409f2a3c691Sahrens /* make sure they aren't trying to receive into the root */ 24109b4f025eSahrens if (strchr(zc.zc_name, '/') == NULL) { 2411fa9e4066Sahrens cp = strchr(zc.zc_name, '@'); 2412fa9e4066Sahrens if (cp) 2413fa9e4066Sahrens *cp = '\0'; 2414*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2415*99653d4eSeschrock "destination '%s' already exists"), zc.zc_name); 2416*99653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2417fa9e4066Sahrens } 2418fa9e4066Sahrens 2419fa9e4066Sahrens if (isprefix) { 2420fa9e4066Sahrens zfs_handle_t *h; 2421fa9e4066Sahrens 24229b4f025eSahrens /* make sure prefix exists */ 2423*99653d4eSeschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 2424*99653d4eSeschrock if (h == NULL) 2425fa9e4066Sahrens return (-1); 2426ea8dc4b6Seschrock zfs_close(h); 2427fa9e4066Sahrens 2428fa9e4066Sahrens /* create any necessary ancestors up to prefix */ 24299b4f025eSahrens zc.zc_objset_type = DMU_OST_ZFS; 2430ea8dc4b6Seschrock 24319b4f025eSahrens /* 24329b4f025eSahrens * zc.zc_name is now the full name of the snap 2433ea8dc4b6Seschrock * we're restoring into. Attempt to create, 2434ea8dc4b6Seschrock * mount, and share any ancestor filesystems, up 2435ea8dc4b6Seschrock * to the one that was named. 24369b4f025eSahrens */ 2437ea8dc4b6Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 2438ea8dc4b6Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 2439ea8dc4b6Seschrock const char *opname; 2440fa9e4066Sahrens *cp = '\0'; 2441ea8dc4b6Seschrock 2442*99653d4eSeschrock opname = dgettext(TEXT_DOMAIN, "create"); 2443*99653d4eSeschrock if (zfs_create(hdl, zc.zc_name, 2444*99653d4eSeschrock ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) { 2445ea8dc4b6Seschrock if (errno == EEXIST) 2446ea8dc4b6Seschrock continue; 2447ea8dc4b6Seschrock goto ancestorerr; 2448fa9e4066Sahrens } 2449ea8dc4b6Seschrock 2450*99653d4eSeschrock opname = dgettext(TEXT_DOMAIN, "open"); 2451*99653d4eSeschrock h = zfs_open(hdl, zc.zc_name, 2452*99653d4eSeschrock ZFS_TYPE_FILESYSTEM); 2453ea8dc4b6Seschrock if (h == NULL) 2454ea8dc4b6Seschrock goto ancestorerr; 2455ea8dc4b6Seschrock 2456*99653d4eSeschrock opname = dgettext(TEXT_DOMAIN, "mount"); 2457ea8dc4b6Seschrock if (zfs_mount(h, NULL, 0) != 0) 2458ea8dc4b6Seschrock goto ancestorerr; 2459ea8dc4b6Seschrock 2460*99653d4eSeschrock opname = dgettext(TEXT_DOMAIN, "share"); 2461ea8dc4b6Seschrock if (zfs_share(h) != 0) 2462ea8dc4b6Seschrock goto ancestorerr; 2463ea8dc4b6Seschrock 2464ea8dc4b6Seschrock zfs_close(h); 2465ea8dc4b6Seschrock 2466ea8dc4b6Seschrock continue; 2467ea8dc4b6Seschrock ancestorerr: 2468*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2469*99653d4eSeschrock "failed to %s ancestor '%s'"), opname, 2470*99653d4eSeschrock zc.zc_name); 2471*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADRESTORE, 2472*99653d4eSeschrock errbuf)); 2473fa9e4066Sahrens } 2474fa9e4066Sahrens } 24759b4f025eSahrens 24769b4f025eSahrens /* Make sure destination fs does not exist */ 24779b4f025eSahrens cp = strchr(zc.zc_name, '@'); 24789b4f025eSahrens *cp = '\0'; 2479*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2480*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2481*99653d4eSeschrock "destination '%s' exists"), zc.zc_name); 2482*99653d4eSeschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 24839b4f025eSahrens } 24849b4f025eSahrens 24859b4f025eSahrens /* Do the recvbackup ioctl to the fs's parent. */ 24869b4f025eSahrens cp = strrchr(zc.zc_name, '/'); 24879b4f025eSahrens *cp = '\0'; 2488fa9e4066Sahrens } 2489fa9e4066Sahrens 2490fa9e4066Sahrens (void) strcpy(zc.zc_prop_value, tosnap); 2491fa9e4066Sahrens zc.zc_cookie = STDIN_FILENO; 2492fa9e4066Sahrens zc.zc_intsz = isprefix; 2493fa9e4066Sahrens if (verbose) { 2494f2a3c691Sahrens (void) printf("%s %s stream of %s into %s\n", 2495f2a3c691Sahrens dryrun ? "would receive" : "receiving", 2496fa9e4066Sahrens drrb->drr_fromguid ? "incremental" : "full", 2497fa9e4066Sahrens drr.drr_u.drr_begin.drr_toname, 2498ea8dc4b6Seschrock zc.zc_filename); 2499fa9e4066Sahrens (void) fflush(stdout); 2500fa9e4066Sahrens } 2501fa9e4066Sahrens if (dryrun) 2502fa9e4066Sahrens return (0); 2503*99653d4eSeschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 25049b4f025eSahrens if (ioctl_err != 0) { 2505fa9e4066Sahrens switch (errno) { 2506fa9e4066Sahrens case ENODEV: 2507*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2508*99653d4eSeschrock "most recent snapshot does not match incremental " 2509*99653d4eSeschrock "source")); 2510*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2511fa9e4066Sahrens break; 2512fa9e4066Sahrens case ETXTBSY: 2513*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2514*99653d4eSeschrock "destination has been modified since most recent " 2515*99653d4eSeschrock "snapshot")); 2516*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2517fa9e4066Sahrens break; 2518fa9e4066Sahrens case EEXIST: 2519fa9e4066Sahrens if (drrb->drr_fromguid == 0) { 2520fa9e4066Sahrens /* it's the containing fs that exists */ 2521ea8dc4b6Seschrock cp = strchr(zc.zc_filename, '@'); 2522fa9e4066Sahrens *cp = '\0'; 2523fa9e4066Sahrens } 2524*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2525*99653d4eSeschrock "destination already exists")); 2526*99653d4eSeschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 2527*99653d4eSeschrock "cannot restore to %s"), zc.zc_filename); 2528fa9e4066Sahrens break; 2529fa9e4066Sahrens case EINVAL: 2530*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 25319b4f025eSahrens break; 2532ea8dc4b6Seschrock case ECKSUM: 2533*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2534*99653d4eSeschrock "invalid stream (checksum mismatch)")); 2535*99653d4eSeschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2536fa9e4066Sahrens break; 2537fa9e4066Sahrens default: 2538*99653d4eSeschrock (void) zfs_standard_error(hdl, errno, errbuf); 2539fa9e4066Sahrens } 2540fa9e4066Sahrens } 2541fa9e4066Sahrens 2542fa9e4066Sahrens /* 25439b4f025eSahrens * Mount or recreate the /dev links for the target filesystem 25449b4f025eSahrens * (if created, or if we tore them down to do an incremental 25459b4f025eSahrens * restore), and the /dev links for the new snapshot (if 25469b4f025eSahrens * created). 2547fa9e4066Sahrens */ 2548ea8dc4b6Seschrock cp = strchr(zc.zc_filename, '@'); 25499b4f025eSahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2550fa9e4066Sahrens zfs_handle_t *h; 2551fa9e4066Sahrens 2552fa9e4066Sahrens *cp = '\0'; 2553*99653d4eSeschrock h = zfs_open(hdl, zc.zc_filename, 2554fa9e4066Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 25559b4f025eSahrens *cp = '@'; 2556fa9e4066Sahrens if (h) { 25579b4f025eSahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2558fa9e4066Sahrens err = zfs_mount(h, NULL, 0); 25599b4f025eSahrens } else { 2560*99653d4eSeschrock err = zvol_create_link(hdl, h->zfs_name); 2561ea8dc4b6Seschrock if (err == 0 && ioctl_err == 0) 2562*99653d4eSeschrock err = zvol_create_link(hdl, 2563*99653d4eSeschrock zc.zc_filename); 25649b4f025eSahrens } 2565fa9e4066Sahrens zfs_close(h); 2566fa9e4066Sahrens } 2567fa9e4066Sahrens } 2568fa9e4066Sahrens 25699b4f025eSahrens if (err || ioctl_err) 25709b4f025eSahrens return (-1); 2571fa9e4066Sahrens 2572fa9e4066Sahrens if (verbose) { 2573fa9e4066Sahrens char buf1[64]; 2574fa9e4066Sahrens char buf2[64]; 2575fa9e4066Sahrens uint64_t bytes = zc.zc_cookie; 2576fa9e4066Sahrens time_t delta = time(NULL) - begin_time; 2577fa9e4066Sahrens if (delta == 0) 2578fa9e4066Sahrens delta = 1; 2579fa9e4066Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2580fa9e4066Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2581fa9e4066Sahrens 2582f2a3c691Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2583fa9e4066Sahrens buf1, delta, buf2); 2584fa9e4066Sahrens } 2585fa9e4066Sahrens return (0); 2586fa9e4066Sahrens } 2587fa9e4066Sahrens 2588fa9e4066Sahrens /* 2589b12a1c38Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 2590b12a1c38Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 2591b12a1c38Slling * is a dependent and we should just destroy it without checking the transaction 2592b12a1c38Slling * group. 2593fa9e4066Sahrens */ 2594b12a1c38Slling typedef struct rollback_data { 2595b12a1c38Slling const char *cb_target; /* the snapshot */ 2596b12a1c38Slling uint64_t cb_create; /* creation time reference */ 2597b12a1c38Slling prop_changelist_t *cb_clp; /* changelist pointer */ 2598b12a1c38Slling int cb_error; 2599*99653d4eSeschrock boolean_t cb_dependent; 2600b12a1c38Slling } rollback_data_t; 2601b12a1c38Slling 2602b12a1c38Slling static int 2603b12a1c38Slling rollback_destroy(zfs_handle_t *zhp, void *data) 2604b12a1c38Slling { 2605b12a1c38Slling rollback_data_t *cbp = data; 2606b12a1c38Slling 2607b12a1c38Slling if (!cbp->cb_dependent) { 2608b12a1c38Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 2609b12a1c38Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 2610b12a1c38Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 2611b12a1c38Slling cbp->cb_create) { 2612b12a1c38Slling 2613*99653d4eSeschrock cbp->cb_dependent = B_TRUE; 2614b12a1c38Slling (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 2615*99653d4eSeschrock cbp->cb_dependent = B_FALSE; 2616b12a1c38Slling 2617b12a1c38Slling if (zfs_destroy(zhp) != 0) 2618b12a1c38Slling cbp->cb_error = 1; 2619b12a1c38Slling else 2620b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 2621b12a1c38Slling } 2622b12a1c38Slling } else { 2623b12a1c38Slling if (zfs_destroy(zhp) != 0) 2624b12a1c38Slling cbp->cb_error = 1; 2625b12a1c38Slling else 2626b12a1c38Slling changelist_remove(zhp, cbp->cb_clp); 2627b12a1c38Slling } 2628b12a1c38Slling 2629b12a1c38Slling zfs_close(zhp); 2630b12a1c38Slling return (0); 2631b12a1c38Slling } 2632b12a1c38Slling 2633b12a1c38Slling /* 2634b12a1c38Slling * Rollback the dataset to its latest snapshot. 2635b12a1c38Slling */ 2636b12a1c38Slling static int 2637b12a1c38Slling do_rollback(zfs_handle_t *zhp) 2638fa9e4066Sahrens { 2639fa9e4066Sahrens int ret; 2640fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2641fa9e4066Sahrens 2642fa9e4066Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2643fa9e4066Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2644fa9e4066Sahrens 2645fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 2646*99653d4eSeschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2647fa9e4066Sahrens return (-1); 2648fa9e4066Sahrens 2649fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2650fa9e4066Sahrens 2651fa9e4066Sahrens if (zhp->zfs_volblocksize != 0) 2652fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2653fa9e4066Sahrens else 2654fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2655fa9e4066Sahrens 2656fa9e4066Sahrens /* 2657fa9e4066Sahrens * We rely on the consumer to verify that there are no newer snapshots 2658fa9e4066Sahrens * for the given dataset. Given these constraints, we can simply pass 2659fa9e4066Sahrens * the name on to the ioctl() call. There is still an unlikely race 2660fa9e4066Sahrens * condition where the user has taken a snapshot since we verified that 2661fa9e4066Sahrens * this was the most recent. 2662fa9e4066Sahrens */ 2663*99653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 2664*99653d4eSeschrock &zc)) != 0) { 2665*99653d4eSeschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 2666*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 2667*99653d4eSeschrock zhp->zfs_name); 2668fa9e4066Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 2669*99653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2670fa9e4066Sahrens } 2671fa9e4066Sahrens 2672fa9e4066Sahrens return (ret); 2673fa9e4066Sahrens } 2674fa9e4066Sahrens 2675b12a1c38Slling /* 2676b12a1c38Slling * Given a dataset, rollback to a specific snapshot, discarding any 2677b12a1c38Slling * data changes since then and making it the active dataset. 2678b12a1c38Slling * 2679b12a1c38Slling * Any snapshots more recent than the target are destroyed, along with 2680b12a1c38Slling * their dependents. 2681b12a1c38Slling */ 2682b12a1c38Slling int 2683b12a1c38Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 2684b12a1c38Slling { 2685b12a1c38Slling int ret; 2686b12a1c38Slling rollback_data_t cb = { 0 }; 2687b12a1c38Slling prop_changelist_t *clp; 2688b12a1c38Slling 2689b12a1c38Slling /* 2690b12a1c38Slling * Unmount all dependendents of the dataset and the dataset itself. 2691b12a1c38Slling * The list we need to gather is the same as for doing rename 2692b12a1c38Slling */ 2693b12a1c38Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 2694b12a1c38Slling if (clp == NULL) 2695b12a1c38Slling return (-1); 2696b12a1c38Slling 2697b12a1c38Slling if ((ret = changelist_prefix(clp)) != 0) 2698b12a1c38Slling goto out; 2699b12a1c38Slling 2700b12a1c38Slling /* 2701b12a1c38Slling * Destroy all recent snapshots and its dependends. 2702b12a1c38Slling */ 2703b12a1c38Slling cb.cb_target = snap->zfs_name; 2704b12a1c38Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 2705b12a1c38Slling cb.cb_clp = clp; 2706b12a1c38Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 2707b12a1c38Slling 2708b12a1c38Slling if ((ret = cb.cb_error) != 0) { 2709b12a1c38Slling (void) changelist_postfix(clp); 2710b12a1c38Slling goto out; 2711b12a1c38Slling } 2712b12a1c38Slling 2713b12a1c38Slling /* 2714b12a1c38Slling * Now that we have verified that the snapshot is the latest, 2715b12a1c38Slling * rollback to the given snapshot. 2716b12a1c38Slling */ 2717b12a1c38Slling ret = do_rollback(zhp); 2718b12a1c38Slling 2719b12a1c38Slling if (ret != 0) { 2720b12a1c38Slling (void) changelist_postfix(clp); 2721b12a1c38Slling goto out; 2722b12a1c38Slling } 2723b12a1c38Slling 2724b12a1c38Slling /* 2725b12a1c38Slling * We only want to re-mount the filesystem if it was mounted in the 2726b12a1c38Slling * first place. 2727b12a1c38Slling */ 2728b12a1c38Slling ret = changelist_postfix(clp); 2729b12a1c38Slling 2730b12a1c38Slling out: 2731b12a1c38Slling changelist_free(clp); 2732b12a1c38Slling return (ret); 2733b12a1c38Slling } 2734b12a1c38Slling 2735fa9e4066Sahrens /* 2736fa9e4066Sahrens * Iterate over all dependents for a given dataset. This includes both 2737fa9e4066Sahrens * hierarchical dependents (children) and data dependents (snapshots and 2738fa9e4066Sahrens * clones). The bulk of the processing occurs in get_dependents() in 2739fa9e4066Sahrens * libzfs_graph.c. 2740fa9e4066Sahrens */ 2741fa9e4066Sahrens int 2742fa9e4066Sahrens zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2743fa9e4066Sahrens { 2744fa9e4066Sahrens char **dependents; 2745fa9e4066Sahrens size_t count; 2746fa9e4066Sahrens int i; 2747fa9e4066Sahrens zfs_handle_t *child; 2748fa9e4066Sahrens int ret = 0; 2749fa9e4066Sahrens 2750*99653d4eSeschrock dependents = get_dependents(zhp->zfs_hdl, zhp->zfs_name, &count); 2751fa9e4066Sahrens for (i = 0; i < count; i++) { 2752*99653d4eSeschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 2753*99653d4eSeschrock dependents[i])) == NULL) 2754fa9e4066Sahrens continue; 2755fa9e4066Sahrens 2756fa9e4066Sahrens if ((ret = func(child, data)) != 0) 2757fa9e4066Sahrens break; 2758fa9e4066Sahrens } 2759fa9e4066Sahrens 2760fa9e4066Sahrens for (i = 0; i < count; i++) 2761fa9e4066Sahrens free(dependents[i]); 2762fa9e4066Sahrens free(dependents); 2763fa9e4066Sahrens 2764fa9e4066Sahrens return (ret); 2765fa9e4066Sahrens } 2766fa9e4066Sahrens 2767fa9e4066Sahrens /* 2768fa9e4066Sahrens * Renames the given dataset. 2769fa9e4066Sahrens */ 2770fa9e4066Sahrens int 2771fa9e4066Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 2772fa9e4066Sahrens { 2773fa9e4066Sahrens int ret; 2774fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2775fa9e4066Sahrens char *delim; 2776fa9e4066Sahrens prop_changelist_t *cl; 2777fa9e4066Sahrens char parent[ZFS_MAXNAMELEN]; 2778*99653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 2779*99653d4eSeschrock char errbuf[1024]; 2780fa9e4066Sahrens 2781fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2782fa9e4066Sahrens (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value)); 2783fa9e4066Sahrens 2784fa9e4066Sahrens /* if we have the same exact name, just return success */ 2785fa9e4066Sahrens if (strcmp(zhp->zfs_name, target) == 0) 2786fa9e4066Sahrens return (0); 2787fa9e4066Sahrens 2788*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2789*99653d4eSeschrock "cannot rename to '%s'"), target); 2790*99653d4eSeschrock 2791fa9e4066Sahrens /* 2792fa9e4066Sahrens * Make sure the target name is valid 2793fa9e4066Sahrens */ 2794*99653d4eSeschrock if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 2795*99653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2796fa9e4066Sahrens 2797fa9e4066Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2798*99653d4eSeschrock 2799fa9e4066Sahrens if ((delim = strchr(target, '@')) == NULL) { 2800*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2801*99653d4eSeschrock "not a snapshot")); 2802*99653d4eSeschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2803fa9e4066Sahrens } 2804fa9e4066Sahrens 2805fa9e4066Sahrens /* 2806fa9e4066Sahrens * Make sure we're renaming within the same dataset. 2807fa9e4066Sahrens */ 2808fa9e4066Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2809fa9e4066Sahrens zhp->zfs_name[delim - target] != '@') { 2810*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2811*99653d4eSeschrock "snapshots must be part of same dataset")); 2812*99653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2813fa9e4066Sahrens } 2814fa9e4066Sahrens 2815fa9e4066Sahrens (void) strncpy(parent, target, delim - target); 2816fa9e4066Sahrens parent[delim - target] = '\0'; 2817fa9e4066Sahrens } else { 2818fa9e4066Sahrens /* validate parents */ 2819*99653d4eSeschrock if (check_parents(hdl, target) != 0) 2820fa9e4066Sahrens return (-1); 2821fa9e4066Sahrens 2822fa9e4066Sahrens (void) parent_name(target, parent, sizeof (parent)); 2823fa9e4066Sahrens 2824fa9e4066Sahrens /* make sure we're in the same pool */ 2825fa9e4066Sahrens verify((delim = strchr(target, '/')) != NULL); 2826fa9e4066Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 2827fa9e4066Sahrens zhp->zfs_name[delim - target] != '/') { 2828*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2829*99653d4eSeschrock "datasets must be within same pool")); 2830*99653d4eSeschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2831fa9e4066Sahrens } 2832fa9e4066Sahrens } 2833fa9e4066Sahrens 2834*99653d4eSeschrock (void) snprintf(errbuf, sizeof (errbuf), 2835*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 2836*99653d4eSeschrock 2837fa9e4066Sahrens if (getzoneid() == GLOBAL_ZONEID && 2838fa9e4066Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 2839*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2840*99653d4eSeschrock "dataset is used in a non-global zone")); 2841*99653d4eSeschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 2842fa9e4066Sahrens } 2843fa9e4066Sahrens 2844fa9e4066Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 2845*99653d4eSeschrock return (-1); 2846fa9e4066Sahrens 2847fa9e4066Sahrens if (changelist_haszonedchild(cl)) { 2848*99653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2849*99653d4eSeschrock "child dataset with inherited mountpoint is used " 2850*99653d4eSeschrock "in a non-global zone")); 2851*99653d4eSeschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 2852fa9e4066Sahrens goto error; 2853fa9e4066Sahrens } 2854fa9e4066Sahrens 2855fa9e4066Sahrens if ((ret = changelist_prefix(cl)) != 0) 2856fa9e4066Sahrens goto error; 2857fa9e4066Sahrens 2858fa9e4066Sahrens if (zhp->zfs_volblocksize != 0) 2859fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2860fa9e4066Sahrens else 2861fa9e4066Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2862fa9e4066Sahrens 2863*99653d4eSeschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 2864*99653d4eSeschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 2865fa9e4066Sahrens 2866fa9e4066Sahrens /* 2867fa9e4066Sahrens * On failure, we still want to remount any filesystems that 2868fa9e4066Sahrens * were previously mounted, so we don't alter the system state. 2869fa9e4066Sahrens */ 2870fa9e4066Sahrens (void) changelist_postfix(cl); 2871fa9e4066Sahrens } else { 2872fa9e4066Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 2873fa9e4066Sahrens 2874fa9e4066Sahrens ret = changelist_postfix(cl); 2875fa9e4066Sahrens } 2876fa9e4066Sahrens 2877fa9e4066Sahrens error: 2878fa9e4066Sahrens changelist_free(cl); 2879fa9e4066Sahrens return (ret); 2880fa9e4066Sahrens } 2881fa9e4066Sahrens 2882fa9e4066Sahrens /* 2883fa9e4066Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 2884fa9e4066Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 2885fa9e4066Sahrens */ 2886fa9e4066Sahrens int 2887*99653d4eSeschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 2888fa9e4066Sahrens { 2889fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2890*99653d4eSeschrock di_devlink_handle_t dhdl; 2891fa9e4066Sahrens 2892fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 2893fa9e4066Sahrens 2894fa9e4066Sahrens /* 2895fa9e4066Sahrens * Issue the appropriate ioctl. 2896fa9e4066Sahrens */ 2897*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 2898fa9e4066Sahrens switch (errno) { 2899fa9e4066Sahrens case EEXIST: 2900fa9e4066Sahrens /* 2901fa9e4066Sahrens * Silently ignore the case where the link already 2902fa9e4066Sahrens * exists. This allows 'zfs volinit' to be run multiple 2903fa9e4066Sahrens * times without errors. 2904fa9e4066Sahrens */ 2905fa9e4066Sahrens return (0); 2906fa9e4066Sahrens 2907fa9e4066Sahrens default: 2908*99653d4eSeschrock return (zfs_standard_error(hdl, errno, 2909*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 2910*99653d4eSeschrock "for '%s'"), dataset)); 2911fa9e4066Sahrens } 2912fa9e4066Sahrens } 2913fa9e4066Sahrens 2914fa9e4066Sahrens /* 2915fa9e4066Sahrens * Call devfsadm and wait for the links to magically appear. 2916fa9e4066Sahrens */ 2917*99653d4eSeschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 2918*99653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 2919*99653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 2920*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot create device links " 2921*99653d4eSeschrock "for '%s'"), dataset); 2922*99653d4eSeschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 2923fa9e4066Sahrens return (-1); 2924fa9e4066Sahrens } else { 2925*99653d4eSeschrock (void) di_devlink_fini(&dhdl); 2926fa9e4066Sahrens } 2927fa9e4066Sahrens 2928fa9e4066Sahrens return (0); 2929fa9e4066Sahrens } 2930fa9e4066Sahrens 2931fa9e4066Sahrens /* 2932fa9e4066Sahrens * Remove a minor node for the given zvol and the associated /dev links. 2933fa9e4066Sahrens */ 2934fa9e4066Sahrens int 2935*99653d4eSeschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 2936fa9e4066Sahrens { 2937fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2938fa9e4066Sahrens 2939fa9e4066Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 2940fa9e4066Sahrens 2941*99653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 2942fa9e4066Sahrens switch (errno) { 2943fa9e4066Sahrens case ENXIO: 2944fa9e4066Sahrens /* 2945fa9e4066Sahrens * Silently ignore the case where the link no longer 2946fa9e4066Sahrens * exists, so that 'zfs volfini' can be run multiple 2947fa9e4066Sahrens * times without errors. 2948fa9e4066Sahrens */ 2949fa9e4066Sahrens return (0); 2950fa9e4066Sahrens 2951fa9e4066Sahrens default: 2952*99653d4eSeschrock return (zfs_standard_error(hdl, errno, 2953*99653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove device " 2954*99653d4eSeschrock "links for '%s'"), dataset)); 2955fa9e4066Sahrens } 2956fa9e4066Sahrens } 2957fa9e4066Sahrens 2958fa9e4066Sahrens return (0); 2959fa9e4066Sahrens } 2960