1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221294Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <assert.h> 29789Sahrens #include <ctype.h> 30789Sahrens #include <errno.h> 31789Sahrens #include <libdevinfo.h> 32789Sahrens #include <libintl.h> 33789Sahrens #include <math.h> 34789Sahrens #include <stdio.h> 35789Sahrens #include <stdlib.h> 36789Sahrens #include <strings.h> 37789Sahrens #include <unistd.h> 38789Sahrens #include <zone.h> 392082Seschrock #include <fcntl.h> 40789Sahrens #include <sys/mntent.h> 41789Sahrens #include <sys/mnttab.h> 421294Slling #include <sys/mount.h> 43789Sahrens 44789Sahrens #include <sys/spa.h> 45789Sahrens #include <sys/zio.h> 462676Seschrock #include <sys/zap.h> 47789Sahrens #include <libzfs.h> 48789Sahrens 49789Sahrens #include "zfs_namecheck.h" 50789Sahrens #include "zfs_prop.h" 51789Sahrens #include "libzfs_impl.h" 52789Sahrens 53789Sahrens /* 54789Sahrens * Given a single type (not a mask of types), return the type in a human 55789Sahrens * readable form. 56789Sahrens */ 57789Sahrens const char * 58789Sahrens zfs_type_to_name(zfs_type_t type) 59789Sahrens { 60789Sahrens switch (type) { 61789Sahrens case ZFS_TYPE_FILESYSTEM: 62789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 63789Sahrens case ZFS_TYPE_SNAPSHOT: 64789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 65789Sahrens case ZFS_TYPE_VOLUME: 66789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 67789Sahrens } 68789Sahrens 69789Sahrens return (NULL); 70789Sahrens } 71789Sahrens 72789Sahrens /* 73789Sahrens * Given a path and mask of ZFS types, return a string describing this dataset. 74789Sahrens * This is used when we fail to open a dataset and we cannot get an exact type. 75789Sahrens * We guess what the type would have been based on the path and the mask of 76789Sahrens * acceptable types. 77789Sahrens */ 78789Sahrens static const char * 79789Sahrens path_to_str(const char *path, int types) 80789Sahrens { 81789Sahrens /* 82789Sahrens * When given a single type, always report the exact type. 83789Sahrens */ 84789Sahrens if (types == ZFS_TYPE_SNAPSHOT) 85789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 86789Sahrens if (types == ZFS_TYPE_FILESYSTEM) 87789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 88789Sahrens if (types == ZFS_TYPE_VOLUME) 89789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 90789Sahrens 91789Sahrens /* 92789Sahrens * The user is requesting more than one type of dataset. If this is the 93789Sahrens * case, consult the path itself. If we're looking for a snapshot, and 94789Sahrens * a '@' is found, then report it as "snapshot". Otherwise, remove the 95789Sahrens * snapshot attribute and try again. 96789Sahrens */ 97789Sahrens if (types & ZFS_TYPE_SNAPSHOT) { 98789Sahrens if (strchr(path, '@') != NULL) 99789Sahrens return (dgettext(TEXT_DOMAIN, "snapshot")); 100789Sahrens return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); 101789Sahrens } 102789Sahrens 103789Sahrens 104789Sahrens /* 105789Sahrens * The user has requested either filesystems or volumes. 106789Sahrens * We have no way of knowing a priori what type this would be, so always 107789Sahrens * report it as "filesystem" or "volume", our two primitive types. 108789Sahrens */ 109789Sahrens if (types & ZFS_TYPE_FILESYSTEM) 110789Sahrens return (dgettext(TEXT_DOMAIN, "filesystem")); 111789Sahrens 112789Sahrens assert(types & ZFS_TYPE_VOLUME); 113789Sahrens return (dgettext(TEXT_DOMAIN, "volume")); 114789Sahrens } 115789Sahrens 116789Sahrens /* 117789Sahrens * Validate a ZFS path. This is used even before trying to open the dataset, to 118789Sahrens * provide a more meaningful error message. We place a more useful message in 119789Sahrens * 'buf' detailing exactly why the name was not valid. 120789Sahrens */ 121789Sahrens static int 1222082Seschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) 123789Sahrens { 124789Sahrens namecheck_err_t why; 125789Sahrens char what; 126789Sahrens 127789Sahrens if (dataset_namecheck(path, &why, &what) != 0) { 1282082Seschrock if (hdl != NULL) { 129789Sahrens switch (why) { 1301003Slling case NAME_ERR_TOOLONG: 1312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1322082Seschrock "name is too long")); 1331003Slling break; 1341003Slling 135789Sahrens case NAME_ERR_LEADING_SLASH: 1362082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1372082Seschrock "leading slash in name")); 138789Sahrens break; 139789Sahrens 140789Sahrens case NAME_ERR_EMPTY_COMPONENT: 1412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1422082Seschrock "empty component in name")); 143789Sahrens break; 144789Sahrens 145789Sahrens case NAME_ERR_TRAILING_SLASH: 1462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1472082Seschrock "trailing slash in name")); 148789Sahrens break; 149789Sahrens 150789Sahrens case NAME_ERR_INVALCHAR: 1512082Seschrock zfs_error_aux(hdl, 152789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 1532082Seschrock "'%c' in name"), what); 154789Sahrens break; 155789Sahrens 156789Sahrens case NAME_ERR_MULTIPLE_AT: 1572082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1582082Seschrock "multiple '@' delimiters in name")); 159789Sahrens break; 160789Sahrens } 161789Sahrens } 162789Sahrens 163789Sahrens return (0); 164789Sahrens } 165789Sahrens 166789Sahrens if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) { 1672082Seschrock if (hdl != NULL) 1682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1692082Seschrock "snapshot delimiter '@' in filesystem name")); 170789Sahrens return (0); 171789Sahrens } 172789Sahrens 1732199Sahrens if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 1742199Sahrens if (hdl != NULL) 1752199Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1762199Sahrens "missing '@' delimeter in snapshot name")); 1772199Sahrens return (0); 1782199Sahrens } 1792199Sahrens 1802082Seschrock return (-1); 181789Sahrens } 182789Sahrens 183789Sahrens int 184789Sahrens zfs_name_valid(const char *name, zfs_type_t type) 185789Sahrens { 1862082Seschrock return (zfs_validate_name(NULL, name, type)); 187789Sahrens } 188789Sahrens 189789Sahrens /* 1902676Seschrock * This function takes the raw DSL properties, and filters out the user-defined 1912676Seschrock * properties into a separate nvlist. 1922676Seschrock */ 1932676Seschrock static int 1942676Seschrock process_user_props(zfs_handle_t *zhp) 1952676Seschrock { 1962676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 1972676Seschrock nvpair_t *elem; 1982676Seschrock nvlist_t *propval; 1992676Seschrock 2002676Seschrock nvlist_free(zhp->zfs_user_props); 2012676Seschrock 2022676Seschrock if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 2032676Seschrock return (no_memory(hdl)); 2042676Seschrock 2052676Seschrock elem = NULL; 2062676Seschrock while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 2072676Seschrock if (!zfs_prop_user(nvpair_name(elem))) 2082676Seschrock continue; 2092676Seschrock 2102676Seschrock verify(nvpair_value_nvlist(elem, &propval) == 0); 2112676Seschrock if (nvlist_add_nvlist(zhp->zfs_user_props, 2122676Seschrock nvpair_name(elem), propval) != 0) 2132676Seschrock return (no_memory(hdl)); 2142676Seschrock } 2152676Seschrock 2162676Seschrock return (0); 2172676Seschrock } 2182676Seschrock 2192676Seschrock /* 220789Sahrens * Utility function to gather stats (objset and zpl) for the given object. 221789Sahrens */ 222789Sahrens static int 223789Sahrens get_stats(zfs_handle_t *zhp) 224789Sahrens { 225789Sahrens zfs_cmd_t zc = { 0 }; 2262676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 227789Sahrens 228789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 229789Sahrens 2302676Seschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 2312082Seschrock return (-1); 2321356Seschrock 2332082Seschrock while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 2341356Seschrock if (errno == ENOMEM) { 2352676Seschrock if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 2362676Seschrock zcmd_free_nvlists(&zc); 2372082Seschrock return (-1); 2382676Seschrock } 2391356Seschrock } else { 2402676Seschrock zcmd_free_nvlists(&zc); 2411356Seschrock return (-1); 2421356Seschrock } 2431356Seschrock } 244789Sahrens 245789Sahrens bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats, 246789Sahrens sizeof (zc.zc_objset_stats)); 247789Sahrens 2482676Seschrock (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 2491544Seschrock 2502082Seschrock if (zhp->zfs_props) { 2512082Seschrock nvlist_free(zhp->zfs_props); 2522082Seschrock zhp->zfs_props = NULL; 2532082Seschrock } 2542082Seschrock 2552676Seschrock if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { 2562676Seschrock zcmd_free_nvlists(&zc); 2572082Seschrock return (-1); 2582082Seschrock } 259789Sahrens 2602676Seschrock zcmd_free_nvlists(&zc); 2612676Seschrock 2622676Seschrock zhp->zfs_volstats = zc.zc_vol_stats; 2632676Seschrock 2642676Seschrock if (process_user_props(zhp) != 0) 2652676Seschrock return (-1); 2662082Seschrock 267789Sahrens return (0); 268789Sahrens } 269789Sahrens 270789Sahrens /* 271789Sahrens * Refresh the properties currently stored in the handle. 272789Sahrens */ 273789Sahrens void 274789Sahrens zfs_refresh_properties(zfs_handle_t *zhp) 275789Sahrens { 276789Sahrens (void) get_stats(zhp); 277789Sahrens } 278789Sahrens 279789Sahrens /* 280789Sahrens * Makes a handle from the given dataset name. Used by zfs_open() and 281789Sahrens * zfs_iter_* to create child handles on the fly. 282789Sahrens */ 283789Sahrens zfs_handle_t * 2842082Seschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path) 285789Sahrens { 2862082Seschrock zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); 2872082Seschrock 2882082Seschrock if (zhp == NULL) 2892082Seschrock return (NULL); 2902082Seschrock 2912082Seschrock zhp->zfs_hdl = hdl; 292789Sahrens 2931758Sahrens top: 294789Sahrens (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 295789Sahrens 296789Sahrens if (get_stats(zhp) != 0) { 297789Sahrens free(zhp); 298789Sahrens return (NULL); 299789Sahrens } 300789Sahrens 3011758Sahrens if (zhp->zfs_dmustats.dds_inconsistent) { 3021758Sahrens zfs_cmd_t zc = { 0 }; 3031758Sahrens 3041758Sahrens /* 3051758Sahrens * If it is dds_inconsistent, then we've caught it in 3061758Sahrens * the middle of a 'zfs receive' or 'zfs destroy', and 3071758Sahrens * it is inconsistent from the ZPL's point of view, so 3081758Sahrens * can't be mounted. However, it could also be that we 3091758Sahrens * have crashed in the middle of one of those 3101758Sahrens * operations, in which case we need to get rid of the 3111758Sahrens * inconsistent state. We do that by either rolling 3121758Sahrens * back to the previous snapshot (which will fail if 3131758Sahrens * there is none), or destroying the filesystem. Note 3141758Sahrens * that if we are still in the middle of an active 3151758Sahrens * 'receive' or 'destroy', then the rollback and destroy 3161758Sahrens * will fail with EBUSY and we will drive on as usual. 3171758Sahrens */ 3181758Sahrens 3191758Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3201758Sahrens 3211758Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3222082Seschrock (void) zvol_remove_link(hdl, zhp->zfs_name); 3231758Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3241758Sahrens } else { 3251758Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3261758Sahrens } 3271758Sahrens 3281758Sahrens /* If we can successfully roll it back, reget the stats */ 3292082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 3301758Sahrens goto top; 3311758Sahrens /* 3321758Sahrens * If we can sucessfully destroy it, pretend that it 3331758Sahrens * never existed. 3341758Sahrens */ 3352082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { 3361758Sahrens free(zhp); 3371758Sahrens errno = ENOENT; 3381758Sahrens return (NULL); 3391758Sahrens } 3401758Sahrens } 3411758Sahrens 342789Sahrens /* 343789Sahrens * We've managed to open the dataset and gather statistics. Determine 344789Sahrens * the high-level type. 345789Sahrens */ 346789Sahrens if (zhp->zfs_dmustats.dds_is_snapshot) 347789Sahrens zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 348789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 349789Sahrens zhp->zfs_type = ZFS_TYPE_VOLUME; 350789Sahrens else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 351789Sahrens zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 352789Sahrens else 3532082Seschrock abort(); /* we should never see any other types */ 354789Sahrens 355789Sahrens return (zhp); 356789Sahrens } 357789Sahrens 358789Sahrens /* 359789Sahrens * Opens the given snapshot, filesystem, or volume. The 'types' 360789Sahrens * argument is a mask of acceptable types. The function will print an 361789Sahrens * appropriate error message and return NULL if it can't be opened. 362789Sahrens */ 363789Sahrens zfs_handle_t * 3642082Seschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types) 365789Sahrens { 366789Sahrens zfs_handle_t *zhp; 3672082Seschrock char errbuf[1024]; 3682082Seschrock 3692082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 3702082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 371789Sahrens 372789Sahrens /* 3732082Seschrock * Validate the name before we even try to open it. 374789Sahrens */ 3752082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { 3762082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3772082Seschrock "invalid dataset name")); 3782082Seschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 379789Sahrens return (NULL); 380789Sahrens } 381789Sahrens 382789Sahrens /* 383789Sahrens * Try to get stats for the dataset, which will tell us if it exists. 384789Sahrens */ 385789Sahrens errno = 0; 3862082Seschrock if ((zhp = make_dataset_handle(hdl, path)) == NULL) { 3872082Seschrock (void) zfs_standard_error(hdl, errno, errbuf, path); 388789Sahrens return (NULL); 389789Sahrens } 390789Sahrens 391789Sahrens if (!(types & zhp->zfs_type)) { 3922082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 3932142Seschrock zfs_close(zhp); 394789Sahrens return (NULL); 395789Sahrens } 396789Sahrens 397789Sahrens return (zhp); 398789Sahrens } 399789Sahrens 400789Sahrens /* 401789Sahrens * Release a ZFS handle. Nothing to do but free the associated memory. 402789Sahrens */ 403789Sahrens void 404789Sahrens zfs_close(zfs_handle_t *zhp) 405789Sahrens { 406789Sahrens if (zhp->zfs_mntopts) 407789Sahrens free(zhp->zfs_mntopts); 4082676Seschrock nvlist_free(zhp->zfs_props); 4092676Seschrock nvlist_free(zhp->zfs_user_props); 410789Sahrens free(zhp); 411789Sahrens } 412789Sahrens 413789Sahrens /* 414789Sahrens * Given a numeric suffix, convert the value into a number of bits that the 415789Sahrens * resulting value must be shifted. 416789Sahrens */ 417789Sahrens static int 4182082Seschrock str2shift(libzfs_handle_t *hdl, const char *buf) 419789Sahrens { 420789Sahrens const char *ends = "BKMGTPEZ"; 421789Sahrens int i; 422789Sahrens 423789Sahrens if (buf[0] == '\0') 424789Sahrens return (0); 425789Sahrens for (i = 0; i < strlen(ends); i++) { 426789Sahrens if (toupper(buf[0]) == ends[i]) 427789Sahrens break; 428789Sahrens } 429789Sahrens if (i == strlen(ends)) { 4302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4312082Seschrock "invalid numeric suffix '%s'"), buf); 432789Sahrens return (-1); 433789Sahrens } 434789Sahrens 435789Sahrens /* 436789Sahrens * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 437789Sahrens * allow 'BB' - that's just weird. 438789Sahrens */ 439789Sahrens if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 4402082Seschrock toupper(buf[0]) != 'B')) 441789Sahrens return (10*i); 4422082Seschrock 4432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4442082Seschrock "invalid numeric suffix '%s'"), buf); 445789Sahrens return (-1); 446789Sahrens } 447789Sahrens 448789Sahrens /* 449789Sahrens * Convert a string of the form '100G' into a real number. Used when setting 450789Sahrens * properties or creating a volume. 'buf' is used to place an extended error 451789Sahrens * message for the caller to use. 452789Sahrens */ 453789Sahrens static int 4542082Seschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 455789Sahrens { 456789Sahrens char *end; 457789Sahrens int shift; 458789Sahrens 459789Sahrens *num = 0; 460789Sahrens 461789Sahrens /* Check to see if this looks like a number. */ 462789Sahrens if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 4632082Seschrock if (hdl) 4642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4652082Seschrock "bad numeric value '%s'"), value); 466789Sahrens return (-1); 467789Sahrens } 468789Sahrens 469789Sahrens /* Rely on stroll() to process the numeric portion. */ 470789Sahrens errno = 0; 471789Sahrens *num = strtoll(value, &end, 10); 472789Sahrens 473789Sahrens /* 474789Sahrens * Check for ERANGE, which indicates that the value is too large to fit 475789Sahrens * in a 64-bit value. 476789Sahrens */ 477789Sahrens if (errno == ERANGE) { 4782082Seschrock if (hdl) 4792082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4802082Seschrock "numeric value is too large")); 481789Sahrens return (-1); 482789Sahrens } 483789Sahrens 484789Sahrens /* 485789Sahrens * If we have a decimal value, then do the computation with floating 486789Sahrens * point arithmetic. Otherwise, use standard arithmetic. 487789Sahrens */ 488789Sahrens if (*end == '.') { 489789Sahrens double fval = strtod(value, &end); 490789Sahrens 4912082Seschrock if ((shift = str2shift(hdl, end)) == -1) 492789Sahrens return (-1); 493789Sahrens 494789Sahrens fval *= pow(2, shift); 495789Sahrens 496789Sahrens if (fval > UINT64_MAX) { 4972082Seschrock if (hdl) 4982082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4992082Seschrock "numeric value is too large")); 500789Sahrens return (-1); 501789Sahrens } 502789Sahrens 503789Sahrens *num = (uint64_t)fval; 504789Sahrens } else { 5052082Seschrock if ((shift = str2shift(hdl, end)) == -1) 506789Sahrens return (-1); 507789Sahrens 508789Sahrens /* Check for overflow */ 509789Sahrens if (shift >= 64 || (*num << shift) >> shift != *num) { 5102082Seschrock if (hdl) 5112082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5122082Seschrock "numeric value is too large")); 513789Sahrens return (-1); 514789Sahrens } 515789Sahrens 516789Sahrens *num <<= shift; 517789Sahrens } 518789Sahrens 519789Sahrens return (0); 520789Sahrens } 521789Sahrens 522789Sahrens int 5232676Seschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 5242676Seschrock { 5252676Seschrock return (nicestrtonum(hdl, str, val)); 5262676Seschrock } 5272676Seschrock 5282676Seschrock /* 5292676Seschrock * The prop_parse_*() functions are designed to allow flexibility in callers 5302676Seschrock * when setting properties. At the DSL layer, all properties are either 64-bit 5312676Seschrock * numbers or strings. We want the user to be able to ignore this fact and 5322676Seschrock * specify properties as native values (boolean, for example) or as strings (to 5332676Seschrock * simplify command line utilities). This also handles converting index types 5342676Seschrock * (compression, checksum, etc) from strings to their on-disk index. 5352676Seschrock */ 5362676Seschrock 5372676Seschrock static int 5382676Seschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) 539789Sahrens { 5402676Seschrock uint64_t ret; 5412676Seschrock 5422676Seschrock switch (nvpair_type(elem)) { 5432676Seschrock case DATA_TYPE_STRING: 5442676Seschrock { 5452676Seschrock char *value; 5462676Seschrock VERIFY(nvpair_value_string(elem, &value) == 0); 5472676Seschrock 5482676Seschrock if (strcmp(value, "on") == 0) { 5492676Seschrock ret = 1; 5502676Seschrock } else if (strcmp(value, "off") == 0) { 5512676Seschrock ret = 0; 5522676Seschrock } else { 5532676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5542676Seschrock "property '%s' must be 'on' or 'off'"), 5552676Seschrock nvpair_name(elem)); 5562676Seschrock return (-1); 5572676Seschrock } 5582676Seschrock break; 5592676Seschrock } 5602676Seschrock 5612676Seschrock case DATA_TYPE_UINT64: 5622676Seschrock { 5632676Seschrock VERIFY(nvpair_value_uint64(elem, &ret) == 0); 5642676Seschrock if (ret > 1) { 5652676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5662676Seschrock "'%s' must be a boolean value"), 5672676Seschrock nvpair_name(elem)); 5682676Seschrock return (-1); 5692676Seschrock } 5702676Seschrock break; 5712676Seschrock } 5722676Seschrock 5732676Seschrock case DATA_TYPE_BOOLEAN_VALUE: 5742676Seschrock { 5752676Seschrock boolean_t value; 5762676Seschrock VERIFY(nvpair_value_boolean_value(elem, &value) == 0); 5772676Seschrock ret = value; 5782676Seschrock break; 5792676Seschrock } 5802676Seschrock 5812676Seschrock default: 5822676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5832676Seschrock "'%s' must be a boolean value"), 5842676Seschrock nvpair_name(elem)); 5852676Seschrock return (-1); 5862676Seschrock } 5872676Seschrock 5882676Seschrock *val = ret; 5892676Seschrock return (0); 5902676Seschrock } 5912676Seschrock 5922676Seschrock static int 5932676Seschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 5942676Seschrock uint64_t *val) 5952676Seschrock { 5962676Seschrock uint64_t ret; 5972676Seschrock boolean_t isnone = B_FALSE; 5982676Seschrock 5992676Seschrock switch (nvpair_type(elem)) { 6002676Seschrock case DATA_TYPE_STRING: 6012676Seschrock { 6022676Seschrock char *value; 6032676Seschrock (void) nvpair_value_string(elem, &value); 6042676Seschrock if (strcmp(value, "none") == 0) { 6052676Seschrock isnone = B_TRUE; 6062676Seschrock ret = 0; 6072676Seschrock } else if (nicestrtonum(hdl, value, &ret) != 0) { 6082676Seschrock return (-1); 6092676Seschrock } 6102676Seschrock break; 6112676Seschrock } 6122676Seschrock 6132676Seschrock case DATA_TYPE_UINT64: 6142676Seschrock (void) nvpair_value_uint64(elem, &ret); 6152676Seschrock break; 6162676Seschrock 6172676Seschrock default: 6182676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6192676Seschrock "'%s' must be a number"), 6202676Seschrock nvpair_name(elem)); 6212676Seschrock return (-1); 6222676Seschrock } 6232676Seschrock 6242676Seschrock /* 6252676Seschrock * Quota special: force 'none' and don't allow 0. 6262676Seschrock */ 6272676Seschrock if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 6282676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6292676Seschrock "use 'none' to disable quota")); 6302676Seschrock return (-1); 6312676Seschrock } 6322676Seschrock 6332676Seschrock *val = ret; 6342676Seschrock return (0); 6352676Seschrock } 6362676Seschrock 6372676Seschrock static int 6382676Seschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 6392676Seschrock uint64_t *val) 6402676Seschrock { 6412676Seschrock char *propname = nvpair_name(elem); 6422676Seschrock char *value; 6432676Seschrock 6442676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 6452676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6462676Seschrock "'%s' must be a string"), propname); 6472676Seschrock return (-1); 6482676Seschrock } 6492676Seschrock 6502676Seschrock (void) nvpair_value_string(elem, &value); 6512676Seschrock 6522676Seschrock if (zfs_prop_string_to_index(prop, value, val) != 0) { 6532676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6542676Seschrock "'%s' must be one of '%s'"), propname, 6552676Seschrock zfs_prop_values(prop)); 6562676Seschrock return (-1); 6572676Seschrock } 6582676Seschrock 6592676Seschrock return (0); 660789Sahrens } 661789Sahrens 662789Sahrens /* 6632676Seschrock * Given an nvlist of properties to set, validates that they are correct, and 6642676Seschrock * parses any numeric properties (index, boolean, etc) if they are specified as 6652676Seschrock * strings. 666789Sahrens */ 6672676Seschrock static nvlist_t * 6682676Seschrock zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 6692676Seschrock uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) 670789Sahrens { 6712676Seschrock nvpair_t *elem; 6722676Seschrock const char *propname; 6732676Seschrock zfs_prop_t prop; 6742676Seschrock uint64_t intval; 6752676Seschrock char *strval; 6762676Seschrock nvlist_t *ret; 6772676Seschrock 6782676Seschrock if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 6792676Seschrock (void) no_memory(hdl); 6802676Seschrock return (NULL); 6812676Seschrock } 6822676Seschrock 6832676Seschrock if (type == ZFS_TYPE_SNAPSHOT) { 6842676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6852676Seschrock "snaphot properties cannot be modified")); 6862676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 6872676Seschrock goto error; 688789Sahrens } 689789Sahrens 6902676Seschrock elem = NULL; 6912676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 6922676Seschrock propname = nvpair_name(elem); 6932676Seschrock 6942676Seschrock /* 6952676Seschrock * Make sure this property is valid and applies to this type. 6962676Seschrock */ 6972676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 6982676Seschrock if (!zfs_prop_user(propname)) { 6992676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7002676Seschrock "invalid property '%s'"), 7012676Seschrock propname); 7022676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7032676Seschrock goto error; 7042676Seschrock } else { 7052676Seschrock /* 7062676Seschrock * If this is a user property, make sure it's a 7072676Seschrock * string, and that it's less than 7082676Seschrock * ZAP_MAXNAMELEN. 7092676Seschrock */ 7102676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7112676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7122676Seschrock "'%s' must be a string"), 7132676Seschrock propname); 7142676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7152676Seschrock errbuf); 7162676Seschrock goto error; 7172676Seschrock } 7182676Seschrock 7192676Seschrock if (strlen(nvpair_name(elem)) >= 7202676Seschrock ZAP_MAXNAMELEN) { 7212676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7222676Seschrock "property name '%s' is too long"), 7232676Seschrock propname); 7242676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 7252676Seschrock errbuf); 7262676Seschrock goto error; 7272676Seschrock } 7282676Seschrock } 7292676Seschrock 7302676Seschrock (void) nvpair_value_string(elem, &strval); 7312676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 7322676Seschrock (void) no_memory(hdl); 7332676Seschrock goto error; 7342676Seschrock } 7352676Seschrock continue; 736789Sahrens } 7372676Seschrock 7382676Seschrock /* 7392676Seschrock * Normalize the name, to get rid of shorthand abbrevations. 7402676Seschrock */ 7412676Seschrock propname = zfs_prop_to_name(prop); 7422676Seschrock 7432676Seschrock if (!zfs_prop_valid_for_type(prop, type)) { 7442676Seschrock zfs_error_aux(hdl, 7452676Seschrock dgettext(TEXT_DOMAIN, "'%s' does not " 7462676Seschrock "apply to datasets of this type"), propname); 7472676Seschrock (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 7482676Seschrock goto error; 7492676Seschrock } 7502676Seschrock 7512676Seschrock if (zfs_prop_readonly(prop) && 7522676Seschrock (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { 7532676Seschrock zfs_error_aux(hdl, 7542676Seschrock dgettext(TEXT_DOMAIN, "'%s' is readonly"), 7552676Seschrock propname); 7562676Seschrock (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 7572676Seschrock goto error; 7582676Seschrock } 7592676Seschrock 7602676Seschrock /* 7612676Seschrock * Convert any properties to the internal DSL value types. 7622676Seschrock */ 7632676Seschrock strval = NULL; 7642676Seschrock switch (zfs_prop_get_type(prop)) { 7652676Seschrock case prop_type_boolean: 7662676Seschrock if (prop_parse_boolean(hdl, elem, &intval) != 0) { 7672676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7682676Seschrock goto error; 7692676Seschrock } 770789Sahrens break; 7712676Seschrock 7722676Seschrock case prop_type_string: 7732676Seschrock if (nvpair_type(elem) != DATA_TYPE_STRING) { 7742082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7752676Seschrock "'%s' must be a string"), 7762676Seschrock propname); 7772676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7782676Seschrock goto error; 779789Sahrens } 7802676Seschrock (void) nvpair_value_string(elem, &strval); 7812676Seschrock if (strlen(strval) >= ZFS_MAXPROPLEN) { 7822082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7832676Seschrock "'%s' is too long"), propname); 7842676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7852676Seschrock goto error; 7862676Seschrock } 7872676Seschrock break; 7882676Seschrock 7892676Seschrock case prop_type_number: 7902676Seschrock if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 7912676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7922676Seschrock goto error; 7932676Seschrock } 7942676Seschrock break; 7952676Seschrock 7962676Seschrock case prop_type_index: 7972676Seschrock if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 7982676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 7992676Seschrock goto error; 800789Sahrens } 801789Sahrens break; 802789Sahrens 8032676Seschrock default: 8042676Seschrock abort(); 8052676Seschrock } 8062676Seschrock 8072676Seschrock /* 8082676Seschrock * Add the result to our return set of properties. 8092676Seschrock */ 8102676Seschrock if (strval) { 8112676Seschrock if (nvlist_add_string(ret, propname, strval) != 0) { 8122676Seschrock (void) no_memory(hdl); 8132676Seschrock goto error; 814789Sahrens } 8152676Seschrock } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 8162676Seschrock (void) no_memory(hdl); 8172676Seschrock goto error; 8182676Seschrock } 8192676Seschrock 8202676Seschrock /* 8212676Seschrock * Perform some additional checks for specific properties. 8222676Seschrock */ 8232676Seschrock switch (prop) { 8242676Seschrock case ZFS_PROP_RECORDSIZE: 8252676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 8262676Seschrock /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 8272676Seschrock if (intval < SPA_MINBLOCKSIZE || 8282676Seschrock intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 8292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8302676Seschrock "'%s' must be power of 2 from %u " 8312676Seschrock "to %uk"), propname, 8322676Seschrock (uint_t)SPA_MINBLOCKSIZE, 8332676Seschrock (uint_t)SPA_MAXBLOCKSIZE >> 10); 8342676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8352676Seschrock goto error; 836789Sahrens } 837789Sahrens break; 838789Sahrens 8392676Seschrock case ZFS_PROP_MOUNTPOINT: 8402676Seschrock if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 8412676Seschrock strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 8422676Seschrock break; 8432676Seschrock 8442676Seschrock if (strval[0] != '/') { 8452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8462676Seschrock "'%s' must be an absolute path, " 8472676Seschrock "'none', or 'legacy'"), propname); 8482676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 8492676Seschrock goto error; 850789Sahrens } 851789Sahrens break; 8522676Seschrock } 8532676Seschrock 8542676Seschrock /* 8552676Seschrock * For the mountpoint and sharenfs properties, check if it can 8562676Seschrock * be set in a global/non-global zone based on the zoned 8572676Seschrock * property value: 8582676Seschrock * 8592676Seschrock * global zone non-global zone 8602676Seschrock * ----------------------------------------------------- 8612676Seschrock * zoned=on mountpoint (no) mountpoint (yes) 8622676Seschrock * sharenfs (no) sharenfs (no) 8632676Seschrock * 8642676Seschrock * zoned=off mountpoint (yes) N/A 8652676Seschrock * sharenfs (yes) 8662676Seschrock */ 8672676Seschrock if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { 8682676Seschrock if (zoned) { 8692676Seschrock if (getzoneid() == GLOBAL_ZONEID) { 8702676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8712676Seschrock "'%s' cannot be set on " 8722676Seschrock "dataset in a non-global zone"), 8732676Seschrock propname); 8742676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 8752676Seschrock errbuf); 8762676Seschrock goto error; 8772676Seschrock } else if (prop == ZFS_PROP_SHARENFS) { 8782676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8792676Seschrock "'%s' cannot be set in " 8802676Seschrock "a non-global zone"), propname); 8812676Seschrock (void) zfs_error(hdl, EZFS_ZONED, 8822676Seschrock errbuf); 8832676Seschrock goto error; 8842676Seschrock } 8852676Seschrock } else if (getzoneid() != GLOBAL_ZONEID) { 8862676Seschrock /* 8872676Seschrock * If zoned property is 'off', this must be in 8882676Seschrock * a globle zone. If not, something is wrong. 8892676Seschrock */ 8902676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 8912676Seschrock "'%s' cannot be set while dataset " 8922676Seschrock "'zoned' property is set"), propname); 8932676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 8942676Seschrock goto error; 8952676Seschrock } 8962676Seschrock } 8972676Seschrock 8982676Seschrock /* 8992676Seschrock * For changes to existing volumes, we have some additional 9002676Seschrock * checks to enforce. 9012676Seschrock */ 9022676Seschrock if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 9032676Seschrock uint64_t volsize = zfs_prop_get_int(zhp, 9042676Seschrock ZFS_PROP_VOLSIZE); 9052676Seschrock uint64_t blocksize = zfs_prop_get_int(zhp, 9062676Seschrock ZFS_PROP_VOLBLOCKSIZE); 9072676Seschrock char buf[64]; 9082676Seschrock 9092676Seschrock switch (prop) { 9102676Seschrock case ZFS_PROP_RESERVATION: 9112676Seschrock if (intval > volsize) { 9122676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9132676Seschrock "'%s' is greater than current " 9142676Seschrock "volume size"), propname); 9152676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9162676Seschrock errbuf); 9172676Seschrock goto error; 9182676Seschrock } 9192676Seschrock break; 9202676Seschrock 9212676Seschrock case ZFS_PROP_VOLSIZE: 9222676Seschrock if (intval % blocksize != 0) { 9232676Seschrock zfs_nicenum(blocksize, buf, 9242676Seschrock sizeof (buf)); 9252676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9262676Seschrock "'%s' must be a multiple of " 9272676Seschrock "volume block size (%s)"), 9282676Seschrock propname, buf); 9292676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9302676Seschrock errbuf); 9312676Seschrock goto error; 9322676Seschrock } 9332676Seschrock 9342676Seschrock if (intval == 0) { 9352676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9362676Seschrock "'%s' cannot be zero"), 9372676Seschrock propname); 9382676Seschrock (void) zfs_error(hdl, EZFS_BADPROP, 9392676Seschrock errbuf); 9402676Seschrock goto error; 941789Sahrens } 942789Sahrens } 943789Sahrens } 944789Sahrens } 945789Sahrens 9462676Seschrock /* 9472676Seschrock * If this is an existing volume, and someone is setting the volsize, 9482676Seschrock * make sure that it matches the reservation, or add it if necessary. 9492676Seschrock */ 9502676Seschrock if (zhp != NULL && type == ZFS_TYPE_VOLUME && 9512676Seschrock nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 9522676Seschrock &intval) == 0) { 9532676Seschrock uint64_t old_volsize = zfs_prop_get_int(zhp, 9542676Seschrock ZFS_PROP_VOLSIZE); 9552676Seschrock uint64_t old_reservation = zfs_prop_get_int(zhp, 9562676Seschrock ZFS_PROP_RESERVATION); 9572676Seschrock uint64_t new_reservation; 9582676Seschrock 9592676Seschrock if (old_volsize == old_reservation && 9602676Seschrock nvlist_lookup_uint64(ret, 9612676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9622676Seschrock &new_reservation) != 0) { 9632676Seschrock if (nvlist_add_uint64(ret, 9642676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 9652676Seschrock intval) != 0) { 9662676Seschrock (void) no_memory(hdl); 9672676Seschrock goto error; 9682676Seschrock } 9692676Seschrock } 9702676Seschrock } 9712676Seschrock 9722676Seschrock return (ret); 9732676Seschrock 9742676Seschrock error: 9752676Seschrock nvlist_free(ret); 9762676Seschrock return (NULL); 977789Sahrens } 978789Sahrens 979789Sahrens /* 980789Sahrens * Given a property name and value, set the property for the given dataset. 981789Sahrens */ 982789Sahrens int 9832676Seschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 984789Sahrens { 985789Sahrens zfs_cmd_t zc = { 0 }; 9862676Seschrock int ret = -1; 9872676Seschrock prop_changelist_t *cl = NULL; 9882082Seschrock char errbuf[1024]; 9892082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 9902676Seschrock nvlist_t *nvl = NULL, *realprops; 9912676Seschrock zfs_prop_t prop; 9922082Seschrock 9932082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 9942676Seschrock dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 9952082Seschrock zhp->zfs_name); 9962082Seschrock 9972676Seschrock if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 9982676Seschrock nvlist_add_string(nvl, propname, propval) != 0) { 9992676Seschrock (void) no_memory(hdl); 10002676Seschrock goto error; 1001789Sahrens } 1002789Sahrens 10032676Seschrock if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl, 10042676Seschrock zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 10052676Seschrock goto error; 10062676Seschrock nvlist_free(nvl); 10072676Seschrock nvl = realprops; 10082676Seschrock 10092676Seschrock prop = zfs_name_to_prop(propname); 10102676Seschrock 1011789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 10122676Seschrock goto error; 1013789Sahrens 1014789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 10152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10162082Seschrock "child dataset with inherited mountpoint is used " 10172082Seschrock "in a non-global zone")); 10182082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1019789Sahrens goto error; 1020789Sahrens } 1021789Sahrens 1022789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1023789Sahrens goto error; 1024789Sahrens 1025789Sahrens /* 1026789Sahrens * Execute the corresponding ioctl() to set this property. 1027789Sahrens */ 1028789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1029789Sahrens 10302676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) 10312676Seschrock goto error; 10322676Seschrock 10332676Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1034789Sahrens 1035789Sahrens if (ret != 0) { 1036789Sahrens switch (errno) { 1037789Sahrens 1038789Sahrens case ENOSPC: 1039789Sahrens /* 1040789Sahrens * For quotas and reservations, ENOSPC indicates 1041789Sahrens * something different; setting a quota or reservation 1042789Sahrens * doesn't use any disk space. 1043789Sahrens */ 1044789Sahrens switch (prop) { 1045789Sahrens case ZFS_PROP_QUOTA: 10462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10472082Seschrock "size is less than current used or " 10482082Seschrock "reserved space")); 10492082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1050789Sahrens break; 1051789Sahrens 1052789Sahrens case ZFS_PROP_RESERVATION: 10532082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10542082Seschrock "size is greater than available space")); 10552082Seschrock (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1056789Sahrens break; 1057789Sahrens 1058789Sahrens default: 10592082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1060789Sahrens break; 1061789Sahrens } 1062789Sahrens break; 1063789Sahrens 1064789Sahrens case EBUSY: 10652082Seschrock if (prop == ZFS_PROP_VOLBLOCKSIZE) 10662082Seschrock (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); 10672082Seschrock else 10682676Seschrock (void) zfs_standard_error(hdl, EBUSY, errbuf); 1069789Sahrens break; 1070789Sahrens 10711175Slling case EROFS: 10722082Seschrock (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 10731175Slling break; 10741175Slling 1075789Sahrens case EOVERFLOW: 1076789Sahrens /* 1077789Sahrens * This platform can't address a volume this big. 1078789Sahrens */ 1079789Sahrens #ifdef _ILP32 1080789Sahrens if (prop == ZFS_PROP_VOLSIZE) { 10812082Seschrock (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1082789Sahrens break; 1083789Sahrens } 1084789Sahrens #endif 10852082Seschrock /* FALLTHROUGH */ 1086789Sahrens default: 10872082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 1088789Sahrens } 1089789Sahrens } else { 1090789Sahrens /* 1091789Sahrens * Refresh the statistics so the new property value 1092789Sahrens * is reflected. 1093789Sahrens */ 10942676Seschrock if ((ret = changelist_postfix(cl)) == 0) 10952676Seschrock (void) get_stats(zhp); 1096789Sahrens } 1097789Sahrens 1098789Sahrens error: 10992676Seschrock nvlist_free(nvl); 11002676Seschrock zcmd_free_nvlists(&zc); 11012676Seschrock if (cl) 11022676Seschrock changelist_free(cl); 1103789Sahrens return (ret); 1104789Sahrens } 1105789Sahrens 1106789Sahrens /* 1107789Sahrens * Given a property, inherit the value from the parent dataset. 1108789Sahrens */ 1109789Sahrens int 11102676Seschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname) 1111789Sahrens { 1112789Sahrens zfs_cmd_t zc = { 0 }; 1113789Sahrens int ret; 1114789Sahrens prop_changelist_t *cl; 11152082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 11162082Seschrock char errbuf[1024]; 11172676Seschrock zfs_prop_t prop; 11182082Seschrock 11192082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 11202082Seschrock "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1121789Sahrens 11222676Seschrock if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { 11232676Seschrock /* 11242676Seschrock * For user properties, the amount of work we have to do is very 11252676Seschrock * small, so just do it here. 11262676Seschrock */ 11272676Seschrock if (!zfs_prop_user(propname)) { 11282676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11292676Seschrock "invalid property")); 11302676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 11312676Seschrock } 11322676Seschrock 11332676Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11342676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 11352676Seschrock 11362676Seschrock if (ioctl(zhp->zfs_hdl->libzfs_fd, 11372676Seschrock ZFS_IOC_SET_PROP, &zc) != 0) 11382676Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 11392676Seschrock 11402676Seschrock return (0); 11412676Seschrock } 11422676Seschrock 1143789Sahrens /* 1144789Sahrens * Verify that this property is inheritable. 1145789Sahrens */ 11462082Seschrock if (zfs_prop_readonly(prop)) 11472082Seschrock return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); 11482082Seschrock 11492082Seschrock if (!zfs_prop_inheritable(prop)) 11502082Seschrock return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); 1151789Sahrens 1152789Sahrens /* 1153789Sahrens * Check to see if the value applies to this type 1154789Sahrens */ 11552082Seschrock if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 11562082Seschrock return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); 1157789Sahrens 1158789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 11592676Seschrock (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1160789Sahrens 1161789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && 1162789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 11632082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11642082Seschrock "dataset is used in a non-global zone")); 11652082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1166789Sahrens } 1167789Sahrens 1168789Sahrens /* 1169789Sahrens * Determine datasets which will be affected by this change, if any. 1170789Sahrens */ 1171789Sahrens if ((cl = changelist_gather(zhp, prop, 0)) == NULL) 1172789Sahrens return (-1); 1173789Sahrens 1174789Sahrens if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 11752082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11762082Seschrock "child dataset with inherited mountpoint is used " 11772082Seschrock "in a non-global zone")); 11782082Seschrock ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1179789Sahrens goto error; 1180789Sahrens } 1181789Sahrens 1182789Sahrens if ((ret = changelist_prefix(cl)) != 0) 1183789Sahrens goto error; 1184789Sahrens 11852082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 11862082Seschrock ZFS_IOC_SET_PROP, &zc)) != 0) { 11872082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1188789Sahrens } else { 1189789Sahrens 11902169Snd150628 if ((ret = changelist_postfix(cl)) != 0) 1191789Sahrens goto error; 1192789Sahrens 1193789Sahrens /* 1194789Sahrens * Refresh the statistics so the new property is reflected. 1195789Sahrens */ 1196789Sahrens (void) get_stats(zhp); 1197789Sahrens } 1198789Sahrens 1199789Sahrens error: 1200789Sahrens changelist_free(cl); 1201789Sahrens return (ret); 1202789Sahrens } 1203789Sahrens 1204789Sahrens static void 1205789Sahrens nicebool(int value, char *buf, size_t buflen) 1206789Sahrens { 1207789Sahrens if (value) 1208789Sahrens (void) strlcpy(buf, "on", buflen); 1209789Sahrens else 1210789Sahrens (void) strlcpy(buf, "off", buflen); 1211789Sahrens } 1212789Sahrens 1213789Sahrens /* 12141356Seschrock * True DSL properties are stored in an nvlist. The following two functions 12151356Seschrock * extract them appropriately. 12161356Seschrock */ 12171356Seschrock static uint64_t 12181356Seschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12191356Seschrock { 12201356Seschrock nvlist_t *nv; 12211356Seschrock uint64_t value; 12221356Seschrock 12231356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12241356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12251356Seschrock verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 12261356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 12271356Seschrock } else { 12281356Seschrock value = zfs_prop_default_numeric(prop); 12291356Seschrock *source = ""; 12301356Seschrock } 12311356Seschrock 12321356Seschrock return (value); 12331356Seschrock } 12341356Seschrock 12351356Seschrock static char * 12361356Seschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 12371356Seschrock { 12381356Seschrock nvlist_t *nv; 12391356Seschrock char *value; 12401356Seschrock 12411356Seschrock if (nvlist_lookup_nvlist(zhp->zfs_props, 12421356Seschrock zfs_prop_to_name(prop), &nv) == 0) { 12431356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 12441356Seschrock verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0); 12451356Seschrock } else { 12461356Seschrock if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 12471356Seschrock value = ""; 12481356Seschrock *source = ""; 12491356Seschrock } 12501356Seschrock 12511356Seschrock return (value); 12521356Seschrock } 12531356Seschrock 12541356Seschrock /* 1255789Sahrens * Internal function for getting a numeric property. Both zfs_prop_get() and 1256789Sahrens * zfs_prop_get_int() are built using this interface. 1257789Sahrens * 1258789Sahrens * Certain properties can be overridden using 'mount -o'. In this case, scan 1259789Sahrens * the contents of the /etc/mnttab entry, searching for the appropriate options. 1260789Sahrens * If they differ from the on-disk values, report the current values and mark 1261789Sahrens * the source "temporary". 1262789Sahrens */ 12632082Seschrock static int 1264789Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, 12652082Seschrock char **source, uint64_t *val) 1266789Sahrens { 1267789Sahrens struct mnttab mnt; 1268789Sahrens 1269789Sahrens *source = NULL; 1270789Sahrens 12712474Seschrock /* 12722474Seschrock * Because looking up the mount options is potentially expensive 12732474Seschrock * (iterating over all of /etc/mnttab), we defer its calculation until 12742474Seschrock * we're looking up a property which requires its presence. 12752474Seschrock */ 12762474Seschrock if (!zhp->zfs_mntcheck && 12772474Seschrock (prop == ZFS_PROP_ATIME || 12782474Seschrock prop == ZFS_PROP_DEVICES || 12792474Seschrock prop == ZFS_PROP_EXEC || 12802474Seschrock prop == ZFS_PROP_READONLY || 12812474Seschrock prop == ZFS_PROP_SETUID || 12822474Seschrock prop == ZFS_PROP_MOUNTED)) { 12832474Seschrock struct mnttab search = { 0 }, entry; 12842474Seschrock 12852474Seschrock search.mnt_special = (char *)zhp->zfs_name; 12862474Seschrock search.mnt_fstype = MNTTYPE_ZFS; 12872474Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 12882474Seschrock 12892474Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, 12902474Seschrock &search) == 0 && (zhp->zfs_mntopts = 12912474Seschrock zfs_strdup(zhp->zfs_hdl, 12922474Seschrock entry.mnt_mntopts)) == NULL) 12932474Seschrock return (-1); 12942474Seschrock 12952474Seschrock zhp->zfs_mntcheck = B_TRUE; 12962474Seschrock } 12972474Seschrock 1298789Sahrens if (zhp->zfs_mntopts == NULL) 1299789Sahrens mnt.mnt_mntopts = ""; 1300789Sahrens else 1301789Sahrens mnt.mnt_mntopts = zhp->zfs_mntopts; 1302789Sahrens 1303789Sahrens switch (prop) { 1304789Sahrens case ZFS_PROP_ATIME: 13052082Seschrock *val = getprop_uint64(zhp, prop, source); 13062082Seschrock 13072082Seschrock if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) { 13082082Seschrock *val = B_TRUE; 1309789Sahrens if (src) 1310789Sahrens *src = ZFS_SRC_TEMPORARY; 13112082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) { 13122082Seschrock *val = B_FALSE; 1313789Sahrens if (src) 1314789Sahrens *src = ZFS_SRC_TEMPORARY; 1315789Sahrens } 13162082Seschrock break; 1317789Sahrens 1318789Sahrens case ZFS_PROP_AVAILABLE: 13192082Seschrock *val = zhp->zfs_dmustats.dds_available; 13202082Seschrock break; 1321789Sahrens 1322789Sahrens case ZFS_PROP_DEVICES: 13232082Seschrock *val = getprop_uint64(zhp, prop, source); 13242082Seschrock 13252082Seschrock if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) { 13262082Seschrock *val = B_TRUE; 1327789Sahrens if (src) 1328789Sahrens *src = ZFS_SRC_TEMPORARY; 13292082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) { 13302082Seschrock *val = B_FALSE; 1331789Sahrens if (src) 1332789Sahrens *src = ZFS_SRC_TEMPORARY; 1333789Sahrens } 13342082Seschrock break; 1335789Sahrens 1336789Sahrens case ZFS_PROP_EXEC: 13372082Seschrock *val = getprop_uint64(zhp, prop, source); 13382082Seschrock 13392082Seschrock if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) { 13402082Seschrock *val = B_TRUE; 1341789Sahrens if (src) 1342789Sahrens *src = ZFS_SRC_TEMPORARY; 13432082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) { 13442082Seschrock *val = B_FALSE; 1345789Sahrens if (src) 1346789Sahrens *src = ZFS_SRC_TEMPORARY; 1347789Sahrens } 13482082Seschrock break; 1349789Sahrens 1350789Sahrens case ZFS_PROP_RECORDSIZE: 1351789Sahrens case ZFS_PROP_COMPRESSION: 13521356Seschrock case ZFS_PROP_ZONED: 13532082Seschrock *val = getprop_uint64(zhp, prop, source); 13542082Seschrock break; 1355789Sahrens 1356789Sahrens case ZFS_PROP_READONLY: 13572082Seschrock *val = getprop_uint64(zhp, prop, source); 13582082Seschrock 13592082Seschrock if (hasmntopt(&mnt, MNTOPT_RO) && !*val) { 13602082Seschrock *val = B_TRUE; 1361789Sahrens if (src) 1362789Sahrens *src = ZFS_SRC_TEMPORARY; 13632082Seschrock } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) { 13642082Seschrock *val = B_FALSE; 1365789Sahrens if (src) 1366789Sahrens *src = ZFS_SRC_TEMPORARY; 1367789Sahrens } 13682082Seschrock break; 1369789Sahrens 13701544Seschrock case ZFS_PROP_CREATION: 13712082Seschrock *val = zhp->zfs_dmustats.dds_creation_time; 13722082Seschrock break; 13731544Seschrock 1374789Sahrens case ZFS_PROP_QUOTA: 1375789Sahrens if (zhp->zfs_dmustats.dds_quota == 0) 1376789Sahrens *source = ""; /* default */ 1377789Sahrens else 1378789Sahrens *source = zhp->zfs_name; 13792082Seschrock *val = zhp->zfs_dmustats.dds_quota; 13802082Seschrock break; 1381789Sahrens 1382789Sahrens case ZFS_PROP_RESERVATION: 1383789Sahrens if (zhp->zfs_dmustats.dds_reserved == 0) 1384789Sahrens *source = ""; /* default */ 1385789Sahrens else 1386789Sahrens *source = zhp->zfs_name; 13872082Seschrock *val = zhp->zfs_dmustats.dds_reserved; 13882082Seschrock break; 1389789Sahrens 1390789Sahrens case ZFS_PROP_COMPRESSRATIO: 1391789Sahrens /* 1392789Sahrens * Using physical space and logical space, calculate the 1393789Sahrens * compression ratio. We return the number as a multiple of 1394789Sahrens * 100, so '2.5x' would be returned as 250. 1395789Sahrens */ 1396789Sahrens if (zhp->zfs_dmustats.dds_compressed_bytes == 0) 13972082Seschrock *val = 100ULL; 1398789Sahrens else 13992082Seschrock *val = 14002082Seschrock (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 / 1401789Sahrens zhp->zfs_dmustats.dds_compressed_bytes); 14022082Seschrock break; 1403789Sahrens 1404789Sahrens case ZFS_PROP_REFERENCED: 1405789Sahrens /* 1406789Sahrens * 'referenced' refers to the amount of physical space 1407789Sahrens * referenced (possibly shared) by this object. 1408789Sahrens */ 14092082Seschrock *val = zhp->zfs_dmustats.dds_space_refd; 14102082Seschrock break; 1411789Sahrens 1412789Sahrens case ZFS_PROP_SETUID: 14132082Seschrock *val = getprop_uint64(zhp, prop, source); 14142082Seschrock 14152082Seschrock if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) { 14162082Seschrock *val = B_TRUE; 1417789Sahrens if (src) 1418789Sahrens *src = ZFS_SRC_TEMPORARY; 14192082Seschrock } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) { 14202082Seschrock *val = B_FALSE; 1421789Sahrens if (src) 1422789Sahrens *src = ZFS_SRC_TEMPORARY; 1423789Sahrens } 14242082Seschrock break; 1425789Sahrens 1426789Sahrens case ZFS_PROP_VOLSIZE: 14272676Seschrock *val = zhp->zfs_volstats.zv_volsize; 14282082Seschrock break; 1429789Sahrens 1430789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 14312676Seschrock *val = zhp->zfs_volstats.zv_volblocksize; 14322082Seschrock break; 1433789Sahrens 1434789Sahrens case ZFS_PROP_USED: 14352082Seschrock *val = zhp->zfs_dmustats.dds_space_used; 14362082Seschrock break; 1437789Sahrens 1438789Sahrens case ZFS_PROP_CREATETXG: 14392082Seschrock *val = zhp->zfs_dmustats.dds_creation_txg; 14402082Seschrock break; 1441789Sahrens 1442789Sahrens case ZFS_PROP_MOUNTED: 14432082Seschrock *val = (zhp->zfs_mntopts != NULL); 14442082Seschrock break; 1445789Sahrens 14462676Seschrock case ZFS_PROP_CANMOUNT: 14472676Seschrock *val = getprop_uint64(zhp, prop, source); 14482676Seschrock break; 14492676Seschrock 1450789Sahrens default: 14512082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 14522082Seschrock "cannot get non-numeric property")); 14532082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 14542082Seschrock dgettext(TEXT_DOMAIN, "internal error"))); 1455789Sahrens } 1456789Sahrens 1457789Sahrens return (0); 1458789Sahrens } 1459789Sahrens 1460789Sahrens /* 1461789Sahrens * Calculate the source type, given the raw source string. 1462789Sahrens */ 1463789Sahrens static void 1464789Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, 1465789Sahrens char *statbuf, size_t statlen) 1466789Sahrens { 1467789Sahrens if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) 1468789Sahrens return; 1469789Sahrens 1470789Sahrens if (source == NULL) { 1471789Sahrens *srctype = ZFS_SRC_NONE; 1472789Sahrens } else if (source[0] == '\0') { 1473789Sahrens *srctype = ZFS_SRC_DEFAULT; 1474789Sahrens } else { 1475789Sahrens if (strcmp(source, zhp->zfs_name) == 0) { 1476789Sahrens *srctype = ZFS_SRC_LOCAL; 1477789Sahrens } else { 1478789Sahrens (void) strlcpy(statbuf, source, statlen); 1479789Sahrens *srctype = ZFS_SRC_INHERITED; 1480789Sahrens } 1481789Sahrens } 1482789Sahrens 1483789Sahrens } 1484789Sahrens 1485789Sahrens /* 1486789Sahrens * Retrieve a property from the given object. If 'literal' is specified, then 1487789Sahrens * numbers are left as exact values. Otherwise, numbers are converted to a 1488789Sahrens * human-readable form. 1489789Sahrens * 1490789Sahrens * Returns 0 on success, or -1 on error. 1491789Sahrens */ 1492789Sahrens int 1493789Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, 14942082Seschrock zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) 1495789Sahrens { 1496789Sahrens char *source = NULL; 1497789Sahrens uint64_t val; 1498789Sahrens char *str; 1499789Sahrens const char *root; 15002676Seschrock const char *strval; 1501789Sahrens 1502789Sahrens /* 1503789Sahrens * Check to see if this property applies to our object 1504789Sahrens */ 1505789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1506789Sahrens return (-1); 1507789Sahrens 1508789Sahrens if (src) 1509789Sahrens *src = ZFS_SRC_NONE; 1510789Sahrens 1511789Sahrens switch (prop) { 1512789Sahrens case ZFS_PROP_ATIME: 1513789Sahrens case ZFS_PROP_READONLY: 1514789Sahrens case ZFS_PROP_SETUID: 1515789Sahrens case ZFS_PROP_ZONED: 1516789Sahrens case ZFS_PROP_DEVICES: 1517789Sahrens case ZFS_PROP_EXEC: 15182676Seschrock case ZFS_PROP_CANMOUNT: 1519789Sahrens /* 1520789Sahrens * Basic boolean values are built on top of 1521789Sahrens * get_numeric_property(). 1522789Sahrens */ 15232082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15242082Seschrock return (-1); 15252082Seschrock nicebool(val, propbuf, proplen); 1526789Sahrens 1527789Sahrens break; 1528789Sahrens 1529789Sahrens case ZFS_PROP_AVAILABLE: 1530789Sahrens case ZFS_PROP_RECORDSIZE: 1531789Sahrens case ZFS_PROP_CREATETXG: 1532789Sahrens case ZFS_PROP_REFERENCED: 1533789Sahrens case ZFS_PROP_USED: 1534789Sahrens case ZFS_PROP_VOLSIZE: 1535789Sahrens case ZFS_PROP_VOLBLOCKSIZE: 1536789Sahrens /* 1537789Sahrens * Basic numeric values are built on top of 1538789Sahrens * get_numeric_property(). 1539789Sahrens */ 15402082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 15412082Seschrock return (-1); 1542789Sahrens if (literal) 1543789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1544789Sahrens else 1545789Sahrens zfs_nicenum(val, propbuf, proplen); 1546789Sahrens break; 1547789Sahrens 1548789Sahrens case ZFS_PROP_COMPRESSION: 1549789Sahrens case ZFS_PROP_CHECKSUM: 1550789Sahrens case ZFS_PROP_SNAPDIR: 1551789Sahrens case ZFS_PROP_ACLMODE: 1552789Sahrens case ZFS_PROP_ACLINHERIT: 15531356Seschrock val = getprop_uint64(zhp, prop, &source); 15542676Seschrock verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 15552676Seschrock (void) strlcpy(propbuf, strval, proplen); 1556789Sahrens break; 1557789Sahrens 1558789Sahrens case ZFS_PROP_CREATION: 1559789Sahrens /* 1560789Sahrens * 'creation' is a time_t stored in the statistics. We convert 1561789Sahrens * this into a string unless 'literal' is specified. 1562789Sahrens */ 1563789Sahrens { 1564789Sahrens time_t time = (time_t) 1565789Sahrens zhp->zfs_dmustats.dds_creation_time; 1566789Sahrens struct tm t; 1567789Sahrens 1568789Sahrens if (literal || 1569789Sahrens localtime_r(&time, &t) == NULL || 1570789Sahrens strftime(propbuf, proplen, "%a %b %e %k:%M %Y", 1571789Sahrens &t) == 0) 1572789Sahrens (void) snprintf(propbuf, proplen, "%llu", 1573789Sahrens zhp->zfs_dmustats.dds_creation_time); 1574789Sahrens } 1575789Sahrens break; 1576789Sahrens 1577789Sahrens case ZFS_PROP_MOUNTPOINT: 1578789Sahrens /* 1579789Sahrens * Getting the precise mountpoint can be tricky. 1580789Sahrens * 1581789Sahrens * - for 'none' or 'legacy', return those values. 1582789Sahrens * - for default mountpoints, construct it as /zfs/<dataset> 1583789Sahrens * - for inherited mountpoints, we want to take everything 1584789Sahrens * after our ancestor and append it to the inherited value. 1585789Sahrens * 1586789Sahrens * If the pool has an alternate root, we want to prepend that 1587789Sahrens * root to any values we return. 1588789Sahrens */ 15891544Seschrock root = zhp->zfs_root; 15901356Seschrock str = getprop_string(zhp, prop, &source); 15911356Seschrock 15921356Seschrock if (str[0] == '\0') { 1593789Sahrens (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1594789Sahrens root, zhp->zfs_name); 15951356Seschrock } else if (str[0] == '/') { 15961356Seschrock const char *relpath = zhp->zfs_name + strlen(source); 1597789Sahrens 1598789Sahrens if (relpath[0] == '/') 1599789Sahrens relpath++; 16001356Seschrock if (str[1] == '\0') 16011356Seschrock str++; 1602789Sahrens 1603789Sahrens if (relpath[0] == '\0') 1604789Sahrens (void) snprintf(propbuf, proplen, "%s%s", 16051356Seschrock root, str); 1606789Sahrens else 1607789Sahrens (void) snprintf(propbuf, proplen, "%s%s%s%s", 16081356Seschrock root, str, relpath[0] == '@' ? "" : "/", 1609789Sahrens relpath); 1610789Sahrens } else { 1611789Sahrens /* 'legacy' or 'none' */ 16121356Seschrock (void) strlcpy(propbuf, str, proplen); 1613789Sahrens } 1614789Sahrens 1615789Sahrens break; 1616789Sahrens 1617789Sahrens case ZFS_PROP_SHARENFS: 16181356Seschrock (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 16191356Seschrock proplen); 1620789Sahrens break; 1621789Sahrens 1622789Sahrens case ZFS_PROP_ORIGIN: 16231544Seschrock (void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of, 1624789Sahrens proplen); 1625789Sahrens /* 1626789Sahrens * If there is no parent at all, return failure to indicate that 1627789Sahrens * it doesn't apply to this dataset. 1628789Sahrens */ 1629789Sahrens if (propbuf[0] == '\0') 1630789Sahrens return (-1); 1631789Sahrens break; 1632789Sahrens 1633789Sahrens case ZFS_PROP_QUOTA: 1634789Sahrens case ZFS_PROP_RESERVATION: 16352082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16362082Seschrock return (-1); 1637789Sahrens 1638789Sahrens /* 1639789Sahrens * If quota or reservation is 0, we translate this into 'none' 1640789Sahrens * (unless literal is set), and indicate that it's the default 1641789Sahrens * value. Otherwise, we print the number nicely and indicate 1642789Sahrens * that its set locally. 1643789Sahrens */ 1644789Sahrens if (val == 0) { 1645789Sahrens if (literal) 1646789Sahrens (void) strlcpy(propbuf, "0", proplen); 1647789Sahrens else 1648789Sahrens (void) strlcpy(propbuf, "none", proplen); 1649789Sahrens } else { 1650789Sahrens if (literal) 1651789Sahrens (void) snprintf(propbuf, proplen, "%llu", val); 1652789Sahrens else 1653789Sahrens zfs_nicenum(val, propbuf, proplen); 1654789Sahrens } 1655789Sahrens break; 1656789Sahrens 1657789Sahrens case ZFS_PROP_COMPRESSRATIO: 16582082Seschrock if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 16592082Seschrock return (-1); 1660789Sahrens (void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100, 1661789Sahrens val % 100); 1662789Sahrens break; 1663789Sahrens 1664789Sahrens case ZFS_PROP_TYPE: 1665789Sahrens switch (zhp->zfs_type) { 1666789Sahrens case ZFS_TYPE_FILESYSTEM: 1667789Sahrens str = "filesystem"; 1668789Sahrens break; 1669789Sahrens case ZFS_TYPE_VOLUME: 1670789Sahrens str = "volume"; 1671789Sahrens break; 1672789Sahrens case ZFS_TYPE_SNAPSHOT: 1673789Sahrens str = "snapshot"; 1674789Sahrens break; 1675789Sahrens default: 16762082Seschrock abort(); 1677789Sahrens } 1678789Sahrens (void) snprintf(propbuf, proplen, "%s", str); 1679789Sahrens break; 1680789Sahrens 1681789Sahrens case ZFS_PROP_MOUNTED: 1682789Sahrens /* 1683789Sahrens * The 'mounted' property is a pseudo-property that described 1684789Sahrens * whether the filesystem is currently mounted. Even though 1685789Sahrens * it's a boolean value, the typical values of "on" and "off" 1686789Sahrens * don't make sense, so we translate to "yes" and "no". 1687789Sahrens */ 16882082Seschrock if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, 16892082Seschrock src, &source, &val) != 0) 16902082Seschrock return (-1); 16912082Seschrock if (val) 1692789Sahrens (void) strlcpy(propbuf, "yes", proplen); 1693789Sahrens else 1694789Sahrens (void) strlcpy(propbuf, "no", proplen); 1695789Sahrens break; 1696789Sahrens 1697789Sahrens case ZFS_PROP_NAME: 1698789Sahrens /* 1699789Sahrens * The 'name' property is a pseudo-property derived from the 1700789Sahrens * dataset name. It is presented as a real property to simplify 1701789Sahrens * consumers. 1702789Sahrens */ 1703789Sahrens (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1704789Sahrens break; 1705789Sahrens 1706789Sahrens default: 17072082Seschrock abort(); 1708789Sahrens } 1709789Sahrens 1710789Sahrens get_source(zhp, src, source, statbuf, statlen); 1711789Sahrens 1712789Sahrens return (0); 1713789Sahrens } 1714789Sahrens 1715789Sahrens /* 1716789Sahrens * Utility function to get the given numeric property. Does no validation that 1717789Sahrens * the given property is the appropriate type; should only be used with 1718789Sahrens * hard-coded property types. 1719789Sahrens */ 1720789Sahrens uint64_t 1721789Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1722789Sahrens { 1723789Sahrens char *source; 1724789Sahrens zfs_source_t sourcetype = ZFS_SRC_NONE; 17252082Seschrock uint64_t val; 17262082Seschrock 17272082Seschrock (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); 17282082Seschrock 17292082Seschrock return (val); 1730789Sahrens } 1731789Sahrens 1732789Sahrens /* 1733789Sahrens * Similar to zfs_prop_get(), but returns the value as an integer. 1734789Sahrens */ 1735789Sahrens int 1736789Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, 1737789Sahrens zfs_source_t *src, char *statbuf, size_t statlen) 1738789Sahrens { 1739789Sahrens char *source; 1740789Sahrens 1741789Sahrens /* 1742789Sahrens * Check to see if this property applies to our object 1743789Sahrens */ 1744789Sahrens if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 17452082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE, 17462082Seschrock dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 17472082Seschrock zfs_prop_to_name(prop))); 1748789Sahrens 1749789Sahrens if (src) 1750789Sahrens *src = ZFS_SRC_NONE; 1751789Sahrens 17522082Seschrock if (get_numeric_property(zhp, prop, src, &source, value) != 0) 17532082Seschrock return (-1); 1754789Sahrens 1755789Sahrens get_source(zhp, src, source, statbuf, statlen); 1756789Sahrens 1757789Sahrens return (0); 1758789Sahrens } 1759789Sahrens 1760789Sahrens /* 1761789Sahrens * Returns the name of the given zfs handle. 1762789Sahrens */ 1763789Sahrens const char * 1764789Sahrens zfs_get_name(const zfs_handle_t *zhp) 1765789Sahrens { 1766789Sahrens return (zhp->zfs_name); 1767789Sahrens } 1768789Sahrens 1769789Sahrens /* 1770789Sahrens * Returns the type of the given zfs handle. 1771789Sahrens */ 1772789Sahrens zfs_type_t 1773789Sahrens zfs_get_type(const zfs_handle_t *zhp) 1774789Sahrens { 1775789Sahrens return (zhp->zfs_type); 1776789Sahrens } 1777789Sahrens 1778789Sahrens /* 17791356Seschrock * Iterate over all child filesystems 1780789Sahrens */ 1781789Sahrens int 17821356Seschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1783789Sahrens { 1784789Sahrens zfs_cmd_t zc = { 0 }; 1785789Sahrens zfs_handle_t *nzhp; 1786789Sahrens int ret; 1787789Sahrens 1788789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 17892082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1790789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1791789Sahrens /* 1792789Sahrens * Ignore private dataset names. 1793789Sahrens */ 1794789Sahrens if (dataset_name_hidden(zc.zc_name)) 1795789Sahrens continue; 1796789Sahrens 1797789Sahrens /* 1798789Sahrens * Silently ignore errors, as the only plausible explanation is 1799789Sahrens * that the pool has since been removed. 1800789Sahrens */ 18012082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18022082Seschrock zc.zc_name)) == NULL) 1803789Sahrens continue; 1804789Sahrens 1805789Sahrens if ((ret = func(nzhp, data)) != 0) 1806789Sahrens return (ret); 1807789Sahrens } 1808789Sahrens 1809789Sahrens /* 1810789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1811789Sahrens * returned, then the underlying dataset has been removed since we 1812789Sahrens * obtained the handle. 1813789Sahrens */ 1814789Sahrens if (errno != ESRCH && errno != ENOENT) 18152082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18162082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1817789Sahrens 18181356Seschrock return (0); 18191356Seschrock } 18201356Seschrock 18211356Seschrock /* 18221356Seschrock * Iterate over all snapshots 18231356Seschrock */ 18241356Seschrock int 18251356Seschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18261356Seschrock { 18271356Seschrock zfs_cmd_t zc = { 0 }; 18281356Seschrock zfs_handle_t *nzhp; 18291356Seschrock int ret; 1830789Sahrens 1831789Sahrens for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 18322082Seschrock ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 18332082Seschrock &zc) == 0; 1834789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1835789Sahrens 18362082Seschrock if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 18372082Seschrock zc.zc_name)) == NULL) 1838789Sahrens continue; 1839789Sahrens 1840789Sahrens if ((ret = func(nzhp, data)) != 0) 1841789Sahrens return (ret); 1842789Sahrens } 1843789Sahrens 1844789Sahrens /* 1845789Sahrens * An errno value of ESRCH indicates normal completion. If ENOENT is 1846789Sahrens * returned, then the underlying dataset has been removed since we 1847789Sahrens * obtained the handle. Silently ignore this case, and return success. 1848789Sahrens */ 1849789Sahrens if (errno != ESRCH && errno != ENOENT) 18502082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 18512082Seschrock dgettext(TEXT_DOMAIN, "cannot iterate filesystems"))); 1852789Sahrens 1853789Sahrens return (0); 1854789Sahrens } 1855789Sahrens 1856789Sahrens /* 18571356Seschrock * Iterate over all children, snapshots and filesystems 18581356Seschrock */ 18591356Seschrock int 18601356Seschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 18611356Seschrock { 18621356Seschrock int ret; 18631356Seschrock 18641356Seschrock if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 18651356Seschrock return (ret); 18661356Seschrock 18671356Seschrock return (zfs_iter_snapshots(zhp, func, data)); 18681356Seschrock } 18691356Seschrock 18701356Seschrock /* 1871789Sahrens * Given a complete name, return just the portion that refers to the parent. 1872789Sahrens * Can return NULL if this is a pool. 1873789Sahrens */ 1874789Sahrens static int 1875789Sahrens parent_name(const char *path, char *buf, size_t buflen) 1876789Sahrens { 1877789Sahrens char *loc; 1878789Sahrens 1879789Sahrens if ((loc = strrchr(path, '/')) == NULL) 1880789Sahrens return (-1); 1881789Sahrens 1882789Sahrens (void) strncpy(buf, path, MIN(buflen, loc - path)); 1883789Sahrens buf[loc - path] = '\0'; 1884789Sahrens 1885789Sahrens return (0); 1886789Sahrens } 1887789Sahrens 1888789Sahrens /* 18892676Seschrock * Checks to make sure that the given path has a parent, and that it exists. We 18902676Seschrock * also fetch the 'zoned' property, which is used to validate property settings 18912676Seschrock * when creating new datasets. 1892789Sahrens */ 1893789Sahrens static int 18942676Seschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) 1895789Sahrens { 1896789Sahrens zfs_cmd_t zc = { 0 }; 1897789Sahrens char parent[ZFS_MAXNAMELEN]; 1898789Sahrens char *slash; 18991356Seschrock zfs_handle_t *zhp; 19002082Seschrock char errbuf[1024]; 19012082Seschrock 19022082Seschrock (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", 19032082Seschrock path); 1904789Sahrens 1905789Sahrens /* get parent, and check to see if this is just a pool */ 1906789Sahrens if (parent_name(path, parent, sizeof (parent)) != 0) { 19072082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19082082Seschrock "missing dataset name")); 19092082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1910789Sahrens } 1911789Sahrens 1912789Sahrens /* check to see if the pool exists */ 1913789Sahrens if ((slash = strchr(parent, '/')) == NULL) 1914789Sahrens slash = parent + strlen(parent); 1915789Sahrens (void) strncpy(zc.zc_name, parent, slash - parent); 1916789Sahrens zc.zc_name[slash - parent] = '\0'; 19172082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1918789Sahrens errno == ENOENT) { 19192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19202082Seschrock "no such pool '%s'"), zc.zc_name); 19212082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1922789Sahrens } 1923789Sahrens 1924789Sahrens /* check to see if the parent dataset exists */ 19252082Seschrock if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1926789Sahrens switch (errno) { 1927789Sahrens case ENOENT: 19282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19292082Seschrock "parent does not exist")); 19302082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1931789Sahrens 1932789Sahrens default: 19332082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 1934789Sahrens } 1935789Sahrens } 1936789Sahrens 19372676Seschrock *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1938789Sahrens /* we are in a non-global zone, but parent is in the global zone */ 19392676Seschrock if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 19402082Seschrock (void) zfs_standard_error(hdl, EPERM, errbuf); 19411356Seschrock zfs_close(zhp); 1942789Sahrens return (-1); 1943789Sahrens } 1944789Sahrens 1945789Sahrens /* make sure parent is a filesystem */ 19461356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 19472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19482082Seschrock "parent is not a filesystem")); 19492082Seschrock (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 19501356Seschrock zfs_close(zhp); 1951789Sahrens return (-1); 1952789Sahrens } 1953789Sahrens 19541356Seschrock zfs_close(zhp); 1955789Sahrens return (0); 1956789Sahrens } 1957789Sahrens 1958789Sahrens /* 19592676Seschrock * Create a new filesystem or volume. 1960789Sahrens */ 1961789Sahrens int 19622082Seschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 19632676Seschrock nvlist_t *props) 1964789Sahrens { 1965789Sahrens zfs_cmd_t zc = { 0 }; 1966789Sahrens int ret; 1967789Sahrens uint64_t size = 0; 1968789Sahrens uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 19692082Seschrock char errbuf[1024]; 19702676Seschrock uint64_t zoned; 19712082Seschrock 19722082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 19732082Seschrock "cannot create '%s'"), path); 1974789Sahrens 1975789Sahrens /* validate the path, taking care to note the extended error message */ 19762082Seschrock if (!zfs_validate_name(hdl, path, type)) 19772082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1978789Sahrens 1979789Sahrens /* validate parents exist */ 19802676Seschrock if (check_parents(hdl, path, &zoned) != 0) 1981789Sahrens return (-1); 1982789Sahrens 1983789Sahrens /* 1984789Sahrens * The failure modes when creating a dataset of a different type over 1985789Sahrens * one that already exists is a little strange. In particular, if you 1986789Sahrens * try to create a dataset on top of an existing dataset, the ioctl() 1987789Sahrens * will return ENOENT, not EEXIST. To prevent this from happening, we 1988789Sahrens * first try to see if the dataset exists. 1989789Sahrens */ 1990789Sahrens (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); 19912082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 19922082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19932082Seschrock "dataset already exists")); 19942082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1995789Sahrens } 1996789Sahrens 1997789Sahrens if (type == ZFS_TYPE_VOLUME) 1998789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 1999789Sahrens else 2000789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2001789Sahrens 20022676Seschrock if (props && (props = zfs_validate_properties(hdl, type, props, zoned, 20032676Seschrock NULL, errbuf)) == 0) 20042676Seschrock return (-1); 20052676Seschrock 2006789Sahrens if (type == ZFS_TYPE_VOLUME) { 20071133Seschrock /* 20081133Seschrock * If we are creating a volume, the size and block size must 20091133Seschrock * satisfy a few restraints. First, the blocksize must be a 20101133Seschrock * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the 20111133Seschrock * volsize must be a multiple of the block size, and cannot be 20121133Seschrock * zero. 20131133Seschrock */ 20142676Seschrock if (props == NULL || nvlist_lookup_uint64(props, 20152676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) { 20162676Seschrock nvlist_free(props); 20172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20182676Seschrock "missing volume size")); 20192676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2020789Sahrens } 2021789Sahrens 20222676Seschrock if ((ret = nvlist_lookup_uint64(props, 20232676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20242676Seschrock &blocksize)) != 0) { 20252676Seschrock if (ret == ENOENT) { 20262676Seschrock blocksize = zfs_prop_default_numeric( 20272676Seschrock ZFS_PROP_VOLBLOCKSIZE); 20282676Seschrock } else { 20292676Seschrock nvlist_free(props); 20302676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20312676Seschrock "missing volume block size")); 20322676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20332676Seschrock } 20342676Seschrock } 20352676Seschrock 20362676Seschrock if (size == 0) { 20372676Seschrock nvlist_free(props); 20382082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20392676Seschrock "volume size cannot be zero")); 20402676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20411133Seschrock } 20421133Seschrock 20431133Seschrock if (size % blocksize != 0) { 20442676Seschrock nvlist_free(props); 20452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20462676Seschrock "volume size must be a multiple of volume block " 20472676Seschrock "size")); 20482676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20491133Seschrock } 2050789Sahrens } 2051789Sahrens 20522676Seschrock if (props && 20532676Seschrock zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) 20542676Seschrock return (-1); 20552676Seschrock nvlist_free(props); 20562676Seschrock 2057789Sahrens /* create the dataset */ 20582082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2059789Sahrens 2060789Sahrens if (ret == 0 && type == ZFS_TYPE_VOLUME) 20612082Seschrock ret = zvol_create_link(hdl, path); 2062789Sahrens 20632676Seschrock zcmd_free_nvlists(&zc); 20642676Seschrock 2065789Sahrens /* check for failure */ 2066789Sahrens if (ret != 0) { 2067789Sahrens char parent[ZFS_MAXNAMELEN]; 2068789Sahrens (void) parent_name(path, parent, sizeof (parent)); 2069789Sahrens 2070789Sahrens switch (errno) { 2071789Sahrens case ENOENT: 20722082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20732082Seschrock "no such parent '%s'"), parent); 20742082Seschrock return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2075789Sahrens 2076789Sahrens case EINVAL: 20772082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20782082Seschrock "parent '%s' is not a filesysem"), parent); 20792082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2080789Sahrens 2081789Sahrens case EDOM: 20822082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20832676Seschrock "volume block size must be power of 2 from " 20842676Seschrock "%u to %uk"), 2085789Sahrens (uint_t)SPA_MINBLOCKSIZE, 2086789Sahrens (uint_t)SPA_MAXBLOCKSIZE >> 10); 20872082Seschrock 20882676Seschrock return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 20892082Seschrock 2090789Sahrens #ifdef _ILP32 2091789Sahrens case EOVERFLOW: 2092789Sahrens /* 2093789Sahrens * This platform can't address a volume this big. 2094789Sahrens */ 20952082Seschrock if (type == ZFS_TYPE_VOLUME) 20962082Seschrock return (zfs_error(hdl, EZFS_VOLTOOBIG, 20972082Seschrock errbuf)); 2098789Sahrens #endif 20992082Seschrock /* FALLTHROUGH */ 2100789Sahrens default: 21012082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2102789Sahrens } 2103789Sahrens } 2104789Sahrens 2105789Sahrens return (0); 2106789Sahrens } 2107789Sahrens 2108789Sahrens /* 2109789Sahrens * Destroys the given dataset. The caller must make sure that the filesystem 2110789Sahrens * isn't mounted, and that there are no active dependents. 2111789Sahrens */ 2112789Sahrens int 2113789Sahrens zfs_destroy(zfs_handle_t *zhp) 2114789Sahrens { 2115789Sahrens zfs_cmd_t zc = { 0 }; 2116789Sahrens int ret; 2117789Sahrens 2118789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2119789Sahrens 21202676Seschrock if (ZFS_IS_VOLUME(zhp)) { 21212082Seschrock if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2122789Sahrens return (-1); 2123789Sahrens 2124789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2125789Sahrens } else { 2126789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2127789Sahrens } 2128789Sahrens 21292082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 21302199Sahrens if (ret != 0) { 21312082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 21322082Seschrock dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 21332082Seschrock zhp->zfs_name)); 21342199Sahrens } 2135789Sahrens 2136789Sahrens remove_mountpoint(zhp); 2137789Sahrens 2138789Sahrens return (0); 2139789Sahrens } 2140789Sahrens 21412199Sahrens struct destroydata { 21422199Sahrens char *snapname; 21432199Sahrens boolean_t gotone; 21442199Sahrens }; 21452199Sahrens 21462199Sahrens static int 21472199Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) 21482199Sahrens { 21492199Sahrens struct destroydata *dd = arg; 21502199Sahrens zfs_handle_t *szhp; 21512199Sahrens char name[ZFS_MAXNAMELEN]; 21522199Sahrens 21532676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 21542676Seschrock (void) strlcat(name, "@", sizeof (name)); 21552676Seschrock (void) strlcat(name, dd->snapname, sizeof (name)); 21562199Sahrens 21572199Sahrens szhp = make_dataset_handle(zhp->zfs_hdl, name); 21582199Sahrens if (szhp) { 21592199Sahrens dd->gotone = B_TRUE; 21602199Sahrens zfs_close(szhp); 21612199Sahrens } 21622199Sahrens 21632199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 21642199Sahrens (void) zvol_remove_link(zhp->zfs_hdl, name); 21652199Sahrens /* 21662199Sahrens * NB: this is simply a best-effort. We don't want to 21672199Sahrens * return an error, because then we wouldn't visit all 21682199Sahrens * the volumes. 21692199Sahrens */ 21702199Sahrens } 21712199Sahrens 21722199Sahrens return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); 21732199Sahrens } 21742199Sahrens 21752199Sahrens /* 21762199Sahrens * Destroys all snapshots with the given name in zhp & descendants. 21772199Sahrens */ 21782199Sahrens int 21792199Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) 21802199Sahrens { 21812199Sahrens zfs_cmd_t zc = { 0 }; 21822199Sahrens int ret; 21832199Sahrens struct destroydata dd = { 0 }; 21842199Sahrens 21852199Sahrens dd.snapname = snapname; 21862199Sahrens (void) zfs_remove_link_cb(zhp, &dd); 21872199Sahrens 21882199Sahrens if (!dd.gotone) { 21892199Sahrens return (zfs_standard_error(zhp->zfs_hdl, ENOENT, 21902199Sahrens dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 21912199Sahrens zhp->zfs_name, snapname)); 21922199Sahrens } 21932199Sahrens 21942199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 21952676Seschrock (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 21962199Sahrens 21972199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); 21982199Sahrens if (ret != 0) { 21992199Sahrens char errbuf[1024]; 22002199Sahrens 22012199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22022199Sahrens "cannot destroy '%s@%s'"), zc.zc_name, snapname); 22032199Sahrens 22042199Sahrens switch (errno) { 22052199Sahrens case EEXIST: 22062199Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22072199Sahrens "snapshot is cloned")); 22082199Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); 22092199Sahrens 22102199Sahrens default: 22112199Sahrens return (zfs_standard_error(zhp->zfs_hdl, errno, 22122199Sahrens errbuf)); 22132199Sahrens } 22142199Sahrens } 22152199Sahrens 22162199Sahrens return (0); 22172199Sahrens } 22182199Sahrens 2219789Sahrens /* 2220789Sahrens * Clones the given dataset. The target must be of the same type as the source. 2221789Sahrens */ 2222789Sahrens int 22232676Seschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) 2224789Sahrens { 2225789Sahrens zfs_cmd_t zc = { 0 }; 2226789Sahrens char parent[ZFS_MAXNAMELEN]; 2227789Sahrens int ret; 22282082Seschrock char errbuf[1024]; 22292082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 22302676Seschrock zfs_type_t type; 22312676Seschrock uint64_t zoned; 2232789Sahrens 2233789Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2234789Sahrens 22352082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 22362082Seschrock "cannot create '%s'"), target); 22372082Seschrock 2238789Sahrens /* validate the target name */ 22392082Seschrock if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) 22402082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2241789Sahrens 2242789Sahrens /* validate parents exist */ 22432676Seschrock if (check_parents(hdl, target, &zoned) != 0) 2244789Sahrens return (-1); 2245789Sahrens 2246789Sahrens (void) parent_name(target, parent, sizeof (parent)); 2247789Sahrens 2248789Sahrens /* do the clone */ 22492676Seschrock if (ZFS_IS_VOLUME(zhp)) { 2250789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2251*2744Snn35248 type = ZFS_TYPE_VOLUME; 22522676Seschrock } else { 2253789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2254*2744Snn35248 type = ZFS_TYPE_FILESYSTEM; 22552676Seschrock } 22562676Seschrock 22572676Seschrock if (props) { 22582676Seschrock if ((props = zfs_validate_properties(hdl, type, props, zoned, 22592676Seschrock zhp, errbuf)) == NULL) 22602676Seschrock return (-1); 22612676Seschrock 22622676Seschrock if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { 22632676Seschrock nvlist_free(props); 22642676Seschrock return (-1); 22652676Seschrock } 22662676Seschrock 22672676Seschrock nvlist_free(props); 22682676Seschrock } 2269789Sahrens 2270789Sahrens (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 22712676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); 22722082Seschrock ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); 2273789Sahrens 22742676Seschrock zcmd_free_nvlists(&zc); 22752676Seschrock 2276789Sahrens if (ret != 0) { 2277789Sahrens switch (errno) { 2278789Sahrens 2279789Sahrens case ENOENT: 2280789Sahrens /* 2281789Sahrens * The parent doesn't exist. We should have caught this 2282789Sahrens * above, but there may a race condition that has since 2283789Sahrens * destroyed the parent. 2284789Sahrens * 2285789Sahrens * At this point, we don't know whether it's the source 2286789Sahrens * that doesn't exist anymore, or whether the target 2287789Sahrens * dataset doesn't exist. 2288789Sahrens */ 22892082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22902082Seschrock "no such parent '%s'"), parent); 22912082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 22922082Seschrock 22932082Seschrock case EXDEV: 22942082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 22952082Seschrock "source and target pools differ")); 22962082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, 22972082Seschrock errbuf)); 22982082Seschrock 22992082Seschrock default: 23002082Seschrock return (zfs_standard_error(zhp->zfs_hdl, errno, 23012082Seschrock errbuf)); 23022082Seschrock } 23032676Seschrock } else if (ZFS_IS_VOLUME(zhp)) { 23042082Seschrock ret = zvol_create_link(zhp->zfs_hdl, target); 23052082Seschrock } 23062082Seschrock 23072082Seschrock return (ret); 23082082Seschrock } 23092082Seschrock 23102082Seschrock typedef struct promote_data { 23112082Seschrock char cb_mountpoint[MAXPATHLEN]; 23122082Seschrock const char *cb_target; 23132082Seschrock const char *cb_errbuf; 23142082Seschrock uint64_t cb_pivot_txg; 23152082Seschrock } promote_data_t; 23162082Seschrock 23172082Seschrock static int 23182082Seschrock promote_snap_cb(zfs_handle_t *zhp, void *data) 23192082Seschrock { 23202082Seschrock promote_data_t *pd = data; 23212082Seschrock zfs_handle_t *szhp; 23222082Seschrock char snapname[MAXPATHLEN]; 23232082Seschrock 23242082Seschrock /* We don't care about snapshots after the pivot point */ 23252082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23262082Seschrock return (0); 23272082Seschrock 23282417Sahrens /* Remove the device link if it's a zvol. */ 23292676Seschrock if (ZFS_IS_VOLUME(zhp)) 23302417Sahrens (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 23312082Seschrock 23322082Seschrock /* Check for conflicting names */ 23332676Seschrock (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); 23342676Seschrock (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); 23352082Seschrock szhp = make_dataset_handle(zhp->zfs_hdl, snapname); 23362082Seschrock if (szhp != NULL) { 23372082Seschrock zfs_close(szhp); 23382082Seschrock zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 23392082Seschrock "snapshot name '%s' from origin \n" 23402082Seschrock "conflicts with '%s' from target"), 23412082Seschrock zhp->zfs_name, snapname); 23422082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf)); 23432082Seschrock } 23442082Seschrock return (0); 23452082Seschrock } 23462082Seschrock 23472417Sahrens static int 23482417Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data) 23492417Sahrens { 23502417Sahrens promote_data_t *pd = data; 23512417Sahrens 23522417Sahrens /* We don't care about snapshots after the pivot point */ 23532417Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) 23542417Sahrens return (0); 23552417Sahrens 23562417Sahrens /* Create the device link if it's a zvol. */ 23572676Seschrock if (ZFS_IS_VOLUME(zhp)) 23582417Sahrens (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 23592417Sahrens 23602417Sahrens return (0); 23612417Sahrens } 23622417Sahrens 23632082Seschrock /* 23642082Seschrock * Promotes the given clone fs to be the clone parent. 23652082Seschrock */ 23662082Seschrock int 23672082Seschrock zfs_promote(zfs_handle_t *zhp) 23682082Seschrock { 23692082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 23702082Seschrock zfs_cmd_t zc = { 0 }; 23712082Seschrock char parent[MAXPATHLEN]; 23722082Seschrock char *cp; 23732082Seschrock int ret; 23742082Seschrock zfs_handle_t *pzhp; 23752082Seschrock promote_data_t pd; 23762082Seschrock char errbuf[1024]; 23772082Seschrock 23782082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 23792082Seschrock "cannot promote '%s'"), zhp->zfs_name); 23802082Seschrock 23812082Seschrock if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 23822082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23832082Seschrock "snapshots can not be promoted")); 23842082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 23852082Seschrock } 23862082Seschrock 23872676Seschrock (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); 23882082Seschrock if (parent[0] == '\0') { 23892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23902082Seschrock "not a cloned filesystem")); 23912082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 23922082Seschrock } 23932082Seschrock cp = strchr(parent, '@'); 23942082Seschrock *cp = '\0'; 23952082Seschrock 23962082Seschrock /* Walk the snapshots we will be moving */ 23972082Seschrock pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); 23982082Seschrock if (pzhp == NULL) 23992082Seschrock return (-1); 24002082Seschrock pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 24012082Seschrock zfs_close(pzhp); 24022082Seschrock pd.cb_target = zhp->zfs_name; 24032082Seschrock pd.cb_errbuf = errbuf; 24042082Seschrock pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); 24052082Seschrock if (pzhp == NULL) 24062082Seschrock return (-1); 24072082Seschrock (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 24082082Seschrock sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 24092082Seschrock ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 24102417Sahrens if (ret != 0) { 24112417Sahrens zfs_close(pzhp); 24122082Seschrock return (-1); 24132417Sahrens } 24142082Seschrock 24152082Seschrock /* issue the ioctl */ 24162676Seschrock (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, 24172676Seschrock sizeof (zc.zc_value)); 24182082Seschrock (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 24192082Seschrock ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); 24202082Seschrock 24212082Seschrock if (ret != 0) { 24222417Sahrens int save_errno = errno; 24232417Sahrens 24242417Sahrens (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 24252417Sahrens zfs_close(pzhp); 24262417Sahrens 24272417Sahrens switch (save_errno) { 2428789Sahrens case EEXIST: 2429789Sahrens /* 24302082Seschrock * There is a conflicting snapshot name. We 24312082Seschrock * should have caught this above, but they could 24322082Seschrock * have renamed something in the mean time. 2433789Sahrens */ 24342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24352082Seschrock "conflicting snapshot name from parent '%s'"), 24362082Seschrock parent); 24372082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2438789Sahrens 2439789Sahrens default: 24402417Sahrens return (zfs_standard_error(hdl, save_errno, errbuf)); 2441789Sahrens } 24422417Sahrens } else { 24432417Sahrens (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); 2444789Sahrens } 2445789Sahrens 24462417Sahrens zfs_close(pzhp); 2447789Sahrens return (ret); 2448789Sahrens } 2449789Sahrens 24502199Sahrens static int 24512199Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg) 24522199Sahrens { 24532199Sahrens char *snapname = arg; 24542676Seschrock int ret; 24552199Sahrens 24562199Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 24572199Sahrens char name[MAXPATHLEN]; 24582199Sahrens 24592676Seschrock (void) strlcpy(name, zhp->zfs_name, sizeof (name)); 24602676Seschrock (void) strlcat(name, "@", sizeof (name)); 24612676Seschrock (void) strlcat(name, snapname, sizeof (name)); 24622199Sahrens (void) zvol_create_link(zhp->zfs_hdl, name); 24632199Sahrens /* 24642199Sahrens * NB: this is simply a best-effort. We don't want to 24652199Sahrens * return an error, because then we wouldn't visit all 24662199Sahrens * the volumes. 24672199Sahrens */ 24682199Sahrens } 24692676Seschrock 24702676Seschrock ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname); 24712676Seschrock 24722676Seschrock zfs_close(zhp); 24732676Seschrock 24742676Seschrock return (ret); 24752199Sahrens } 24762199Sahrens 2477789Sahrens /* 2478789Sahrens * Takes a snapshot of the given dataset 2479789Sahrens */ 2480789Sahrens int 24812199Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) 2482789Sahrens { 2483789Sahrens const char *delim; 2484789Sahrens char *parent; 2485789Sahrens zfs_handle_t *zhp; 2486789Sahrens zfs_cmd_t zc = { 0 }; 2487789Sahrens int ret; 24882082Seschrock char errbuf[1024]; 24892082Seschrock 24902082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 24912082Seschrock "cannot snapshot '%s'"), path); 24922082Seschrock 24932082Seschrock /* validate the target name */ 24942082Seschrock if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) 24952082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2496789Sahrens 2497789Sahrens /* make sure the parent exists and is of the appropriate type */ 24982199Sahrens delim = strchr(path, '@'); 24992082Seschrock if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 25002082Seschrock return (-1); 2501789Sahrens (void) strncpy(parent, path, delim - path); 2502789Sahrens parent[delim - path] = '\0'; 2503789Sahrens 25042082Seschrock if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2505789Sahrens ZFS_TYPE_VOLUME)) == NULL) { 2506789Sahrens free(parent); 2507789Sahrens return (-1); 2508789Sahrens } 2509789Sahrens 25102199Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 25112676Seschrock (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); 25122199Sahrens zc.zc_cookie = recursive; 25132199Sahrens ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); 25142199Sahrens 25152199Sahrens /* 25162199Sahrens * if it was recursive, the one that actually failed will be in 25172199Sahrens * zc.zc_name. 25182199Sahrens */ 25192199Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25202676Seschrock "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 25212199Sahrens if (ret == 0 && recursive) { 25222199Sahrens (void) zfs_iter_filesystems(zhp, 25232199Sahrens zfs_create_link_cb, (char *)delim+1); 25242199Sahrens } 2525789Sahrens if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 25262082Seschrock ret = zvol_create_link(zhp->zfs_hdl, path); 25272199Sahrens if (ret != 0) { 25282082Seschrock (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 25292082Seschrock &zc); 25302199Sahrens } 2531789Sahrens } 2532789Sahrens 25332082Seschrock if (ret != 0) 25342082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2535789Sahrens 2536789Sahrens free(parent); 2537789Sahrens zfs_close(zhp); 2538789Sahrens 2539789Sahrens return (ret); 2540789Sahrens } 2541789Sahrens 2542789Sahrens /* 2543789Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 2544789Sahrens */ 2545789Sahrens int 25461749Sahrens zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from) 2547789Sahrens { 2548789Sahrens zfs_cmd_t zc = { 0 }; 2549789Sahrens int ret; 25502082Seschrock char errbuf[1024]; 25512082Seschrock libzfs_handle_t *hdl = zhp_to->zfs_hdl; 25522082Seschrock 25532082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 25542082Seschrock "cannot send '%s'"), zhp_to->zfs_name); 2555789Sahrens 2556789Sahrens /* do the ioctl() */ 2557789Sahrens (void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name)); 2558789Sahrens if (zhp_from) { 25592676Seschrock (void) strlcpy(zc.zc_value, zhp_from->zfs_name, 2560789Sahrens sizeof (zc.zc_name)); 2561789Sahrens } else { 25622676Seschrock zc.zc_value[0] = '\0'; 2563789Sahrens } 2564789Sahrens zc.zc_cookie = STDOUT_FILENO; 2565789Sahrens 25662082Seschrock ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc); 2567789Sahrens if (ret != 0) { 2568789Sahrens switch (errno) { 2569789Sahrens 2570789Sahrens case EXDEV: 25712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 25722082Seschrock "not an ealier snapshot from the same fs")); 25732082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2574789Sahrens 2575789Sahrens case EDQUOT: 2576789Sahrens case EFBIG: 2577789Sahrens case EIO: 2578789Sahrens case ENOLINK: 2579789Sahrens case ENOSPC: 2580789Sahrens case ENOSTR: 2581789Sahrens case ENXIO: 2582789Sahrens case EPIPE: 2583789Sahrens case ERANGE: 2584789Sahrens case EFAULT: 2585789Sahrens case EROFS: 25862082Seschrock zfs_error_aux(hdl, strerror(errno)); 25872082Seschrock return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2588789Sahrens 2589789Sahrens default: 25902082Seschrock return (zfs_standard_error(hdl, errno, errbuf)); 2591789Sahrens } 2592789Sahrens } 2593789Sahrens 2594789Sahrens return (ret); 2595789Sahrens } 2596789Sahrens 2597789Sahrens /* 2598789Sahrens * Restores a backup of tosnap from stdin. 2599789Sahrens */ 2600789Sahrens int 26012082Seschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 26022665Snd150628 int verbose, int dryrun, boolean_t force) 2603789Sahrens { 2604789Sahrens zfs_cmd_t zc = { 0 }; 2605789Sahrens time_t begin_time; 2606868Sahrens int ioctl_err, err, bytes, size; 2607789Sahrens char *cp; 2608789Sahrens dmu_replay_record_t drr; 2609789Sahrens struct drr_begin *drrb = &zc.zc_begin_record; 26102082Seschrock char errbuf[1024]; 26112665Snd150628 prop_changelist_t *clp; 2612789Sahrens 2613789Sahrens begin_time = time(NULL); 2614789Sahrens 26152082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 26162082Seschrock "cannot receive")); 26172082Seschrock 2618789Sahrens /* trim off snapname, if any */ 26192676Seschrock (void) strlcpy(zc.zc_name, tosnap, sizeof (zc.zc_name)); 2620789Sahrens cp = strchr(zc.zc_name, '@'); 2621789Sahrens if (cp) 2622789Sahrens *cp = '\0'; 2623789Sahrens 2624789Sahrens /* read in the BEGIN record */ 2625789Sahrens cp = (char *)&drr; 2626789Sahrens bytes = 0; 2627789Sahrens do { 2628868Sahrens size = read(STDIN_FILENO, cp, sizeof (drr) - bytes); 2629868Sahrens cp += size; 2630868Sahrens bytes += size; 2631868Sahrens } while (size > 0); 2632868Sahrens 2633868Sahrens if (size < 0 || bytes != sizeof (drr)) { 26342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26352082Seschrock "stream (failed to read first record)")); 26362082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2637789Sahrens } 2638789Sahrens 2639789Sahrens zc.zc_begin_record = drr.drr_u.drr_begin; 2640789Sahrens 2641789Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2642789Sahrens drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 26432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 26442082Seschrock "stream (bad magic number)")); 26452082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2646789Sahrens } 2647789Sahrens 2648789Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION && 2649789Sahrens drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 26502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 26512082Seschrock "0x%llx is supported (stream is version 0x%llx)"), 2652789Sahrens DMU_BACKUP_VERSION, drrb->drr_version); 26532082Seschrock return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2654789Sahrens } 2655789Sahrens 2656789Sahrens /* 2657789Sahrens * Determine name of destination snapshot. 2658789Sahrens */ 26592676Seschrock (void) strlcpy(zc.zc_value, tosnap, sizeof (zc.zc_value)); 2660789Sahrens if (isprefix) { 2661789Sahrens if (strchr(tosnap, '@') != NULL) { 26622082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 26632082Seschrock "destination must be a filesystem")); 26642082Seschrock return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2665789Sahrens } 2666789Sahrens 2667789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '/'); 2668789Sahrens if (cp == NULL) 2669789Sahrens cp = drr.drr_u.drr_begin.drr_toname; 2670789Sahrens else 2671789Sahrens cp++; 2672789Sahrens 26732676Seschrock (void) strcat(zc.zc_value, "/"); 26742676Seschrock (void) strcat(zc.zc_value, cp); 2675789Sahrens } else if (strchr(tosnap, '@') == NULL) { 2676789Sahrens /* 2677789Sahrens * they specified just a filesystem; tack on the 2678789Sahrens * snapname from the backup. 2679789Sahrens */ 2680789Sahrens cp = strchr(drr.drr_u.drr_begin.drr_toname, '@'); 26812082Seschrock if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) 26822082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 26832676Seschrock (void) strcat(zc.zc_value, cp); 2684789Sahrens } 2685789Sahrens 2686789Sahrens if (drrb->drr_fromguid) { 2687789Sahrens zfs_handle_t *h; 2688789Sahrens /* incremental backup stream */ 2689789Sahrens 2690789Sahrens /* do the ioctl to the containing fs */ 26912676Seschrock (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name)); 2692789Sahrens cp = strchr(zc.zc_name, '@'); 2693789Sahrens *cp = '\0'; 2694789Sahrens 2695789Sahrens /* make sure destination fs exists */ 26962082Seschrock h = zfs_open(hdl, zc.zc_name, 26972082Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 26982082Seschrock if (h == NULL) 2699789Sahrens return (-1); 2700868Sahrens if (!dryrun) { 27012665Snd150628 /* 27022665Snd150628 * We need to unmount all the dependents of the dataset 27032665Snd150628 * and the dataset itself. If it's a volume 27042665Snd150628 * then remove device link. 27052665Snd150628 */ 2706868Sahrens if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 27072665Snd150628 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 27082665Snd150628 if (clp == NULL) 27092665Snd150628 return (-1); 27102665Snd150628 if (changelist_prefix(clp) != 0) { 27112665Snd150628 changelist_free(clp); 27122665Snd150628 return (-1); 27132665Snd150628 } 2714868Sahrens } else { 27152082Seschrock (void) zvol_remove_link(hdl, h->zfs_name); 2716868Sahrens } 2717868Sahrens } 2718789Sahrens zfs_close(h); 2719789Sahrens } else { 2720789Sahrens /* full backup stream */ 2721789Sahrens 27222676Seschrock (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name)); 2723868Sahrens 27241749Sahrens /* make sure they aren't trying to receive into the root */ 2725868Sahrens if (strchr(zc.zc_name, '/') == NULL) { 2726789Sahrens cp = strchr(zc.zc_name, '@'); 2727789Sahrens if (cp) 2728789Sahrens *cp = '\0'; 27292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27302082Seschrock "destination '%s' already exists"), zc.zc_name); 27312082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2732789Sahrens } 2733789Sahrens 2734789Sahrens if (isprefix) { 2735868Sahrens zfs_handle_t *h; 2736868Sahrens 2737789Sahrens /* make sure prefix exists */ 27382082Seschrock h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM); 27392082Seschrock if (h == NULL) 2740789Sahrens return (-1); 27411544Seschrock zfs_close(h); 2742789Sahrens 2743789Sahrens /* create any necessary ancestors up to prefix */ 2744868Sahrens zc.zc_objset_type = DMU_OST_ZFS; 27451544Seschrock 2746868Sahrens /* 2747868Sahrens * zc.zc_name is now the full name of the snap 27481544Seschrock * we're restoring into. Attempt to create, 27491544Seschrock * mount, and share any ancestor filesystems, up 27501544Seschrock * to the one that was named. 2751868Sahrens */ 27521544Seschrock for (cp = zc.zc_name + strlen(tosnap) + 1; 27531544Seschrock cp = strchr(cp, '/'); *cp = '/', cp++) { 27541544Seschrock const char *opname; 2755789Sahrens *cp = '\0'; 27561544Seschrock 27572082Seschrock opname = dgettext(TEXT_DOMAIN, "create"); 27582082Seschrock if (zfs_create(hdl, zc.zc_name, 27592676Seschrock ZFS_TYPE_FILESYSTEM, NULL) != 0) { 27601544Seschrock if (errno == EEXIST) 27611544Seschrock continue; 27621544Seschrock goto ancestorerr; 2763789Sahrens } 27641544Seschrock 27652082Seschrock opname = dgettext(TEXT_DOMAIN, "open"); 27662082Seschrock h = zfs_open(hdl, zc.zc_name, 27672082Seschrock ZFS_TYPE_FILESYSTEM); 27681544Seschrock if (h == NULL) 27691544Seschrock goto ancestorerr; 27701544Seschrock 27712082Seschrock opname = dgettext(TEXT_DOMAIN, "mount"); 27721544Seschrock if (zfs_mount(h, NULL, 0) != 0) 27731544Seschrock goto ancestorerr; 27741544Seschrock 27752082Seschrock opname = dgettext(TEXT_DOMAIN, "share"); 27761544Seschrock if (zfs_share(h) != 0) 27771544Seschrock goto ancestorerr; 27781544Seschrock 27791544Seschrock zfs_close(h); 27801544Seschrock 27811544Seschrock continue; 27821544Seschrock ancestorerr: 27832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27842082Seschrock "failed to %s ancestor '%s'"), opname, 27852082Seschrock zc.zc_name); 27862082Seschrock return (zfs_error(hdl, EZFS_BADRESTORE, 27872082Seschrock errbuf)); 2788789Sahrens } 2789789Sahrens } 2790868Sahrens 2791868Sahrens /* Make sure destination fs does not exist */ 2792868Sahrens cp = strchr(zc.zc_name, '@'); 2793868Sahrens *cp = '\0'; 27942082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 27952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27962082Seschrock "destination '%s' exists"), zc.zc_name); 27972082Seschrock return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2798868Sahrens } 2799868Sahrens 2800868Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 2801868Sahrens cp = strrchr(zc.zc_name, '/'); 2802868Sahrens *cp = '\0'; 2803789Sahrens } 2804789Sahrens 2805789Sahrens zc.zc_cookie = STDIN_FILENO; 28062676Seschrock zc.zc_guid = force; 2807789Sahrens if (verbose) { 28081749Sahrens (void) printf("%s %s stream of %s into %s\n", 28091749Sahrens dryrun ? "would receive" : "receiving", 2810789Sahrens drrb->drr_fromguid ? "incremental" : "full", 2811789Sahrens drr.drr_u.drr_begin.drr_toname, 28122676Seschrock zc.zc_value); 2813789Sahrens (void) fflush(stdout); 2814789Sahrens } 2815789Sahrens if (dryrun) 2816789Sahrens return (0); 28172082Seschrock err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2818868Sahrens if (ioctl_err != 0) { 2819789Sahrens switch (errno) { 2820789Sahrens case ENODEV: 28212082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28222082Seschrock "most recent snapshot does not match incremental " 28232082Seschrock "source")); 28242082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2825789Sahrens break; 2826789Sahrens case ETXTBSY: 28272082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28282082Seschrock "destination has been modified since most recent " 28292082Seschrock "snapshot")); 28302082Seschrock (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2831789Sahrens break; 2832789Sahrens case EEXIST: 2833789Sahrens if (drrb->drr_fromguid == 0) { 2834789Sahrens /* it's the containing fs that exists */ 28352676Seschrock cp = strchr(zc.zc_value, '@'); 2836789Sahrens *cp = '\0'; 2837789Sahrens } 28382082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28392082Seschrock "destination already exists")); 28402082Seschrock (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN, 28412676Seschrock "cannot restore to %s"), zc.zc_value); 2842789Sahrens break; 2843789Sahrens case EINVAL: 28442082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2845868Sahrens break; 28461544Seschrock case ECKSUM: 28472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 28482082Seschrock "invalid stream (checksum mismatch)")); 28492082Seschrock (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2850789Sahrens break; 2851789Sahrens default: 28522082Seschrock (void) zfs_standard_error(hdl, errno, errbuf); 2853789Sahrens } 2854789Sahrens } 2855789Sahrens 2856789Sahrens /* 2857868Sahrens * Mount or recreate the /dev links for the target filesystem 2858868Sahrens * (if created, or if we tore them down to do an incremental 2859868Sahrens * restore), and the /dev links for the new snapshot (if 28602665Snd150628 * created). Also mount any children of the target filesystem 28612665Snd150628 * if we did an incremental receive. 2862789Sahrens */ 28632676Seschrock cp = strchr(zc.zc_value, '@'); 2864868Sahrens if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2865789Sahrens zfs_handle_t *h; 2866789Sahrens 2867789Sahrens *cp = '\0'; 28682676Seschrock h = zfs_open(hdl, zc.zc_value, 2869789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2870868Sahrens *cp = '@'; 2871789Sahrens if (h) { 28722665Snd150628 if (h->zfs_type == ZFS_TYPE_VOLUME) { 28732082Seschrock err = zvol_create_link(hdl, h->zfs_name); 28741544Seschrock if (err == 0 && ioctl_err == 0) 28752082Seschrock err = zvol_create_link(hdl, 28762676Seschrock zc.zc_value); 28772665Snd150628 } else { 28782665Snd150628 if (drrb->drr_fromguid) { 28792665Snd150628 err = changelist_postfix(clp); 28802665Snd150628 changelist_free(clp); 28812665Snd150628 } else { 28822665Snd150628 err = zfs_mount(h, NULL, 0); 28832665Snd150628 } 2884868Sahrens } 28852665Snd150628 zfs_close(h); 2886789Sahrens } 2887789Sahrens } 2888789Sahrens 2889868Sahrens if (err || ioctl_err) 2890868Sahrens return (-1); 2891789Sahrens 2892789Sahrens if (verbose) { 2893789Sahrens char buf1[64]; 2894789Sahrens char buf2[64]; 2895789Sahrens uint64_t bytes = zc.zc_cookie; 2896789Sahrens time_t delta = time(NULL) - begin_time; 2897789Sahrens if (delta == 0) 2898789Sahrens delta = 1; 2899789Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 2900789Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 2901789Sahrens 29021749Sahrens (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 2903789Sahrens buf1, delta, buf2); 2904789Sahrens } 29052665Snd150628 2906789Sahrens return (0); 2907789Sahrens } 2908789Sahrens 2909789Sahrens /* 29101294Slling * Destroy any more recent snapshots. We invoke this callback on any dependents 29111294Slling * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 29121294Slling * is a dependent and we should just destroy it without checking the transaction 29131294Slling * group. 2914789Sahrens */ 29151294Slling typedef struct rollback_data { 29161294Slling const char *cb_target; /* the snapshot */ 29171294Slling uint64_t cb_create; /* creation time reference */ 29181294Slling prop_changelist_t *cb_clp; /* changelist pointer */ 29191294Slling int cb_error; 29202082Seschrock boolean_t cb_dependent; 29211294Slling } rollback_data_t; 29221294Slling 29231294Slling static int 29241294Slling rollback_destroy(zfs_handle_t *zhp, void *data) 29251294Slling { 29261294Slling rollback_data_t *cbp = data; 29271294Slling 29281294Slling if (!cbp->cb_dependent) { 29291294Slling if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 29301294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 29311294Slling zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 29321294Slling cbp->cb_create) { 29331294Slling 29342082Seschrock cbp->cb_dependent = B_TRUE; 29352474Seschrock if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 29362474Seschrock cbp) != 0) 29372474Seschrock cbp->cb_error = 1; 29382082Seschrock cbp->cb_dependent = B_FALSE; 29391294Slling 29401294Slling if (zfs_destroy(zhp) != 0) 29411294Slling cbp->cb_error = 1; 29421294Slling else 29431294Slling changelist_remove(zhp, cbp->cb_clp); 29441294Slling } 29451294Slling } else { 29461294Slling if (zfs_destroy(zhp) != 0) 29471294Slling cbp->cb_error = 1; 29481294Slling else 29491294Slling changelist_remove(zhp, cbp->cb_clp); 29501294Slling } 29511294Slling 29521294Slling zfs_close(zhp); 29531294Slling return (0); 29541294Slling } 29551294Slling 29561294Slling /* 29571294Slling * Rollback the dataset to its latest snapshot. 29581294Slling */ 29591294Slling static int 29601294Slling do_rollback(zfs_handle_t *zhp) 2961789Sahrens { 2962789Sahrens int ret; 2963789Sahrens zfs_cmd_t zc = { 0 }; 2964789Sahrens 2965789Sahrens assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 2966789Sahrens zhp->zfs_type == ZFS_TYPE_VOLUME); 2967789Sahrens 2968789Sahrens if (zhp->zfs_type == ZFS_TYPE_VOLUME && 29692082Seschrock zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2970789Sahrens return (-1); 2971789Sahrens 2972789Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2973789Sahrens 29742676Seschrock if (ZFS_IS_VOLUME(zhp)) 2975789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 2976789Sahrens else 2977789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 2978789Sahrens 2979789Sahrens /* 2980789Sahrens * We rely on the consumer to verify that there are no newer snapshots 2981789Sahrens * for the given dataset. Given these constraints, we can simply pass 2982789Sahrens * the name on to the ioctl() call. There is still an unlikely race 2983789Sahrens * condition where the user has taken a snapshot since we verified that 2984789Sahrens * this was the most recent. 2985789Sahrens */ 29862082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 29872082Seschrock &zc)) != 0) { 29882082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, 29892082Seschrock dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 29902082Seschrock zhp->zfs_name); 2991789Sahrens } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 29922082Seschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 2993789Sahrens } 2994789Sahrens 2995789Sahrens return (ret); 2996789Sahrens } 2997789Sahrens 2998789Sahrens /* 29991294Slling * Given a dataset, rollback to a specific snapshot, discarding any 30001294Slling * data changes since then and making it the active dataset. 30011294Slling * 30021294Slling * Any snapshots more recent than the target are destroyed, along with 30031294Slling * their dependents. 30041294Slling */ 30051294Slling int 30061294Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) 30071294Slling { 30081294Slling int ret; 30091294Slling rollback_data_t cb = { 0 }; 30101294Slling prop_changelist_t *clp; 30111294Slling 30121294Slling /* 30131294Slling * Unmount all dependendents of the dataset and the dataset itself. 30141294Slling * The list we need to gather is the same as for doing rename 30151294Slling */ 30161294Slling clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 30171294Slling if (clp == NULL) 30181294Slling return (-1); 30191294Slling 30201294Slling if ((ret = changelist_prefix(clp)) != 0) 30211294Slling goto out; 30221294Slling 30231294Slling /* 30241294Slling * Destroy all recent snapshots and its dependends. 30251294Slling */ 30261294Slling cb.cb_target = snap->zfs_name; 30271294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 30281294Slling cb.cb_clp = clp; 30291294Slling (void) zfs_iter_children(zhp, rollback_destroy, &cb); 30301294Slling 30311294Slling if ((ret = cb.cb_error) != 0) { 30321294Slling (void) changelist_postfix(clp); 30331294Slling goto out; 30341294Slling } 30351294Slling 30361294Slling /* 30371294Slling * Now that we have verified that the snapshot is the latest, 30381294Slling * rollback to the given snapshot. 30391294Slling */ 30401294Slling ret = do_rollback(zhp); 30411294Slling 30421294Slling if (ret != 0) { 30431294Slling (void) changelist_postfix(clp); 30441294Slling goto out; 30451294Slling } 30461294Slling 30471294Slling /* 30481294Slling * We only want to re-mount the filesystem if it was mounted in the 30491294Slling * first place. 30501294Slling */ 30511294Slling ret = changelist_postfix(clp); 30521294Slling 30531294Slling out: 30541294Slling changelist_free(clp); 30551294Slling return (ret); 30561294Slling } 30571294Slling 30581294Slling /* 3059789Sahrens * Iterate over all dependents for a given dataset. This includes both 3060789Sahrens * hierarchical dependents (children) and data dependents (snapshots and 3061789Sahrens * clones). The bulk of the processing occurs in get_dependents() in 3062789Sahrens * libzfs_graph.c. 3063789Sahrens */ 3064789Sahrens int 30652474Seschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 30662474Seschrock zfs_iter_f func, void *data) 3067789Sahrens { 3068789Sahrens char **dependents; 3069789Sahrens size_t count; 3070789Sahrens int i; 3071789Sahrens zfs_handle_t *child; 3072789Sahrens int ret = 0; 3073789Sahrens 30742474Seschrock if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, 30752474Seschrock &dependents, &count) != 0) 30762474Seschrock return (-1); 30772474Seschrock 3078789Sahrens for (i = 0; i < count; i++) { 30792082Seschrock if ((child = make_dataset_handle(zhp->zfs_hdl, 30802082Seschrock dependents[i])) == NULL) 3081789Sahrens continue; 3082789Sahrens 3083789Sahrens if ((ret = func(child, data)) != 0) 3084789Sahrens break; 3085789Sahrens } 3086789Sahrens 3087789Sahrens for (i = 0; i < count; i++) 3088789Sahrens free(dependents[i]); 3089789Sahrens free(dependents); 3090789Sahrens 3091789Sahrens return (ret); 3092789Sahrens } 3093789Sahrens 3094789Sahrens /* 3095789Sahrens * Renames the given dataset. 3096789Sahrens */ 3097789Sahrens int 3098789Sahrens zfs_rename(zfs_handle_t *zhp, const char *target) 3099789Sahrens { 3100789Sahrens int ret; 3101789Sahrens zfs_cmd_t zc = { 0 }; 3102789Sahrens char *delim; 3103789Sahrens prop_changelist_t *cl; 3104789Sahrens char parent[ZFS_MAXNAMELEN]; 31052082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 31062082Seschrock char errbuf[1024]; 3107789Sahrens 3108789Sahrens /* if we have the same exact name, just return success */ 3109789Sahrens if (strcmp(zhp->zfs_name, target) == 0) 3110789Sahrens return (0); 3111789Sahrens 31122082Seschrock (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31132082Seschrock "cannot rename to '%s'"), target); 31142082Seschrock 3115789Sahrens /* 3116789Sahrens * Make sure the target name is valid 3117789Sahrens */ 3118789Sahrens if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 31192665Snd150628 if ((strchr(target, '@') == NULL) || 31202665Snd150628 *target == '@') { 31212665Snd150628 /* 31222665Snd150628 * Snapshot target name is abbreviated, 31232665Snd150628 * reconstruct full dataset name 31242665Snd150628 */ 31252665Snd150628 (void) strlcpy(parent, zhp->zfs_name, 31262665Snd150628 sizeof (parent)); 31272665Snd150628 delim = strchr(parent, '@'); 31282665Snd150628 if (strchr(target, '@') == NULL) 31292665Snd150628 *(++delim) = '\0'; 31302665Snd150628 else 31312665Snd150628 *delim = '\0'; 31322665Snd150628 (void) strlcat(parent, target, sizeof (parent)); 31332665Snd150628 target = parent; 31342665Snd150628 } else { 31352665Snd150628 /* 31362665Snd150628 * Make sure we're renaming within the same dataset. 31372665Snd150628 */ 31382665Snd150628 delim = strchr(target, '@'); 31392665Snd150628 if (strncmp(zhp->zfs_name, target, delim - target) 31402665Snd150628 != 0 || zhp->zfs_name[delim - target] != '@') { 31412665Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31422665Snd150628 "snapshots must be part of same " 31432665Snd150628 "dataset")); 31442665Snd150628 return (zfs_error(hdl, EZFS_CROSSTARGET, 31452665Snd150628 errbuf)); 31462665Snd150628 } 3147789Sahrens } 31482665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31492665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3150789Sahrens } else { 31512665Snd150628 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) 31522665Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31532676Seschrock uint64_t unused; 31542676Seschrock 3155789Sahrens /* validate parents */ 31562676Seschrock if (check_parents(hdl, target, &unused) != 0) 3157789Sahrens return (-1); 3158789Sahrens 3159789Sahrens (void) parent_name(target, parent, sizeof (parent)); 3160789Sahrens 3161789Sahrens /* make sure we're in the same pool */ 3162789Sahrens verify((delim = strchr(target, '/')) != NULL); 3163789Sahrens if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3164789Sahrens zhp->zfs_name[delim - target] != '/') { 31652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31662082Seschrock "datasets must be within same pool")); 31672082Seschrock return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 3168789Sahrens } 31692440Snd150628 31702440Snd150628 /* new name cannot be a child of the current dataset name */ 31712440Snd150628 if (strncmp(parent, zhp->zfs_name, 31722440Snd150628 strlen(zhp->zfs_name)) == 0) { 31732440Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31742440Snd150628 "New dataset name cannot be a descendent of " 31752440Snd150628 "current dataset name")); 31762440Snd150628 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 31772440Snd150628 } 3178789Sahrens } 3179789Sahrens 31802082Seschrock (void) snprintf(errbuf, sizeof (errbuf), 31812082Seschrock dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); 31822082Seschrock 3183789Sahrens if (getzoneid() == GLOBAL_ZONEID && 3184789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 31852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31862082Seschrock "dataset is used in a non-global zone")); 31872082Seschrock return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3188789Sahrens } 3189789Sahrens 3190789Sahrens if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) 31912082Seschrock return (-1); 3192789Sahrens 3193789Sahrens if (changelist_haszonedchild(cl)) { 31942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31952082Seschrock "child dataset with inherited mountpoint is used " 31962082Seschrock "in a non-global zone")); 31972676Seschrock (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3198789Sahrens goto error; 3199789Sahrens } 3200789Sahrens 3201789Sahrens if ((ret = changelist_prefix(cl)) != 0) 3202789Sahrens goto error; 3203789Sahrens 32042676Seschrock if (ZFS_IS_VOLUME(zhp)) 3205789Sahrens zc.zc_objset_type = DMU_OST_ZVOL; 3206789Sahrens else 3207789Sahrens zc.zc_objset_type = DMU_OST_ZFS; 3208789Sahrens 32092665Snd150628 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 32102676Seschrock (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 32112665Snd150628 32122082Seschrock if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { 32132082Seschrock (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3214789Sahrens 3215789Sahrens /* 3216789Sahrens * On failure, we still want to remount any filesystems that 3217789Sahrens * were previously mounted, so we don't alter the system state. 3218789Sahrens */ 3219789Sahrens (void) changelist_postfix(cl); 3220789Sahrens } else { 3221789Sahrens changelist_rename(cl, zfs_get_name(zhp), target); 3222789Sahrens 3223789Sahrens ret = changelist_postfix(cl); 3224789Sahrens } 3225789Sahrens 3226789Sahrens error: 3227789Sahrens changelist_free(cl); 3228789Sahrens return (ret); 3229789Sahrens } 3230789Sahrens 3231789Sahrens /* 3232789Sahrens * Given a zvol dataset, issue the ioctl to create the appropriate minor node, 3233789Sahrens * poke devfsadm to create the /dev link, and then wait for the link to appear. 3234789Sahrens */ 3235789Sahrens int 32362082Seschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset) 3237789Sahrens { 3238789Sahrens zfs_cmd_t zc = { 0 }; 32392082Seschrock di_devlink_handle_t dhdl; 3240789Sahrens 3241789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3242789Sahrens 3243789Sahrens /* 3244789Sahrens * Issue the appropriate ioctl. 3245789Sahrens */ 32462082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { 3247789Sahrens switch (errno) { 3248789Sahrens case EEXIST: 3249789Sahrens /* 3250789Sahrens * Silently ignore the case where the link already 3251789Sahrens * exists. This allows 'zfs volinit' to be run multiple 3252789Sahrens * times without errors. 3253789Sahrens */ 3254789Sahrens return (0); 3255789Sahrens 3256789Sahrens default: 32572082Seschrock return (zfs_standard_error(hdl, errno, 32582082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32592082Seschrock "for '%s'"), dataset)); 3260789Sahrens } 3261789Sahrens } 3262789Sahrens 3263789Sahrens /* 3264789Sahrens * Call devfsadm and wait for the links to magically appear. 3265789Sahrens */ 32662082Seschrock if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 32672082Seschrock zfs_error_aux(hdl, strerror(errno)); 32682082Seschrock (void) zfs_error(hdl, EZFS_DEVLINKS, 32692082Seschrock dgettext(TEXT_DOMAIN, "cannot create device links " 32702082Seschrock "for '%s'"), dataset); 32712082Seschrock (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3272789Sahrens return (-1); 3273789Sahrens } else { 32742082Seschrock (void) di_devlink_fini(&dhdl); 3275789Sahrens } 3276789Sahrens 3277789Sahrens return (0); 3278789Sahrens } 3279789Sahrens 3280789Sahrens /* 3281789Sahrens * Remove a minor node for the given zvol and the associated /dev links. 3282789Sahrens */ 3283789Sahrens int 32842082Seschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) 3285789Sahrens { 3286789Sahrens zfs_cmd_t zc = { 0 }; 3287789Sahrens 3288789Sahrens (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3289789Sahrens 32902082Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { 3291789Sahrens switch (errno) { 3292789Sahrens case ENXIO: 3293789Sahrens /* 3294789Sahrens * Silently ignore the case where the link no longer 3295789Sahrens * exists, so that 'zfs volfini' can be run multiple 3296789Sahrens * times without errors. 3297789Sahrens */ 3298789Sahrens return (0); 3299789Sahrens 3300789Sahrens default: 33012082Seschrock return (zfs_standard_error(hdl, errno, 33022082Seschrock dgettext(TEXT_DOMAIN, "cannot remove device " 33032082Seschrock "links for '%s'"), dataset)); 3304789Sahrens } 3305789Sahrens } 3306789Sahrens 3307789Sahrens return (0); 3308789Sahrens } 33092676Seschrock 33102676Seschrock nvlist_t * 33112676Seschrock zfs_get_user_props(zfs_handle_t *zhp) 33122676Seschrock { 33132676Seschrock return (zhp->zfs_user_props); 33142676Seschrock } 33152676Seschrock 33162676Seschrock /* 33172676Seschrock * Given a comma-separated list of properties, contruct a property list 33182676Seschrock * containing both user-defined and native properties. This function will 33192676Seschrock * return a NULL list if 'all' is specified, which can later be expanded on a 33202676Seschrock * per-dataset basis by zfs_expand_proplist(). 33212676Seschrock */ 33222676Seschrock int 33232676Seschrock zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 33242676Seschrock { 33252676Seschrock int i; 33262676Seschrock size_t len; 33272676Seschrock char *s, *p; 33282676Seschrock char c; 33292676Seschrock zfs_prop_t prop; 33302676Seschrock zfs_proplist_t *entry; 33312676Seschrock zfs_proplist_t **last; 33322676Seschrock 33332676Seschrock *listp = NULL; 33342676Seschrock last = listp; 33352676Seschrock 33362676Seschrock /* 33372676Seschrock * If 'all' is specified, return a NULL list. 33382676Seschrock */ 33392676Seschrock if (strcmp(fields, "all") == 0) 33402676Seschrock return (0); 33412676Seschrock 33422676Seschrock /* 33432676Seschrock * If no fields were specified, return an error. 33442676Seschrock */ 33452676Seschrock if (fields[0] == '\0') { 33462676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33472676Seschrock "no properties specified")); 33482676Seschrock return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 33492676Seschrock "bad property list"))); 33502676Seschrock } 33512676Seschrock 33522676Seschrock /* 33532676Seschrock * It would be nice to use getsubopt() here, but the inclusion of column 33542676Seschrock * aliases makes this more effort than it's worth. 33552676Seschrock */ 33562676Seschrock s = fields; 33572676Seschrock while (*s != '\0') { 33582676Seschrock if ((p = strchr(s, ',')) == NULL) { 33592676Seschrock len = strlen(s); 33602676Seschrock p = s + len; 33612676Seschrock } else { 33622676Seschrock len = p - s; 33632676Seschrock } 33642676Seschrock 33652676Seschrock /* 33662676Seschrock * Check for empty options. 33672676Seschrock */ 33682676Seschrock if (len == 0) { 33692676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33702676Seschrock "empty property name")); 33712676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 33722676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 33732676Seschrock } 33742676Seschrock 33752676Seschrock /* 33762676Seschrock * Check all regular property names. 33772676Seschrock */ 33782676Seschrock c = s[len]; 33792676Seschrock s[len] = '\0'; 33802676Seschrock for (i = 0; i < ZFS_NPROP_ALL; i++) { 33812676Seschrock if ((prop = zfs_name_to_prop(s)) != ZFS_PROP_INVAL) 33822676Seschrock break; 33832676Seschrock } 33842676Seschrock 33852676Seschrock /* 33862676Seschrock * If no column is specified, and this isn't a user property, 33872676Seschrock * return failure. 33882676Seschrock */ 33892676Seschrock if (i == ZFS_NPROP_ALL && !zfs_prop_user(s)) { 33902676Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33912676Seschrock "invalid property '%s'"), s); 33922676Seschrock return (zfs_error(hdl, EZFS_BADPROP, 33932676Seschrock dgettext(TEXT_DOMAIN, "bad property list"))); 33942676Seschrock } 33952676Seschrock 33962676Seschrock if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 33972676Seschrock return (-1); 33982676Seschrock 33992676Seschrock entry->pl_prop = prop; 34002676Seschrock if (prop == ZFS_PROP_INVAL) { 34012676Seschrock if ((entry->pl_user_prop = 34022676Seschrock zfs_strdup(hdl, s)) == NULL) { 34032676Seschrock free(entry); 34042676Seschrock return (-1); 34052676Seschrock } 34062676Seschrock entry->pl_width = strlen(s); 34072676Seschrock } else { 34082676Seschrock entry->pl_width = zfs_prop_width(prop, 34092676Seschrock &entry->pl_fixed); 34102676Seschrock } 34112676Seschrock 34122676Seschrock *last = entry; 34132676Seschrock last = &entry->pl_next; 34142676Seschrock 34152676Seschrock s = p; 34162676Seschrock if (c == ',') 34172676Seschrock s++; 34182676Seschrock } 34192676Seschrock 34202676Seschrock return (0); 34212676Seschrock } 34222676Seschrock 34232676Seschrock void 34242676Seschrock zfs_free_proplist(zfs_proplist_t *pl) 34252676Seschrock { 34262676Seschrock zfs_proplist_t *next; 34272676Seschrock 34282676Seschrock while (pl != NULL) { 34292676Seschrock next = pl->pl_next; 34302676Seschrock free(pl->pl_user_prop); 34312676Seschrock free(pl); 34322676Seschrock pl = next; 34332676Seschrock } 34342676Seschrock } 34352676Seschrock 34362676Seschrock /* 34372676Seschrock * This function is used by 'zfs list' to determine the exact set of columns to 34382676Seschrock * display, and their maximum widths. This does two main things: 34392676Seschrock * 34402676Seschrock * - If this is a list of all properties, then expand the list to include 34412676Seschrock * all native properties, and set a flag so that for each dataset we look 34422676Seschrock * for new unique user properties and add them to the list. 34432676Seschrock * 34442676Seschrock * - For non fixed-width properties, keep track of the maximum width seen 34452676Seschrock * so that we can size the column appropriately. 34462676Seschrock */ 34472676Seschrock int 34482676Seschrock zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) 34492676Seschrock { 34502676Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 34512676Seschrock zfs_prop_t prop; 34522676Seschrock zfs_proplist_t *entry; 34532676Seschrock zfs_proplist_t **last, **start; 34542676Seschrock nvlist_t *userprops, *propval; 34552676Seschrock nvpair_t *elem; 34562676Seschrock char *strval; 34572676Seschrock char buf[ZFS_MAXPROPLEN]; 34582676Seschrock 34592676Seschrock if (*plp == NULL) { 34602676Seschrock /* 34612676Seschrock * If this is the very first time we've been called for an 'all' 34622676Seschrock * specification, expand the list to include all native 34632676Seschrock * properties. 34642676Seschrock */ 34652676Seschrock last = plp; 34662676Seschrock for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) { 34672676Seschrock if ((entry = zfs_alloc(hdl, 34682676Seschrock sizeof (zfs_proplist_t))) == NULL) 34692676Seschrock return (-1); 34702676Seschrock 34712676Seschrock entry->pl_prop = prop; 34722676Seschrock entry->pl_width = zfs_prop_width(prop, 34732676Seschrock &entry->pl_fixed); 34742676Seschrock entry->pl_all = B_TRUE; 34752676Seschrock 34762676Seschrock *last = entry; 34772676Seschrock last = &entry->pl_next; 34782676Seschrock } 34792676Seschrock 34802676Seschrock /* 34812676Seschrock * Add 'name' to the beginning of the list, which is handled 34822676Seschrock * specially. 34832676Seschrock */ 34842676Seschrock if ((entry = zfs_alloc(hdl, 34852676Seschrock sizeof (zfs_proplist_t))) == NULL) 34862676Seschrock return (-1); 34872676Seschrock 34882676Seschrock entry->pl_prop = ZFS_PROP_NAME; 34892676Seschrock entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 34902676Seschrock &entry->pl_fixed); 34912676Seschrock entry->pl_all = B_TRUE; 34922676Seschrock entry->pl_next = *plp; 34932676Seschrock *plp = entry; 34942676Seschrock } 34952676Seschrock 34962676Seschrock userprops = zfs_get_user_props(zhp); 34972676Seschrock 34982676Seschrock entry = *plp; 34992676Seschrock if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 35002676Seschrock /* 35012676Seschrock * Go through and add any user properties as necessary. We 35022676Seschrock * start by incrementing our list pointer to the first 35032676Seschrock * non-native property. 35042676Seschrock */ 35052676Seschrock start = plp; 35062676Seschrock while (*start != NULL) { 35072676Seschrock if ((*start)->pl_prop == ZFS_PROP_INVAL) 35082676Seschrock break; 35092676Seschrock start = &(*start)->pl_next; 35102676Seschrock } 35112676Seschrock 35122676Seschrock elem = NULL; 35132676Seschrock while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 35142676Seschrock /* 35152676Seschrock * See if we've already found this property in our list. 35162676Seschrock */ 35172676Seschrock for (last = start; *last != NULL; 35182676Seschrock last = &(*last)->pl_next) { 35192676Seschrock if (strcmp((*last)->pl_user_prop, 35202676Seschrock nvpair_name(elem)) == 0) 35212676Seschrock break; 35222676Seschrock } 35232676Seschrock 35242676Seschrock if (*last == NULL) { 35252676Seschrock if ((entry = zfs_alloc(hdl, 35262676Seschrock sizeof (zfs_proplist_t))) == NULL || 35272676Seschrock ((entry->pl_user_prop = zfs_strdup(hdl, 35282676Seschrock nvpair_name(elem)))) == NULL) { 35292676Seschrock free(entry); 35302676Seschrock return (-1); 35312676Seschrock } 35322676Seschrock 35332676Seschrock entry->pl_prop = ZFS_PROP_INVAL; 35342676Seschrock entry->pl_width = strlen(nvpair_name(elem)); 35352676Seschrock entry->pl_all = B_TRUE; 35362676Seschrock *last = entry; 35372676Seschrock } 35382676Seschrock } 35392676Seschrock } 35402676Seschrock 35412676Seschrock /* 35422676Seschrock * Now go through and check the width of any non-fixed columns 35432676Seschrock */ 35442676Seschrock for (entry = *plp; entry != NULL; entry = entry->pl_next) { 35452676Seschrock if (entry->pl_fixed) 35462676Seschrock continue; 35472676Seschrock 35482676Seschrock if (entry->pl_prop != ZFS_PROP_INVAL) { 35492676Seschrock if (zfs_prop_get(zhp, entry->pl_prop, 35502676Seschrock buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 35512676Seschrock if (strlen(buf) > entry->pl_width) 35522676Seschrock entry->pl_width = strlen(buf); 35532676Seschrock } 35542676Seschrock } else if (nvlist_lookup_nvlist(userprops, 35552676Seschrock entry->pl_user_prop, &propval) == 0) { 35562676Seschrock verify(nvlist_lookup_string(propval, 35572676Seschrock ZFS_PROP_VALUE, &strval) == 0); 35582676Seschrock if (strlen(strval) > entry->pl_width) 35592676Seschrock entry->pl_width = strlen(strval); 35602676Seschrock } 35612676Seschrock } 35622676Seschrock 35632676Seschrock return (0); 35642676Seschrock } 3565