Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_util.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright 2020 Joyent, Inc. All rights reserved.25* Copyright (c) 2011, 2024 by Delphix. All rights reserved.26* Copyright 2016 Igor Kozhukhov <[email protected]>27* Copyright (c) 2017 Datto Inc.28* Copyright (c) 2020 The FreeBSD Foundation29*30* Portions of this software were developed by Allan Jude31* under sponsorship from the FreeBSD Foundation.32*/3334/*35* Internal utility routines for the ZFS library.36*/3738#include <errno.h>39#include <fcntl.h>40#include <libintl.h>41#include <stdarg.h>42#include <stdio.h>43#include <stdlib.h>44#include <strings.h>45#include <unistd.h>46#include <math.h>47#if LIBFETCH_DYNAMIC48#include <dlfcn.h>49#endif50#include <sys/stat.h>51#include <sys/mnttab.h>52#include <sys/mntent.h>53#include <sys/types.h>54#include <sys/wait.h>5556#include <libzfs.h>57#include <libzfs_core.h>5859#include "libzfs_impl.h"60#include "zfs_prop.h"61#include "zfeature_common.h"62#include <zfs_fletcher.h>63#include <libzutil.h>6465/*66* We only care about the scheme in order to match the scheme67* with the handler. Each handler should validate the full URI68* as necessary.69*/70#define URI_REGEX "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):"71#define STR_NUMS "0123456789"7273int74libzfs_errno(libzfs_handle_t *hdl)75{76return (hdl->libzfs_error);77}7879const char *80libzfs_error_action(libzfs_handle_t *hdl)81{82return (hdl->libzfs_action);83}8485const char *86libzfs_error_description(libzfs_handle_t *hdl)87{88if (hdl->libzfs_desc[0] != '\0')89return (hdl->libzfs_desc);9091switch (hdl->libzfs_error) {92case EZFS_NOMEM:93return (dgettext(TEXT_DOMAIN, "out of memory"));94case EZFS_BADPROP:95return (dgettext(TEXT_DOMAIN, "invalid property value"));96case EZFS_PROPREADONLY:97return (dgettext(TEXT_DOMAIN, "read-only property"));98case EZFS_PROPTYPE:99return (dgettext(TEXT_DOMAIN, "property doesn't apply to "100"datasets of this type"));101case EZFS_PROPNONINHERIT:102return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));103case EZFS_PROPSPACE:104return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));105case EZFS_BADTYPE:106return (dgettext(TEXT_DOMAIN, "operation not applicable to "107"datasets of this type"));108case EZFS_BUSY:109return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));110case EZFS_EXISTS:111return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));112case EZFS_NOENT:113return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));114case EZFS_BADSTREAM:115return (dgettext(TEXT_DOMAIN, "invalid backup stream"));116case EZFS_DSREADONLY:117return (dgettext(TEXT_DOMAIN, "dataset is read-only"));118case EZFS_VOLTOOBIG:119return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "120"this system"));121case EZFS_INVALIDNAME:122return (dgettext(TEXT_DOMAIN, "invalid name"));123case EZFS_BADRESTORE:124return (dgettext(TEXT_DOMAIN, "unable to restore to "125"destination"));126case EZFS_BADBACKUP:127return (dgettext(TEXT_DOMAIN, "backup failed"));128case EZFS_BADTARGET:129return (dgettext(TEXT_DOMAIN, "invalid target vdev"));130case EZFS_NODEVICE:131return (dgettext(TEXT_DOMAIN, "no such device in pool"));132case EZFS_BADDEV:133return (dgettext(TEXT_DOMAIN, "invalid device"));134case EZFS_NOREPLICAS:135return (dgettext(TEXT_DOMAIN, "no valid replicas"));136case EZFS_RESILVERING:137return (dgettext(TEXT_DOMAIN, "currently resilvering"));138case EZFS_BADVERSION:139return (dgettext(TEXT_DOMAIN, "unsupported version or "140"feature"));141case EZFS_POOLUNAVAIL:142return (dgettext(TEXT_DOMAIN, "pool is unavailable"));143case EZFS_DEVOVERFLOW:144return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));145case EZFS_BADPATH:146return (dgettext(TEXT_DOMAIN, "must be an absolute path"));147case EZFS_CROSSTARGET:148return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "149"pools"));150case EZFS_ZONED:151return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));152case EZFS_MOUNTFAILED:153return (dgettext(TEXT_DOMAIN, "mount failed"));154case EZFS_UMOUNTFAILED:155return (dgettext(TEXT_DOMAIN, "unmount failed"));156case EZFS_UNSHARENFSFAILED:157return (dgettext(TEXT_DOMAIN, "NFS share removal failed"));158case EZFS_SHARENFSFAILED:159return (dgettext(TEXT_DOMAIN, "NFS share creation failed"));160case EZFS_UNSHARESMBFAILED:161return (dgettext(TEXT_DOMAIN, "SMB share removal failed"));162case EZFS_SHARESMBFAILED:163return (dgettext(TEXT_DOMAIN, "SMB share creation failed"));164case EZFS_PERM:165return (dgettext(TEXT_DOMAIN, "permission denied"));166case EZFS_NOSPC:167return (dgettext(TEXT_DOMAIN, "out of space"));168case EZFS_FAULT:169return (dgettext(TEXT_DOMAIN, "bad address"));170case EZFS_IO:171return (dgettext(TEXT_DOMAIN, "I/O error"));172case EZFS_INTR:173return (dgettext(TEXT_DOMAIN, "signal received"));174case EZFS_CKSUM:175return (dgettext(TEXT_DOMAIN, "insufficient replicas"));176case EZFS_ISSPARE:177return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "178"spare"));179case EZFS_INVALCONFIG:180return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));181case EZFS_RECURSIVE:182return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));183case EZFS_NOHISTORY:184return (dgettext(TEXT_DOMAIN, "no history available"));185case EZFS_POOLPROPS:186return (dgettext(TEXT_DOMAIN, "failed to retrieve "187"pool properties"));188case EZFS_POOL_NOTSUP:189return (dgettext(TEXT_DOMAIN, "operation not supported "190"on this type of pool"));191case EZFS_POOL_INVALARG:192return (dgettext(TEXT_DOMAIN, "invalid argument for "193"this pool operation"));194case EZFS_NAMETOOLONG:195return (dgettext(TEXT_DOMAIN, "dataset name is too long"));196case EZFS_OPENFAILED:197return (dgettext(TEXT_DOMAIN, "open failed"));198case EZFS_NOCAP:199return (dgettext(TEXT_DOMAIN,200"disk capacity information could not be retrieved"));201case EZFS_LABELFAILED:202return (dgettext(TEXT_DOMAIN, "write of label failed"));203case EZFS_BADWHO:204return (dgettext(TEXT_DOMAIN, "invalid user/group"));205case EZFS_BADPERM:206return (dgettext(TEXT_DOMAIN, "invalid permission"));207case EZFS_BADPERMSET:208return (dgettext(TEXT_DOMAIN, "invalid permission set name"));209case EZFS_NODELEGATION:210return (dgettext(TEXT_DOMAIN, "delegated administration is "211"disabled on pool"));212case EZFS_BADCACHE:213return (dgettext(TEXT_DOMAIN, "invalid or missing cache file"));214case EZFS_ISL2CACHE:215return (dgettext(TEXT_DOMAIN, "device is in use as a cache"));216case EZFS_VDEVNOTSUP:217return (dgettext(TEXT_DOMAIN, "vdev specification is not "218"supported"));219case EZFS_NOTSUP:220return (dgettext(TEXT_DOMAIN, "operation not supported "221"on this dataset"));222case EZFS_IOC_NOTSUPPORTED:223return (dgettext(TEXT_DOMAIN, "operation not supported by "224"zfs kernel module"));225case EZFS_ACTIVE_SPARE:226return (dgettext(TEXT_DOMAIN, "pool has active shared spare "227"device"));228case EZFS_UNPLAYED_LOGS:229return (dgettext(TEXT_DOMAIN, "log device has unplayed intent "230"logs"));231case EZFS_REFTAG_RELE:232return (dgettext(TEXT_DOMAIN, "no such tag on this dataset"));233case EZFS_REFTAG_HOLD:234return (dgettext(TEXT_DOMAIN, "tag already exists on this "235"dataset"));236case EZFS_TAGTOOLONG:237return (dgettext(TEXT_DOMAIN, "tag too long"));238case EZFS_PIPEFAILED:239return (dgettext(TEXT_DOMAIN, "pipe create failed"));240case EZFS_THREADCREATEFAILED:241return (dgettext(TEXT_DOMAIN, "thread create failed"));242case EZFS_POSTSPLIT_ONLINE:243return (dgettext(TEXT_DOMAIN, "disk was split from this pool "244"into a new one"));245case EZFS_SCRUB_PAUSED:246return (dgettext(TEXT_DOMAIN, "scrub is paused; "247"use 'zpool scrub' to resume scrub"));248case EZFS_SCRUB_PAUSED_TO_CANCEL:249return (dgettext(TEXT_DOMAIN, "scrub is paused; "250"use 'zpool scrub' to resume or 'zpool scrub -s' to "251"cancel scrub"));252case EZFS_SCRUBBING:253return (dgettext(TEXT_DOMAIN, "currently scrubbing; "254"use 'zpool scrub -s' to cancel scrub"));255case EZFS_ERRORSCRUBBING:256return (dgettext(TEXT_DOMAIN, "currently error scrubbing; "257"use 'zpool scrub -s' to cancel error scrub"));258case EZFS_ERRORSCRUB_PAUSED:259return (dgettext(TEXT_DOMAIN, "error scrub is paused; "260"use 'zpool scrub -e' to resume error scrub"));261case EZFS_NO_SCRUB:262return (dgettext(TEXT_DOMAIN, "there is no active scrub"));263case EZFS_DIFF:264return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));265case EZFS_DIFFDATA:266return (dgettext(TEXT_DOMAIN, "invalid diff data"));267case EZFS_POOLREADONLY:268return (dgettext(TEXT_DOMAIN, "pool is read-only"));269case EZFS_NO_PENDING:270return (dgettext(TEXT_DOMAIN, "operation is not "271"in progress"));272case EZFS_CHECKPOINT_EXISTS:273return (dgettext(TEXT_DOMAIN, "checkpoint exists"));274case EZFS_DISCARDING_CHECKPOINT:275return (dgettext(TEXT_DOMAIN, "currently discarding "276"checkpoint"));277case EZFS_NO_CHECKPOINT:278return (dgettext(TEXT_DOMAIN, "checkpoint does not exist"));279case EZFS_DEVRM_IN_PROGRESS:280return (dgettext(TEXT_DOMAIN, "device removal in progress"));281case EZFS_VDEV_TOO_BIG:282return (dgettext(TEXT_DOMAIN, "device exceeds supported size"));283case EZFS_ACTIVE_POOL:284return (dgettext(TEXT_DOMAIN, "pool is imported on a "285"different host"));286case EZFS_CRYPTOFAILED:287return (dgettext(TEXT_DOMAIN, "encryption failure"));288case EZFS_TOOMANY:289return (dgettext(TEXT_DOMAIN, "argument list too long"));290case EZFS_INITIALIZING:291return (dgettext(TEXT_DOMAIN, "currently initializing"));292case EZFS_NO_INITIALIZE:293return (dgettext(TEXT_DOMAIN, "there is no active "294"initialization"));295case EZFS_WRONG_PARENT:296return (dgettext(TEXT_DOMAIN, "invalid parent dataset"));297case EZFS_TRIMMING:298return (dgettext(TEXT_DOMAIN, "currently trimming"));299case EZFS_NO_TRIM:300return (dgettext(TEXT_DOMAIN, "there is no active trim"));301case EZFS_TRIM_NOTSUP:302return (dgettext(TEXT_DOMAIN, "trim operations are not "303"supported by this device"));304case EZFS_NO_RESILVER_DEFER:305return (dgettext(TEXT_DOMAIN, "this action requires the "306"resilver_defer feature"));307case EZFS_EXPORT_IN_PROGRESS:308return (dgettext(TEXT_DOMAIN, "pool export in progress"));309case EZFS_REBUILDING:310return (dgettext(TEXT_DOMAIN, "currently sequentially "311"resilvering"));312case EZFS_VDEV_NOTSUP:313return (dgettext(TEXT_DOMAIN, "operation not supported "314"on this type of vdev"));315case EZFS_NOT_USER_NAMESPACE:316return (dgettext(TEXT_DOMAIN, "the provided file "317"was not a user namespace file"));318case EZFS_RESUME_EXISTS:319return (dgettext(TEXT_DOMAIN, "Resuming recv on existing "320"dataset without force"));321case EZFS_RAIDZ_EXPAND_IN_PROGRESS:322return (dgettext(TEXT_DOMAIN, "raidz expansion in progress"));323case EZFS_ASHIFT_MISMATCH:324return (dgettext(TEXT_DOMAIN, "adding devices with "325"different physical sector sizes is not allowed"));326case EZFS_UNKNOWN:327return (dgettext(TEXT_DOMAIN, "unknown error"));328default:329assert(hdl->libzfs_error == 0);330return (dgettext(TEXT_DOMAIN, "no error"));331}332}333334void335zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)336{337va_list ap;338339va_start(ap, fmt);340341(void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),342fmt, ap);343hdl->libzfs_desc_active = 1;344345va_end(ap);346}347348static void349zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)350{351(void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),352fmt, ap);353hdl->libzfs_error = error;354355if (hdl->libzfs_desc_active)356hdl->libzfs_desc_active = 0;357else358hdl->libzfs_desc[0] = '\0';359360if (hdl->libzfs_printerr) {361if (error == EZFS_UNKNOWN) {362(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "363"error: %s: %s\n"), hdl->libzfs_action,364libzfs_error_description(hdl));365abort();366}367368(void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,369libzfs_error_description(hdl));370if (error == EZFS_NOMEM)371exit(1);372}373}374375int376zfs_error(libzfs_handle_t *hdl, int error, const char *msg)377{378return (zfs_error_fmt(hdl, error, "%s", msg));379}380381int382zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)383{384va_list ap;385386va_start(ap, fmt);387388zfs_verror(hdl, error, fmt, ap);389390va_end(ap);391392return (-1);393}394395static int396zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,397va_list ap)398{399switch (error) {400case EPERM:401case EACCES:402zfs_verror(hdl, EZFS_PERM, fmt, ap);403return (-1);404405case ECANCELED:406zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap);407return (-1);408409case EIO:410zfs_verror(hdl, EZFS_IO, fmt, ap);411return (-1);412413case EFAULT:414zfs_verror(hdl, EZFS_FAULT, fmt, ap);415return (-1);416417case EINTR:418zfs_verror(hdl, EZFS_INTR, fmt, ap);419return (-1);420421case ECKSUM:422zfs_verror(hdl, EZFS_CKSUM, fmt, ap);423return (-1);424}425426return (0);427}428429int430zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)431{432return (zfs_standard_error_fmt(hdl, error, "%s", msg));433}434435int436zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)437{438va_list ap;439440va_start(ap, fmt);441442if (zfs_common_error(hdl, error, fmt, ap) != 0) {443va_end(ap);444return (-1);445}446447switch (error) {448case ENXIO:449case ENODEV:450case EPIPE:451zfs_verror(hdl, EZFS_IO, fmt, ap);452break;453454case ENOENT:455zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,456"dataset does not exist"));457zfs_verror(hdl, EZFS_NOENT, fmt, ap);458break;459460case ENOSPC:461case EDQUOT:462zfs_verror(hdl, EZFS_NOSPC, fmt, ap);463break;464465case EEXIST:466zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,467"dataset already exists"));468zfs_verror(hdl, EZFS_EXISTS, fmt, ap);469break;470471case EBUSY:472zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,473"dataset is busy"));474zfs_verror(hdl, EZFS_BUSY, fmt, ap);475break;476case EROFS:477zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);478break;479case ENAMETOOLONG:480zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);481break;482case ENOTSUP:483zfs_verror(hdl, EZFS_BADVERSION, fmt, ap);484break;485case EAGAIN:486zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,487"pool I/O is currently suspended"));488zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);489break;490case EREMOTEIO:491zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);492break;493case ZFS_ERR_UNKNOWN_SEND_STREAM_FEATURE:494case ZFS_ERR_IOC_CMD_UNAVAIL:495zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "496"module does not support this operation. A reboot may "497"be required to enable this operation."));498zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);499break;500case ZFS_ERR_IOC_ARG_UNAVAIL:501zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "502"module does not support an option for this operation. "503"A reboot may be required to enable this option."));504zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);505break;506case ZFS_ERR_IOC_ARG_REQUIRED:507case ZFS_ERR_IOC_ARG_BADTYPE:508zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);509break;510case ZFS_ERR_WRONG_PARENT:511zfs_verror(hdl, EZFS_WRONG_PARENT, fmt, ap);512break;513case ZFS_ERR_BADPROP:514zfs_verror(hdl, EZFS_BADPROP, fmt, ap);515break;516case ZFS_ERR_NOT_USER_NAMESPACE:517zfs_verror(hdl, EZFS_NOT_USER_NAMESPACE, fmt, ap);518break;519default:520zfs_error_aux(hdl, "%s", zfs_strerror(error));521zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);522break;523}524525va_end(ap);526return (-1);527}528529void530zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,531char *errbuf)532{533switch (err) {534535case ENOSPC:536/*537* For quotas and reservations, ENOSPC indicates538* something different; setting a quota or reservation539* doesn't use any disk space.540*/541switch (prop) {542case ZFS_PROP_QUOTA:543case ZFS_PROP_REFQUOTA:544zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,545"size is less than current used or "546"reserved space"));547(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);548break;549550case ZFS_PROP_RESERVATION:551case ZFS_PROP_REFRESERVATION:552zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,553"size is greater than available space"));554(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);555break;556557default:558(void) zfs_standard_error(hdl, err, errbuf);559break;560}561break;562563case EBUSY:564(void) zfs_standard_error(hdl, EBUSY, errbuf);565break;566567case EROFS:568(void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);569break;570571case E2BIG:572zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,573"property value too long"));574(void) zfs_error(hdl, EZFS_BADPROP, errbuf);575break;576577case ENOTSUP:578zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,579"pool and or dataset must be upgraded to set this "580"property or value"));581(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);582break;583584case ERANGE:585if (prop == ZFS_PROP_COMPRESSION ||586prop == ZFS_PROP_DNODESIZE ||587prop == ZFS_PROP_RECORDSIZE) {588(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,589"property setting is not allowed on "590"bootable datasets"));591(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);592} else if (prop == ZFS_PROP_CHECKSUM ||593prop == ZFS_PROP_DEDUP) {594(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,595"property setting is not allowed on "596"root pools"));597(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);598} else {599(void) zfs_standard_error(hdl, err, errbuf);600}601break;602603case EINVAL:604if (prop == ZPROP_INVAL) {605(void) zfs_error(hdl, EZFS_BADPROP, errbuf);606} else {607(void) zfs_standard_error(hdl, err, errbuf);608}609break;610611case ZFS_ERR_BADPROP:612(void) zfs_error(hdl, EZFS_BADPROP, errbuf);613break;614615case EACCES:616if (prop == ZFS_PROP_KEYLOCATION) {617zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,618"keylocation may only be set on encryption roots"));619(void) zfs_error(hdl, EZFS_BADPROP, errbuf);620} else {621(void) zfs_standard_error(hdl, err, errbuf);622}623break;624625case EOVERFLOW:626/*627* This platform can't address a volume this big.628*/629#ifdef _ILP32630if (prop == ZFS_PROP_VOLSIZE) {631(void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);632break;633}634zfs_fallthrough;635#endif636default:637(void) zfs_standard_error(hdl, err, errbuf);638}639}640641int642zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)643{644return (zpool_standard_error_fmt(hdl, error, "%s", msg));645}646647int648zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)649{650va_list ap;651652va_start(ap, fmt);653654if (zfs_common_error(hdl, error, fmt, ap) != 0) {655va_end(ap);656return (-1);657}658659switch (error) {660case ENODEV:661zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);662break;663664case ENOENT:665zfs_error_aux(hdl,666dgettext(TEXT_DOMAIN, "no such pool or dataset"));667zfs_verror(hdl, EZFS_NOENT, fmt, ap);668break;669670case EEXIST:671zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,672"pool already exists"));673zfs_verror(hdl, EZFS_EXISTS, fmt, ap);674break;675676case EBUSY:677zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));678zfs_verror(hdl, EZFS_BUSY, fmt, ap);679break;680681/* There is no pending operation to cancel */682case ENOTACTIVE:683zfs_verror(hdl, EZFS_NO_PENDING, fmt, ap);684break;685686case ENXIO:687zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,688"one or more devices is currently unavailable"));689zfs_verror(hdl, EZFS_BADDEV, fmt, ap);690break;691692case ENAMETOOLONG:693zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);694break;695696case ENOTSUP:697zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);698break;699700case EINVAL:701zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);702break;703704case ENOSPC:705case EDQUOT:706zfs_verror(hdl, EZFS_NOSPC, fmt, ap);707break;708709case EAGAIN:710zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,711"pool I/O is currently suspended"));712zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);713break;714715case EROFS:716zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);717break;718case EDOM:719zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,720"block size out of range or does not match"));721zfs_verror(hdl, EZFS_BADPROP, fmt, ap);722break;723case EREMOTEIO:724zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);725break;726case ZFS_ERR_CHECKPOINT_EXISTS:727zfs_verror(hdl, EZFS_CHECKPOINT_EXISTS, fmt, ap);728break;729case ZFS_ERR_DISCARDING_CHECKPOINT:730zfs_verror(hdl, EZFS_DISCARDING_CHECKPOINT, fmt, ap);731break;732case ZFS_ERR_NO_CHECKPOINT:733zfs_verror(hdl, EZFS_NO_CHECKPOINT, fmt, ap);734break;735case ZFS_ERR_DEVRM_IN_PROGRESS:736zfs_verror(hdl, EZFS_DEVRM_IN_PROGRESS, fmt, ap);737break;738case ZFS_ERR_VDEV_TOO_BIG:739zfs_verror(hdl, EZFS_VDEV_TOO_BIG, fmt, ap);740break;741case ZFS_ERR_EXPORT_IN_PROGRESS:742zfs_verror(hdl, EZFS_EXPORT_IN_PROGRESS, fmt, ap);743break;744case ZFS_ERR_RESILVER_IN_PROGRESS:745zfs_verror(hdl, EZFS_RESILVERING, fmt, ap);746break;747case ZFS_ERR_REBUILD_IN_PROGRESS:748zfs_verror(hdl, EZFS_REBUILDING, fmt, ap);749break;750case ZFS_ERR_BADPROP:751zfs_verror(hdl, EZFS_BADPROP, fmt, ap);752break;753case ZFS_ERR_VDEV_NOTSUP:754zfs_verror(hdl, EZFS_VDEV_NOTSUP, fmt, ap);755break;756case ZFS_ERR_IOC_CMD_UNAVAIL:757zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "758"module does not support this operation. A reboot may "759"be required to enable this operation."));760zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);761break;762case ZFS_ERR_IOC_ARG_UNAVAIL:763zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "764"module does not support an option for this operation. "765"A reboot may be required to enable this option."));766zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);767break;768case ZFS_ERR_IOC_ARG_REQUIRED:769case ZFS_ERR_IOC_ARG_BADTYPE:770zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);771break;772case ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS:773zfs_verror(hdl, EZFS_RAIDZ_EXPAND_IN_PROGRESS, fmt, ap);774break;775case ZFS_ERR_ASHIFT_MISMATCH:776zfs_verror(hdl, EZFS_ASHIFT_MISMATCH, fmt, ap);777break;778case ZFS_ERR_TOO_MANY_SITOUTS:779zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "too many disks "780"already sitting out"));781zfs_verror(hdl, EZFS_BUSY, fmt, ap);782break;783default:784zfs_error_aux(hdl, "%s", zfs_strerror(error));785zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);786}787788va_end(ap);789return (-1);790}791792int793zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)794{795return (lzc_ioctl_fd(hdl->libzfs_fd, request, zc));796}797798/*799* Display an out of memory error message and abort the current program.800*/801int802no_memory(libzfs_handle_t *hdl)803{804return (zfs_error(hdl, EZFS_NOMEM, "internal error"));805}806807/*808* A safe form of malloc() which will die if the allocation fails.809*/810void *811zfs_alloc(libzfs_handle_t *hdl, size_t size)812{813void *data;814815if ((data = calloc(1, size)) == NULL)816(void) no_memory(hdl);817818return (data);819}820821/*822* A safe form of asprintf() which will die if the allocation fails.823*/824char *825zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...)826{827va_list ap;828char *ret;829int err;830831va_start(ap, fmt);832833err = vasprintf(&ret, fmt, ap);834835va_end(ap);836837if (err < 0) {838(void) no_memory(hdl);839ret = NULL;840}841842return (ret);843}844845/*846* A safe form of realloc(), which also zeroes newly allocated space.847*/848void *849zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)850{851void *ret;852853if ((ret = realloc(ptr, newsize)) == NULL) {854(void) no_memory(hdl);855return (NULL);856}857858memset((char *)ret + oldsize, 0, newsize - oldsize);859return (ret);860}861862/*863* A safe form of strdup() which will die if the allocation fails.864*/865char *866zfs_strdup(libzfs_handle_t *hdl, const char *str)867{868char *ret;869870if ((ret = strdup(str)) == NULL)871(void) no_memory(hdl);872873return (ret);874}875876void877libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)878{879hdl->libzfs_printerr = printerr;880}881882/*883* Read lines from an open file descriptor and store them in an array of884* strings until EOF. lines[] will be allocated and populated with all the885* lines read. All newlines are replaced with NULL terminators for886* convenience. lines[] must be freed after use with libzfs_free_str_array().887*888* Returns the number of lines read.889*/890static int891libzfs_read_stdout_from_fd(int fd, char **lines[])892{893894FILE *fp;895int lines_cnt = 0;896size_t len = 0;897char *line = NULL;898char **tmp_lines = NULL, **tmp;899900fp = fdopen(fd, "r");901if (fp == NULL) {902close(fd);903return (0);904}905while (getline(&line, &len, fp) != -1) {906tmp = realloc(tmp_lines, sizeof (*tmp_lines) * (lines_cnt + 1));907if (tmp == NULL) {908/* Return the lines we were able to process */909break;910}911tmp_lines = tmp;912913/* Remove newline if not EOF */914if (line[strlen(line) - 1] == '\n')915line[strlen(line) - 1] = '\0';916917tmp_lines[lines_cnt] = strdup(line);918if (tmp_lines[lines_cnt] == NULL)919break;920++lines_cnt;921}922free(line);923fclose(fp);924*lines = tmp_lines;925return (lines_cnt);926}927928static int929libzfs_run_process_impl(const char *path, char *argv[], char *env[], int flags,930char **lines[], int *lines_cnt)931{932pid_t pid;933int error, devnull_fd;934int link[2];935936/*937* Setup a pipe between our child and parent process if we're938* reading stdout.939*/940if (lines != NULL && pipe2(link, O_NONBLOCK | O_CLOEXEC) == -1)941return (-EPIPE);942943pid = fork();944if (pid == 0) {945/* Child process */946setpgid(0, 0);947devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);948949if (devnull_fd < 0)950_exit(-1);951952if (!(flags & STDOUT_VERBOSE) && (lines == NULL))953(void) dup2(devnull_fd, STDOUT_FILENO);954else if (lines != NULL) {955/* Save the output to lines[] */956dup2(link[1], STDOUT_FILENO);957}958959if (!(flags & STDERR_VERBOSE))960(void) dup2(devnull_fd, STDERR_FILENO);961962if (flags & NO_DEFAULT_PATH) {963if (env == NULL)964execv(path, argv);965else966execve(path, argv, env);967} else {968if (env == NULL)969execvp(path, argv);970else971execvpe(path, argv, env);972}973974_exit(-1);975} else if (pid > 0) {976/* Parent process */977int status;978979while ((error = waitpid(pid, &status, 0)) == -1 &&980errno == EINTR)981;982if (error < 0 || !WIFEXITED(status))983return (-1);984985if (lines != NULL) {986close(link[1]);987*lines_cnt = libzfs_read_stdout_from_fd(link[0], lines);988}989return (WEXITSTATUS(status));990}991992return (-1);993}994995int996libzfs_run_process(const char *path, char *argv[], int flags)997{998return (libzfs_run_process_impl(path, argv, NULL, flags, NULL, NULL));999}10001001/*1002* Run a command and store its stdout lines in an array of strings (lines[]).1003* lines[] is allocated and populated for you, and the number of lines is set in1004* lines_cnt. lines[] must be freed after use with libzfs_free_str_array().1005* All newlines (\n) in lines[] are terminated for convenience.1006*/1007int1008libzfs_run_process_get_stdout(const char *path, char *argv[], char *env[],1009char **lines[], int *lines_cnt)1010{1011return (libzfs_run_process_impl(path, argv, env, 0, lines, lines_cnt));1012}10131014/*1015* Same as libzfs_run_process_get_stdout(), but run without $PATH set. This1016* means that *path needs to be the full path to the executable.1017*/1018int1019libzfs_run_process_get_stdout_nopath(const char *path, char *argv[],1020char *env[], char **lines[], int *lines_cnt)1021{1022return (libzfs_run_process_impl(path, argv, env, NO_DEFAULT_PATH,1023lines, lines_cnt));1024}10251026/*1027* Free an array of strings. Free both the strings contained in the array and1028* the array itself.1029*/1030void1031libzfs_free_str_array(char **strs, int count)1032{1033while (--count >= 0)1034free(strs[count]);10351036free(strs);1037}10381039/*1040* Returns 1 if environment variable is set to "YES", "yes", "ON", "on", or1041* a non-zero number.1042*1043* Returns 0 otherwise.1044*/1045boolean_t1046libzfs_envvar_is_set(const char *envvar)1047{1048char *env = getenv(envvar);1049return (env && (strtoul(env, NULL, 0) > 0 ||1050(!strncasecmp(env, "YES", 3) && strnlen(env, 4) == 3) ||1051(!strncasecmp(env, "ON", 2) && strnlen(env, 3) == 2)));1052}10531054libzfs_handle_t *1055libzfs_init(void)1056{1057libzfs_handle_t *hdl;1058int error;1059char *env;10601061if ((error = libzfs_load_module()) != 0) {1062errno = error;1063return (NULL);1064}10651066if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) {1067return (NULL);1068}10691070if (regcomp(&hdl->libzfs_urire, URI_REGEX, 0) != 0) {1071free(hdl);1072return (NULL);1073}10741075if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR|O_EXCL|O_CLOEXEC)) < 0) {1076free(hdl);1077return (NULL);1078}10791080if (libzfs_core_init() != 0) {1081(void) close(hdl->libzfs_fd);1082free(hdl);1083return (NULL);1084}10851086zfs_prop_init();1087zpool_prop_init();1088zpool_feature_init();1089vdev_prop_init();1090libzfs_mnttab_init(hdl);1091fletcher_4_init();10921093if (getenv("ZFS_PROP_DEBUG") != NULL) {1094hdl->libzfs_prop_debug = B_TRUE;1095}1096if ((env = getenv("ZFS_SENDRECV_MAX_NVLIST")) != NULL) {1097if ((error = zfs_nicestrtonum(hdl, env,1098&hdl->libzfs_max_nvlist))) {1099errno = error;1100(void) close(hdl->libzfs_fd);1101free(hdl);1102return (NULL);1103}1104} else {1105hdl->libzfs_max_nvlist = (SPA_MAXBLOCKSIZE * 4);1106}11071108/*1109* For testing, remove some settable properties and features1110*/1111if (libzfs_envvar_is_set("ZFS_SYSFS_PROP_SUPPORT_TEST")) {1112zprop_desc_t *proptbl;11131114proptbl = zpool_prop_get_table();1115proptbl[ZPOOL_PROP_COMMENT].pd_zfs_mod_supported = B_FALSE;11161117proptbl = zfs_prop_get_table();1118proptbl[ZFS_PROP_DNODESIZE].pd_zfs_mod_supported = B_FALSE;11191120zfeature_info_t *ftbl = spa_feature_table;1121ftbl[SPA_FEATURE_LARGE_BLOCKS].fi_zfs_mod_supported = B_FALSE;1122}11231124return (hdl);1125}11261127void1128libzfs_fini(libzfs_handle_t *hdl)1129{1130(void) close(hdl->libzfs_fd);1131zpool_free_handles(hdl);1132namespace_clear(hdl);1133libzfs_mnttab_fini(hdl);1134libzfs_core_fini();1135regfree(&hdl->libzfs_urire);1136fletcher_4_fini();1137#if LIBFETCH_DYNAMIC1138if (hdl->libfetch != (void *)-1 && hdl->libfetch != NULL)1139(void) dlclose(hdl->libfetch);1140free(hdl->libfetch_load_error);1141#endif1142free(hdl);1143}11441145libzfs_handle_t *1146zpool_get_handle(zpool_handle_t *zhp)1147{1148return (zhp->zpool_hdl);1149}11501151libzfs_handle_t *1152zfs_get_handle(zfs_handle_t *zhp)1153{1154return (zhp->zfs_hdl);1155}11561157zpool_handle_t *1158zfs_get_pool_handle(const zfs_handle_t *zhp)1159{1160return (zhp->zpool_hdl);1161}11621163/*1164* Given a name, determine whether or not it's a valid path1165* (starts with '/' or "./"). If so, walk the mnttab trying1166* to match the device number. If not, treat the path as an1167* fs/vol/snap/bkmark name.1168*/1169zfs_handle_t *1170zfs_path_to_zhandle(libzfs_handle_t *hdl, const char *path, zfs_type_t argtype)1171{1172struct stat64 statbuf;1173struct extmnttab entry;11741175if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {1176/*1177* It's not a valid path, assume it's a name of type 'argtype'.1178*/1179return (zfs_open(hdl, path, argtype));1180}11811182if (getextmntent(path, &entry, &statbuf) != 0)1183return (NULL);11841185if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {1186(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),1187path);1188return (NULL);1189}11901191return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));1192}11931194/*1195* Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from1196* an ioctl().1197*/1198void1199zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)1200{1201if (len == 0)1202len = 256 * 1024;1203zc->zc_nvlist_dst_size = len;1204zc->zc_nvlist_dst =1205(uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);1206}12071208/*1209* Called when an ioctl() which returns an nvlist fails with ENOMEM. This will1210* expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was1211* filled in by the kernel to indicate the actual required size.1212*/1213void1214zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)1215{1216free((void *)(uintptr_t)zc->zc_nvlist_dst);1217zc->zc_nvlist_dst =1218(uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);1219}12201221/*1222* Called to free the src and dst nvlists stored in the command structure.1223*/1224void1225zcmd_free_nvlists(zfs_cmd_t *zc)1226{1227free((void *)(uintptr_t)zc->zc_nvlist_conf);1228free((void *)(uintptr_t)zc->zc_nvlist_src);1229free((void *)(uintptr_t)zc->zc_nvlist_dst);1230zc->zc_nvlist_conf = 0;1231zc->zc_nvlist_src = 0;1232zc->zc_nvlist_dst = 0;1233}12341235static void1236zcmd_write_nvlist_com(libzfs_handle_t *hdl, uint64_t *outnv, uint64_t *outlen,1237nvlist_t *nvl)1238{1239char *packed;12401241size_t len = fnvlist_size(nvl);1242packed = zfs_alloc(hdl, len);12431244verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);12451246*outnv = (uint64_t)(uintptr_t)packed;1247*outlen = len;1248}12491250void1251zcmd_write_conf_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)1252{1253zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_conf,1254&zc->zc_nvlist_conf_size, nvl);1255}12561257void1258zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)1259{1260zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_src,1261&zc->zc_nvlist_src_size, nvl);1262}12631264/*1265* Unpacks an nvlist from the ZFS ioctl command structure.1266*/1267int1268zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)1269{1270if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,1271zc->zc_nvlist_dst_size, nvlp, 0) != 0)1272return (no_memory(hdl));12731274return (0);1275}12761277/*1278* ================================================================1279* API shared by zfs and zpool property management1280* ================================================================1281*/12821283void1284zcmd_print_json(nvlist_t *nvl)1285{1286nvlist_print_json(stdout, nvl);1287(void) putchar('\n');1288nvlist_free(nvl);1289}12901291static void1292zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)1293{1294zprop_list_t *pl;1295int i;1296char *title;1297size_t len;12981299cbp->cb_first = B_FALSE;1300if (cbp->cb_scripted)1301return;13021303/*1304* Start with the length of the column headers.1305*/1306cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));1307cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,1308"PROPERTY"));1309cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,1310"VALUE"));1311cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,1312"RECEIVED"));1313cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,1314"SOURCE"));13151316/* first property is always NAME */1317assert(cbp->cb_proplist->pl_prop ==1318((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :1319((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : ZFS_PROP_NAME)));13201321/*1322* Go through and calculate the widths for each column. For the1323* 'source' column, we kludge it up by taking the worst-case scenario of1324* inheriting from the longest name. This is acceptable because in the1325* majority of cases 'SOURCE' is the last column displayed, and we don't1326* use the width anyway. Note that the 'VALUE' column can be oversized,1327* if the name of the property is much longer than any values we find.1328*/1329for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {1330/*1331* 'PROPERTY' column1332*/1333if (pl->pl_prop != ZPROP_USERPROP) {1334const char *propname = (type == ZFS_TYPE_POOL) ?1335zpool_prop_to_name(pl->pl_prop) :1336((type == ZFS_TYPE_VDEV) ?1337vdev_prop_to_name(pl->pl_prop) :1338zfs_prop_to_name(pl->pl_prop));13391340assert(propname != NULL);1341len = strlen(propname);1342if (len > cbp->cb_colwidths[GET_COL_PROPERTY])1343cbp->cb_colwidths[GET_COL_PROPERTY] = len;1344} else {1345assert(pl->pl_user_prop != NULL);1346len = strlen(pl->pl_user_prop);1347if (len > cbp->cb_colwidths[GET_COL_PROPERTY])1348cbp->cb_colwidths[GET_COL_PROPERTY] = len;1349}13501351/*1352* 'VALUE' column. The first property is always the 'name'1353* property that was tacked on either by /sbin/zfs's1354* zfs_do_get() or when calling zprop_expand_list(), so we1355* ignore its width. If the user specified the name property1356* to display, then it will be later in the list in any case.1357*/1358if (pl != cbp->cb_proplist &&1359pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])1360cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;13611362/* 'RECEIVED' column. */1363if (pl != cbp->cb_proplist &&1364pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])1365cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;13661367/*1368* 'NAME' and 'SOURCE' columns1369*/1370if (pl->pl_prop == ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :1371((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME :1372ZFS_PROP_NAME)) && pl->pl_width >1373cbp->cb_colwidths[GET_COL_NAME]) {1374cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;1375cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +1376strlen(dgettext(TEXT_DOMAIN, "inherited from"));1377}1378}13791380/*1381* Now go through and print the headers.1382*/1383for (i = 0; i < ZFS_GET_NCOLS; i++) {1384switch (cbp->cb_columns[i]) {1385case GET_COL_NAME:1386title = dgettext(TEXT_DOMAIN, "NAME");1387break;1388case GET_COL_PROPERTY:1389title = dgettext(TEXT_DOMAIN, "PROPERTY");1390break;1391case GET_COL_VALUE:1392title = dgettext(TEXT_DOMAIN, "VALUE");1393break;1394case GET_COL_RECVD:1395title = dgettext(TEXT_DOMAIN, "RECEIVED");1396break;1397case GET_COL_SOURCE:1398title = dgettext(TEXT_DOMAIN, "SOURCE");1399break;1400default:1401title = NULL;1402}14031404if (title != NULL) {1405if (i == (ZFS_GET_NCOLS - 1) ||1406cbp->cb_columns[i + 1] == GET_COL_NONE)1407(void) printf("%s", title);1408else1409(void) printf("%-*s ",1410cbp->cb_colwidths[cbp->cb_columns[i]],1411title);1412}1413}1414(void) printf("\n");1415}14161417/*1418* Add property value and source to provided nvlist, according to1419* settings in cb structure. Later to be printed in JSON format.1420*/1421int1422zprop_nvlist_one_property(const char *propname,1423const char *value, zprop_source_t sourcetype, const char *source,1424const char *recvd_value, nvlist_t *nvl, boolean_t as_int)1425{1426int ret = 0;1427nvlist_t *src_nv, *prop;1428boolean_t all_numeric = strspn(value, STR_NUMS) == strlen(value);1429src_nv = prop = NULL;14301431if ((nvlist_alloc(&prop, NV_UNIQUE_NAME, 0) != 0) ||1432(nvlist_alloc(&src_nv, NV_UNIQUE_NAME, 0) != 0)) {1433ret = -1;1434goto err;1435}14361437if (as_int && all_numeric) {1438uint64_t val;1439sscanf(value, "%lld", (u_longlong_t *)&val);1440if (nvlist_add_uint64(prop, "value", val) != 0) {1441ret = -1;1442goto err;1443}1444} else {1445if (nvlist_add_string(prop, "value", value) != 0) {1446ret = -1;1447goto err;1448}1449}14501451switch (sourcetype) {1452case ZPROP_SRC_NONE:1453if (nvlist_add_string(src_nv, "type", "NONE") != 0 ||1454(nvlist_add_string(src_nv, "data", "-") != 0)) {1455ret = -1;1456goto err;1457}1458break;1459case ZPROP_SRC_DEFAULT:1460if (nvlist_add_string(src_nv, "type", "DEFAULT") != 0 ||1461(nvlist_add_string(src_nv, "data", "-") != 0)) {1462ret = -1;1463goto err;1464}1465break;1466case ZPROP_SRC_LOCAL:1467if (nvlist_add_string(src_nv, "type", "LOCAL") != 0 ||1468(nvlist_add_string(src_nv, "data", "-") != 0)) {1469ret = -1;1470goto err;1471}1472break;1473case ZPROP_SRC_TEMPORARY:1474if (nvlist_add_string(src_nv, "type", "TEMPORARY") != 0 ||1475(nvlist_add_string(src_nv, "data", "-") != 0)) {1476ret = -1;1477goto err;1478}1479break;1480case ZPROP_SRC_INHERITED:1481if (nvlist_add_string(src_nv, "type", "INHERITED") != 0 ||1482(nvlist_add_string(src_nv, "data", source) != 0)) {1483ret = -1;1484goto err;1485}1486break;1487case ZPROP_SRC_RECEIVED:1488if (nvlist_add_string(src_nv, "type", "RECEIVED") != 0 ||1489(nvlist_add_string(src_nv, "data",1490(recvd_value == NULL ? "-" : recvd_value)) != 0)) {1491ret = -1;1492goto err;1493}1494break;1495default:1496assert(!"unhandled zprop_source_t");1497if (nvlist_add_string(src_nv, "type",1498"unhandled zprop_source_t") != 0) {1499ret = -1;1500goto err;1501}1502}1503if ((nvlist_add_nvlist(prop, "source", src_nv) != 0) ||1504(nvlist_add_nvlist(nvl, propname, prop)) != 0) {1505ret = -1;1506goto err;1507}1508err:1509nvlist_free(src_nv);1510nvlist_free(prop);1511return (ret);1512}15131514/*1515* Display a single line of output, according to the settings in the callback1516* structure.1517*/1518void1519zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,1520const char *propname, const char *value, zprop_source_t sourcetype,1521const char *source, const char *recvd_value)1522{1523int i;1524const char *str = NULL;1525char buf[128];15261527/*1528* Ignore those source types that the user has chosen to ignore.1529*/1530if ((sourcetype & cbp->cb_sources) == 0)1531return;15321533if (cbp->cb_first)1534zprop_print_headers(cbp, cbp->cb_type);15351536for (i = 0; i < ZFS_GET_NCOLS; i++) {1537switch (cbp->cb_columns[i]) {1538case GET_COL_NAME:1539str = name;1540break;15411542case GET_COL_PROPERTY:1543str = propname;1544break;15451546case GET_COL_VALUE:1547str = value;1548break;15491550case GET_COL_SOURCE:1551switch (sourcetype) {1552case ZPROP_SRC_NONE:1553str = "-";1554break;15551556case ZPROP_SRC_DEFAULT:1557str = "default";1558break;15591560case ZPROP_SRC_LOCAL:1561str = "local";1562break;15631564case ZPROP_SRC_TEMPORARY:1565str = "temporary";1566break;15671568case ZPROP_SRC_INHERITED:1569(void) snprintf(buf, sizeof (buf),1570"inherited from %s", source);1571str = buf;1572break;1573case ZPROP_SRC_RECEIVED:1574str = "received";1575break;15761577default:1578str = NULL;1579assert(!"unhandled zprop_source_t");1580}1581break;15821583case GET_COL_RECVD:1584str = (recvd_value == NULL ? "-" : recvd_value);1585break;15861587default:1588continue;1589}15901591if (i == (ZFS_GET_NCOLS - 1) ||1592cbp->cb_columns[i + 1] == GET_COL_NONE)1593(void) printf("%s", str);1594else if (cbp->cb_scripted)1595(void) printf("%s\t", str);1596else1597(void) printf("%-*s ",1598cbp->cb_colwidths[cbp->cb_columns[i]],1599str);1600}16011602(void) printf("\n");1603}16041605int1606zprop_collect_property(const char *name, zprop_get_cbdata_t *cbp,1607const char *propname, const char *value, zprop_source_t sourcetype,1608const char *source, const char *recvd_value, nvlist_t *nvl)1609{1610if (cbp->cb_json) {1611if ((sourcetype & cbp->cb_sources) == 0)1612return (0);1613else {1614return (zprop_nvlist_one_property(propname, value,1615sourcetype, source, recvd_value, nvl,1616cbp->cb_json_as_int));1617}1618} else {1619zprop_print_one_property(name, cbp,1620propname, value, sourcetype, source, recvd_value);1621return (0);1622}1623}16241625/*1626* Given a numeric suffix, convert the value into a number of bits that the1627* resulting value must be shifted.1628*/1629static int1630str2shift(libzfs_handle_t *hdl, const char *buf)1631{1632const char *ends = "BKMGTPEZ";1633int i, len;16341635if (buf[0] == '\0')1636return (0);16371638len = strlen(ends);1639for (i = 0; i < len; i++) {1640if (toupper(buf[0]) == ends[i])1641break;1642}1643if (i == len) {1644if (hdl)1645zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1646"invalid numeric suffix '%s'"), buf);1647return (-1);1648}16491650/*1651* Allow 'G' = 'GB' = 'GiB', case-insensitively.1652* However, 'BB' and 'BiB' are disallowed.1653*/1654if (buf[1] == '\0' ||1655(toupper(buf[0]) != 'B' &&1656((toupper(buf[1]) == 'B' && buf[2] == '\0') ||1657(toupper(buf[1]) == 'I' && toupper(buf[2]) == 'B' &&1658buf[3] == '\0'))))1659return (10 * i);16601661if (hdl)1662zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1663"invalid numeric suffix '%s'"), buf);1664return (-1);1665}16661667/*1668* Convert a string of the form '100G' into a real number. Used when setting1669* properties or creating a volume. 'buf' is used to place an extended error1670* message for the caller to use.1671*/1672int1673zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)1674{1675char *end;1676int shift;16771678*num = 0;16791680/* Check to see if this looks like a number. */1681if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {1682if (hdl)1683zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1684"bad numeric value '%s'"), value);1685return (-1);1686}16871688/* Rely on strtoull() to process the numeric portion. */1689errno = 0;1690*num = strtoull(value, &end, 10);16911692/*1693* Check for ERANGE, which indicates that the value is too large to fit1694* in a 64-bit value.1695*/1696if (errno == ERANGE) {1697if (hdl)1698zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1699"numeric value is too large"));1700return (-1);1701}17021703/*1704* If we have a decimal value, then do the computation with floating1705* point arithmetic. Otherwise, use standard arithmetic.1706*/1707if (*end == '.') {1708double fval = strtod(value, &end);17091710if ((shift = str2shift(hdl, end)) == -1)1711return (-1);17121713fval *= pow(2, shift);17141715/*1716* UINT64_MAX is not exactly representable as a double.1717* The closest representation is UINT64_MAX + 1, so we1718* use a >= comparison instead of > for the bounds check.1719*/1720if (fval >= (double)UINT64_MAX) {1721if (hdl)1722zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1723"numeric value is too large"));1724return (-1);1725}17261727*num = (uint64_t)fval;1728} else {1729if ((shift = str2shift(hdl, end)) == -1)1730return (-1);17311732/* Check for overflow */1733if (shift >= 64 || (*num << shift) >> shift != *num) {1734if (hdl)1735zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1736"numeric value is too large"));1737return (-1);1738}17391740*num <<= shift;1741}17421743return (0);1744}17451746/*1747* Given a propname=value nvpair to set, parse any numeric properties1748* (index, boolean, etc) if they are specified as strings and add the1749* resulting nvpair to the returned nvlist.1750*1751* At the DSL layer, all properties are either 64-bit numbers or strings.1752* We want the user to be able to ignore this fact and specify properties1753* as native values (numbers, for example) or as strings (to simplify1754* command line utilities). This also handles converting index types1755* (compression, checksum, etc) from strings to their on-disk index.1756*/1757int1758zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,1759zfs_type_t type, nvlist_t *ret, const char **svalp, uint64_t *ivalp,1760const char *errbuf)1761{1762data_type_t datatype = nvpair_type(elem);1763zprop_type_t proptype;1764const char *propname;1765const char *value;1766boolean_t isnone = B_FALSE;1767boolean_t isauto = B_FALSE;1768int err = 0;17691770if (type == ZFS_TYPE_POOL) {1771proptype = zpool_prop_get_type(prop);1772propname = zpool_prop_to_name(prop);1773} else if (type == ZFS_TYPE_VDEV) {1774proptype = vdev_prop_get_type(prop);1775propname = vdev_prop_to_name(prop);1776} else {1777proptype = zfs_prop_get_type(prop);1778propname = zfs_prop_to_name(prop);1779}17801781/*1782* Convert any properties to the internal DSL value types.1783*/1784*svalp = NULL;1785*ivalp = 0;17861787switch (proptype) {1788case PROP_TYPE_STRING:1789if (datatype != DATA_TYPE_STRING) {1790zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1791"'%s' must be a string"), nvpair_name(elem));1792goto error;1793}1794err = nvpair_value_string(elem, svalp);1795if (err != 0) {1796zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1797"'%s' is invalid"), nvpair_name(elem));1798goto error;1799}1800if (strlen(*svalp) >= ZFS_MAXPROPLEN) {1801zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1802"'%s' is too long"), nvpair_name(elem));1803goto error;1804}1805break;18061807case PROP_TYPE_NUMBER:1808if (datatype == DATA_TYPE_STRING) {1809(void) nvpair_value_string(elem, &value);1810if (strcmp(value, "none") == 0) {1811isnone = B_TRUE;1812} else if (strcmp(value, "auto") == 0) {1813isauto = B_TRUE;1814} else if (zfs_nicestrtonum(hdl, value, ivalp) != 0) {1815goto error;1816}1817} else if (datatype == DATA_TYPE_UINT64) {1818(void) nvpair_value_uint64(elem, ivalp);1819} else {1820zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1821"'%s' must be a number"), nvpair_name(elem));1822goto error;1823}18241825/*1826* Quota special: force 'none' and don't allow 0.1827*/1828if ((type & ZFS_TYPE_DATASET) && *ivalp == 0 && !isnone &&1829(prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_REFQUOTA)) {1830zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1831"use 'none' to disable quota/refquota"));1832goto error;1833}1834/*1835* Pool dedup table quota; force use of 'none' instead of 01836*/1837if ((type & ZFS_TYPE_POOL) && *ivalp == 0 &&1838(!isnone && !isauto) &&1839prop == ZPOOL_PROP_DEDUP_TABLE_QUOTA) {1840zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1841"use 'none' to disable ddt table quota"));1842goto error;1843}18441845/*1846* Special handling for "*_limit=none". In this case it's not1847* 0 but UINT64_MAX.1848*/1849if ((type & ZFS_TYPE_DATASET) && isnone &&1850(prop == ZFS_PROP_FILESYSTEM_LIMIT ||1851prop == ZFS_PROP_SNAPSHOT_LIMIT)) {1852*ivalp = UINT64_MAX;1853}18541855/*1856* Special handling for "checksum_*=none". In this case it's not1857* 0 but UINT64_MAX.1858*/1859if ((type & ZFS_TYPE_VDEV) && isnone &&1860(prop == VDEV_PROP_CHECKSUM_N ||1861prop == VDEV_PROP_CHECKSUM_T ||1862prop == VDEV_PROP_IO_N ||1863prop == VDEV_PROP_IO_T ||1864prop == VDEV_PROP_SLOW_IO_N ||1865prop == VDEV_PROP_SLOW_IO_T)) {1866*ivalp = UINT64_MAX;1867}18681869/*1870* Special handling for setting 'refreservation' to 'auto'. Use1871* UINT64_MAX to tell the caller to use zfs_fix_auto_resv().1872* 'auto' is only allowed on volumes.1873*/1874if (isauto) {1875switch (prop) {1876case ZFS_PROP_REFRESERVATION:1877if ((type & ZFS_TYPE_VOLUME) == 0) {1878zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1879"'%s=auto' only allowed on "1880"volumes"), nvpair_name(elem));1881goto error;1882}1883*ivalp = UINT64_MAX;1884break;1885case ZPOOL_PROP_DEDUP_TABLE_QUOTA:1886ASSERT(type & ZFS_TYPE_POOL);1887*ivalp = UINT64_MAX;1888break;1889default:1890zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1891"'auto' is invalid value for '%s'"),1892nvpair_name(elem));1893goto error;1894}1895}18961897break;18981899case PROP_TYPE_INDEX:1900if (datatype != DATA_TYPE_STRING) {1901zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1902"'%s' must be a string"), nvpair_name(elem));1903goto error;1904}19051906(void) nvpair_value_string(elem, &value);19071908if (zprop_string_to_index(prop, value, ivalp, type) != 0) {1909zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1910"'%s' must be one of '%s'"), propname,1911zprop_values(prop, type));1912goto error;1913}1914break;19151916default:1917abort();1918}19191920/*1921* Add the result to our return set of properties.1922*/1923if (*svalp != NULL) {1924if (nvlist_add_string(ret, propname, *svalp) != 0) {1925(void) no_memory(hdl);1926return (-1);1927}1928} else {1929if (nvlist_add_uint64(ret, propname, *ivalp) != 0) {1930(void) no_memory(hdl);1931return (-1);1932}1933}19341935return (0);1936error:1937(void) zfs_error(hdl, EZFS_BADPROP, errbuf);1938return (-1);1939}19401941static int1942addlist(libzfs_handle_t *hdl, const char *propname, zprop_list_t **listp,1943zfs_type_t type)1944{1945int prop = zprop_name_to_prop(propname, type);1946if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type, B_FALSE))1947prop = ZPROP_INVAL;19481949/*1950* Return failure if no property table entry was found and this isn't1951* a user-defined property.1952*/1953if (prop == ZPROP_USERPROP && ((type == ZFS_TYPE_POOL &&1954!zfs_prop_user(propname) &&1955!zpool_prop_feature(propname) &&1956!zpool_prop_unsupported(propname)) ||1957((type == ZFS_TYPE_DATASET) && !zfs_prop_user(propname) &&1958!zfs_prop_userquota(propname) && !zfs_prop_written(propname)) ||1959((type == ZFS_TYPE_VDEV) && !vdev_prop_user(propname)))) {1960zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1961"invalid property '%s'"), propname);1962return (zfs_error(hdl, EZFS_BADPROP,1963dgettext(TEXT_DOMAIN, "bad property list")));1964}19651966zprop_list_t *entry = zfs_alloc(hdl, sizeof (*entry));19671968entry->pl_prop = prop;1969if (prop == ZPROP_USERPROP) {1970entry->pl_user_prop = zfs_strdup(hdl, propname);1971entry->pl_width = strlen(propname);1972} else {1973entry->pl_width = zprop_width(prop, &entry->pl_fixed,1974type);1975}19761977*listp = entry;19781979return (0);1980}19811982/*1983* Given a comma-separated list of properties, construct a property list1984* containing both user-defined and native properties. This function will1985* return a NULL list if 'all' is specified, which can later be expanded1986* by zprop_expand_list().1987*/1988int1989zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,1990zfs_type_t type)1991{1992*listp = NULL;19931994/*1995* If 'all' is specified, return a NULL list.1996*/1997if (strcmp(props, "all") == 0)1998return (0);19992000/*2001* If no props were specified, return an error.2002*/2003if (props[0] == '\0') {2004zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2005"no properties specified"));2006return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,2007"bad property list")));2008}20092010for (char *p; (p = strsep(&props, ",")); )2011if (strcmp(p, "space") == 0) {2012static const char *const spaceprops[] = {2013"name", "avail", "used", "usedbysnapshots",2014"usedbydataset", "usedbyrefreservation",2015"usedbychildren"2016};20172018for (int i = 0; i < ARRAY_SIZE(spaceprops); i++) {2019if (addlist(hdl, spaceprops[i], listp, type))2020return (-1);2021listp = &(*listp)->pl_next;2022}2023} else {2024if (addlist(hdl, p, listp, type))2025return (-1);2026listp = &(*listp)->pl_next;2027}20282029return (0);2030}20312032void2033zprop_free_list(zprop_list_t *pl)2034{2035zprop_list_t *next;20362037while (pl != NULL) {2038next = pl->pl_next;2039free(pl->pl_user_prop);2040free(pl);2041pl = next;2042}2043}20442045typedef struct expand_data {2046zprop_list_t **last;2047libzfs_handle_t *hdl;2048zfs_type_t type;2049} expand_data_t;20502051static int2052zprop_expand_list_cb(int prop, void *cb)2053{2054zprop_list_t *entry;2055expand_data_t *edp = cb;20562057entry = zfs_alloc(edp->hdl, sizeof (zprop_list_t));20582059entry->pl_prop = prop;2060entry->pl_width = zprop_width(prop, &entry->pl_fixed, edp->type);2061entry->pl_all = B_TRUE;20622063*(edp->last) = entry;2064edp->last = &entry->pl_next;20652066return (ZPROP_CONT);2067}20682069int2070zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type)2071{2072zprop_list_t *entry;2073zprop_list_t **last;2074expand_data_t exp;20752076if (*plp == NULL) {2077/*2078* If this is the very first time we've been called for an 'all'2079* specification, expand the list to include all native2080* properties.2081*/2082last = plp;20832084exp.last = last;2085exp.hdl = hdl;2086exp.type = type;20872088if (zprop_iter_common(zprop_expand_list_cb, &exp, B_FALSE,2089B_FALSE, type) == ZPROP_INVAL)2090return (-1);20912092/*2093* Add 'name' to the beginning of the list, which is handled2094* specially.2095*/2096entry = zfs_alloc(hdl, sizeof (zprop_list_t));2097entry->pl_prop = ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :2098((type == ZFS_TYPE_VDEV) ? VDEV_PROP_NAME : ZFS_PROP_NAME));2099entry->pl_width = zprop_width(entry->pl_prop,2100&entry->pl_fixed, type);2101entry->pl_all = B_TRUE;2102entry->pl_next = *plp;2103*plp = entry;2104}2105return (0);2106}21072108int2109zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,2110zfs_type_t type)2111{2112return (zprop_iter_common(func, cb, show_all, ordered, type));2113}21142115const char *2116zfs_version_userland(void)2117{2118return (ZFS_META_ALIAS);2119}21202121/*2122* Prints both zfs userland and kernel versions2123* Returns 0 on success, and -1 on error2124*/2125int2126zfs_version_print(void)2127{2128(void) puts(ZFS_META_ALIAS);21292130char *kver = zfs_version_kernel();2131if (kver == NULL) {2132fprintf(stderr, "zfs_version_kernel() failed: %s\n",2133zfs_strerror(errno));2134return (-1);2135}21362137(void) printf("zfs-kmod-%s\n", kver);2138free(kver);2139return (0);2140}21412142/*2143* Returns an nvlist with both zfs userland and kernel versions.2144* Returns NULL on error.2145*/2146nvlist_t *2147zfs_version_nvlist(void)2148{2149nvlist_t *nvl;2150char kmod_ver[64];2151if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)2152return (NULL);2153if (nvlist_add_string(nvl, "userland", ZFS_META_ALIAS) != 0)2154goto err;2155char *kver = zfs_version_kernel();2156if (kver == NULL) {2157fprintf(stderr, "zfs_version_kernel() failed: %s\n",2158zfs_strerror(errno));2159goto err;2160}2161(void) snprintf(kmod_ver, 64, "zfs-kmod-%s", kver);2162if (nvlist_add_string(nvl, "kernel", kmod_ver) != 0)2163goto err;2164return (nvl);2165err:2166nvlist_free(nvl);2167return (NULL);2168}21692170/*2171* Return 1 if the user requested ANSI color output, and our terminal supports2172* it. Return 0 for no color.2173*/2174int2175use_color(void)2176{2177static int use_color = -1;2178char *term;21792180/*2181* Optimization:2182*2183* For each zpool invocation, we do a single check to see if we should2184* be using color or not, and cache that value for the lifetime of the2185* the zpool command. That makes it cheap to call use_color() when2186* we're printing with color. We assume that the settings are not going2187* to change during the invocation of a zpool command (the user isn't2188* going to change the ZFS_COLOR value while zpool is running, for2189* example).2190*/2191if (use_color != -1) {2192/*2193* We've already figured out if we should be using color or2194* not. Return the cached value.2195*/2196return (use_color);2197}21982199term = getenv("TERM");2200/*2201* The user sets the ZFS_COLOR env var set to enable zpool ANSI color2202* output. However if NO_COLOR is set (https://no-color.org/) then2203* don't use it. Also, don't use color if terminal doesn't support2204* it.2205*/2206if (libzfs_envvar_is_set("ZFS_COLOR") &&2207!libzfs_envvar_is_set("NO_COLOR") &&2208isatty(STDOUT_FILENO) && term && strcmp("dumb", term) != 0 &&2209strcmp("unknown", term) != 0) {2210/* Color supported */2211use_color = 1;2212} else {2213use_color = 0;2214}22152216return (use_color);2217}22182219/*2220* The functions color_start() and color_end() are used for when you want2221* to colorize a block of text.2222*2223* For example:2224* color_start(ANSI_RED)2225* printf("hello");2226* printf("world");2227* color_end();2228*/2229void2230color_start(const char *color)2231{2232if (color && use_color()) {2233fputs(color, stdout);2234fflush(stdout);2235}2236}22372238void2239color_end(void)2240{2241if (use_color()) {2242fputs(ANSI_RESET, stdout);2243fflush(stdout);2244}22452246}22472248/*2249* printf() with a color. If color is NULL, then do a normal printf.2250*/2251int2252printf_color(const char *color, const char *format, ...)2253{2254va_list aptr;2255int rc;22562257if (color)2258color_start(color);22592260va_start(aptr, format);2261rc = vprintf(format, aptr);2262va_end(aptr);22632264if (color)2265color_end();22662267return (rc);2268}22692270/* PATH + 5 env vars + a NULL entry = 7 */2271#define ZPOOL_VDEV_SCRIPT_ENV_COUNT 722722273/*2274* There's a few places where ZFS will call external scripts (like the script2275* in zpool.d/ and `zfs_prepare_disk`). These scripts are called with a2276* reduced $PATH, and some vdev specific environment vars set. This function2277* will allocate an populate the environment variable array that is passed to2278* these scripts. The user must free the arrays with zpool_vdev_free_env() when2279* they are done.2280*2281* The following env vars will be set (but value could be blank):2282*2283* POOL_NAME2284* VDEV_PATH2285* VDEV_UPATH2286* VDEV_ENC_SYSFS_PATH2287*2288* In addition, you can set an optional environment variable named 'opt_key'2289* to 'opt_val' if you want.2290*2291* Returns allocated env[] array on success, NULL otherwise.2292*/2293char **2294zpool_vdev_script_alloc_env(const char *pool_name,2295const char *vdev_path, const char *vdev_upath,2296const char *vdev_enc_sysfs_path, const char *opt_key, const char *opt_val)2297{2298char **env = NULL;2299int rc;23002301env = calloc(ZPOOL_VDEV_SCRIPT_ENV_COUNT, sizeof (*env));2302if (!env)2303return (NULL);23042305env[0] = strdup("PATH=/bin:/sbin:/usr/bin:/usr/sbin");2306if (!env[0])2307goto error;23082309/* Setup our custom environment variables */2310rc = asprintf(&env[1], "POOL_NAME=%s", pool_name ? pool_name : "");2311if (rc == -1) {2312env[1] = NULL;2313goto error;2314}23152316rc = asprintf(&env[2], "VDEV_PATH=%s", vdev_path ? vdev_path : "");2317if (rc == -1) {2318env[2] = NULL;2319goto error;2320}23212322rc = asprintf(&env[3], "VDEV_UPATH=%s", vdev_upath ? vdev_upath : "");2323if (rc == -1) {2324env[3] = NULL;2325goto error;2326}23272328rc = asprintf(&env[4], "VDEV_ENC_SYSFS_PATH=%s",2329vdev_enc_sysfs_path ? vdev_enc_sysfs_path : "");2330if (rc == -1) {2331env[4] = NULL;2332goto error;2333}23342335if (opt_key != NULL) {2336rc = asprintf(&env[5], "%s=%s", opt_key,2337opt_val ? opt_val : "");2338if (rc == -1) {2339env[5] = NULL;2340goto error;2341}2342}23432344return (env);23452346error:2347for (int i = 0; i < ZPOOL_VDEV_SCRIPT_ENV_COUNT; i++)2348free(env[i]);23492350free(env);23512352return (NULL);2353}23542355/*2356* Free the env[] array that was allocated by zpool_vdev_script_alloc_env().2357*/2358void2359zpool_vdev_script_free_env(char **env)2360{2361for (int i = 0; i < ZPOOL_VDEV_SCRIPT_ENV_COUNT; i++)2362free(env[i]);23632364free(env);2365}23662367/*2368* Prepare a disk by (optionally) running a program before labeling the disk.2369* This can be useful for installing disk firmware or doing some pre-flight2370* checks on the disk before it becomes part of the pool. The program run is2371* located at ZFSEXECDIR/zfs_prepare_disk2372* (E.x: /usr/local/libexec/zfs/zfs_prepare_disk).2373*2374* Return 0 on success, non-zero on failure.2375*/2376int2377zpool_prepare_disk(zpool_handle_t *zhp, nvlist_t *vdev_nv,2378const char *prepare_str, char **lines[], int *lines_cnt)2379{2380const char *script_path = ZFSEXECDIR "/zfs_prepare_disk";2381const char *pool_name;2382int rc = 0;23832384/* Path to script and a NULL entry */2385char *argv[2] = {(char *)script_path};2386char **env = NULL;2387const char *path = NULL, *enc_sysfs_path = NULL;2388char *upath;2389*lines_cnt = 0;23902391if (access(script_path, X_OK) != 0) {2392/* No script, nothing to do */2393return (0);2394}23952396(void) nvlist_lookup_string(vdev_nv, ZPOOL_CONFIG_PATH, &path);2397(void) nvlist_lookup_string(vdev_nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,2398&enc_sysfs_path);23992400upath = zfs_get_underlying_path(path);2401pool_name = zhp ? zpool_get_name(zhp) : NULL;24022403env = zpool_vdev_script_alloc_env(pool_name, path, upath,2404enc_sysfs_path, "VDEV_PREPARE", prepare_str);24052406free(upath);24072408if (env == NULL) {2409return (ENOMEM);2410}24112412rc = libzfs_run_process_get_stdout(script_path, argv, env, lines,2413lines_cnt);24142415zpool_vdev_script_free_env(env);24162417return (rc);2418}24192420/*2421* Optionally run a script and then label a disk. The script can be used to2422* prepare a disk for inclusion into the pool. For example, it might update2423* the disk's firmware or check its health.2424*2425* The 'name' provided is the short name, stripped of any leading2426* /dev path, and is passed to zpool_label_disk. vdev_nv is the nvlist for2427* the vdev. prepare_str is a string that gets passed as the VDEV_PREPARE2428* env variable to the script.2429*2430* The following env vars are passed to the script:2431*2432* POOL_NAME: The pool name (blank during zpool create)2433* VDEV_PREPARE: Reason why the disk is being prepared for inclusion:2434* "create", "add", "replace", or "autoreplace"2435* VDEV_PATH: Path to the disk2436* VDEV_UPATH: One of the 'underlying paths' to the disk. This is2437* useful for DM devices.2438* VDEV_ENC_SYSFS_PATH: Path to the disk's enclosure sysfs path, if available.2439*2440* Note, some of these values can be blank.2441*2442* Return 0 on success, non-zero otherwise.2443*/2444int2445zpool_prepare_and_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp,2446const char *name, nvlist_t *vdev_nv, const char *prepare_str,2447char **lines[], int *lines_cnt)2448{2449int rc;2450char vdev_path[MAXPATHLEN];2451(void) snprintf(vdev_path, sizeof (vdev_path), "%s/%s", DISK_ROOT,2452name);24532454/* zhp will be NULL when creating a pool */2455rc = zpool_prepare_disk(zhp, vdev_nv, prepare_str, lines, lines_cnt);2456if (rc != 0)2457return (rc);24582459rc = zpool_label_disk(hdl, zhp, name);2460return (rc);2461}246224632464