1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21ad135b5dSChristopher Siden 22fa9e4066Sahrens /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24d8ab6e12SDon Brady * Copyright 2020 Joyent, Inc. 25*7ac89354SDon Brady * Copyright (c) 2011, 2018 by Delphix. All rights reserved. 2688f61deeSIgor Kozhukhov * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> 271702cce7SAlek Pinchuk * Copyright (c) 2017 Datto Inc. 28fa9e4066Sahrens */ 29fa9e4066Sahrens 30fa9e4066Sahrens /* 31fa9e4066Sahrens * Internal utility routines for the ZFS library. 32fa9e4066Sahrens */ 33fa9e4066Sahrens 34d8ab6e12SDon Brady #include <ctype.h> 35fa9e4066Sahrens #include <errno.h> 36fa9e4066Sahrens #include <fcntl.h> 37fa9e4066Sahrens #include <libintl.h> 38fa9e4066Sahrens #include <stdarg.h> 39fa9e4066Sahrens #include <stdio.h> 40fa9e4066Sahrens #include <stdlib.h> 41fa9e4066Sahrens #include <strings.h> 42990b4856Slling #include <math.h> 432bcf0248SMax Grossman #include <sys/filio.h> 44fa9e4066Sahrens #include <sys/mnttab.h> 455aba80dbSck #include <sys/mntent.h> 465aba80dbSck #include <sys/types.h> 470a055120SJason King #include <libcmdutils.h> 48fa9e4066Sahrens 49fa9e4066Sahrens #include <libzfs.h> 504445fffbSMatthew Ahrens #include <libzfs_core.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include "libzfs_impl.h" 5391ebeef5Sahrens #include "zfs_prop.h" 54e0f1c0afSOlaf Faaland #include "zfs_comutil.h" 55ad135b5dSChristopher Siden #include "zfeature_common.h" 56d8ab6e12SDon Brady #include <libzutil.h> 57fa9e4066Sahrens 5899653d4eSeschrock int 5999653d4eSeschrock libzfs_errno(libzfs_handle_t *hdl) 6099653d4eSeschrock { 6199653d4eSeschrock return (hdl->libzfs_error); 6299653d4eSeschrock } 63fa9e4066Sahrens 6499653d4eSeschrock const char * 6599653d4eSeschrock libzfs_error_action(libzfs_handle_t *hdl) 6699653d4eSeschrock { 6799653d4eSeschrock return (hdl->libzfs_action); 6899653d4eSeschrock } 69fa9e4066Sahrens 7099653d4eSeschrock const char * 7199653d4eSeschrock libzfs_error_description(libzfs_handle_t *hdl) 7299653d4eSeschrock { 7399653d4eSeschrock if (hdl->libzfs_desc[0] != '\0') 7499653d4eSeschrock return (hdl->libzfs_desc); 7599653d4eSeschrock 7699653d4eSeschrock switch (hdl->libzfs_error) { 7799653d4eSeschrock case EZFS_NOMEM: 7899653d4eSeschrock return (dgettext(TEXT_DOMAIN, "out of memory")); 7999653d4eSeschrock case EZFS_BADPROP: 8099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid property value")); 8199653d4eSeschrock case EZFS_PROPREADONLY: 82f9af39baSGeorge Wilson return (dgettext(TEXT_DOMAIN, "read-only property")); 8399653d4eSeschrock case EZFS_PROPTYPE: 8499653d4eSeschrock return (dgettext(TEXT_DOMAIN, "property doesn't apply to " 8599653d4eSeschrock "datasets of this type")); 8699653d4eSeschrock case EZFS_PROPNONINHERIT: 8799653d4eSeschrock return (dgettext(TEXT_DOMAIN, "property cannot be inherited")); 8899653d4eSeschrock case EZFS_PROPSPACE: 8999653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid quota or reservation")); 9099653d4eSeschrock case EZFS_BADTYPE: 9199653d4eSeschrock return (dgettext(TEXT_DOMAIN, "operation not applicable to " 9299653d4eSeschrock "datasets of this type")); 9399653d4eSeschrock case EZFS_BUSY: 9499653d4eSeschrock return (dgettext(TEXT_DOMAIN, "pool or dataset is busy")); 9599653d4eSeschrock case EZFS_EXISTS: 9699653d4eSeschrock return (dgettext(TEXT_DOMAIN, "pool or dataset exists")); 9799653d4eSeschrock case EZFS_NOENT: 9899653d4eSeschrock return (dgettext(TEXT_DOMAIN, "no such pool or dataset")); 9999653d4eSeschrock case EZFS_BADSTREAM: 10099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid backup stream")); 10199653d4eSeschrock case EZFS_DSREADONLY: 102f9af39baSGeorge Wilson return (dgettext(TEXT_DOMAIN, "dataset is read-only")); 10399653d4eSeschrock case EZFS_VOLTOOBIG: 10499653d4eSeschrock return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for " 10599653d4eSeschrock "this system")); 10699653d4eSeschrock case EZFS_INVALIDNAME: 10799653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid name")); 10899653d4eSeschrock case EZFS_BADRESTORE: 10999653d4eSeschrock return (dgettext(TEXT_DOMAIN, "unable to restore to " 11099653d4eSeschrock "destination")); 11199653d4eSeschrock case EZFS_BADBACKUP: 11299653d4eSeschrock return (dgettext(TEXT_DOMAIN, "backup failed")); 11399653d4eSeschrock case EZFS_BADTARGET: 11499653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid target vdev")); 11599653d4eSeschrock case EZFS_NODEVICE: 11699653d4eSeschrock return (dgettext(TEXT_DOMAIN, "no such device in pool")); 11799653d4eSeschrock case EZFS_BADDEV: 11899653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid device")); 11999653d4eSeschrock case EZFS_NOREPLICAS: 12099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "no valid replicas")); 12199653d4eSeschrock case EZFS_RESILVERING: 12299653d4eSeschrock return (dgettext(TEXT_DOMAIN, "currently resilvering")); 12399653d4eSeschrock case EZFS_BADVERSION: 124ad135b5dSChristopher Siden return (dgettext(TEXT_DOMAIN, "unsupported version or " 125ad135b5dSChristopher Siden "feature")); 12699653d4eSeschrock case EZFS_POOLUNAVAIL: 12799653d4eSeschrock return (dgettext(TEXT_DOMAIN, "pool is unavailable")); 12899653d4eSeschrock case EZFS_DEVOVERFLOW: 12999653d4eSeschrock return (dgettext(TEXT_DOMAIN, "too many devices in one vdev")); 13099653d4eSeschrock case EZFS_BADPATH: 13199653d4eSeschrock return (dgettext(TEXT_DOMAIN, "must be an absolute path")); 13299653d4eSeschrock case EZFS_CROSSTARGET: 13399653d4eSeschrock return (dgettext(TEXT_DOMAIN, "operation crosses datasets or " 13499653d4eSeschrock "pools")); 13599653d4eSeschrock case EZFS_ZONED: 13699653d4eSeschrock return (dgettext(TEXT_DOMAIN, "dataset in use by local zone")); 13799653d4eSeschrock case EZFS_MOUNTFAILED: 13899653d4eSeschrock return (dgettext(TEXT_DOMAIN, "mount failed")); 13999653d4eSeschrock case EZFS_UMOUNTFAILED: 14099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "umount failed")); 141f3861e1aSahl case EZFS_UNSHARENFSFAILED: 14299653d4eSeschrock return (dgettext(TEXT_DOMAIN, "unshare(1M) failed")); 143f3861e1aSahl case EZFS_SHARENFSFAILED: 14499653d4eSeschrock return (dgettext(TEXT_DOMAIN, "share(1M) failed")); 145da6c28aaSamw case EZFS_UNSHARESMBFAILED: 146da6c28aaSamw return (dgettext(TEXT_DOMAIN, "smb remove share failed")); 147da6c28aaSamw case EZFS_SHARESMBFAILED: 148da6c28aaSamw return (dgettext(TEXT_DOMAIN, "smb add share failed")); 14999653d4eSeschrock case EZFS_PERM: 15099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "permission denied")); 15199653d4eSeschrock case EZFS_NOSPC: 15299653d4eSeschrock return (dgettext(TEXT_DOMAIN, "out of space")); 1536e27f868SSam Falkner case EZFS_FAULT: 1546e27f868SSam Falkner return (dgettext(TEXT_DOMAIN, "bad address")); 15599653d4eSeschrock case EZFS_IO: 15699653d4eSeschrock return (dgettext(TEXT_DOMAIN, "I/O error")); 15799653d4eSeschrock case EZFS_INTR: 15899653d4eSeschrock return (dgettext(TEXT_DOMAIN, "signal received")); 15999653d4eSeschrock case EZFS_ISSPARE: 16099653d4eSeschrock return (dgettext(TEXT_DOMAIN, "device is reserved as a hot " 16199653d4eSeschrock "spare")); 16299653d4eSeschrock case EZFS_INVALCONFIG: 16399653d4eSeschrock return (dgettext(TEXT_DOMAIN, "invalid vdev configuration")); 1643bb79becSeschrock case EZFS_RECURSIVE: 1653bb79becSeschrock return (dgettext(TEXT_DOMAIN, "recursive dataset dependency")); 16606eeb2adSek case EZFS_NOHISTORY: 16706eeb2adSek return (dgettext(TEXT_DOMAIN, "no history available")); 168b1b8ab34Slling case EZFS_POOLPROPS: 169b1b8ab34Slling return (dgettext(TEXT_DOMAIN, "failed to retrieve " 170b1b8ab34Slling "pool properties")); 171b1b8ab34Slling case EZFS_POOL_NOTSUP: 172b1b8ab34Slling return (dgettext(TEXT_DOMAIN, "operation not supported " 173b1b8ab34Slling "on this type of pool")); 174b1b8ab34Slling case EZFS_POOL_INVALARG: 175b1b8ab34Slling return (dgettext(TEXT_DOMAIN, "invalid argument for " 176b1b8ab34Slling "this pool operation")); 177b7661cccSmmusante case EZFS_NAMETOOLONG: 178b7661cccSmmusante return (dgettext(TEXT_DOMAIN, "dataset name is too long")); 1798488aeb5Staylor case EZFS_OPENFAILED: 1808488aeb5Staylor return (dgettext(TEXT_DOMAIN, "open failed")); 1818488aeb5Staylor case EZFS_NOCAP: 1828488aeb5Staylor return (dgettext(TEXT_DOMAIN, 1838488aeb5Staylor "disk capacity information could not be retrieved")); 1848488aeb5Staylor case EZFS_LABELFAILED: 1858488aeb5Staylor return (dgettext(TEXT_DOMAIN, "write of label failed")); 186ecd6cf80Smarks case EZFS_BADWHO: 187ecd6cf80Smarks return (dgettext(TEXT_DOMAIN, "invalid user/group")); 188ecd6cf80Smarks case EZFS_BADPERM: 189ecd6cf80Smarks return (dgettext(TEXT_DOMAIN, "invalid permission")); 190ecd6cf80Smarks case EZFS_BADPERMSET: 191ecd6cf80Smarks return (dgettext(TEXT_DOMAIN, "invalid permission set name")); 192ecd6cf80Smarks case EZFS_NODELEGATION: 193ecd6cf80Smarks return (dgettext(TEXT_DOMAIN, "delegated administration is " 194ecd6cf80Smarks "disabled on pool")); 1952f8aaab3Seschrock case EZFS_BADCACHE: 1962f8aaab3Seschrock return (dgettext(TEXT_DOMAIN, "invalid or missing cache file")); 197fa94a07fSbrendan case EZFS_ISL2CACHE: 198fa94a07fSbrendan return (dgettext(TEXT_DOMAIN, "device is in use as a cache")); 199e7cbe64fSgw case EZFS_VDEVNOTSUP: 200e7cbe64fSgw return (dgettext(TEXT_DOMAIN, "vdev specification is not " 201e7cbe64fSgw "supported")); 20215e6edf1Sgw case EZFS_NOTSUP: 20315e6edf1Sgw return (dgettext(TEXT_DOMAIN, "operation not supported " 20415e6edf1Sgw "on this dataset")); 205*7ac89354SDon Brady case EZFS_IOC_NOTSUPPORTED: 206*7ac89354SDon Brady return (dgettext(TEXT_DOMAIN, "operation not supported by " 207*7ac89354SDon Brady "zfs kernel module")); 20889a89ebfSlling case EZFS_ACTIVE_SPARE: 20989a89ebfSlling return (dgettext(TEXT_DOMAIN, "pool has active shared spare " 21089a89ebfSlling "device")); 211e6ca193dSGeorge Wilson case EZFS_UNPLAYED_LOGS: 212e6ca193dSGeorge Wilson return (dgettext(TEXT_DOMAIN, "log device has unplayed intent " 213e6ca193dSGeorge Wilson "logs")); 214842727c2SChris Kirby case EZFS_REFTAG_RELE: 215842727c2SChris Kirby return (dgettext(TEXT_DOMAIN, "no such tag on this dataset")); 216842727c2SChris Kirby case EZFS_REFTAG_HOLD: 217842727c2SChris Kirby return (dgettext(TEXT_DOMAIN, "tag already exists on this " 218842727c2SChris Kirby "dataset")); 219ca45db41SChris Kirby case EZFS_TAGTOOLONG: 220ca45db41SChris Kirby return (dgettext(TEXT_DOMAIN, "tag too long")); 2219e69d7d0SLori Alt case EZFS_PIPEFAILED: 2229e69d7d0SLori Alt return (dgettext(TEXT_DOMAIN, "pipe create failed")); 2239e69d7d0SLori Alt case EZFS_THREADCREATEFAILED: 2249e69d7d0SLori Alt return (dgettext(TEXT_DOMAIN, "thread create failed")); 2251195e687SMark J Musante case EZFS_POSTSPLIT_ONLINE: 2261195e687SMark J Musante return (dgettext(TEXT_DOMAIN, "disk was split from this pool " 2271195e687SMark J Musante "into a new one")); 2281702cce7SAlek Pinchuk case EZFS_SCRUB_PAUSED: 2291702cce7SAlek Pinchuk return (dgettext(TEXT_DOMAIN, "scrub is paused; " 2301702cce7SAlek Pinchuk "use 'zpool scrub' to resume")); 2313f9d6ad7SLin Ling case EZFS_SCRUBBING: 2323f9d6ad7SLin Ling return (dgettext(TEXT_DOMAIN, "currently scrubbing; " 2333f9d6ad7SLin Ling "use 'zpool scrub -s' to cancel current scrub")); 2343f9d6ad7SLin Ling case EZFS_NO_SCRUB: 2353f9d6ad7SLin Ling return (dgettext(TEXT_DOMAIN, "there is no active scrub")); 23699d5e173STim Haley case EZFS_DIFF: 23799d5e173STim Haley return (dgettext(TEXT_DOMAIN, "unable to generate diffs")); 23899d5e173STim Haley case EZFS_DIFFDATA: 23999d5e173STim Haley return (dgettext(TEXT_DOMAIN, "invalid diff data")); 240f9af39baSGeorge Wilson case EZFS_POOLREADONLY: 241f9af39baSGeorge Wilson return (dgettext(TEXT_DOMAIN, "pool is read-only")); 2425cabbc6bSPrashanth Sreenivasa case EZFS_NO_PENDING: 2435cabbc6bSPrashanth Sreenivasa return (dgettext(TEXT_DOMAIN, "operation is not " 2445cabbc6bSPrashanth Sreenivasa "in progress")); 24586714001SSerapheim Dimitropoulos case EZFS_CHECKPOINT_EXISTS: 24686714001SSerapheim Dimitropoulos return (dgettext(TEXT_DOMAIN, "checkpoint exists")); 24786714001SSerapheim Dimitropoulos case EZFS_DISCARDING_CHECKPOINT: 24886714001SSerapheim Dimitropoulos return (dgettext(TEXT_DOMAIN, "currently discarding " 24986714001SSerapheim Dimitropoulos "checkpoint")); 25086714001SSerapheim Dimitropoulos case EZFS_NO_CHECKPOINT: 25186714001SSerapheim Dimitropoulos return (dgettext(TEXT_DOMAIN, "checkpoint does not exist")); 25286714001SSerapheim Dimitropoulos case EZFS_DEVRM_IN_PROGRESS: 25386714001SSerapheim Dimitropoulos return (dgettext(TEXT_DOMAIN, "device removal in progress")); 25486714001SSerapheim Dimitropoulos case EZFS_VDEV_TOO_BIG: 25586714001SSerapheim Dimitropoulos return (dgettext(TEXT_DOMAIN, "device exceeds supported size")); 256e0f1c0afSOlaf Faaland case EZFS_ACTIVE_POOL: 257e0f1c0afSOlaf Faaland return (dgettext(TEXT_DOMAIN, "pool is imported on a " 258e0f1c0afSOlaf Faaland "different host")); 259084fd14fSBrian Behlendorf case EZFS_CRYPTOFAILED: 260084fd14fSBrian Behlendorf return (dgettext(TEXT_DOMAIN, "encryption failure")); 261094e47e9SGeorge Wilson case EZFS_TOOMANY: 262094e47e9SGeorge Wilson return (dgettext(TEXT_DOMAIN, "argument list too long")); 263094e47e9SGeorge Wilson case EZFS_INITIALIZING: 264094e47e9SGeorge Wilson return (dgettext(TEXT_DOMAIN, "currently initializing")); 265094e47e9SGeorge Wilson case EZFS_NO_INITIALIZE: 266094e47e9SGeorge Wilson return (dgettext(TEXT_DOMAIN, "there is no active " 267094e47e9SGeorge Wilson "initialization")); 2686ccda740Sloli case EZFS_WRONG_PARENT: 2696ccda740Sloli return (dgettext(TEXT_DOMAIN, "invalid parent dataset")); 270084fd14fSBrian Behlendorf case EZFS_TRIMMING: 271084fd14fSBrian Behlendorf return (dgettext(TEXT_DOMAIN, "currently trimming")); 272084fd14fSBrian Behlendorf case EZFS_NO_TRIM: 273084fd14fSBrian Behlendorf return (dgettext(TEXT_DOMAIN, "there is no active trim")); 274084fd14fSBrian Behlendorf case EZFS_TRIM_NOTSUP: 275084fd14fSBrian Behlendorf return (dgettext(TEXT_DOMAIN, "trim operations are not " 276084fd14fSBrian Behlendorf "supported by this device")); 277e4c795beSTom Caputi case EZFS_NO_RESILVER_DEFER: 278e4c795beSTom Caputi return (dgettext(TEXT_DOMAIN, "this action requires the " 279e4c795beSTom Caputi "resilver_defer feature")); 28099653d4eSeschrock case EZFS_UNKNOWN: 28199653d4eSeschrock return (dgettext(TEXT_DOMAIN, "unknown error")); 28299653d4eSeschrock default: 283c08432ebSeschrock assert(hdl->libzfs_error == 0); 284c08432ebSeschrock return (dgettext(TEXT_DOMAIN, "no error")); 28599653d4eSeschrock } 28699653d4eSeschrock } 28799653d4eSeschrock 28899653d4eSeschrock /*PRINTFLIKE2*/ 289fa9e4066Sahrens void 29099653d4eSeschrock zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...) 291fa9e4066Sahrens { 292fa9e4066Sahrens va_list ap; 293fa9e4066Sahrens 294fa9e4066Sahrens va_start(ap, fmt); 295fa9e4066Sahrens 29699653d4eSeschrock (void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc), 29799653d4eSeschrock fmt, ap); 29899653d4eSeschrock hdl->libzfs_desc_active = 1; 29999653d4eSeschrock 30099653d4eSeschrock va_end(ap); 30199653d4eSeschrock } 30299653d4eSeschrock 30399653d4eSeschrock static void 30499653d4eSeschrock zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap) 30599653d4eSeschrock { 30699653d4eSeschrock (void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action), 30799653d4eSeschrock fmt, ap); 30899653d4eSeschrock hdl->libzfs_error = error; 30999653d4eSeschrock 31099653d4eSeschrock if (hdl->libzfs_desc_active) 31199653d4eSeschrock hdl->libzfs_desc_active = 0; 31299653d4eSeschrock else 31399653d4eSeschrock hdl->libzfs_desc[0] = '\0'; 31499653d4eSeschrock 31599653d4eSeschrock if (hdl->libzfs_printerr) { 31699653d4eSeschrock if (error == EZFS_UNKNOWN) { 31799653d4eSeschrock (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal " 31899653d4eSeschrock "error: %s\n"), libzfs_error_description(hdl)); 31999653d4eSeschrock abort(); 32099653d4eSeschrock } 32199653d4eSeschrock 32299653d4eSeschrock (void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action, 323b1b8ab34Slling libzfs_error_description(hdl)); 32499653d4eSeschrock if (error == EZFS_NOMEM) 32599653d4eSeschrock exit(1); 326fa9e4066Sahrens } 32799653d4eSeschrock } 32899653d4eSeschrock 329ece3d9b3Slling int 330ece3d9b3Slling zfs_error(libzfs_handle_t *hdl, int error, const char *msg) 331ece3d9b3Slling { 332ece3d9b3Slling return (zfs_error_fmt(hdl, error, "%s", msg)); 333ece3d9b3Slling } 334ece3d9b3Slling 33599653d4eSeschrock /*PRINTFLIKE3*/ 33699653d4eSeschrock int 337ece3d9b3Slling zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) 33899653d4eSeschrock { 33999653d4eSeschrock va_list ap; 34099653d4eSeschrock 34199653d4eSeschrock va_start(ap, fmt); 34299653d4eSeschrock 34399653d4eSeschrock zfs_verror(hdl, error, fmt, ap); 344fa9e4066Sahrens 345fa9e4066Sahrens va_end(ap); 34699653d4eSeschrock 34799653d4eSeschrock return (-1); 348fa9e4066Sahrens } 349fa9e4066Sahrens 35099653d4eSeschrock static int 35199653d4eSeschrock zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt, 35299653d4eSeschrock va_list ap) 35399653d4eSeschrock { 35499653d4eSeschrock switch (error) { 35599653d4eSeschrock case EPERM: 35699653d4eSeschrock case EACCES: 35799653d4eSeschrock zfs_verror(hdl, EZFS_PERM, fmt, ap); 35899653d4eSeschrock return (-1); 35999653d4eSeschrock 360ecd6cf80Smarks case ECANCELED: 361ecd6cf80Smarks zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap); 362ecd6cf80Smarks return (-1); 363ecd6cf80Smarks 36499653d4eSeschrock case EIO: 36599653d4eSeschrock zfs_verror(hdl, EZFS_IO, fmt, ap); 36699653d4eSeschrock return (-1); 36799653d4eSeschrock 3686e27f868SSam Falkner case EFAULT: 3696e27f868SSam Falkner zfs_verror(hdl, EZFS_FAULT, fmt, ap); 3706e27f868SSam Falkner return (-1); 3716e27f868SSam Falkner 37299653d4eSeschrock case EINTR: 37399653d4eSeschrock zfs_verror(hdl, EZFS_INTR, fmt, ap); 37499653d4eSeschrock return (-1); 37599653d4eSeschrock } 37699653d4eSeschrock 37799653d4eSeschrock return (0); 37899653d4eSeschrock } 37999653d4eSeschrock 380ece3d9b3Slling int 381ece3d9b3Slling zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg) 382ece3d9b3Slling { 383ece3d9b3Slling return (zfs_standard_error_fmt(hdl, error, "%s", msg)); 384ece3d9b3Slling } 385ece3d9b3Slling 38699653d4eSeschrock /*PRINTFLIKE3*/ 38799653d4eSeschrock int 388ece3d9b3Slling zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) 389fa9e4066Sahrens { 390fa9e4066Sahrens va_list ap; 391fa9e4066Sahrens 392fa9e4066Sahrens va_start(ap, fmt); 393fa9e4066Sahrens 39499653d4eSeschrock if (zfs_common_error(hdl, error, fmt, ap) != 0) { 39599653d4eSeschrock va_end(ap); 39699653d4eSeschrock return (-1); 397fa9e4066Sahrens } 398fa9e4066Sahrens 39999653d4eSeschrock switch (error) { 40099653d4eSeschrock case ENXIO: 40197d9e3a6Sck case ENODEV: 40219b94df9SMatthew Ahrens case EPIPE: 40399653d4eSeschrock zfs_verror(hdl, EZFS_IO, fmt, ap); 40499653d4eSeschrock break; 40599653d4eSeschrock 40699653d4eSeschrock case ENOENT: 40799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 40899653d4eSeschrock "dataset does not exist")); 40999653d4eSeschrock zfs_verror(hdl, EZFS_NOENT, fmt, ap); 41099653d4eSeschrock break; 41199653d4eSeschrock 41299653d4eSeschrock case ENOSPC: 41399653d4eSeschrock case EDQUOT: 41499653d4eSeschrock zfs_verror(hdl, EZFS_NOSPC, fmt, ap); 41599653d4eSeschrock return (-1); 41699653d4eSeschrock 41799653d4eSeschrock case EEXIST: 41899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 41999653d4eSeschrock "dataset already exists")); 42099653d4eSeschrock zfs_verror(hdl, EZFS_EXISTS, fmt, ap); 42199653d4eSeschrock break; 42299653d4eSeschrock 42399653d4eSeschrock case EBUSY: 42499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 42599653d4eSeschrock "dataset is busy")); 42699653d4eSeschrock zfs_verror(hdl, EZFS_BUSY, fmt, ap); 42799653d4eSeschrock break; 428ecd6cf80Smarks case EROFS: 429f9af39baSGeorge Wilson zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap); 430ecd6cf80Smarks break; 431b7661cccSmmusante case ENAMETOOLONG: 432b7661cccSmmusante zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap); 433b7661cccSmmusante break; 43440ff3960Sck case ENOTSUP: 43540ff3960Sck zfs_verror(hdl, EZFS_BADVERSION, fmt, ap); 43640ff3960Sck break; 43754d692b7SGeorge Wilson case EAGAIN: 43854d692b7SGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 43954d692b7SGeorge Wilson "pool I/O is currently suspended")); 44054d692b7SGeorge Wilson zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap); 44154d692b7SGeorge Wilson break; 442e0f1c0afSOlaf Faaland case EREMOTEIO: 443e0f1c0afSOlaf Faaland zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap); 444e0f1c0afSOlaf Faaland break; 445*7ac89354SDon Brady case ZFS_ERR_IOC_CMD_UNAVAIL: 446*7ac89354SDon Brady zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs " 447*7ac89354SDon Brady "module does not support this operation. A reboot may " 448*7ac89354SDon Brady "be required to enable this operation.")); 449*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 450*7ac89354SDon Brady break; 451*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_UNAVAIL: 452*7ac89354SDon Brady zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs " 453*7ac89354SDon Brady "module does not support an option for this operation. " 454*7ac89354SDon Brady "A reboot may be required to enable this option.")); 455*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 456*7ac89354SDon Brady break; 457*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_REQUIRED: 458*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_BADTYPE: 459*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 460*7ac89354SDon Brady break; 46199653d4eSeschrock default: 46292241e0bSTom Erickson zfs_error_aux(hdl, strerror(error)); 46399653d4eSeschrock zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap); 46499653d4eSeschrock break; 46599653d4eSeschrock } 46699653d4eSeschrock 46799653d4eSeschrock va_end(ap); 46899653d4eSeschrock return (-1); 469fa9e4066Sahrens } 470fa9e4066Sahrens 471ece3d9b3Slling int 472ece3d9b3Slling zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg) 473ece3d9b3Slling { 474ece3d9b3Slling return (zpool_standard_error_fmt(hdl, error, "%s", msg)); 475ece3d9b3Slling } 476ece3d9b3Slling 47799653d4eSeschrock /*PRINTFLIKE3*/ 47899653d4eSeschrock int 479ece3d9b3Slling zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) 480fa9e4066Sahrens { 48199653d4eSeschrock va_list ap; 48299653d4eSeschrock 48399653d4eSeschrock va_start(ap, fmt); 48499653d4eSeschrock 48599653d4eSeschrock if (zfs_common_error(hdl, error, fmt, ap) != 0) { 48699653d4eSeschrock va_end(ap); 48799653d4eSeschrock return (-1); 48899653d4eSeschrock } 48999653d4eSeschrock 49099653d4eSeschrock switch (error) { 49199653d4eSeschrock case ENODEV: 49299653d4eSeschrock zfs_verror(hdl, EZFS_NODEVICE, fmt, ap); 49399653d4eSeschrock break; 49499653d4eSeschrock 49599653d4eSeschrock case ENOENT: 496b1b8ab34Slling zfs_error_aux(hdl, 497b1b8ab34Slling dgettext(TEXT_DOMAIN, "no such pool or dataset")); 49899653d4eSeschrock zfs_verror(hdl, EZFS_NOENT, fmt, ap); 49999653d4eSeschrock break; 50099653d4eSeschrock 50199653d4eSeschrock case EEXIST: 50299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50399653d4eSeschrock "pool already exists")); 50499653d4eSeschrock zfs_verror(hdl, EZFS_EXISTS, fmt, ap); 50599653d4eSeschrock break; 50699653d4eSeschrock 50799653d4eSeschrock case EBUSY: 50899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy")); 50943afaaa8SEric Schrock zfs_verror(hdl, EZFS_BUSY, fmt, ap); 51099653d4eSeschrock break; 51199653d4eSeschrock 51299653d4eSeschrock case ENXIO: 51399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 51499653d4eSeschrock "one or more devices is currently unavailable")); 51599653d4eSeschrock zfs_verror(hdl, EZFS_BADDEV, fmt, ap); 51699653d4eSeschrock break; 51799653d4eSeschrock 51899653d4eSeschrock case ENAMETOOLONG: 51999653d4eSeschrock zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap); 52099653d4eSeschrock break; 52199653d4eSeschrock 522b1b8ab34Slling case ENOTSUP: 523b1b8ab34Slling zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap); 524b1b8ab34Slling break; 525b1b8ab34Slling 526b1b8ab34Slling case EINVAL: 527b1b8ab34Slling zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap); 528b1b8ab34Slling break; 529b1b8ab34Slling 530ecd6cf80Smarks case ENOSPC: 531ecd6cf80Smarks case EDQUOT: 532ecd6cf80Smarks zfs_verror(hdl, EZFS_NOSPC, fmt, ap); 533ecd6cf80Smarks return (-1); 534f9af39baSGeorge Wilson 53554d692b7SGeorge Wilson case EAGAIN: 53654d692b7SGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 53754d692b7SGeorge Wilson "pool I/O is currently suspended")); 53854d692b7SGeorge Wilson zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap); 53954d692b7SGeorge Wilson break; 540ecd6cf80Smarks 541f9af39baSGeorge Wilson case EROFS: 542f9af39baSGeorge Wilson zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap); 543f9af39baSGeorge Wilson break; 5445cabbc6bSPrashanth Sreenivasa /* There is no pending operation to cancel */ 5455cabbc6bSPrashanth Sreenivasa case ENOTACTIVE: 5465cabbc6bSPrashanth Sreenivasa zfs_verror(hdl, EZFS_NO_PENDING, fmt, ap); 5475cabbc6bSPrashanth Sreenivasa break; 548e0f1c0afSOlaf Faaland case EREMOTEIO: 549e0f1c0afSOlaf Faaland zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap); 550e0f1c0afSOlaf Faaland break; 55186714001SSerapheim Dimitropoulos case ZFS_ERR_CHECKPOINT_EXISTS: 55286714001SSerapheim Dimitropoulos zfs_verror(hdl, EZFS_CHECKPOINT_EXISTS, fmt, ap); 55386714001SSerapheim Dimitropoulos break; 55486714001SSerapheim Dimitropoulos case ZFS_ERR_DISCARDING_CHECKPOINT: 55586714001SSerapheim Dimitropoulos zfs_verror(hdl, EZFS_DISCARDING_CHECKPOINT, fmt, ap); 55686714001SSerapheim Dimitropoulos break; 55786714001SSerapheim Dimitropoulos case ZFS_ERR_NO_CHECKPOINT: 55886714001SSerapheim Dimitropoulos zfs_verror(hdl, EZFS_NO_CHECKPOINT, fmt, ap); 55986714001SSerapheim Dimitropoulos break; 56086714001SSerapheim Dimitropoulos case ZFS_ERR_DEVRM_IN_PROGRESS: 56186714001SSerapheim Dimitropoulos zfs_verror(hdl, EZFS_DEVRM_IN_PROGRESS, fmt, ap); 56286714001SSerapheim Dimitropoulos break; 56386714001SSerapheim Dimitropoulos case ZFS_ERR_VDEV_TOO_BIG: 56486714001SSerapheim Dimitropoulos zfs_verror(hdl, EZFS_VDEV_TOO_BIG, fmt, ap); 56586714001SSerapheim Dimitropoulos break; 566*7ac89354SDon Brady case ZFS_ERR_IOC_CMD_UNAVAIL: 567*7ac89354SDon Brady zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs " 568*7ac89354SDon Brady "module does not support this operation. A reboot may " 569*7ac89354SDon Brady "be required to enable this operation.")); 570*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 571*7ac89354SDon Brady break; 572*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_UNAVAIL: 573*7ac89354SDon Brady zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs " 574*7ac89354SDon Brady "module does not support an option for this operation. " 575*7ac89354SDon Brady "A reboot may be required to enable this option.")); 576*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 577*7ac89354SDon Brady break; 578*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_REQUIRED: 579*7ac89354SDon Brady case ZFS_ERR_IOC_ARG_BADTYPE: 580*7ac89354SDon Brady zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap); 581*7ac89354SDon Brady break; 58299653d4eSeschrock default: 58399653d4eSeschrock zfs_error_aux(hdl, strerror(error)); 58499653d4eSeschrock zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap); 58599653d4eSeschrock } 58699653d4eSeschrock 58799653d4eSeschrock va_end(ap); 58899653d4eSeschrock return (-1); 589fa9e4066Sahrens } 590fa9e4066Sahrens 591fa9e4066Sahrens /* 592fa9e4066Sahrens * Display an out of memory error message and abort the current program. 593fa9e4066Sahrens */ 59499653d4eSeschrock int 59599653d4eSeschrock no_memory(libzfs_handle_t *hdl) 596fa9e4066Sahrens { 59799653d4eSeschrock return (zfs_error(hdl, EZFS_NOMEM, "internal error")); 598fa9e4066Sahrens } 599fa9e4066Sahrens 600fa9e4066Sahrens /* 601fa9e4066Sahrens * A safe form of malloc() which will die if the allocation fails. 602fa9e4066Sahrens */ 603fa9e4066Sahrens void * 60499653d4eSeschrock zfs_alloc(libzfs_handle_t *hdl, size_t size) 605fa9e4066Sahrens { 606fa9e4066Sahrens void *data; 607fa9e4066Sahrens 608fa9e4066Sahrens if ((data = calloc(1, size)) == NULL) 60999653d4eSeschrock (void) no_memory(hdl); 610fa9e4066Sahrens 611fa9e4066Sahrens return (data); 612fa9e4066Sahrens } 613fa9e4066Sahrens 61499d5e173STim Haley /* 61599d5e173STim Haley * A safe form of asprintf() which will die if the allocation fails. 61699d5e173STim Haley */ 61799d5e173STim Haley /*PRINTFLIKE2*/ 61899d5e173STim Haley char * 61999d5e173STim Haley zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...) 62099d5e173STim Haley { 62199d5e173STim Haley va_list ap; 62299d5e173STim Haley char *ret; 62399d5e173STim Haley int err; 62499d5e173STim Haley 62599d5e173STim Haley va_start(ap, fmt); 62699d5e173STim Haley 62799d5e173STim Haley err = vasprintf(&ret, fmt, ap); 62899d5e173STim Haley 62999d5e173STim Haley va_end(ap); 63099d5e173STim Haley 63199d5e173STim Haley if (err < 0) 63299d5e173STim Haley (void) no_memory(hdl); 63399d5e173STim Haley 63499d5e173STim Haley return (ret); 63599d5e173STim Haley } 63699d5e173STim Haley 637e9dbad6fSeschrock /* 638e9dbad6fSeschrock * A safe form of realloc(), which also zeroes newly allocated space. 639e9dbad6fSeschrock */ 640e9dbad6fSeschrock void * 641e9dbad6fSeschrock zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize) 642e9dbad6fSeschrock { 643e9dbad6fSeschrock void *ret; 644e9dbad6fSeschrock 645e9dbad6fSeschrock if ((ret = realloc(ptr, newsize)) == NULL) { 646e9dbad6fSeschrock (void) no_memory(hdl); 647e9dbad6fSeschrock return (NULL); 648e9dbad6fSeschrock } 649e9dbad6fSeschrock 650e9dbad6fSeschrock bzero((char *)ret + oldsize, (newsize - oldsize)); 651e9dbad6fSeschrock return (ret); 652e9dbad6fSeschrock } 653e9dbad6fSeschrock 654fa9e4066Sahrens /* 655fa9e4066Sahrens * A safe form of strdup() which will die if the allocation fails. 656fa9e4066Sahrens */ 657fa9e4066Sahrens char * 65899653d4eSeschrock zfs_strdup(libzfs_handle_t *hdl, const char *str) 659fa9e4066Sahrens { 660fa9e4066Sahrens char *ret; 661fa9e4066Sahrens 662fa9e4066Sahrens if ((ret = strdup(str)) == NULL) 66399653d4eSeschrock (void) no_memory(hdl); 664fa9e4066Sahrens 665fa9e4066Sahrens return (ret); 666fa9e4066Sahrens } 667fa9e4066Sahrens 66899653d4eSeschrock void 66999653d4eSeschrock libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr) 67099653d4eSeschrock { 67199653d4eSeschrock hdl->libzfs_printerr = printerr; 67299653d4eSeschrock } 67399653d4eSeschrock 67499653d4eSeschrock libzfs_handle_t * 67599653d4eSeschrock libzfs_init(void) 67699653d4eSeschrock { 67799653d4eSeschrock libzfs_handle_t *hdl; 67899653d4eSeschrock 67999d5e173STim Haley if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) { 68099653d4eSeschrock return (NULL); 68199653d4eSeschrock } 68299653d4eSeschrock 6836c24238bSJason King if (regcomp(&hdl->libzfs_urire, URI_REGEX, REG_EXTENDED) != 0) { 6846c24238bSJason King free(hdl); 6856c24238bSJason King return (NULL); 6866c24238bSJason King } 6876c24238bSJason King 688c08432ebSeschrock if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) { 6896c24238bSJason King regfree(&hdl->libzfs_urire); 69099653d4eSeschrock free(hdl); 69199653d4eSeschrock return (NULL); 69299653d4eSeschrock } 69399653d4eSeschrock 694bde3d612SSimon Klinkert if ((hdl->libzfs_mnttab = fopen(MNTTAB, "rF")) == NULL) { 69599653d4eSeschrock (void) close(hdl->libzfs_fd); 6966c24238bSJason King regfree(&hdl->libzfs_urire); 69799653d4eSeschrock free(hdl); 69899653d4eSeschrock return (NULL); 69999653d4eSeschrock } 70099653d4eSeschrock 701bde3d612SSimon Klinkert hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "rF"); 70299653d4eSeschrock 7034445fffbSMatthew Ahrens if (libzfs_core_init() != 0) { 7044445fffbSMatthew Ahrens (void) close(hdl->libzfs_fd); 7054445fffbSMatthew Ahrens (void) fclose(hdl->libzfs_mnttab); 7064445fffbSMatthew Ahrens (void) fclose(hdl->libzfs_sharetab); 7076c24238bSJason King regfree(&hdl->libzfs_urire); 7084445fffbSMatthew Ahrens free(hdl); 7094445fffbSMatthew Ahrens return (NULL); 7104445fffbSMatthew Ahrens } 7114445fffbSMatthew Ahrens 71291ebeef5Sahrens zfs_prop_init(); 713990b4856Slling zpool_prop_init(); 714ad135b5dSChristopher Siden zpool_feature_init(); 715b2634b9cSEric Taylor libzfs_mnttab_init(hdl); 71691ebeef5Sahrens 717dfc11533SChris Williamson if (getenv("ZFS_PROP_DEBUG") != NULL) { 718dfc11533SChris Williamson hdl->libzfs_prop_debug = B_TRUE; 719dfc11533SChris Williamson } 720dfc11533SChris Williamson 72199653d4eSeschrock return (hdl); 72299653d4eSeschrock } 72399653d4eSeschrock 72499653d4eSeschrock void 72599653d4eSeschrock libzfs_fini(libzfs_handle_t *hdl) 72699653d4eSeschrock { 72799653d4eSeschrock (void) close(hdl->libzfs_fd); 728727feae5SJoshua M. Clulow if (hdl->libzfs_mnttab != NULL) 72999653d4eSeschrock (void) fclose(hdl->libzfs_mnttab); 730727feae5SJoshua M. Clulow if (hdl->libzfs_sharetab != NULL) 73199653d4eSeschrock (void) fclose(hdl->libzfs_sharetab); 732727feae5SJoshua M. Clulow if (hdl->libzfs_devlink != NULL) 733727feae5SJoshua M. Clulow (void) di_devlink_fini(&hdl->libzfs_devlink); 73467331909Sdougm zfs_uninit_libshare(hdl); 73529ab75c9Srm zpool_free_handles(hdl); 736069f55e2SEric Schrock libzfs_fru_clear(hdl, B_TRUE); 73799653d4eSeschrock namespace_clear(hdl); 738b2634b9cSEric Taylor libzfs_mnttab_fini(hdl); 7394445fffbSMatthew Ahrens libzfs_core_fini(); 7406c24238bSJason King regfree(&hdl->libzfs_urire); 74199653d4eSeschrock free(hdl); 74299653d4eSeschrock } 74399653d4eSeschrock 74499653d4eSeschrock libzfs_handle_t * 74599653d4eSeschrock zpool_get_handle(zpool_handle_t *zhp) 74699653d4eSeschrock { 74799653d4eSeschrock return (zhp->zpool_hdl); 74899653d4eSeschrock } 74999653d4eSeschrock 75099653d4eSeschrock libzfs_handle_t * 75199653d4eSeschrock zfs_get_handle(zfs_handle_t *zhp) 75299653d4eSeschrock { 75399653d4eSeschrock return (zhp->zfs_hdl); 75499653d4eSeschrock } 755e9dbad6fSeschrock 756d5b5bb25SRich Morris zpool_handle_t * 757d5b5bb25SRich Morris zfs_get_pool_handle(const zfs_handle_t *zhp) 758d5b5bb25SRich Morris { 759d5b5bb25SRich Morris return (zhp->zpool_hdl); 760d5b5bb25SRich Morris } 761d5b5bb25SRich Morris 7625aba80dbSck /* 7635aba80dbSck * Given a name, determine whether or not it's a valid path 7645aba80dbSck * (starts with '/' or "./"). If so, walk the mnttab trying 7655aba80dbSck * to match the device number. If not, treat the path as an 766edb901aaSMarcel Telka * fs/vol/snap/bkmark name. 7675aba80dbSck */ 7685aba80dbSck zfs_handle_t * 7695aba80dbSck zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype) 7705aba80dbSck { 7715aba80dbSck struct stat64 statbuf; 7725aba80dbSck struct extmnttab entry; 7735aba80dbSck int ret; 7745aba80dbSck 7755aba80dbSck if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) { 7765aba80dbSck /* 7775aba80dbSck * It's not a valid path, assume it's a name of type 'argtype'. 7785aba80dbSck */ 7795aba80dbSck return (zfs_open(hdl, path, argtype)); 7805aba80dbSck } 7815aba80dbSck 7825aba80dbSck if (stat64(path, &statbuf) != 0) { 7835aba80dbSck (void) fprintf(stderr, "%s: %s\n", path, strerror(errno)); 7845aba80dbSck return (NULL); 7855aba80dbSck } 7865aba80dbSck 7875aba80dbSck rewind(hdl->libzfs_mnttab); 7885aba80dbSck while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) { 7895aba80dbSck if (makedevice(entry.mnt_major, entry.mnt_minor) == 7905aba80dbSck statbuf.st_dev) { 7915aba80dbSck break; 7925aba80dbSck } 7935aba80dbSck } 7945aba80dbSck if (ret != 0) { 7955aba80dbSck return (NULL); 7965aba80dbSck } 7975aba80dbSck 7985aba80dbSck if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 7995aba80dbSck (void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"), 8005aba80dbSck path); 8015aba80dbSck return (NULL); 8025aba80dbSck } 8035aba80dbSck 8045aba80dbSck return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM)); 8055aba80dbSck } 8065aba80dbSck 807e9dbad6fSeschrock /* 808e9dbad6fSeschrock * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from 809e9dbad6fSeschrock * an ioctl(). 810e9dbad6fSeschrock */ 811e9dbad6fSeschrock int 812e9dbad6fSeschrock zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len) 813e9dbad6fSeschrock { 814e9dbad6fSeschrock if (len == 0) 8154b964adaSGeorge Wilson len = 16 * 1024; 816e9dbad6fSeschrock zc->zc_nvlist_dst_size = len; 81730925561SChris Williamson zc->zc_nvlist_dst = 81830925561SChris Williamson (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size); 81930925561SChris Williamson if (zc->zc_nvlist_dst == 0) 820e9dbad6fSeschrock return (-1); 821e9dbad6fSeschrock 822e9dbad6fSeschrock return (0); 823e9dbad6fSeschrock } 824e9dbad6fSeschrock 825e9dbad6fSeschrock /* 826e9dbad6fSeschrock * Called when an ioctl() which returns an nvlist fails with ENOMEM. This will 827e9dbad6fSeschrock * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was 828e9dbad6fSeschrock * filled in by the kernel to indicate the actual required size. 829e9dbad6fSeschrock */ 830e9dbad6fSeschrock int 831e9dbad6fSeschrock zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc) 832e9dbad6fSeschrock { 833e9dbad6fSeschrock free((void *)(uintptr_t)zc->zc_nvlist_dst); 83430925561SChris Williamson zc->zc_nvlist_dst = 83530925561SChris Williamson (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size); 83630925561SChris Williamson if (zc->zc_nvlist_dst == 0) 837e9dbad6fSeschrock return (-1); 838e9dbad6fSeschrock 839e9dbad6fSeschrock return (0); 840e9dbad6fSeschrock } 841e9dbad6fSeschrock 842e9dbad6fSeschrock /* 843a2eea2e1Sahrens * Called to free the src and dst nvlists stored in the command structure. 844e9dbad6fSeschrock */ 845e9dbad6fSeschrock void 846e9dbad6fSeschrock zcmd_free_nvlists(zfs_cmd_t *zc) 847e9dbad6fSeschrock { 848990b4856Slling free((void *)(uintptr_t)zc->zc_nvlist_conf); 849e9dbad6fSeschrock free((void *)(uintptr_t)zc->zc_nvlist_src); 850e9dbad6fSeschrock free((void *)(uintptr_t)zc->zc_nvlist_dst); 8515b8cbb8eSToomas Soome zc->zc_nvlist_conf = 0; 8525b8cbb8eSToomas Soome zc->zc_nvlist_src = 0; 8535b8cbb8eSToomas Soome zc->zc_nvlist_dst = 0; 854e9dbad6fSeschrock } 855e9dbad6fSeschrock 856990b4856Slling static int 857990b4856Slling zcmd_write_nvlist_com(libzfs_handle_t *hdl, uint64_t *outnv, uint64_t *outlen, 858990b4856Slling nvlist_t *nvl) 859e9dbad6fSeschrock { 860e9dbad6fSeschrock char *packed; 861e9dbad6fSeschrock size_t len; 862e9dbad6fSeschrock 863e9dbad6fSeschrock verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0); 864e9dbad6fSeschrock 865e9dbad6fSeschrock if ((packed = zfs_alloc(hdl, len)) == NULL) 866e9dbad6fSeschrock return (-1); 867e9dbad6fSeschrock 868e9dbad6fSeschrock verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0); 869e9dbad6fSeschrock 870990b4856Slling *outnv = (uint64_t)(uintptr_t)packed; 871990b4856Slling *outlen = len; 872e9dbad6fSeschrock 873e9dbad6fSeschrock return (0); 874e9dbad6fSeschrock } 875e9dbad6fSeschrock 876990b4856Slling int 877990b4856Slling zcmd_write_conf_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl) 878990b4856Slling { 879990b4856Slling return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_conf, 880990b4856Slling &zc->zc_nvlist_conf_size, nvl)); 881990b4856Slling } 882990b4856Slling 883990b4856Slling int 884990b4856Slling zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl) 885990b4856Slling { 886990b4856Slling return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_src, 887990b4856Slling &zc->zc_nvlist_src_size, nvl)); 888990b4856Slling } 889990b4856Slling 890e9dbad6fSeschrock /* 891e9dbad6fSeschrock * Unpacks an nvlist from the ZFS ioctl command structure. 892e9dbad6fSeschrock */ 893e9dbad6fSeschrock int 894e9dbad6fSeschrock zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp) 895e9dbad6fSeschrock { 896e9dbad6fSeschrock if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst, 897e9dbad6fSeschrock zc->zc_nvlist_dst_size, nvlp, 0) != 0) 898e9dbad6fSeschrock return (no_memory(hdl)); 899e9dbad6fSeschrock 900e9dbad6fSeschrock return (0); 901e9dbad6fSeschrock } 902b1b8ab34Slling 903990b4856Slling int 904990b4856Slling zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc) 905990b4856Slling { 9064445fffbSMatthew Ahrens return (ioctl(hdl->libzfs_fd, request, zc)); 907990b4856Slling } 908990b4856Slling 909990b4856Slling /* 910990b4856Slling * ================================================================ 911990b4856Slling * API shared by zfs and zpool property management 912990b4856Slling * ================================================================ 913990b4856Slling */ 914990b4856Slling 915b1b8ab34Slling static void 916990b4856Slling zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) 917b1b8ab34Slling { 918990b4856Slling zprop_list_t *pl = cbp->cb_proplist; 919b1b8ab34Slling int i; 920b1b8ab34Slling char *title; 921b1b8ab34Slling size_t len; 922b1b8ab34Slling 923b1b8ab34Slling cbp->cb_first = B_FALSE; 924b1b8ab34Slling if (cbp->cb_scripted) 925b1b8ab34Slling return; 926b1b8ab34Slling 927b1b8ab34Slling /* 928b1b8ab34Slling * Start with the length of the column headers. 929b1b8ab34Slling */ 930b1b8ab34Slling cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME")); 931b1b8ab34Slling cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN, 932b1b8ab34Slling "PROPERTY")); 933b1b8ab34Slling cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN, 934b1b8ab34Slling "VALUE")); 93592241e0bSTom Erickson cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN, 93692241e0bSTom Erickson "RECEIVED")); 937b1b8ab34Slling cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN, 938b1b8ab34Slling "SOURCE")); 939b1b8ab34Slling 940deb8317bSMark J Musante /* first property is always NAME */ 941deb8317bSMark J Musante assert(cbp->cb_proplist->pl_prop == 942deb8317bSMark J Musante ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : ZFS_PROP_NAME)); 943deb8317bSMark J Musante 944b1b8ab34Slling /* 945b1b8ab34Slling * Go through and calculate the widths for each column. For the 946b1b8ab34Slling * 'source' column, we kludge it up by taking the worst-case scenario of 947b1b8ab34Slling * inheriting from the longest name. This is acceptable because in the 948b1b8ab34Slling * majority of cases 'SOURCE' is the last column displayed, and we don't 949b1b8ab34Slling * use the width anyway. Note that the 'VALUE' column can be oversized, 95092241e0bSTom Erickson * if the name of the property is much longer than any values we find. 951b1b8ab34Slling */ 952b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 953b1b8ab34Slling /* 954b1b8ab34Slling * 'PROPERTY' column 955b1b8ab34Slling */ 956990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 957990b4856Slling const char *propname = (type == ZFS_TYPE_POOL) ? 958990b4856Slling zpool_prop_to_name(pl->pl_prop) : 959990b4856Slling zfs_prop_to_name(pl->pl_prop); 960990b4856Slling 961990b4856Slling len = strlen(propname); 962b1b8ab34Slling if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 963b1b8ab34Slling cbp->cb_colwidths[GET_COL_PROPERTY] = len; 964b1b8ab34Slling } else { 965b1b8ab34Slling len = strlen(pl->pl_user_prop); 966b1b8ab34Slling if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 967b1b8ab34Slling cbp->cb_colwidths[GET_COL_PROPERTY] = len; 968b1b8ab34Slling } 969b1b8ab34Slling 970b1b8ab34Slling /* 971deb8317bSMark J Musante * 'VALUE' column. The first property is always the 'name' 972deb8317bSMark J Musante * property that was tacked on either by /sbin/zfs's 973deb8317bSMark J Musante * zfs_do_get() or when calling zprop_expand_list(), so we 974deb8317bSMark J Musante * ignore its width. If the user specified the name property 975deb8317bSMark J Musante * to display, then it will be later in the list in any case. 976b1b8ab34Slling */ 977deb8317bSMark J Musante if (pl != cbp->cb_proplist && 978b1b8ab34Slling pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE]) 979b1b8ab34Slling cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width; 980b1b8ab34Slling 98192241e0bSTom Erickson /* 'RECEIVED' column. */ 98292241e0bSTom Erickson if (pl != cbp->cb_proplist && 98392241e0bSTom Erickson pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD]) 98492241e0bSTom Erickson cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width; 98592241e0bSTom Erickson 986b1b8ab34Slling /* 987b1b8ab34Slling * 'NAME' and 'SOURCE' columns 988b1b8ab34Slling */ 989990b4856Slling if (pl->pl_prop == (type == ZFS_TYPE_POOL ? ZPOOL_PROP_NAME : 990990b4856Slling ZFS_PROP_NAME) && 991b1b8ab34Slling pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) { 992b1b8ab34Slling cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width; 993b1b8ab34Slling cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width + 994b1b8ab34Slling strlen(dgettext(TEXT_DOMAIN, "inherited from")); 995b1b8ab34Slling } 996b1b8ab34Slling } 997b1b8ab34Slling 998b1b8ab34Slling /* 999b1b8ab34Slling * Now go through and print the headers. 1000b1b8ab34Slling */ 100192241e0bSTom Erickson for (i = 0; i < ZFS_GET_NCOLS; i++) { 1002b1b8ab34Slling switch (cbp->cb_columns[i]) { 1003b1b8ab34Slling case GET_COL_NAME: 1004b1b8ab34Slling title = dgettext(TEXT_DOMAIN, "NAME"); 1005b1b8ab34Slling break; 1006b1b8ab34Slling case GET_COL_PROPERTY: 1007b1b8ab34Slling title = dgettext(TEXT_DOMAIN, "PROPERTY"); 1008b1b8ab34Slling break; 1009b1b8ab34Slling case GET_COL_VALUE: 1010b1b8ab34Slling title = dgettext(TEXT_DOMAIN, "VALUE"); 1011b1b8ab34Slling break; 101292241e0bSTom Erickson case GET_COL_RECVD: 101392241e0bSTom Erickson title = dgettext(TEXT_DOMAIN, "RECEIVED"); 101492241e0bSTom Erickson break; 1015b1b8ab34Slling case GET_COL_SOURCE: 1016b1b8ab34Slling title = dgettext(TEXT_DOMAIN, "SOURCE"); 1017b1b8ab34Slling break; 1018b1b8ab34Slling default: 1019b1b8ab34Slling title = NULL; 1020b1b8ab34Slling } 1021b1b8ab34Slling 1022b1b8ab34Slling if (title != NULL) { 102392241e0bSTom Erickson if (i == (ZFS_GET_NCOLS - 1) || 102492241e0bSTom Erickson cbp->cb_columns[i + 1] == GET_COL_NONE) 1025b1b8ab34Slling (void) printf("%s", title); 1026b1b8ab34Slling else 1027b1b8ab34Slling (void) printf("%-*s ", 1028b1b8ab34Slling cbp->cb_colwidths[cbp->cb_columns[i]], 1029b1b8ab34Slling title); 1030b1b8ab34Slling } 1031b1b8ab34Slling } 1032b1b8ab34Slling (void) printf("\n"); 1033b1b8ab34Slling } 1034b1b8ab34Slling 1035b1b8ab34Slling /* 1036b1b8ab34Slling * Display a single line of output, according to the settings in the callback 1037b1b8ab34Slling * structure. 1038b1b8ab34Slling */ 1039b1b8ab34Slling void 1040990b4856Slling zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp, 1041990b4856Slling const char *propname, const char *value, zprop_source_t sourcetype, 104292241e0bSTom Erickson const char *source, const char *recvd_value) 1043b1b8ab34Slling { 1044b1b8ab34Slling int i; 1045f83b46baSPaul Dagnelie const char *str = NULL; 1046b1b8ab34Slling char buf[128]; 1047b1b8ab34Slling 1048b1b8ab34Slling /* 1049b1b8ab34Slling * Ignore those source types that the user has chosen to ignore. 1050b1b8ab34Slling */ 1051b1b8ab34Slling if ((sourcetype & cbp->cb_sources) == 0) 1052b1b8ab34Slling return; 1053b1b8ab34Slling 1054b1b8ab34Slling if (cbp->cb_first) 1055990b4856Slling zprop_print_headers(cbp, cbp->cb_type); 1056b1b8ab34Slling 105792241e0bSTom Erickson for (i = 0; i < ZFS_GET_NCOLS; i++) { 1058b1b8ab34Slling switch (cbp->cb_columns[i]) { 1059b1b8ab34Slling case GET_COL_NAME: 1060b1b8ab34Slling str = name; 1061b1b8ab34Slling break; 1062b1b8ab34Slling 1063b1b8ab34Slling case GET_COL_PROPERTY: 1064b1b8ab34Slling str = propname; 1065b1b8ab34Slling break; 1066b1b8ab34Slling 1067b1b8ab34Slling case GET_COL_VALUE: 1068b1b8ab34Slling str = value; 1069b1b8ab34Slling break; 1070b1b8ab34Slling 1071b1b8ab34Slling case GET_COL_SOURCE: 1072b1b8ab34Slling switch (sourcetype) { 1073990b4856Slling case ZPROP_SRC_NONE: 1074b1b8ab34Slling str = "-"; 1075b1b8ab34Slling break; 1076b1b8ab34Slling 1077990b4856Slling case ZPROP_SRC_DEFAULT: 1078b1b8ab34Slling str = "default"; 1079b1b8ab34Slling break; 1080b1b8ab34Slling 1081990b4856Slling case ZPROP_SRC_LOCAL: 1082b1b8ab34Slling str = "local"; 1083b1b8ab34Slling break; 1084b1b8ab34Slling 1085990b4856Slling case ZPROP_SRC_TEMPORARY: 1086b1b8ab34Slling str = "temporary"; 1087b1b8ab34Slling break; 1088b1b8ab34Slling 1089990b4856Slling case ZPROP_SRC_INHERITED: 1090b1b8ab34Slling (void) snprintf(buf, sizeof (buf), 1091b1b8ab34Slling "inherited from %s", source); 1092b1b8ab34Slling str = buf; 1093b1b8ab34Slling break; 109492241e0bSTom Erickson case ZPROP_SRC_RECEIVED: 109592241e0bSTom Erickson str = "received"; 109692241e0bSTom Erickson break; 109788f61deeSIgor Kozhukhov 109888f61deeSIgor Kozhukhov default: 109988f61deeSIgor Kozhukhov str = NULL; 110088f61deeSIgor Kozhukhov assert(!"unhandled zprop_source_t"); 1101b1b8ab34Slling } 1102b1b8ab34Slling break; 1103b1b8ab34Slling 110492241e0bSTom Erickson case GET_COL_RECVD: 110592241e0bSTom Erickson str = (recvd_value == NULL ? "-" : recvd_value); 110692241e0bSTom Erickson break; 110792241e0bSTom Erickson 1108b1b8ab34Slling default: 1109b1b8ab34Slling continue; 1110b1b8ab34Slling } 1111b1b8ab34Slling 111292241e0bSTom Erickson if (cbp->cb_columns[i + 1] == GET_COL_NONE) 1113b1b8ab34Slling (void) printf("%s", str); 1114b1b8ab34Slling else if (cbp->cb_scripted) 1115b1b8ab34Slling (void) printf("%s\t", str); 1116b1b8ab34Slling else 1117b1b8ab34Slling (void) printf("%-*s ", 1118b1b8ab34Slling cbp->cb_colwidths[cbp->cb_columns[i]], 1119b1b8ab34Slling str); 1120b1b8ab34Slling } 1121b1b8ab34Slling 1122b1b8ab34Slling (void) printf("\n"); 1123b1b8ab34Slling } 1124ecd6cf80Smarks 1125990b4856Slling /* 1126990b4856Slling * Given a numeric suffix, convert the value into a number of bits that the 1127990b4856Slling * resulting value must be shifted. 1128990b4856Slling */ 1129990b4856Slling static int 1130990b4856Slling str2shift(libzfs_handle_t *hdl, const char *buf) 1131990b4856Slling { 1132990b4856Slling const char *ends = "BKMGTPEZ"; 1133990b4856Slling int i; 1134990b4856Slling 1135990b4856Slling if (buf[0] == '\0') 1136990b4856Slling return (0); 1137990b4856Slling for (i = 0; i < strlen(ends); i++) { 1138990b4856Slling if (toupper(buf[0]) == ends[i]) 1139990b4856Slling break; 1140990b4856Slling } 1141990b4856Slling if (i == strlen(ends)) { 1142990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1143990b4856Slling "invalid numeric suffix '%s'"), buf); 1144990b4856Slling return (-1); 1145990b4856Slling } 1146990b4856Slling 1147990b4856Slling /* 1148990b4856Slling * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 1149990b4856Slling * allow 'BB' - that's just weird. 1150990b4856Slling */ 1151990b4856Slling if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 1152990b4856Slling toupper(buf[0]) != 'B')) 1153990b4856Slling return (10*i); 1154990b4856Slling 1155990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1156990b4856Slling "invalid numeric suffix '%s'"), buf); 1157990b4856Slling return (-1); 1158990b4856Slling } 1159990b4856Slling 1160990b4856Slling /* 1161990b4856Slling * Convert a string of the form '100G' into a real number. Used when setting 1162990b4856Slling * properties or creating a volume. 'buf' is used to place an extended error 1163990b4856Slling * message for the caller to use. 1164990b4856Slling */ 1165ecd6cf80Smarks int 1166990b4856Slling zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 1167ecd6cf80Smarks { 1168990b4856Slling char *end; 1169990b4856Slling int shift; 1170ecd6cf80Smarks 1171990b4856Slling *num = 0; 1172990b4856Slling 1173990b4856Slling /* Check to see if this looks like a number. */ 1174990b4856Slling if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 1175990b4856Slling if (hdl) 1176990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1177990b4856Slling "bad numeric value '%s'"), value); 1178990b4856Slling return (-1); 1179ecd6cf80Smarks } 1180ecd6cf80Smarks 1181069f55e2SEric Schrock /* Rely on strtoull() to process the numeric portion. */ 1182990b4856Slling errno = 0; 1183f67f35c3SEric Schrock *num = strtoull(value, &end, 10); 1184990b4856Slling 1185990b4856Slling /* 1186990b4856Slling * Check for ERANGE, which indicates that the value is too large to fit 1187990b4856Slling * in a 64-bit value. 1188990b4856Slling */ 1189990b4856Slling if (errno == ERANGE) { 1190990b4856Slling if (hdl) 1191990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1192990b4856Slling "numeric value is too large")); 1193990b4856Slling return (-1); 1194990b4856Slling } 1195990b4856Slling 1196990b4856Slling /* 1197990b4856Slling * If we have a decimal value, then do the computation with floating 1198990b4856Slling * point arithmetic. Otherwise, use standard arithmetic. 1199990b4856Slling */ 1200990b4856Slling if (*end == '.') { 1201990b4856Slling double fval = strtod(value, &end); 1202990b4856Slling 1203990b4856Slling if ((shift = str2shift(hdl, end)) == -1) 1204990b4856Slling return (-1); 1205990b4856Slling 1206990b4856Slling fval *= pow(2, shift); 1207990b4856Slling 1208990b4856Slling if (fval > UINT64_MAX) { 1209990b4856Slling if (hdl) 1210990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1211990b4856Slling "numeric value is too large")); 1212990b4856Slling return (-1); 1213990b4856Slling } 1214990b4856Slling 1215990b4856Slling *num = (uint64_t)fval; 1216990b4856Slling } else { 1217990b4856Slling if ((shift = str2shift(hdl, end)) == -1) 1218990b4856Slling return (-1); 1219990b4856Slling 1220990b4856Slling /* Check for overflow */ 1221990b4856Slling if (shift >= 64 || (*num << shift) >> shift != *num) { 1222990b4856Slling if (hdl) 1223990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1224990b4856Slling "numeric value is too large")); 1225990b4856Slling return (-1); 1226990b4856Slling } 1227990b4856Slling 1228990b4856Slling *num <<= shift; 1229990b4856Slling } 1230990b4856Slling 1231990b4856Slling return (0); 1232990b4856Slling } 1233990b4856Slling 1234990b4856Slling /* 1235990b4856Slling * Given a propname=value nvpair to set, parse any numeric properties 1236990b4856Slling * (index, boolean, etc) if they are specified as strings and add the 1237990b4856Slling * resulting nvpair to the returned nvlist. 1238990b4856Slling * 1239990b4856Slling * At the DSL layer, all properties are either 64-bit numbers or strings. 1240990b4856Slling * We want the user to be able to ignore this fact and specify properties 1241990b4856Slling * as native values (numbers, for example) or as strings (to simplify 1242990b4856Slling * command line utilities). This also handles converting index types 1243990b4856Slling * (compression, checksum, etc) from strings to their on-disk index. 1244990b4856Slling */ 1245990b4856Slling int 1246990b4856Slling zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop, 1247990b4856Slling zfs_type_t type, nvlist_t *ret, char **svalp, uint64_t *ivalp, 1248990b4856Slling const char *errbuf) 1249990b4856Slling { 1250990b4856Slling data_type_t datatype = nvpair_type(elem); 1251990b4856Slling zprop_type_t proptype; 1252990b4856Slling const char *propname; 1253990b4856Slling char *value; 1254990b4856Slling boolean_t isnone = B_FALSE; 12551c10ae76SMike Gerdts boolean_t isauto = B_FALSE; 1256990b4856Slling 1257990b4856Slling if (type == ZFS_TYPE_POOL) { 1258990b4856Slling proptype = zpool_prop_get_type(prop); 1259990b4856Slling propname = zpool_prop_to_name(prop); 1260990b4856Slling } else { 1261990b4856Slling proptype = zfs_prop_get_type(prop); 1262990b4856Slling propname = zfs_prop_to_name(prop); 1263990b4856Slling } 1264990b4856Slling 1265990b4856Slling /* 1266990b4856Slling * Convert any properties to the internal DSL value types. 1267990b4856Slling */ 1268990b4856Slling *svalp = NULL; 1269990b4856Slling *ivalp = 0; 1270990b4856Slling 1271990b4856Slling switch (proptype) { 1272990b4856Slling case PROP_TYPE_STRING: 1273990b4856Slling if (datatype != DATA_TYPE_STRING) { 1274990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1275990b4856Slling "'%s' must be a string"), nvpair_name(elem)); 1276990b4856Slling goto error; 1277990b4856Slling } 1278990b4856Slling (void) nvpair_value_string(elem, svalp); 1279990b4856Slling if (strlen(*svalp) >= ZFS_MAXPROPLEN) { 1280990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1281990b4856Slling "'%s' is too long"), nvpair_name(elem)); 1282990b4856Slling goto error; 1283990b4856Slling } 1284990b4856Slling break; 1285990b4856Slling 1286990b4856Slling case PROP_TYPE_NUMBER: 1287990b4856Slling if (datatype == DATA_TYPE_STRING) { 1288990b4856Slling (void) nvpair_value_string(elem, &value); 1289990b4856Slling if (strcmp(value, "none") == 0) { 1290990b4856Slling isnone = B_TRUE; 12911c10ae76SMike Gerdts } else if (strcmp(value, "auto") == 0) { 12921c10ae76SMike Gerdts isauto = B_TRUE; 12931c10ae76SMike Gerdts } else if (zfs_nicestrtonum(hdl, value, ivalp) != 0) { 1294990b4856Slling goto error; 1295990b4856Slling } 1296990b4856Slling } else if (datatype == DATA_TYPE_UINT64) { 1297990b4856Slling (void) nvpair_value_uint64(elem, ivalp); 1298990b4856Slling } else { 1299990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1300990b4856Slling "'%s' must be a number"), nvpair_name(elem)); 1301990b4856Slling goto error; 1302990b4856Slling } 1303990b4856Slling 1304990b4856Slling /* 1305990b4856Slling * Quota special: force 'none' and don't allow 0. 1306990b4856Slling */ 1307a9799022Sck if ((type & ZFS_TYPE_DATASET) && *ivalp == 0 && !isnone && 1308a9799022Sck (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_REFQUOTA)) { 1309990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1310a9799022Sck "use 'none' to disable quota/refquota")); 1311990b4856Slling goto error; 1312990b4856Slling } 1313a2afb611SJerry Jelinek 1314a2afb611SJerry Jelinek /* 1315a2afb611SJerry Jelinek * Special handling for "*_limit=none". In this case it's not 1316a2afb611SJerry Jelinek * 0 but UINT64_MAX. 1317a2afb611SJerry Jelinek */ 1318a2afb611SJerry Jelinek if ((type & ZFS_TYPE_DATASET) && isnone && 1319a2afb611SJerry Jelinek (prop == ZFS_PROP_FILESYSTEM_LIMIT || 1320a2afb611SJerry Jelinek prop == ZFS_PROP_SNAPSHOT_LIMIT)) { 1321a2afb611SJerry Jelinek *ivalp = UINT64_MAX; 1322a2afb611SJerry Jelinek } 13231c10ae76SMike Gerdts 13241c10ae76SMike Gerdts /* 13251c10ae76SMike Gerdts * Special handling for setting 'refreservation' to 'auto'. Use 13261c10ae76SMike Gerdts * UINT64_MAX to tell the caller to use zfs_fix_auto_resv(). 13271c10ae76SMike Gerdts * 'auto' is only allowed on volumes. 13281c10ae76SMike Gerdts */ 13291c10ae76SMike Gerdts if (isauto) { 13301c10ae76SMike Gerdts switch (prop) { 13311c10ae76SMike Gerdts case ZFS_PROP_REFRESERVATION: 13321c10ae76SMike Gerdts if ((type & ZFS_TYPE_VOLUME) == 0) { 13331c10ae76SMike Gerdts zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13341c10ae76SMike Gerdts "'%s=auto' only allowed on " 13351c10ae76SMike Gerdts "volumes"), nvpair_name(elem)); 13361c10ae76SMike Gerdts goto error; 13371c10ae76SMike Gerdts } 13381c10ae76SMike Gerdts *ivalp = UINT64_MAX; 13391c10ae76SMike Gerdts break; 13401c10ae76SMike Gerdts default: 13411c10ae76SMike Gerdts zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13421c10ae76SMike Gerdts "'auto' is invalid value for '%s'"), 13431c10ae76SMike Gerdts nvpair_name(elem)); 13441c10ae76SMike Gerdts goto error; 13451c10ae76SMike Gerdts } 13461c10ae76SMike Gerdts } 13471c10ae76SMike Gerdts 1348990b4856Slling break; 1349990b4856Slling 1350990b4856Slling case PROP_TYPE_INDEX: 1351a9799022Sck if (datatype != DATA_TYPE_STRING) { 1352990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1353990b4856Slling "'%s' must be a string"), nvpair_name(elem)); 1354990b4856Slling goto error; 1355990b4856Slling } 1356990b4856Slling 1357a9799022Sck (void) nvpair_value_string(elem, &value); 1358a9799022Sck 1359990b4856Slling if (zprop_string_to_index(prop, value, ivalp, type) != 0) { 1360990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1361990b4856Slling "'%s' must be one of '%s'"), propname, 1362990b4856Slling zprop_values(prop, type)); 1363990b4856Slling goto error; 1364990b4856Slling } 1365990b4856Slling break; 1366990b4856Slling 1367990b4856Slling default: 1368990b4856Slling abort(); 1369990b4856Slling } 1370990b4856Slling 1371990b4856Slling /* 1372990b4856Slling * Add the result to our return set of properties. 1373990b4856Slling */ 1374990b4856Slling if (*svalp != NULL) { 1375990b4856Slling if (nvlist_add_string(ret, propname, *svalp) != 0) { 1376990b4856Slling (void) no_memory(hdl); 1377990b4856Slling return (-1); 1378990b4856Slling } 1379990b4856Slling } else { 1380990b4856Slling if (nvlist_add_uint64(ret, propname, *ivalp) != 0) { 1381990b4856Slling (void) no_memory(hdl); 1382990b4856Slling return (-1); 1383990b4856Slling } 1384990b4856Slling } 1385990b4856Slling 1386990b4856Slling return (0); 1387990b4856Slling error: 1388990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 1389990b4856Slling return (-1); 1390990b4856Slling } 1391990b4856Slling 139274e7dc98SMatthew Ahrens static int 139374e7dc98SMatthew Ahrens addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, 139474e7dc98SMatthew Ahrens zfs_type_t type) 139574e7dc98SMatthew Ahrens { 139674e7dc98SMatthew Ahrens int prop; 139774e7dc98SMatthew Ahrens zprop_list_t *entry; 139874e7dc98SMatthew Ahrens 139974e7dc98SMatthew Ahrens prop = zprop_name_to_prop(propname, type); 140074e7dc98SMatthew Ahrens 140174e7dc98SMatthew Ahrens if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type)) 140274e7dc98SMatthew Ahrens prop = ZPROP_INVAL; 140374e7dc98SMatthew Ahrens 140474e7dc98SMatthew Ahrens /* 140574e7dc98SMatthew Ahrens * When no property table entry can be found, return failure if 140674e7dc98SMatthew Ahrens * this is a pool property or if this isn't a user-defined 140774e7dc98SMatthew Ahrens * dataset property, 140874e7dc98SMatthew Ahrens */ 1409ad135b5dSChristopher Siden if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL && 1410ad135b5dSChristopher Siden !zpool_prop_feature(propname) && 1411ad135b5dSChristopher Siden !zpool_prop_unsupported(propname)) || 1412ad135b5dSChristopher Siden (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) && 1413ad135b5dSChristopher Siden !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) { 141474e7dc98SMatthew Ahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 141574e7dc98SMatthew Ahrens "invalid property '%s'"), propname); 141674e7dc98SMatthew Ahrens return (zfs_error(hdl, EZFS_BADPROP, 141774e7dc98SMatthew Ahrens dgettext(TEXT_DOMAIN, "bad property list"))); 141874e7dc98SMatthew Ahrens } 141974e7dc98SMatthew Ahrens 142074e7dc98SMatthew Ahrens if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL) 142174e7dc98SMatthew Ahrens return (-1); 142274e7dc98SMatthew Ahrens 142374e7dc98SMatthew Ahrens entry->pl_prop = prop; 142474e7dc98SMatthew Ahrens if (prop == ZPROP_INVAL) { 1425ad135b5dSChristopher Siden if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) == 1426ad135b5dSChristopher Siden NULL) { 142774e7dc98SMatthew Ahrens free(entry); 142874e7dc98SMatthew Ahrens return (-1); 142974e7dc98SMatthew Ahrens } 143074e7dc98SMatthew Ahrens entry->pl_width = strlen(propname); 143174e7dc98SMatthew Ahrens } else { 143274e7dc98SMatthew Ahrens entry->pl_width = zprop_width(prop, &entry->pl_fixed, 143374e7dc98SMatthew Ahrens type); 143474e7dc98SMatthew Ahrens } 143574e7dc98SMatthew Ahrens 143674e7dc98SMatthew Ahrens *listp = entry; 143774e7dc98SMatthew Ahrens 143874e7dc98SMatthew Ahrens return (0); 143974e7dc98SMatthew Ahrens } 144074e7dc98SMatthew Ahrens 1441990b4856Slling /* 1442990b4856Slling * Given a comma-separated list of properties, construct a property list 1443990b4856Slling * containing both user-defined and native properties. This function will 1444990b4856Slling * return a NULL list if 'all' is specified, which can later be expanded 1445990b4856Slling * by zprop_expand_list(). 1446990b4856Slling */ 1447990b4856Slling int 1448990b4856Slling zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp, 1449990b4856Slling zfs_type_t type) 1450990b4856Slling { 1451990b4856Slling *listp = NULL; 1452990b4856Slling 1453990b4856Slling /* 1454990b4856Slling * If 'all' is specified, return a NULL list. 1455990b4856Slling */ 1456990b4856Slling if (strcmp(props, "all") == 0) 1457990b4856Slling return (0); 1458990b4856Slling 1459990b4856Slling /* 1460990b4856Slling * If no props were specified, return an error. 1461990b4856Slling */ 1462990b4856Slling if (props[0] == '\0') { 1463990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1464990b4856Slling "no properties specified")); 1465990b4856Slling return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 1466990b4856Slling "bad property list"))); 1467990b4856Slling } 1468990b4856Slling 1469990b4856Slling /* 1470990b4856Slling * It would be nice to use getsubopt() here, but the inclusion of column 1471990b4856Slling * aliases makes this more effort than it's worth. 1472990b4856Slling */ 147374e7dc98SMatthew Ahrens while (*props != '\0') { 147474e7dc98SMatthew Ahrens size_t len; 147574e7dc98SMatthew Ahrens char *p; 147674e7dc98SMatthew Ahrens char c; 147774e7dc98SMatthew Ahrens 147874e7dc98SMatthew Ahrens if ((p = strchr(props, ',')) == NULL) { 147974e7dc98SMatthew Ahrens len = strlen(props); 148074e7dc98SMatthew Ahrens p = props + len; 1481990b4856Slling } else { 148274e7dc98SMatthew Ahrens len = p - props; 1483990b4856Slling } 1484990b4856Slling 1485990b4856Slling /* 1486990b4856Slling * Check for empty options. 1487990b4856Slling */ 1488990b4856Slling if (len == 0) { 1489990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1490990b4856Slling "empty property name")); 1491990b4856Slling return (zfs_error(hdl, EZFS_BADPROP, 1492990b4856Slling dgettext(TEXT_DOMAIN, "bad property list"))); 1493990b4856Slling } 1494990b4856Slling 1495990b4856Slling /* 1496990b4856Slling * Check all regular property names. 1497990b4856Slling */ 149874e7dc98SMatthew Ahrens c = props[len]; 149974e7dc98SMatthew Ahrens props[len] = '\0'; 150074e7dc98SMatthew Ahrens 150174e7dc98SMatthew Ahrens if (strcmp(props, "space") == 0) { 150274e7dc98SMatthew Ahrens static char *spaceprops[] = { 150374e7dc98SMatthew Ahrens "name", "avail", "used", "usedbysnapshots", 150474e7dc98SMatthew Ahrens "usedbydataset", "usedbyrefreservation", 150574e7dc98SMatthew Ahrens "usedbychildren", NULL 150674e7dc98SMatthew Ahrens }; 150774e7dc98SMatthew Ahrens int i; 150874e7dc98SMatthew Ahrens 150974e7dc98SMatthew Ahrens for (i = 0; spaceprops[i]; i++) { 151074e7dc98SMatthew Ahrens if (addlist(hdl, spaceprops[i], listp, type)) 151174e7dc98SMatthew Ahrens return (-1); 151274e7dc98SMatthew Ahrens listp = &(*listp)->pl_next; 1513990b4856Slling } 1514990b4856Slling } else { 151574e7dc98SMatthew Ahrens if (addlist(hdl, props, listp, type)) 151674e7dc98SMatthew Ahrens return (-1); 151774e7dc98SMatthew Ahrens listp = &(*listp)->pl_next; 1518990b4856Slling } 1519990b4856Slling 152074e7dc98SMatthew Ahrens props = p; 1521990b4856Slling if (c == ',') 152274e7dc98SMatthew Ahrens props++; 1523990b4856Slling } 1524990b4856Slling 1525990b4856Slling return (0); 1526990b4856Slling } 1527990b4856Slling 1528990b4856Slling void 1529990b4856Slling zprop_free_list(zprop_list_t *pl) 1530990b4856Slling { 1531990b4856Slling zprop_list_t *next; 1532990b4856Slling 1533990b4856Slling while (pl != NULL) { 1534990b4856Slling next = pl->pl_next; 1535990b4856Slling free(pl->pl_user_prop); 1536990b4856Slling free(pl); 1537990b4856Slling pl = next; 1538990b4856Slling } 1539990b4856Slling } 1540990b4856Slling 1541990b4856Slling typedef struct expand_data { 1542990b4856Slling zprop_list_t **last; 1543990b4856Slling libzfs_handle_t *hdl; 1544990b4856Slling zfs_type_t type; 1545990b4856Slling } expand_data_t; 1546990b4856Slling 1547990b4856Slling int 1548990b4856Slling zprop_expand_list_cb(int prop, void *cb) 1549990b4856Slling { 1550990b4856Slling zprop_list_t *entry; 1551990b4856Slling expand_data_t *edp = cb; 1552990b4856Slling 1553990b4856Slling if ((entry = zfs_alloc(edp->hdl, sizeof (zprop_list_t))) == NULL) 1554990b4856Slling return (ZPROP_INVAL); 1555990b4856Slling 1556990b4856Slling entry->pl_prop = prop; 1557990b4856Slling entry->pl_width = zprop_width(prop, &entry->pl_fixed, edp->type); 1558990b4856Slling entry->pl_all = B_TRUE; 1559990b4856Slling 1560990b4856Slling *(edp->last) = entry; 1561990b4856Slling edp->last = &entry->pl_next; 1562990b4856Slling 1563990b4856Slling return (ZPROP_CONT); 1564990b4856Slling } 1565990b4856Slling 1566990b4856Slling int 1567990b4856Slling zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type) 1568990b4856Slling { 1569990b4856Slling zprop_list_t *entry; 1570990b4856Slling zprop_list_t **last; 1571990b4856Slling expand_data_t exp; 1572990b4856Slling 1573990b4856Slling if (*plp == NULL) { 1574990b4856Slling /* 1575990b4856Slling * If this is the very first time we've been called for an 'all' 1576990b4856Slling * specification, expand the list to include all native 1577990b4856Slling * properties. 1578990b4856Slling */ 1579990b4856Slling last = plp; 1580990b4856Slling 1581990b4856Slling exp.last = last; 1582990b4856Slling exp.hdl = hdl; 1583990b4856Slling exp.type = type; 1584990b4856Slling 1585990b4856Slling if (zprop_iter_common(zprop_expand_list_cb, &exp, B_FALSE, 1586990b4856Slling B_FALSE, type) == ZPROP_INVAL) 1587990b4856Slling return (-1); 1588990b4856Slling 1589990b4856Slling /* 1590990b4856Slling * Add 'name' to the beginning of the list, which is handled 1591990b4856Slling * specially. 1592990b4856Slling */ 1593990b4856Slling if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL) 1594990b4856Slling return (-1); 1595990b4856Slling 1596990b4856Slling entry->pl_prop = (type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : 1597990b4856Slling ZFS_PROP_NAME; 1598990b4856Slling entry->pl_width = zprop_width(entry->pl_prop, 1599990b4856Slling &entry->pl_fixed, type); 1600990b4856Slling entry->pl_all = B_TRUE; 1601990b4856Slling entry->pl_next = *plp; 1602990b4856Slling *plp = entry; 1603990b4856Slling } 1604990b4856Slling return (0); 1605990b4856Slling } 1606990b4856Slling 1607990b4856Slling int 1608990b4856Slling zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered, 1609990b4856Slling zfs_type_t type) 1610990b4856Slling { 1611990b4856Slling return (zprop_iter_common(func, cb, show_all, ordered, type)); 1612ecd6cf80Smarks } 16132bcf0248SMax Grossman 16142bcf0248SMax Grossman /* 16152bcf0248SMax Grossman * zfs_get_hole_count retrieves the number of holes (blocks which are 16162bcf0248SMax Grossman * zero-filled) in the specified file using the _FIO_COUNT_FILLED ioctl. It 16172bcf0248SMax Grossman * also optionally fetches the block size when bs is non-NULL. With hole count 16182bcf0248SMax Grossman * and block size the full space consumed by the holes of a file can be 16192bcf0248SMax Grossman * calculated. 16202bcf0248SMax Grossman * 16212bcf0248SMax Grossman * On success, zero is returned, the count argument is set to the 16222bcf0248SMax Grossman * number of holes, and the bs argument is set to the block size (if it is 16232bcf0248SMax Grossman * not NULL). On error, a non-zero errno is returned and the values in count 16242bcf0248SMax Grossman * and bs are undefined. 16252bcf0248SMax Grossman */ 16262bcf0248SMax Grossman int 16279a686fbcSPaul Dagnelie zfs_get_hole_count(const char *path, uint64_t *count, uint64_t *bs) 16289a686fbcSPaul Dagnelie { 16292bcf0248SMax Grossman int fd, err; 16302bcf0248SMax Grossman struct stat64 ss; 16312bcf0248SMax Grossman uint64_t fill; 16322bcf0248SMax Grossman 16332bcf0248SMax Grossman fd = open(path, O_RDONLY | O_LARGEFILE); 16342bcf0248SMax Grossman if (fd == -1) 16352bcf0248SMax Grossman return (errno); 16362bcf0248SMax Grossman 16372bcf0248SMax Grossman if (ioctl(fd, _FIO_COUNT_FILLED, &fill) == -1) { 16382bcf0248SMax Grossman err = errno; 16392bcf0248SMax Grossman (void) close(fd); 16402bcf0248SMax Grossman return (err); 16412bcf0248SMax Grossman } 16422bcf0248SMax Grossman 16432bcf0248SMax Grossman if (fstat64(fd, &ss) == -1) { 16442bcf0248SMax Grossman err = errno; 16452bcf0248SMax Grossman (void) close(fd); 16462bcf0248SMax Grossman return (err); 16472bcf0248SMax Grossman } 16482bcf0248SMax Grossman 16492bcf0248SMax Grossman *count = (ss.st_size + ss.st_blksize - 1) / ss.st_blksize - fill; 16502bcf0248SMax Grossman VERIFY3S(*count, >=, 0); 16512bcf0248SMax Grossman if (bs != NULL) { 16522bcf0248SMax Grossman *bs = ss.st_blksize; 16532bcf0248SMax Grossman } 16542bcf0248SMax Grossman 16552bcf0248SMax Grossman if (close(fd) == -1) { 16562bcf0248SMax Grossman return (errno); 16572bcf0248SMax Grossman } 16582bcf0248SMax Grossman return (0); 16592bcf0248SMax Grossman } 1660